项目需求、任务以及模块精简
This commit is contained in:
@@ -93,19 +93,22 @@
|
||||
});
|
||||
};
|
||||
|
||||
const loadComponent = (vueName: string) => {
|
||||
const loadComponent = (vueName: string): Component => {
|
||||
return defineAsyncComponent({
|
||||
loader: () => import(`./components/${vueName}.vue`),
|
||||
delay: 200,
|
||||
timeout: 5000,
|
||||
onError(error) {
|
||||
console.error('加载组件失败', error);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
async function getChartList() {
|
||||
try {
|
||||
const reqParams = {
|
||||
ustatus: '1',
|
||||
chartCode: 'erp',
|
||||
ustatus: '1',
|
||||
chartCode: 'erp',
|
||||
};
|
||||
const res = await myChartInfoListAll(reqParams);
|
||||
chartData.value = res || [];
|
||||
@@ -132,7 +135,9 @@
|
||||
await getChartList();
|
||||
|
||||
const newComponentMap: ComponentMap = {};
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))];
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))].filter(
|
||||
(vueName) => vueName && vueName !== 'ChartTop',
|
||||
);
|
||||
for (const vueName of uniqueComponents) {
|
||||
if (vueName) {
|
||||
newComponentMap[vueName] = loadComponent(vueName);
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
import { ref, watch, onMounted, defineAsyncComponent } from 'vue';
|
||||
import type { Component } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import ChartTop from './components/ChartTop.vue';
|
||||
@@ -68,21 +68,22 @@
|
||||
});
|
||||
};
|
||||
|
||||
const loadComponent = async (vueName: string): Promise<Component | null> => {
|
||||
try {
|
||||
const module = await import(`./components/${vueName}.vue`);
|
||||
return module.default;
|
||||
} catch (error) {
|
||||
console.error('加载组件失败', error);
|
||||
return null;
|
||||
}
|
||||
const loadComponent = (vueName: string): Component => {
|
||||
return defineAsyncComponent({
|
||||
loader: () => import(`./components/${vueName}.vue`),
|
||||
delay: 200,
|
||||
timeout: 5000,
|
||||
onError(error) {
|
||||
console.error('加载组件失败', error);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
async function getChartList() {
|
||||
try {
|
||||
const reqParams = {
|
||||
ustatus: '1',
|
||||
chartCode: 'home',
|
||||
ustatus: '1',
|
||||
chartCode: 'home',
|
||||
};
|
||||
const res = await myChartInfoListAll(reqParams);
|
||||
chartData.value = res || [];
|
||||
@@ -95,15 +96,17 @@
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await getChartList();
|
||||
|
||||
|
||||
const newComponentMap: ComponentMap = {};
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))];
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))].filter(
|
||||
(vueName) => vueName && vueName !== 'ChartTop',
|
||||
);
|
||||
for (const vueName of uniqueComponents) {
|
||||
if (vueName) {
|
||||
newComponentMap[vueName] = loadComponent(vueName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
componentMap.value = newComponentMap;
|
||||
} catch (error) {
|
||||
console.error('加载图表数据失败:', error);
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
import { ref, watch, onMounted, defineAsyncComponent } from 'vue';
|
||||
import type { Component } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import ChartTop from './components/ChartTop.vue';
|
||||
@@ -68,21 +68,22 @@
|
||||
});
|
||||
};
|
||||
|
||||
const loadComponent = async (vueName: string): Promise<Component | null> => {
|
||||
try {
|
||||
const module = await import(`./components/${vueName}.vue`);
|
||||
return module.default;
|
||||
} catch (error) {
|
||||
console.error('加载组件失败', error);
|
||||
return null;
|
||||
}
|
||||
const loadComponent = (vueName: string): Component => {
|
||||
return defineAsyncComponent({
|
||||
loader: () => import(`./components/${vueName}.vue`),
|
||||
delay: 200,
|
||||
timeout: 5000,
|
||||
onError(error) {
|
||||
console.error('加载组件失败', error);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
async function getChartList() {
|
||||
try {
|
||||
const reqParams = {
|
||||
ustatus: '1',
|
||||
chartCode: 'sys',
|
||||
ustatus: '1',
|
||||
chartCode: 'sys',
|
||||
};
|
||||
const res = await myChartInfoListAll(reqParams);
|
||||
chartData.value = res || [];
|
||||
@@ -95,15 +96,17 @@
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await getChartList();
|
||||
|
||||
|
||||
const newComponentMap: ComponentMap = {};
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))];
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))].filter(
|
||||
(vueName) => vueName && vueName !== 'ChartTop',
|
||||
);
|
||||
for (const vueName of uniqueComponents) {
|
||||
if (vueName) {
|
||||
newComponentMap[vueName] = loadComponent(vueName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
componentMap.value = newComponentMap;
|
||||
} catch (error) {
|
||||
console.error('加载图表数据失败:', error);
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
import { ref, watch, onMounted, defineAsyncComponent } from 'vue';
|
||||
import type { Component } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import ChartTop from './components/ChartTop.vue';
|
||||
@@ -80,21 +80,22 @@
|
||||
});
|
||||
};
|
||||
|
||||
const loadComponent = async (vueName: string): Promise<Component | null> => {
|
||||
try {
|
||||
const module = await import(`./components/${vueName}.vue`);
|
||||
return module.default;
|
||||
} catch (error) {
|
||||
console.error('加载组件失败', error);
|
||||
return null;
|
||||
}
|
||||
const loadComponent = (vueName: string): Component => {
|
||||
return defineAsyncComponent({
|
||||
loader: () => import(`./components/${vueName}.vue`),
|
||||
delay: 200,
|
||||
timeout: 5000,
|
||||
onError(error) {
|
||||
console.error('加载组件失败', error);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
async function getChartList() {
|
||||
try {
|
||||
const reqParams = {
|
||||
ustatus: '1',
|
||||
chartCode: 'work',
|
||||
ustatus: '1',
|
||||
chartCode: 'work',
|
||||
};
|
||||
const res = await myChartInfoListAll(reqParams);
|
||||
chartData.value = res || [];
|
||||
@@ -107,15 +108,17 @@
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await getChartList();
|
||||
|
||||
|
||||
const newComponentMap: ComponentMap = {};
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))];
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))].filter(
|
||||
(vueName) => vueName && vueName !== 'ChartTop',
|
||||
);
|
||||
for (const vueName of uniqueComponents) {
|
||||
if (vueName) {
|
||||
newComponentMap[vueName] = loadComponent(vueName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
componentMap.value = newComponentMap;
|
||||
} catch (error) {
|
||||
console.error('加载图表数据失败:', error);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<template>
|
||||
<PageWrapper>
|
||||
<template #headerContent>
|
||||
|
||||
</template>
|
||||
<PageWrapper :contentFullHeight="true" :dense="true" title="false" contentClass="about-page-wrapper">
|
||||
<template #headerContent> </template>
|
||||
<div class="jeesite-workbench">
|
||||
<div class="workbench-layout">
|
||||
<div class="workbench-top">10% 区域</div>
|
||||
@@ -14,10 +12,10 @@
|
||||
<div class="workbench-col">30% 区域左侧</div>
|
||||
<div class="workbench-col">30% 区域右侧</div>
|
||||
</div>
|
||||
<div class="workbench-row">
|
||||
<div class="workbench-col">30% 区域左侧</div>
|
||||
<div class="workbench-col">30% 区域右侧</div>
|
||||
</div>
|
||||
<div class="workbench-row">
|
||||
<div class="workbench-col">30% 区域左侧</div>
|
||||
<div class="workbench-col">30% 区域右侧</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
@@ -34,28 +32,48 @@
|
||||
|
||||
<style lang="less">
|
||||
@dark-bg: #141414;
|
||||
@desktop-page-gap: 12px;
|
||||
@desktop-page-padding: 0;
|
||||
@desktop-card-radius: 10px;
|
||||
@desktop-card-border: 1px solid rgb(226 232 240);
|
||||
@desktop-card-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
@desktop-dark-border: rgb(51 65 85);
|
||||
|
||||
.about-page-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 0 !important;
|
||||
overflow: hidden !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.jeesite-workbench {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
margin: 0;
|
||||
background: #FFFFFF;
|
||||
border-radius: 10px;
|
||||
background: #ffffff;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-layout {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
gap: @desktop-page-gap;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 4px;
|
||||
padding: @desktop-page-padding;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border-radius: 10px;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-top {
|
||||
@@ -66,7 +84,7 @@
|
||||
.jeesite-workbench .workbench-row {
|
||||
display: flex;
|
||||
flex: 0 0 30%;
|
||||
gap: 12px;
|
||||
gap: @desktop-page-gap;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
@@ -75,9 +93,10 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgb(226 232 240);
|
||||
background: #FFFFFF;
|
||||
border-radius: @desktop-card-radius;
|
||||
border: @desktop-card-border;
|
||||
background: #ffffff;
|
||||
box-shadow: @desktop-card-shadow;
|
||||
color: rgb(71 85 105);
|
||||
}
|
||||
|
||||
@@ -94,8 +113,9 @@
|
||||
|
||||
html[data-theme='dark'] .jeesite-workbench .workbench-top,
|
||||
html[data-theme='dark'] .jeesite-workbench .workbench-col {
|
||||
border-color: rgb(51 65 85);
|
||||
border-color: @desktop-dark-border;
|
||||
background: @dark-bg !important;
|
||||
color: rgb(226 232 240);
|
||||
box-shadow: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-hover-bg: rgb(30 41 59);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.biz-apps-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -122,7 +126,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .biz-apps-card {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -131,12 +135,13 @@
|
||||
|
||||
.biz-apps-item {
|
||||
border-color: rgb(51 65 85);
|
||||
background: rgb(20, 20, 20);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
|
||||
&:hover {
|
||||
border-color: rgb(96 165 250);
|
||||
box-shadow: 0 14px 32px rgb(37 99 235 / 22%);
|
||||
background: @analysis-dark-hover-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
|
||||
&__name {
|
||||
|
||||
@@ -276,6 +276,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-hover-bg: rgb(30 41 59);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.host-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -413,7 +417,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .host-card {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -438,20 +442,21 @@
|
||||
}
|
||||
|
||||
.host-gauge-panel {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
|
||||
.metric-item {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
|
||||
&__label {
|
||||
color: rgb(148 163 184);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 12px 28px rgb(96 165 250 / 20%);
|
||||
background: @analysis-dark-hover-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +206,9 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@dark-bg: #141414;
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-hover-bg: rgb(30 41 59);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.notice-card {
|
||||
width: 100%;
|
||||
@@ -591,7 +593,7 @@
|
||||
|
||||
html[data-theme='dark'] .notice-card {
|
||||
box-shadow: none;
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -616,15 +618,27 @@
|
||||
.table-container {
|
||||
.el-table {
|
||||
--el-table-border-color: transparent;
|
||||
--el-table-header-bg-color: rgb(20, 20, 20);
|
||||
--el-table-header-bg-color: @analysis-dark-bg;
|
||||
--el-table-tr-bg-color: transparent;
|
||||
--el-table-row-hover-bg-color: rgb(30 41 59);
|
||||
--el-table-row-hover-bg-color: @analysis-dark-hover-bg;
|
||||
--el-table-text-color: rgb(148 163 184);
|
||||
--el-table-header-text-color: rgb(226 232 240);
|
||||
background: transparent;
|
||||
|
||||
th.el-table__cell {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
.el-loading-mask {
|
||||
background-color: rgb(20 20 20 / 72%);
|
||||
}
|
||||
|
||||
.el-loading-spinner .path {
|
||||
stroke: rgb(147 197 253);
|
||||
}
|
||||
|
||||
.el-loading-spinner .el-loading-text {
|
||||
color: rgb(203 213 225);
|
||||
}
|
||||
|
||||
th.el-table__cell,
|
||||
@@ -650,25 +664,25 @@
|
||||
|
||||
&__content-panel,
|
||||
&__attachments-panel {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
&__attachments-panel {
|
||||
border-color: rgb(51 65 85);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
&__content {
|
||||
color: rgb(226 232 240);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
border-color: rgb(51 65 85);
|
||||
}
|
||||
|
||||
&__attachment-item,
|
||||
&__attachments-empty {
|
||||
border-color: rgb(71 85 105);
|
||||
background: rgb(20, 20, 20);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
color: rgb(226 232 240);
|
||||
}
|
||||
|
||||
@@ -686,8 +700,8 @@
|
||||
|
||||
&__attachment-item:hover {
|
||||
border-color: rgb(96 165 250);
|
||||
background: rgb(37 99 235 / 22%);
|
||||
box-shadow: 0 14px 32px rgb(37 99 235 / 22%);
|
||||
background: @analysis-dark-hover-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
color: rgb(241 245 249);
|
||||
}
|
||||
|
||||
@@ -698,27 +712,27 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .notice-info-dialog {
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
--el-dialog-bg-color: rgb(20, 20, 20);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
--el-dialog-bg-color: @analysis-dark-bg;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
|
||||
.el-dialog {
|
||||
background: rgb(20, 20, 20) !important;
|
||||
--el-dialog-bg-color: rgb(20, 20, 20);
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
box-shadow: 0 14px 36px rgb(0 0 0 / 42%);
|
||||
background: @analysis-dark-bg !important;
|
||||
--el-dialog-bg-color: @analysis-dark-bg;
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
|
||||
.el-dialog__wrapper,
|
||||
.el-overlay-dialog,
|
||||
.el-dialog__content {
|
||||
background: rgb(20, 20, 20) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
.el-dialog__header {
|
||||
border-bottom: 1px solid rgb(51 65 85) !important;
|
||||
background: rgb(20, 20, 20) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
@@ -730,14 +744,14 @@
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
background: rgb(20, 20, 20) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
.el-dialog__header,
|
||||
.el-dialog__body,
|
||||
.el-dialog__footer {
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
.el-divider {
|
||||
@@ -746,7 +760,7 @@
|
||||
|
||||
.notice-dialog {
|
||||
&__attachments-title {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
color: rgb(226 232 240);
|
||||
}
|
||||
|
||||
|
||||
@@ -196,6 +196,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-hover-bg: rgb(30 41 59);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.oper-log-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -369,7 +373,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .oper-log-card {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -378,8 +382,8 @@
|
||||
|
||||
.query-panel,
|
||||
.table-panel {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
|
||||
.query-form {
|
||||
@@ -391,7 +395,7 @@
|
||||
:deep(.el-select__wrapper) {
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: 0 0 0 1px rgb(71 85 105) inset;
|
||||
}
|
||||
|
||||
@@ -404,7 +408,7 @@
|
||||
:deep(.el-select-dropdown),
|
||||
:deep(.el-popper),
|
||||
:deep(.el-select__popper.el-popper) {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
border-color: rgb(51 65 85);
|
||||
}
|
||||
|
||||
@@ -415,7 +419,7 @@
|
||||
:deep(.el-select-dropdown__item.hover),
|
||||
:deep(.el-select-dropdown__item:hover),
|
||||
:deep(.el-select-dropdown__item.is-hovering) {
|
||||
background: rgb(30 41 59);
|
||||
background: @analysis-dark-hover-bg;
|
||||
color: rgb(241 245 249);
|
||||
}
|
||||
|
||||
@@ -453,28 +457,28 @@
|
||||
}
|
||||
|
||||
:deep(.el-button) {
|
||||
--el-fill-color-blank: rgb(30 41 59);
|
||||
--el-bg-color: rgb(30 41 59);
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
border-color: rgb(71 85 105);
|
||||
background: rgb(30 41 59);
|
||||
background: @analysis-dark-bg;
|
||||
color: rgb(226 232 240);
|
||||
}
|
||||
|
||||
:deep(.el-button:hover) {
|
||||
border-color: rgb(96 165 250);
|
||||
background: rgb(37 99 235 / 22%);
|
||||
background: @analysis-dark-hover-bg;
|
||||
color: rgb(241 245 249);
|
||||
}
|
||||
|
||||
:deep(.el-button--primary) {
|
||||
border-color: rgb(59 130 246);
|
||||
background: rgb(37 99 235);
|
||||
border-color: rgb(96 165 250);
|
||||
background: @analysis-dark-bg;
|
||||
color: rgb(248 250 252);
|
||||
}
|
||||
|
||||
:deep(.el-button--primary:hover) {
|
||||
border-color: rgb(96 165 250);
|
||||
background: rgb(59 130 246);
|
||||
background: @analysis-dark-hover-bg;
|
||||
color: rgb(248 250 252);
|
||||
}
|
||||
}
|
||||
@@ -482,15 +486,15 @@
|
||||
.table-panel {
|
||||
.el-table {
|
||||
--el-table-border-color: transparent;
|
||||
--el-table-header-bg-color: rgb(20, 20, 20);
|
||||
--el-table-header-bg-color: @analysis-dark-bg;
|
||||
--el-table-tr-bg-color: transparent;
|
||||
--el-table-row-hover-bg-color: rgb(30 41 59);
|
||||
--el-table-row-hover-bg-color: @analysis-dark-hover-bg;
|
||||
--el-table-text-color: rgb(148 163 184);
|
||||
--el-table-header-text-color: rgb(226 232 240);
|
||||
background: transparent;
|
||||
|
||||
th.el-table__cell {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
th.el-table__cell,
|
||||
@@ -499,11 +503,23 @@
|
||||
}
|
||||
|
||||
.el-table__footer-wrapper td.el-table__cell {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
border-top: 1px solid rgb(51 65 85);
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.el-loading-mask {
|
||||
background-color: rgb(20 20 20 / 72%);
|
||||
}
|
||||
|
||||
.el-loading-spinner .path {
|
||||
stroke: rgb(147 197 253);
|
||||
}
|
||||
|
||||
.el-loading-spinner .el-loading-text {
|
||||
color: rgb(203 213 225);
|
||||
}
|
||||
|
||||
.el-table__footer-wrapper .cell {
|
||||
color: rgb(226 232 240);
|
||||
}
|
||||
@@ -517,7 +533,7 @@
|
||||
:deep(.el-pagination) {
|
||||
--el-pagination-text-color: rgb(226 232 240);
|
||||
--el-pagination-button-color: rgb(226 232 240);
|
||||
--el-pagination-button-bg-color: rgb(30 41 59);
|
||||
--el-pagination-button-bg-color: @analysis-dark-bg;
|
||||
--el-pagination-hover-color: rgb(147 197 253);
|
||||
}
|
||||
|
||||
@@ -525,7 +541,7 @@
|
||||
:deep(.btn-next),
|
||||
:deep(.el-pager li),
|
||||
:deep(.el-pagination button) {
|
||||
background: rgb(30 41 59) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
color: rgb(226 232 240) !important;
|
||||
}
|
||||
|
||||
@@ -578,7 +594,7 @@
|
||||
html[data-theme='dark'] .el-select-dropdown__item.hover,
|
||||
html[data-theme='dark'] .el-select-dropdown__item:hover,
|
||||
html[data-theme='dark'] .el-select-dropdown__item.is-hovering {
|
||||
background: rgb(30 41 59) !important;
|
||||
background: @analysis-dark-hover-bg !important;
|
||||
color: rgb(241 245 249) !important;
|
||||
}
|
||||
|
||||
@@ -590,7 +606,7 @@
|
||||
html[data-theme='dark'] .el-pagination .btn-next,
|
||||
html[data-theme='dark'] .el-pagination .el-pager li,
|
||||
html[data-theme='dark'] .el-pagination button {
|
||||
background: rgb(30 41 59) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
color: rgb(226 232 240) !important;
|
||||
}
|
||||
|
||||
@@ -632,7 +648,7 @@
|
||||
|
||||
html[data-theme='dark'] .oper-log-card .el-input.is-disabled .el-input__wrapper,
|
||||
html[data-theme='dark'] .oper-log-card .el-select.is-disabled .el-select__wrapper {
|
||||
background: rgb(30 41 59) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .oper-log-card .el-input__suffix,
|
||||
@@ -644,16 +660,16 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .oper-log-card .query-form__actions .el-button {
|
||||
--el-button-bg-color: rgb(30 41 59) !important;
|
||||
--el-button-bg-color: @analysis-dark-bg !important;
|
||||
--el-button-border-color: rgb(71 85 105) !important;
|
||||
--el-button-text-color: rgb(226 232 240) !important;
|
||||
--el-button-hover-bg-color: rgb(37 99 235 / 22%) !important;
|
||||
--el-button-hover-bg-color: @analysis-dark-hover-bg !important;
|
||||
--el-button-hover-border-color: rgb(96 165 250) !important;
|
||||
--el-button-hover-text-color: rgb(241 245 249) !important;
|
||||
--el-button-active-bg-color: rgb(37 99 235 / 28%) !important;
|
||||
--el-button-active-bg-color: @analysis-dark-hover-bg !important;
|
||||
--el-button-active-border-color: rgb(96 165 250) !important;
|
||||
--el-button-active-text-color: rgb(241 245 249) !important;
|
||||
background: rgb(30 41 59) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
border-color: rgb(71 85 105) !important;
|
||||
color: rgb(226 232 240) !important;
|
||||
box-shadow: none !important;
|
||||
@@ -661,26 +677,26 @@
|
||||
|
||||
html[data-theme='dark'] .oper-log-card .query-form__actions .el-button:hover,
|
||||
html[data-theme='dark'] .oper-log-card .query-form__actions .el-button:focus {
|
||||
background: rgb(37 99 235 / 22%) !important;
|
||||
background: @analysis-dark-hover-bg !important;
|
||||
border-color: rgb(96 165 250) !important;
|
||||
color: rgb(241 245 249) !important;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .oper-log-card .query-form__actions .el-button--primary {
|
||||
--el-button-bg-color: rgb(37 99 235) !important;
|
||||
--el-button-border-color: rgb(59 130 246) !important;
|
||||
--el-button-bg-color: @analysis-dark-bg !important;
|
||||
--el-button-border-color: rgb(96 165 250) !important;
|
||||
--el-button-text-color: rgb(248 250 252) !important;
|
||||
--el-button-hover-bg-color: rgb(59 130 246) !important;
|
||||
--el-button-hover-bg-color: @analysis-dark-hover-bg !important;
|
||||
--el-button-hover-border-color: rgb(96 165 250) !important;
|
||||
--el-button-hover-text-color: rgb(248 250 252) !important;
|
||||
background: rgb(37 99 235) !important;
|
||||
border-color: rgb(59 130 246) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
border-color: rgb(96 165 250) !important;
|
||||
color: rgb(248 250 252) !important;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .oper-log-card .query-form__actions .el-button--primary:hover,
|
||||
html[data-theme='dark'] .oper-log-card .query-form__actions .el-button--primary:focus {
|
||||
background: rgb(59 130 246) !important;
|
||||
background: @analysis-dark-hover-bg !important;
|
||||
border-color: rgb(96 165 250) !important;
|
||||
color: rgb(248 250 252) !important;
|
||||
}
|
||||
|
||||
@@ -184,6 +184,9 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.province-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -241,7 +244,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .province-card {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -253,8 +256,8 @@
|
||||
}
|
||||
|
||||
.province-chart-panel {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -157,6 +157,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-hover-bg: rgb(30 41 59);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.quick-login-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -292,7 +296,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .quick-login-card {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -301,12 +305,13 @@
|
||||
|
||||
.quick-login-item {
|
||||
border-color: rgb(51 65 85);
|
||||
background: rgb(20, 20, 20);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
|
||||
&:hover {
|
||||
border-color: rgb(96 165 250);
|
||||
box-shadow: 0 14px 32px rgb(37 99 235 / 22%);
|
||||
background: @analysis-dark-hover-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
|
||||
&__name {
|
||||
@@ -314,7 +319,7 @@
|
||||
}
|
||||
|
||||
&__image-wrap {
|
||||
background: rgb(30 41 59);
|
||||
background: @analysis-dark-bg;
|
||||
border-color: rgb(59 130 246 / 35%);
|
||||
box-shadow: 0 6px 14px rgb(37 99 235 / 16%);
|
||||
}
|
||||
|
||||
@@ -255,6 +255,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-hover-bg: rgb(30 41 59);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.notice-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -568,7 +572,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .notice-card {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -593,15 +597,27 @@
|
||||
.table-container {
|
||||
.el-table {
|
||||
--el-table-border-color: transparent;
|
||||
--el-table-header-bg-color: rgb(20, 20, 20);
|
||||
--el-table-header-bg-color: @analysis-dark-bg;
|
||||
--el-table-tr-bg-color: transparent;
|
||||
--el-table-row-hover-bg-color: rgb(30 41 59);
|
||||
--el-table-row-hover-bg-color: @analysis-dark-hover-bg;
|
||||
--el-table-text-color: rgb(148 163 184);
|
||||
--el-table-header-text-color: rgb(226 232 240);
|
||||
background: transparent;
|
||||
|
||||
th.el-table__cell {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
.el-loading-mask {
|
||||
background-color: rgb(20 20 20 / 72%);
|
||||
}
|
||||
|
||||
.el-loading-spinner .path {
|
||||
stroke: rgb(147 197 253);
|
||||
}
|
||||
|
||||
.el-loading-spinner .el-loading-text {
|
||||
color: rgb(203 213 225);
|
||||
}
|
||||
|
||||
th.el-table__cell,
|
||||
@@ -629,7 +645,7 @@
|
||||
&__form-panel,
|
||||
&__content,
|
||||
&__section-title {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
&__content {
|
||||
@@ -649,7 +665,7 @@
|
||||
&__textarea :deep(.el-textarea__inner) {
|
||||
border: 1px solid rgb(71 85 105) !important;
|
||||
border-color: rgb(71 85 105);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
color: rgb(226 232 240);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
@@ -668,38 +684,38 @@
|
||||
|
||||
&__textarea :deep(.el-input__count) {
|
||||
color: rgb(148 163 184);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .todo-info-dialog {
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
--el-dialog-bg-color: rgb(20, 20, 20);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
--el-dialog-bg-color: @analysis-dark-bg;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
|
||||
.el-dialog {
|
||||
background: rgb(20, 20, 20) !important;
|
||||
--el-dialog-bg-color: rgb(20, 20, 20);
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
box-shadow: 0 14px 36px rgb(0 0 0 / 42%);
|
||||
background: @analysis-dark-bg !important;
|
||||
--el-dialog-bg-color: @analysis-dark-bg;
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
|
||||
.el-dialog__wrapper,
|
||||
.el-overlay-dialog,
|
||||
.el-dialog__content {
|
||||
background: rgb(20, 20, 20) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
.el-dialog__header {
|
||||
border-bottom: 1px solid rgb(51 65 85) !important;
|
||||
background: rgb(20, 20, 20) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
.el-dialog__body,
|
||||
.el-dialog__footer {
|
||||
background: rgb(20, 20, 20) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
.el-textarea,
|
||||
@@ -708,8 +724,8 @@
|
||||
--el-input-border-color: rgb(71 85 105);
|
||||
--el-input-hover-border-color: rgb(96 165 250);
|
||||
--el-input-focus-border-color: rgb(96 165 250);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
background: rgb(20, 20, 20) !important;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
background: @analysis-dark-bg !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
@@ -728,8 +744,8 @@
|
||||
.el-dialog__header,
|
||||
.el-dialog__body,
|
||||
.el-dialog__footer {
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
.el-divider {
|
||||
@@ -742,26 +758,26 @@
|
||||
|
||||
.todo-dialog__footer {
|
||||
.el-button:not(.el-button--primary) {
|
||||
border-color: rgb(71 85 105);
|
||||
background: rgb(30 41 59);
|
||||
border-color: rgb(96 165 250);
|
||||
background: @analysis-dark-bg;
|
||||
color: rgb(226 232 240);
|
||||
}
|
||||
|
||||
.el-button:not(.el-button--primary):hover {
|
||||
border-color: rgb(96 165 250);
|
||||
background: rgb(37 99 235 / 22%);
|
||||
background: @analysis-dark-hover-bg;
|
||||
color: rgb(241 245 249);
|
||||
}
|
||||
|
||||
.el-button--primary {
|
||||
border-color: rgb(59 130 246);
|
||||
background: rgb(37 99 235);
|
||||
border-color: rgb(96 165 250);
|
||||
background: @analysis-dark-bg;
|
||||
color: rgb(248 250 252);
|
||||
}
|
||||
|
||||
.el-button--primary:hover {
|
||||
border-color: rgb(96 165 250);
|
||||
background: rgb(59 130 246);
|
||||
background: @analysis-dark-hover-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,12 @@
|
||||
</script>
|
||||
<style lang="less">
|
||||
@dark-bg: #141414;
|
||||
@desktop-page-gap: 12px;
|
||||
@desktop-page-padding: 0;
|
||||
@desktop-card-radius: 10px;
|
||||
@desktop-card-border: 1px solid rgb(226 232 240);
|
||||
@desktop-card-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
@desktop-dark-border: rgb(51 65 85);
|
||||
|
||||
.analysis-page-wrapper {
|
||||
display: flex;
|
||||
@@ -97,18 +103,19 @@
|
||||
--analysis-card-title-padding: 8px 16px;
|
||||
--analysis-card-content-padding: 8px 12px 12px;
|
||||
--analysis-card-item-gap: 8px;
|
||||
--analysis-card-radius: 10px;
|
||||
--analysis-gap: @desktop-page-gap;
|
||||
--analysis-card-radius: @desktop-card-radius;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
min-height: 0;
|
||||
gap: var(--analysis-gap);
|
||||
padding: 0;
|
||||
padding: @desktop-page-padding;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border-radius: 10px;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
.mySpring-analysis .analysis-left,
|
||||
@@ -148,16 +155,16 @@
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
border-radius: var(--analysis-card-radius);
|
||||
border: 1px solid rgb(226 232 240);
|
||||
border: @desktop-card-border;
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
box-shadow: @desktop-card-shadow;
|
||||
overflow: hidden;
|
||||
color: rgb(71 85 105);
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .mySpring-analysis .analysis-panel {
|
||||
border-color: rgb(51 65 85);
|
||||
border-color: @desktop-dark-border;
|
||||
background: @dark-bg !important;
|
||||
color: rgb(203 213 225);
|
||||
box-shadow: none;
|
||||
@@ -171,7 +178,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .mySpring-analysis {
|
||||
border-radius: 10px;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .mySpring-analysis,
|
||||
|
||||
@@ -0,0 +1,585 @@
|
||||
<template>
|
||||
<div ref="contractCardRef" class="contract-info-card">
|
||||
<div class="card-title">
|
||||
<span>项目合同</span>
|
||||
<el-button class="card-title__more" link type="primary" @click="goMore">更多</el-button>
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<div class="contract-overview">
|
||||
<div class="task-chart-panel task-chart-panel--pie">
|
||||
<div ref="pieChartRef" class="task-chart"></div>
|
||||
</div>
|
||||
|
||||
<div class="task-chart-panel task-chart-panel--bar">
|
||||
<div ref="barChartRef" class="task-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import * as echarts from 'echarts';
|
||||
import { MyProjectContract, myProjectContractListAll } from '@jeesite/biz/api/biz/myProjectContract';
|
||||
import { DictData, dictDataListData } from '@jeesite/core/api/sys/dictData';
|
||||
import { useUserStore } from '@jeesite/core/store/modules/user';
|
||||
import { firstCurrentYear, formatToDate } from '@jeesite/core/utils/dateUtil';
|
||||
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
const userinfo = computed(() => userStore.getUserInfo);
|
||||
|
||||
const contractCardRef = ref<HTMLElement>();
|
||||
const pieChartRef = ref<HTMLElement>();
|
||||
const barChartRef = ref<HTMLElement>();
|
||||
const sourceData = ref<MyProjectContract[]>([]);
|
||||
const statusDict = ref<DictData[]>([]);
|
||||
|
||||
const STATUS_COLORS = ['#3B82F6', '#10B981', '#F97316', '#EC4899', '#8B5CF6', '#06B6D4'];
|
||||
let pieChartInstance: echarts.ECharts | null = null;
|
||||
let barChartInstance: echarts.ECharts | null = null;
|
||||
let resizeObserver: ResizeObserver | null = null;
|
||||
let themeObserver: MutationObserver | null = null;
|
||||
|
||||
function goMore() {
|
||||
router.push('/biz/myProjectContract/list');
|
||||
}
|
||||
|
||||
const pieChartData = computed(() => {
|
||||
if (!statusDict.value.length) {
|
||||
const fallbackMap = new Map<string, number>();
|
||||
sourceData.value.forEach((item) => {
|
||||
const label = item.contractStatus || '未设置';
|
||||
fallbackMap.set(label, (fallbackMap.get(label) || 0) + 1);
|
||||
});
|
||||
return Array.from(fallbackMap.entries()).map(([name, value], index) => ({
|
||||
name,
|
||||
value,
|
||||
itemStyle: { color: STATUS_COLORS[index % STATUS_COLORS.length] },
|
||||
}));
|
||||
}
|
||||
|
||||
const countMap = new Map<string, number>();
|
||||
sourceData.value.forEach((item) => {
|
||||
const key = item.contractStatus || 'unknown';
|
||||
countMap.set(key, (countMap.get(key) || 0) + 1);
|
||||
});
|
||||
|
||||
return statusDict.value
|
||||
.map((item, index) => ({
|
||||
name: item.dictLabelRaw,
|
||||
value: countMap.get(item.dictValue || '') || 0,
|
||||
itemStyle: { color: STATUS_COLORS[index % STATUS_COLORS.length] },
|
||||
}))
|
||||
.filter((item) => item.value > 0);
|
||||
});
|
||||
|
||||
const barChartData = computed(() => {
|
||||
const statusItems = statusDict.value.length
|
||||
? statusDict.value.map((item, index) => ({
|
||||
key: item.dictValue,
|
||||
label: item.dictLabelRaw,
|
||||
color: STATUS_COLORS[index % STATUS_COLORS.length],
|
||||
}))
|
||||
: [];
|
||||
|
||||
const monthStatusMap = new Map<string, Map<string, number>>();
|
||||
const monthOrderMap = new Map<string, number>();
|
||||
|
||||
sourceData.value.forEach((item) => {
|
||||
if (!item.signDate) return;
|
||||
const date = new Date(item.signDate);
|
||||
if (Number.isNaN(date.getTime())) return;
|
||||
const monthLabel = `${date.getMonth() + 1}月`;
|
||||
monthOrderMap.set(monthLabel, date.getMonth() + 1);
|
||||
const statusKey = item.contractStatus || 'unknown';
|
||||
if (!monthStatusMap.has(monthLabel)) {
|
||||
monthStatusMap.set(monthLabel, new Map<string, number>());
|
||||
}
|
||||
const monthMap = monthStatusMap.get(monthLabel)!;
|
||||
monthMap.set(statusKey, (monthMap.get(statusKey) || 0) + 1);
|
||||
});
|
||||
|
||||
const months = Array.from(monthStatusMap.keys()).sort((a, b) => {
|
||||
return (monthOrderMap.get(a) || 0) - (monthOrderMap.get(b) || 0);
|
||||
});
|
||||
|
||||
const totalByMonth = months.map((month) => {
|
||||
const monthMap = monthStatusMap.get(month);
|
||||
return Array.from(monthMap?.values() || []).reduce((sum, count) => sum + count, 0);
|
||||
});
|
||||
|
||||
const fallbackStatusMap = new Map<string, number>();
|
||||
sourceData.value.forEach((item) => {
|
||||
if (!statusDict.value.length) {
|
||||
const key = item.contractStatus || '未设置';
|
||||
fallbackStatusMap.set(key, (fallbackStatusMap.get(key) || 0) + 1);
|
||||
}
|
||||
});
|
||||
|
||||
const fallbackSeries = Array.from(fallbackStatusMap.keys()).map((key, index) => ({
|
||||
key,
|
||||
label: key,
|
||||
color: STATUS_COLORS[index % STATUS_COLORS.length],
|
||||
}));
|
||||
|
||||
return {
|
||||
months,
|
||||
totals: totalByMonth,
|
||||
statusItems: statusItems.length ? statusItems : fallbackSeries,
|
||||
monthStatusMap,
|
||||
};
|
||||
});
|
||||
|
||||
async function getDict() {
|
||||
try {
|
||||
statusDict.value = await dictDataListData({ dictType: 'contract_status' });
|
||||
} catch (error) {
|
||||
statusDict.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
async function getList() {
|
||||
try {
|
||||
const reqParams = {
|
||||
createTime_gte: firstCurrentYear(),
|
||||
createUser: userinfo.value.loginCode,
|
||||
};
|
||||
const res = await myProjectContractListAll(reqParams);
|
||||
sourceData.value = res || [];
|
||||
} catch (error) {
|
||||
sourceData.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
function renderPieChart() {
|
||||
if (!pieChartRef.value) return;
|
||||
if (!pieChartInstance) {
|
||||
pieChartInstance = echarts.init(pieChartRef.value);
|
||||
}
|
||||
|
||||
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
|
||||
const total = pieChartData.value.reduce((sum, item) => sum + Number(item.value || 0), 0);
|
||||
const data = total
|
||||
? pieChartData.value
|
||||
: statusDict.value.map((item, index) => ({
|
||||
name: item.dictLabelRaw,
|
||||
value: 0,
|
||||
itemStyle: { color: STATUS_COLORS[index % STATUS_COLORS.length] },
|
||||
}));
|
||||
const legendData = statusDict.value.length
|
||||
? statusDict.value.map((item) => item.dictLabelRaw)
|
||||
: pieChartData.value.map((item) => item.name);
|
||||
const series: echarts.SeriesOption[] = [];
|
||||
|
||||
if (!total) {
|
||||
series.push({
|
||||
name: '空态环',
|
||||
type: 'pie',
|
||||
radius: ['46%', '72%'],
|
||||
center: ['50%', '44%'],
|
||||
silent: true,
|
||||
legendHoverLink: false,
|
||||
tooltip: {
|
||||
show: false,
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
itemStyle: {
|
||||
color: isDark ? 'rgba(148, 163, 184, 0.18)' : 'rgba(203, 213, 225, 0.55)',
|
||||
borderRadius: 10,
|
||||
borderColor: isDark ? '#141414' : '#ffffff',
|
||||
borderWidth: 3,
|
||||
},
|
||||
data: [{ name: 'empty-ring', value: 1 }],
|
||||
});
|
||||
}
|
||||
|
||||
series.push({
|
||||
name: '合同状态',
|
||||
type: 'pie',
|
||||
radius: total ? ['46%', '72%'] : [0, 0],
|
||||
center: ['50%', '44%'],
|
||||
avoidLabelOverlap: true,
|
||||
minAngle: total ? 4 : 0,
|
||||
itemStyle: {
|
||||
borderRadius: 10,
|
||||
borderColor: isDark ? '#141414' : '#ffffff',
|
||||
borderWidth: 3,
|
||||
},
|
||||
label: {
|
||||
show: total,
|
||||
formatter: ({ name, value, percent }) => (total ? `${name}\n${value}项 / ${percent}%` : ''),
|
||||
color: isDark ? '#e2e8f0' : '#334155',
|
||||
fontSize: 12,
|
||||
},
|
||||
emphasis: {
|
||||
scale: true,
|
||||
scaleSize: 6,
|
||||
},
|
||||
data,
|
||||
silent: !total,
|
||||
labelLine: {
|
||||
show: total,
|
||||
},
|
||||
});
|
||||
|
||||
pieChartInstance.setOption({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
backgroundColor: isDark ? 'rgba(20, 20, 20, 0.96)' : 'rgba(255, 255, 255, 0.96)',
|
||||
borderColor: isDark ? 'rgb(51 65 85)' : 'rgb(226 232 240)',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: isDark ? '#e2e8f0' : '#334155',
|
||||
},
|
||||
formatter: ({ name, value, percent }) => {
|
||||
if (!total) return `${name}<br/>数量:0`;
|
||||
return `${name}<br/>数量:${value}<br/>占比:${percent}%`;
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
show: legendData.length > 0,
|
||||
bottom: 4,
|
||||
left: 'center',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
data: legendData,
|
||||
textStyle: {
|
||||
color: isDark ? '#cbd5e1' : '#475569',
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
series,
|
||||
graphic: total
|
||||
? [
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: '34%',
|
||||
style: {
|
||||
text: '合同总数',
|
||||
fill: isDark ? '#94a3b8' : '#64748b',
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: '41%',
|
||||
style: {
|
||||
text: `${total}`,
|
||||
fill: isDark ? '#f8fafc' : '#0f172a',
|
||||
fontSize: 24,
|
||||
fontWeight: 700,
|
||||
},
|
||||
},
|
||||
]
|
||||
: [],
|
||||
});
|
||||
}
|
||||
|
||||
function renderBarChart() {
|
||||
if (!barChartRef.value) return;
|
||||
if (!barChartInstance) {
|
||||
barChartInstance = echarts.init(barChartRef.value);
|
||||
}
|
||||
|
||||
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
|
||||
const { months, totals, statusItems, monthStatusMap } = barChartData.value;
|
||||
const hasData = totals.some((item) => item > 0);
|
||||
const categories = months.length ? months : [];
|
||||
const series = statusItems.length
|
||||
? statusItems.map((status) => ({
|
||||
name: status.label,
|
||||
type: 'bar',
|
||||
stack: 'month-total',
|
||||
barWidth: '12%',
|
||||
itemStyle: {
|
||||
color: status.color,
|
||||
borderRadius: 0,
|
||||
},
|
||||
emphasis: {
|
||||
focus: 'series',
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inside',
|
||||
formatter: ({ value }) => (Number(value) > 0 ? `${value}` : ''),
|
||||
color: '#ffffff',
|
||||
fontSize: 11,
|
||||
},
|
||||
data: categories.map((month) => monthStatusMap.get(month)?.get(status.key) || 0),
|
||||
}))
|
||||
: [
|
||||
{
|
||||
type: 'bar',
|
||||
barWidth: '12%',
|
||||
itemStyle: {
|
||||
color: isDark ? '#334155' : '#E2E8F0',
|
||||
borderRadius: [10, 10, 0, 0],
|
||||
},
|
||||
data: categories.map(() => 0),
|
||||
},
|
||||
];
|
||||
|
||||
if (hasData) {
|
||||
series.push({
|
||||
name: '总数',
|
||||
type: 'bar',
|
||||
stack: 'month-total',
|
||||
silent: true,
|
||||
legendHoverLink: false,
|
||||
itemStyle: {
|
||||
color: 'rgba(0,0,0,0)',
|
||||
},
|
||||
tooltip: {
|
||||
show: false,
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
color: isDark ? '#cbd5e1' : '#475569',
|
||||
fontSize: 11,
|
||||
formatter: ({ dataIndex }) => (totals[dataIndex] > 0 ? `${totals[dataIndex]}` : ''),
|
||||
},
|
||||
data: categories.map(() => 0),
|
||||
z: 10,
|
||||
});
|
||||
}
|
||||
|
||||
barChartInstance.setOption({
|
||||
grid: {
|
||||
left: 12,
|
||||
right: 12,
|
||||
top: 52,
|
||||
bottom: 10,
|
||||
containLabel: true,
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
backgroundColor: isDark ? 'rgba(20, 20, 20, 0.96)' : 'rgba(255, 255, 255, 0.96)',
|
||||
borderColor: isDark ? 'rgb(51 65 85)' : 'rgb(226 232 240)',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: isDark ? '#e2e8f0' : '#334155',
|
||||
},
|
||||
formatter: (params) => {
|
||||
const dataIndex = params[0]?.dataIndex || 0;
|
||||
if (!hasData) return '';
|
||||
const lines = params
|
||||
.filter((item) => item.seriesName !== '总数' && Number(item.value) > 0)
|
||||
.map((item) => `${item.marker}${item.seriesName}:${item.value}项`);
|
||||
lines.push(`总数:${totals[dataIndex]}项`);
|
||||
return `${categories[dataIndex]}<br/>${lines.join('<br/>')}`;
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
top: 6,
|
||||
left: 'center',
|
||||
itemGap: 16,
|
||||
data: statusItems.map((item) => item.label),
|
||||
textStyle: {
|
||||
color: isDark ? '#e2e8f0' : '#475569',
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: categories,
|
||||
boundaryGap: ['2%', '2%'],
|
||||
axisTick: {
|
||||
alignWithLabel: true,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: isDark ? '#475569' : '#cbd5e1',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: isDark ? '#cbd5e1' : '#64748b',
|
||||
interval: 0,
|
||||
margin: 8,
|
||||
rotate: 30,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
minInterval: 1,
|
||||
name: '数量',
|
||||
nameTextStyle: {
|
||||
color: isDark ? '#94a3b8' : '#64748b',
|
||||
padding: [0, 0, 2, 0],
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: isDark ? 'rgba(71, 85, 105, 0.35)' : 'rgba(203, 213, 225, 0.55)',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: isDark ? '#94a3b8' : '#64748b',
|
||||
},
|
||||
},
|
||||
series,
|
||||
});
|
||||
}
|
||||
|
||||
function renderCharts() {
|
||||
renderPieChart();
|
||||
renderBarChart();
|
||||
}
|
||||
|
||||
function resizeCharts() {
|
||||
pieChartInstance?.resize();
|
||||
barChartInstance?.resize();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await Promise.all([getDict(), getList()]);
|
||||
await nextTick();
|
||||
renderCharts();
|
||||
|
||||
if (contractCardRef.value) {
|
||||
resizeObserver = new ResizeObserver(() => {
|
||||
resizeCharts();
|
||||
});
|
||||
resizeObserver.observe(contractCardRef.value);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', resizeCharts);
|
||||
|
||||
themeObserver = new MutationObserver(() => {
|
||||
nextTick(() => {
|
||||
renderCharts();
|
||||
});
|
||||
});
|
||||
themeObserver.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['data-theme'],
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
resizeObserver?.disconnect();
|
||||
themeObserver?.disconnect();
|
||||
window.removeEventListener('resize', resizeCharts);
|
||||
pieChartInstance?.dispose();
|
||||
barChartInstance?.dispose();
|
||||
pieChartInstance = null;
|
||||
barChartInstance = null;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@workbench-dark-panel-bg: rgb(20, 20, 20);
|
||||
@workbench-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.contract-info-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
color: rgb(51 65 85);
|
||||
border-bottom: 1px solid rgb(226 232 240);
|
||||
background: transparent;
|
||||
|
||||
&__more {
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.contract-overview {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(220px, 0.9fr) minmax(0, 1.6fr);
|
||||
gap: 12px;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.task-chart-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 0 8px 24px rgb(148 163 184 / 14%);
|
||||
}
|
||||
|
||||
.task-chart {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .contract-info-card {
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
border-bottom-color: rgb(51 65 85);
|
||||
|
||||
&__more:deep(.el-button) {
|
||||
color: rgb(147 197 253);
|
||||
}
|
||||
}
|
||||
|
||||
.task-chart-panel {
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.contract-info-card {
|
||||
.contract-overview {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.contract-info-card {
|
||||
.card-content {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.task-chart-panel {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.task-chart {
|
||||
min-height: 220px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -331,6 +331,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@workbench-dark-panel-bg: rgb(20, 20, 20);
|
||||
@workbench-dark-solid-bg: rgb(20, 20, 20);
|
||||
@workbench-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.note-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -508,14 +512,14 @@
|
||||
|
||||
.metric-item,
|
||||
.note-chart-panel {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
|
||||
.metric-item {
|
||||
&__pane {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
|
||||
&__extra,
|
||||
@@ -525,12 +529,12 @@
|
||||
|
||||
&__label {
|
||||
border-color: rgb(51 65 85);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @workbench-dark-solid-bg;
|
||||
}
|
||||
|
||||
&__label--active {
|
||||
border-color: rgb(59 130 246 / 40%);
|
||||
background: rgb(37 99 235 / 14%) !important;
|
||||
background: @workbench-dark-solid-bg !important;
|
||||
color: rgb(191 219 254) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,612 @@
|
||||
<template>
|
||||
<div ref="projectTaskCardRef" class="project-task-card">
|
||||
<div class="card-title">
|
||||
<span>项目任务</span>
|
||||
<el-button class="card-title__more" link type="primary" @click="goMore">更多</el-button>
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<div class="project-task-overview">
|
||||
<div class="task-chart-panel task-chart-panel--pie">
|
||||
<div ref="pieChartRef" class="task-chart"></div>
|
||||
</div>
|
||||
|
||||
<div class="task-chart-panel task-chart-panel--bar">
|
||||
<div ref="barChartRef" class="task-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import * as echarts from 'echarts';
|
||||
import { MyProjectTask, myProjectTaskListAll } from '@jeesite/biz/api/biz/myProjectTask';
|
||||
import { DictData, dictDataListData } from '@jeesite/core/api/sys/dictData';
|
||||
import { useUserStore } from '@jeesite/core/store/modules/user';
|
||||
import { firstCurrentYear, formatToDate } from '@jeesite/core/utils/dateUtil';
|
||||
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
const userinfo = computed(() => userStore.getUserInfo);
|
||||
|
||||
const projectTaskCardRef = ref<HTMLElement>();
|
||||
const pieChartRef = ref<HTMLElement>();
|
||||
const barChartRef = ref<HTMLElement>();
|
||||
const sourceData = ref<MyProjectTask[]>([]);
|
||||
const statusDict = ref<DictData[]>([]);
|
||||
|
||||
const STATUS_COLORS = ['#3B82F6', '#10B981', '#F97316', '#EC4899', '#8B5CF6', '#06B6D4'];
|
||||
let pieChartInstance: echarts.ECharts | null = null;
|
||||
let barChartInstance: echarts.ECharts | null = null;
|
||||
let resizeObserver: ResizeObserver | null = null;
|
||||
let themeObserver: MutationObserver | null = null;
|
||||
|
||||
function goMore() {
|
||||
router.push('/biz/myProjectTask/list');
|
||||
}
|
||||
|
||||
const pieChartData = computed(() => {
|
||||
if (!statusDict.value.length) {
|
||||
const fallbackMap = new Map<string, number>();
|
||||
sourceData.value.forEach((item) => {
|
||||
const label = item.taskStatus || '未设置';
|
||||
fallbackMap.set(label, (fallbackMap.get(label) || 0) + 1);
|
||||
});
|
||||
return Array.from(fallbackMap.entries()).map(([name, value], index) => ({
|
||||
name,
|
||||
value,
|
||||
itemStyle: { color: STATUS_COLORS[index % STATUS_COLORS.length] },
|
||||
}));
|
||||
}
|
||||
|
||||
const countMap = new Map<string, number>();
|
||||
sourceData.value.forEach((item) => {
|
||||
const key = item.taskStatus || 'unknown';
|
||||
countMap.set(key, (countMap.get(key) || 0) + 1);
|
||||
});
|
||||
|
||||
return statusDict.value
|
||||
.map((item, index) => ({
|
||||
name: item.dictLabelRaw,
|
||||
value: countMap.get(item.dictValue || '') || 0,
|
||||
itemStyle: { color: STATUS_COLORS[index % STATUS_COLORS.length] },
|
||||
}))
|
||||
.filter((item) => item.value > 0);
|
||||
});
|
||||
|
||||
const barChartData = computed(() => {
|
||||
const statusItems = statusDict.value.length
|
||||
? statusDict.value.map((item, index) => ({
|
||||
key: item.dictValue,
|
||||
label: item.dictLabelRaw,
|
||||
color: STATUS_COLORS[index % STATUS_COLORS.length],
|
||||
}))
|
||||
: [];
|
||||
|
||||
const monthStatusMap = new Map<string, Map<string, number>>();
|
||||
const monthOrderMap = new Map<string, number>();
|
||||
|
||||
sourceData.value.forEach((item) => {
|
||||
if (!item.createTime) return;
|
||||
const date = new Date(item.createTime);
|
||||
if (Number.isNaN(date.getTime())) return;
|
||||
const monthLabel = `${date.getMonth() + 1}月`;
|
||||
monthOrderMap.set(monthLabel, date.getMonth() + 1);
|
||||
const statusKey = item.taskStatus || 'unknown';
|
||||
if (!monthStatusMap.has(monthLabel)) {
|
||||
monthStatusMap.set(monthLabel, new Map<string, number>());
|
||||
}
|
||||
const monthMap = monthStatusMap.get(monthLabel)!;
|
||||
monthMap.set(statusKey, (monthMap.get(statusKey) || 0) + 1);
|
||||
});
|
||||
|
||||
const months = Array.from(monthStatusMap.keys()).sort((a, b) => {
|
||||
return (monthOrderMap.get(a) || 0) - (monthOrderMap.get(b) || 0);
|
||||
});
|
||||
|
||||
const totalByMonth = months.map((month) => {
|
||||
const monthMap = monthStatusMap.get(month);
|
||||
return Array.from(monthMap?.values() || []).reduce((sum, count) => sum + count, 0);
|
||||
});
|
||||
|
||||
const fallbackStatusMap = new Map<string, number>();
|
||||
sourceData.value.forEach((item) => {
|
||||
if (!statusDict.value.length) {
|
||||
const key = item.taskStatus || '未设置';
|
||||
fallbackStatusMap.set(key, (fallbackStatusMap.get(key) || 0) + 1);
|
||||
}
|
||||
});
|
||||
|
||||
const fallbackSeries = Array.from(fallbackStatusMap.keys()).map((key, index) => ({
|
||||
key,
|
||||
label: key,
|
||||
color: STATUS_COLORS[index % STATUS_COLORS.length],
|
||||
}));
|
||||
|
||||
return {
|
||||
months,
|
||||
totals: totalByMonth,
|
||||
statusItems: statusItems.length ? statusItems : fallbackSeries,
|
||||
monthStatusMap,
|
||||
};
|
||||
});
|
||||
|
||||
async function getDict() {
|
||||
try {
|
||||
statusDict.value = await dictDataListData({ dictType: 'task_status' });
|
||||
} catch (error) {
|
||||
statusDict.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
async function getList() {
|
||||
try {
|
||||
const reqParams = {
|
||||
createTime_gte: firstCurrentYear(),
|
||||
createUser: userinfo.value.loginCode,
|
||||
};
|
||||
const res = await myProjectTaskListAll(reqParams);
|
||||
sourceData.value = res || [];
|
||||
} catch (error) {
|
||||
sourceData.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
function renderPieChart() {
|
||||
if (!pieChartRef.value) return;
|
||||
if (!pieChartInstance) {
|
||||
pieChartInstance = echarts.init(pieChartRef.value);
|
||||
}
|
||||
|
||||
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
|
||||
const total = pieChartData.value.reduce((sum, item) => sum + Number(item.value || 0), 0);
|
||||
const data = total
|
||||
? pieChartData.value
|
||||
: statusDict.value.map((item, index) => ({
|
||||
name: item.dictLabelRaw,
|
||||
value: 0,
|
||||
itemStyle: { color: STATUS_COLORS[index % STATUS_COLORS.length] },
|
||||
}));
|
||||
const legendData = statusDict.value.length
|
||||
? statusDict.value.map((item) => item.dictLabelRaw)
|
||||
: pieChartData.value.map((item) => item.name);
|
||||
const series: echarts.SeriesOption[] = [];
|
||||
|
||||
if (!total) {
|
||||
series.push({
|
||||
name: '空态环',
|
||||
type: 'pie',
|
||||
radius: ['46%', '72%'],
|
||||
center: ['50%', '44%'],
|
||||
silent: true,
|
||||
legendHoverLink: false,
|
||||
tooltip: {
|
||||
show: false,
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
itemStyle: {
|
||||
color: isDark ? 'rgba(148, 163, 184, 0.18)' : 'rgba(203, 213, 225, 0.55)',
|
||||
borderRadius: 10,
|
||||
borderColor: isDark ? '#141414' : '#ffffff',
|
||||
borderWidth: 3,
|
||||
},
|
||||
data: [{ name: 'empty-ring', value: 1 }],
|
||||
});
|
||||
}
|
||||
|
||||
series.push({
|
||||
name: '任务状态',
|
||||
type: 'pie',
|
||||
radius: total ? ['46%', '72%'] : [0, 0],
|
||||
center: ['50%', '44%'],
|
||||
avoidLabelOverlap: true,
|
||||
minAngle: total ? 4 : 0,
|
||||
itemStyle: {
|
||||
borderRadius: 10,
|
||||
borderColor: isDark ? '#141414' : '#ffffff',
|
||||
borderWidth: 3,
|
||||
},
|
||||
label: {
|
||||
show: total,
|
||||
formatter: ({ name, value, percent }) => (total ? `${name}\n${value}项 / ${percent}%` : ''),
|
||||
color: isDark ? '#e2e8f0' : '#334155',
|
||||
fontSize: 12,
|
||||
},
|
||||
emphasis: {
|
||||
scale: true,
|
||||
scaleSize: 6,
|
||||
},
|
||||
data,
|
||||
silent: !total,
|
||||
labelLine: {
|
||||
show: total,
|
||||
},
|
||||
});
|
||||
|
||||
pieChartInstance.setOption({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
backgroundColor: isDark ? 'rgba(20, 20, 20, 0.96)' : 'rgba(255, 255, 255, 0.96)',
|
||||
borderColor: isDark ? 'rgb(51 65 85)' : 'rgb(226 232 240)',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: isDark ? '#e2e8f0' : '#334155',
|
||||
},
|
||||
formatter: ({ name, value, percent }) => {
|
||||
if (!total) return `${name}<br/>数量:0`;
|
||||
return `${name}<br/>数量:${value}<br/>占比:${percent}%`;
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
show: legendData.length > 0,
|
||||
bottom: 4,
|
||||
left: 'center',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
data: legendData,
|
||||
textStyle: {
|
||||
color: isDark ? '#cbd5e1' : '#475569',
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
series,
|
||||
graphic: total
|
||||
? [
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: '34%',
|
||||
style: {
|
||||
text: '任务总数',
|
||||
fill: isDark ? '#94a3b8' : '#64748b',
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: '41%',
|
||||
style: {
|
||||
text: `${total}`,
|
||||
fill: isDark ? '#f8fafc' : '#0f172a',
|
||||
fontSize: 24,
|
||||
fontWeight: 700,
|
||||
},
|
||||
},
|
||||
]
|
||||
: [],
|
||||
});
|
||||
}
|
||||
|
||||
function renderBarChart() {
|
||||
if (!barChartRef.value) return;
|
||||
if (!barChartInstance) {
|
||||
barChartInstance = echarts.init(barChartRef.value);
|
||||
}
|
||||
|
||||
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
|
||||
const { months, totals, statusItems, monthStatusMap } = barChartData.value;
|
||||
const hasData = totals.some((item) => item > 0);
|
||||
const categories = months.length ? months : [];
|
||||
const series = statusItems.length
|
||||
? statusItems.map((status) => ({
|
||||
name: status.label,
|
||||
type: 'bar',
|
||||
stack: 'month-total',
|
||||
barWidth: '12%',
|
||||
itemStyle: {
|
||||
color: status.color,
|
||||
borderRadius: 0,
|
||||
},
|
||||
emphasis: {
|
||||
focus: 'series',
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inside',
|
||||
formatter: ({ value }) => (Number(value) > 0 ? `${value}` : ''),
|
||||
color: '#ffffff',
|
||||
fontSize: 11,
|
||||
},
|
||||
data: categories.map((month) => monthStatusMap.get(month)?.get(status.key) || 0),
|
||||
}))
|
||||
: [
|
||||
{
|
||||
type: 'bar',
|
||||
barWidth: '12%',
|
||||
itemStyle: {
|
||||
color: isDark ? '#334155' : '#E2E8F0',
|
||||
borderRadius: [10, 10, 0, 0],
|
||||
},
|
||||
data: categories.map(() => 0),
|
||||
},
|
||||
];
|
||||
|
||||
if (hasData) {
|
||||
series.push({
|
||||
name: '总数',
|
||||
type: 'bar',
|
||||
stack: 'month-total',
|
||||
silent: true,
|
||||
legendHoverLink: false,
|
||||
itemStyle: {
|
||||
color: 'rgba(0,0,0,0)',
|
||||
},
|
||||
tooltip: {
|
||||
show: false,
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
color: isDark ? '#cbd5e1' : '#475569',
|
||||
fontSize: 11,
|
||||
formatter: ({ dataIndex }) => (totals[dataIndex] > 0 ? `${totals[dataIndex]}` : ''),
|
||||
},
|
||||
data: categories.map(() => 0),
|
||||
z: 10,
|
||||
});
|
||||
}
|
||||
|
||||
barChartInstance.setOption({
|
||||
grid: {
|
||||
left: 12,
|
||||
right: 12,
|
||||
top: 52,
|
||||
bottom: 10,
|
||||
containLabel: true,
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
backgroundColor: isDark ? 'rgba(20, 20, 20, 0.96)' : 'rgba(255, 255, 255, 0.96)',
|
||||
borderColor: isDark ? 'rgb(51 65 85)' : 'rgb(226 232 240)',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: isDark ? '#e2e8f0' : '#334155',
|
||||
},
|
||||
formatter: (params) => {
|
||||
const dataIndex = params[0]?.dataIndex || 0;
|
||||
if (!hasData) return '';
|
||||
const lines = params
|
||||
.filter((item) => item.seriesName !== '总数' && Number(item.value) > 0)
|
||||
.map((item) => `${item.marker}${item.seriesName}:${item.value}项`);
|
||||
lines.push(`总数:${totals[dataIndex]}项`);
|
||||
return `${categories[dataIndex]}<br/>${lines.join('<br/>')}`;
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
top: 6,
|
||||
left: 'center',
|
||||
itemGap: 16,
|
||||
data: statusItems.map((item) => item.label),
|
||||
textStyle: {
|
||||
color: isDark ? '#e2e8f0' : '#475569',
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: categories,
|
||||
boundaryGap: ['2%', '2%'],
|
||||
axisTick: {
|
||||
alignWithLabel: true,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: isDark ? '#475569' : '#cbd5e1',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: isDark ? '#cbd5e1' : '#64748b',
|
||||
interval: 0,
|
||||
margin: 8,
|
||||
rotate: 30,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '数量',
|
||||
nameTextStyle: {
|
||||
color: isDark ? '#94a3b8' : '#64748b',
|
||||
padding: [0, 0, 2, 0],
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: isDark ? 'rgba(71, 85, 105, 0.35)' : 'rgba(203, 213, 225, 0.55)',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: isDark ? '#94a3b8' : '#64748b',
|
||||
},
|
||||
},
|
||||
series,
|
||||
});
|
||||
}
|
||||
|
||||
function renderCharts() {
|
||||
renderPieChart();
|
||||
renderBarChart();
|
||||
}
|
||||
|
||||
function resizeCharts() {
|
||||
pieChartInstance?.resize();
|
||||
barChartInstance?.resize();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await Promise.all([getDict(), getList()]);
|
||||
await nextTick();
|
||||
renderCharts();
|
||||
|
||||
if (projectTaskCardRef.value) {
|
||||
resizeObserver = new ResizeObserver(() => {
|
||||
resizeCharts();
|
||||
});
|
||||
resizeObserver.observe(projectTaskCardRef.value);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', resizeCharts);
|
||||
|
||||
themeObserver = new MutationObserver(() => {
|
||||
nextTick(() => {
|
||||
renderCharts();
|
||||
});
|
||||
});
|
||||
themeObserver.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['data-theme'],
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
resizeObserver?.disconnect();
|
||||
themeObserver?.disconnect();
|
||||
window.removeEventListener('resize', resizeCharts);
|
||||
pieChartInstance?.dispose();
|
||||
barChartInstance?.dispose();
|
||||
pieChartInstance = null;
|
||||
barChartInstance = null;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@workbench-dark-panel-bg: rgb(20, 20, 20);
|
||||
@workbench-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.project-task-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
color: rgb(51 65 85);
|
||||
border-bottom: 1px solid rgb(226 232 240);
|
||||
background: transparent;
|
||||
|
||||
&__more {
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.project-task-overview {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(220px, 0.9fr) minmax(0, 1.6fr);
|
||||
gap: 12px;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.task-chart-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 0 8px 24px rgb(148 163 184 / 14%);
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
color: rgb(51 65 85);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.panel-subtitle {
|
||||
color: rgb(100 116 139);
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.task-chart {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .project-task-card {
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
border-bottom-color: rgb(51 65 85);
|
||||
|
||||
&__more:deep(.el-button) {
|
||||
color: rgb(147 197 253);
|
||||
}
|
||||
}
|
||||
|
||||
.task-chart-panel {
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
color: rgb(226 232 240);
|
||||
}
|
||||
|
||||
.panel-subtitle {
|
||||
color: rgb(148 163 184);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.project-task-card {
|
||||
.project-task-overview {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.project-task-card {
|
||||
.card-content {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.task-chart-panel {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.task-chart {
|
||||
min-height: 220px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -314,6 +314,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@workbench-dark-panel-bg: rgb(20, 20, 20);
|
||||
@workbench-dark-solid-bg: rgb(20, 20, 20);
|
||||
@workbench-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.schedule-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -700,14 +704,14 @@
|
||||
|
||||
.summary-item,
|
||||
.schedule-panel {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
|
||||
.summary-item {
|
||||
&__pane {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
|
||||
&__extra,
|
||||
@@ -717,7 +721,7 @@
|
||||
|
||||
&__label {
|
||||
border-color: rgb(51 65 85);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @workbench-dark-solid-bg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -734,12 +738,12 @@
|
||||
|
||||
.panel-tag,
|
||||
.timeline-scroll {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
|
||||
.timeline-row__hint {
|
||||
background: rgb(30 41 59 / 75%);
|
||||
background: @workbench-dark-solid-bg;
|
||||
}
|
||||
|
||||
.timeline-row__hint-title {
|
||||
@@ -756,7 +760,7 @@
|
||||
|
||||
.timeline-event {
|
||||
border-color: rgb(51 65 85);
|
||||
background: rgb(30 41 59 / 55%);
|
||||
background: @workbench-dark-solid-bg;
|
||||
color: rgb(226 232 240);
|
||||
|
||||
&:hover {
|
||||
@@ -778,7 +782,7 @@
|
||||
}
|
||||
|
||||
&__label {
|
||||
background: rgb(69 10 10);
|
||||
background: @workbench-dark-solid-bg;
|
||||
color: rgb(254 202 202);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<PageWrapper :contentFullHeight="true">
|
||||
<PageWrapper :contentFullHeight="true" :dense="true" title="false" contentClass="workbench-page-wrapper">
|
||||
<template #headerContent>
|
||||
<WorkbenchHeader />
|
||||
</template>
|
||||
@@ -10,12 +10,16 @@
|
||||
<NoteInfo />
|
||||
</div>
|
||||
<div class="workbench-col">
|
||||
<ScheduleInfo />
|
||||
<ScheduleInfo />
|
||||
</div>
|
||||
</div>
|
||||
<div class="workbench-row">
|
||||
<div class="workbench-col">下左</div>
|
||||
<div class="workbench-col">下右</div>
|
||||
<div class="workbench-col">
|
||||
<ProjectTask />
|
||||
</div>
|
||||
<div class="workbench-col">
|
||||
<ContractInfo />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -26,6 +30,8 @@
|
||||
import { PageWrapper } from '@jeesite/core/components/Page';
|
||||
import WorkbenchHeader from './components/WorkbenchHeader.vue';
|
||||
import NoteInfo from './components/NoteInfo.vue';
|
||||
import ProjectTask from './components/ProjectTask.vue';
|
||||
import ContractInfo from './components/ContractInfo.vue';
|
||||
import ScheduleInfo from './components/ScheduleInfo.vue';
|
||||
|
||||
const loading = ref(true);
|
||||
@@ -36,44 +42,64 @@
|
||||
|
||||
<style lang="less">
|
||||
@dark-bg: #141414;
|
||||
@desktop-page-gap: 12px;
|
||||
@desktop-page-padding: 0;
|
||||
@desktop-card-radius: 10px;
|
||||
@desktop-card-border: 1px solid rgb(226 232 240);
|
||||
@desktop-card-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
@desktop-dark-border: rgb(51 65 85);
|
||||
|
||||
.workbench-page-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 0 !important;
|
||||
overflow: hidden !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.jeesite-workbench {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
margin: 0;
|
||||
background: rgb(255, 255, 255);
|
||||
border-radius: 10px;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-layout {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
gap: @desktop-page-gap;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
padding: @desktop-page-padding;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border-radius: 10px;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-row {
|
||||
display: flex;
|
||||
flex: 1 1 0;
|
||||
gap: 8px;
|
||||
gap: @desktop-page-gap;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgb(226 232 240);
|
||||
border-radius: @desktop-card-radius;
|
||||
border: @desktop-card-border;
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
box-shadow: @desktop-card-shadow;
|
||||
color: rgb(71 85 105);
|
||||
font-size: 16px;
|
||||
overflow: hidden;
|
||||
@@ -91,7 +117,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .jeesite-workbench .workbench-col {
|
||||
border-color: rgb(51 65 85);
|
||||
border-color: @desktop-dark-border;
|
||||
background: @dark-bg !important;
|
||||
color: rgb(226 232 240);
|
||||
box-shadow: none;
|
||||
|
||||
@@ -19,4 +19,12 @@ export function formatToDate(date: dayjs.ConfigType | undefined = undefined, for
|
||||
return dayjs(date).format(format);
|
||||
}
|
||||
|
||||
export function firstCurrentYear(format = DATE_FORMAT): string {
|
||||
return dayjs().startOf('year').format(format);
|
||||
}
|
||||
|
||||
export function firstCurrentMonth(format = DATE_FORMAT): string {
|
||||
return dayjs().startOf('month').format(format);
|
||||
}
|
||||
|
||||
export const dateUtil = dayjs;
|
||||
|
||||
Reference in New Issue
Block a user