项目初始化
This commit is contained in:
@@ -100,9 +100,9 @@ public class MyProjectInfo extends DataEntity<MyProjectInfo> implements Serializ
|
||||
@ExcelField(title = "预计结束日期", attrName = "endDate", align = Align.CENTER, sort = 100, dataFormat = "yyyy-MM-dd hh:mm"),
|
||||
@ExcelField(title = "实际结束日期", attrName = "actualEndDate", align = Align.CENTER, sort = 110, dataFormat = "yyyy-MM-dd hh:mm"),
|
||||
@ExcelField(title = "项目预算", attrName = "budget", align = Align.CENTER, sort = 120),
|
||||
@ExcelField(title = "项目类型", attrName = "projectType", align = Align.CENTER, sort = 130),
|
||||
@ExcelField(title = "项目类型", attrName = "projectType", dictType = "project_type", align = Align.CENTER, sort = 130),
|
||||
@ExcelField(title = "级别", attrName = "priority", dictType = "biz_priority", align = Align.CENTER, sort = 135),
|
||||
@ExcelField(title = "项目状态", attrName = "projectStatus", align = Align.CENTER, sort = 140),
|
||||
@ExcelField(title = "项目状态", attrName = "projectStatus", dictType = "project_status",align = Align.CENTER, sort = 140),
|
||||
@ExcelField(title = "更新时间", attrName = "updateTime", align = Align.CENTER, sort = 150, dataFormat = "yyyy-MM-dd hh:mm"),
|
||||
})
|
||||
public MyProjectInfo() {
|
||||
|
||||
@@ -11,16 +11,22 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="项目类型">
|
||||
<el-select v-model="searchForm.projectType" placeholder="请选择项目类型" clearable>
|
||||
<el-option label="新增" value="新增" />
|
||||
<el-option label="修改" value="修改" />
|
||||
<el-option label="删除" value="删除" />
|
||||
<el-option label="导出" value="导出" />
|
||||
<el-option
|
||||
v-for="item in projectTypeDict"
|
||||
:key="item.dictValue"
|
||||
:label="item.dictLabelRaw"
|
||||
:value="item.dictValue"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="项目状态">
|
||||
<el-select v-model="searchForm.projectStatus" placeholder="请选择项目状态" clearable>
|
||||
<el-option label="成功" value="成功" />
|
||||
<el-option label="失败" value="失败" />
|
||||
<el-option
|
||||
v-for="item in projectStatusDict"
|
||||
:key="item.dictValue"
|
||||
:label="item.dictLabelRaw"
|
||||
:value="item.dictValue"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="query-form__actions">
|
||||
@@ -43,10 +49,22 @@
|
||||
>
|
||||
<el-table-column prop="projectCode" label="项目编码" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="projectName" label="项目名称" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="projectType" label="项目类型" width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="priority" label="项目级别" width="100" show-overflow-tooltip />
|
||||
<el-table-column prop="projectStatus" label="项目状态" width="100" />
|
||||
<el-table-column prop="budget" label="项目预算" width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="projectType" label="项目类型" width="120" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
{{ getDictLabel(projectTypeDict, row.projectType) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="priority" label="项目级别" width="100" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
{{ getDictLabel(priorityDict, row.priority) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="projectStatus" label="项目状态" width="100">
|
||||
<template #default="{ row }">
|
||||
{{ getDictLabel(projectStatusDict, row.projectStatus) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="budget" label="项目预算(元)" width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="startDate" label="开始日期" width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="endDate" label="结束日期" width="150" show-overflow-tooltip />
|
||||
</el-table>
|
||||
@@ -59,7 +77,6 @@
|
||||
:total="total"
|
||||
:page-sizes="[10, 20, 50, 99]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
size="small"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
background
|
||||
@@ -77,7 +94,11 @@
|
||||
import { MyProjectInfo, myProjectInfoPageList } from '@jeesite/biz/api/biz/myProjectInfo';
|
||||
import { DictData, dictDataListData } from '@jeesite/core/api/sys/dictData';
|
||||
|
||||
const priorityDict = ref<DictData[]>([]);
|
||||
const projectTypeDict = ref<DictData[]>([]);
|
||||
const projectStatusDict = ref<DictData[]>([]);
|
||||
const sourceData = ref<MyProjectInfo[]>([]);
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
const searchForm = reactive({
|
||||
@@ -116,6 +137,25 @@
|
||||
getList();
|
||||
};
|
||||
|
||||
async function getDict() {
|
||||
try {
|
||||
priorityDict.value = await dictDataListData({ dictType: 'biz_priority' });
|
||||
projectTypeDict.value = await dictDataListData({ dictType: 'project_type' });
|
||||
projectStatusDict.value = await dictDataListData({ dictType: 'project_status' });
|
||||
} catch (error) {
|
||||
priorityDict.value = [];
|
||||
projectTypeDict.value = [];
|
||||
projectStatusDict.value = [];
|
||||
console.error('获取数据字典失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function getDictLabel(dictList: DictData[] | undefined, value?: string) {
|
||||
if (!value) return '-';
|
||||
const target = dictList?.find((item) => item.dictValue === value);
|
||||
return target?.dictLabelRaw || value;
|
||||
}
|
||||
|
||||
async function getList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
@@ -138,6 +178,7 @@
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
getDict();
|
||||
});
|
||||
|
||||
function getSummaries({ columns, data }: { columns: TableColumnCtx<MyProjectInfo>[]; data: MyProjectInfo[] }) {
|
||||
|
||||
@@ -17,15 +17,15 @@
|
||||
<div class="analysis-right">
|
||||
<div class="analysis-right-top">
|
||||
<section class="analysis-panel">
|
||||
<QuickLogin />
|
||||
</section>
|
||||
<QuickLogin />
|
||||
</section>
|
||||
<section class="analysis-panel">
|
||||
<BizApps />
|
||||
</section>
|
||||
<BizApps />
|
||||
</section>
|
||||
</div>
|
||||
<section class="analysis-panel">
|
||||
<ProjectInfo />
|
||||
</section>
|
||||
<ProjectInfo />
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -34,13 +34,12 @@
|
||||
</template>
|
||||
<script lang="ts" setup name="Analysis">
|
||||
import { PageWrapper } from '@jeesite/core/components/Page';
|
||||
import BizApps from './components/BizApps.vue'
|
||||
import BizApps from './components/BizApps.vue';
|
||||
import HostInfo from './components/HostInfo.vue';
|
||||
import TodoInfo from './components/TodoInfo.vue';
|
||||
import NoticeInfo from './components/NoticeInfo.vue';
|
||||
import QuickLogin from './components/QuickLogin.vue';
|
||||
import ProjectInfo from './components/ProjectInfo.vue'
|
||||
|
||||
import ProjectInfo from './components/ProjectInfo.vue';
|
||||
</script>
|
||||
<style lang="less">
|
||||
@dark-bg: #141414;
|
||||
@@ -142,7 +141,7 @@
|
||||
padding: 0;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgb(226 232 240);
|
||||
background: rgb(248 250 252);
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
overflow: hidden;
|
||||
color: rgb(71 85 105);
|
||||
|
||||
@@ -0,0 +1,524 @@
|
||||
<template>
|
||||
<div ref="noteCardRef" class="note-card">
|
||||
<div class="card-title">
|
||||
<span>便签信息</span>
|
||||
<el-tooltip content="刷新" placement="top" :show-after="200">
|
||||
<el-button
|
||||
class="card-title__refresh"
|
||||
link
|
||||
type="primary"
|
||||
:icon="RefreshRight"
|
||||
:loading="loading"
|
||||
@click="getList"
|
||||
/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<div class="note-overview">
|
||||
<div class="note-metrics">
|
||||
<div v-for="item in metricCards" :key="item.key" class="metric-item">
|
||||
<div class="metric-item__main">
|
||||
<div class="metric-item__pane metric-item__pane--left">
|
||||
<div class="metric-item__value" :style="{ color: item.color }">{{ item.total }}</div>
|
||||
<div class="metric-item__extra">总数</div>
|
||||
</div>
|
||||
<div class="metric-item__pane metric-item__pane--right">
|
||||
<div class="metric-item__value metric-item__value--small" :style="{ color: item.color }">{{
|
||||
item.finished
|
||||
}}</div>
|
||||
<div class="metric-item__extra">已完成</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric-item__label">{{ item.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="note-chart-panel">
|
||||
<div ref="chartRef" class="note-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import dayjs from 'dayjs';
|
||||
import { RefreshRight } from '@element-plus/icons-vue';
|
||||
import { DictData, dictDataListData } from '@jeesite/core/api/sys/dictData';
|
||||
import { MyNotes, myNotesListData } from '@jeesite/biz/api/biz/myNotes';
|
||||
|
||||
interface MetricCard {
|
||||
key: string;
|
||||
label: string;
|
||||
value: number;
|
||||
color: string;
|
||||
total: number;
|
||||
finished: number;
|
||||
}
|
||||
|
||||
const noteCardRef = ref<HTMLElement>();
|
||||
const chartRef = ref<HTMLElement>();
|
||||
const loading = ref(false);
|
||||
const noteList = ref<MyNotes[]>([]);
|
||||
const typeDict = ref<DictData[]>([]);
|
||||
const statusDict = ref<DictData[]>([]);
|
||||
const statusGroups = [
|
||||
{ key: 'pending', label: '待开始', color: '#F97316' },
|
||||
{ key: 'processing', label: '进行中', color: '#3B82F6' },
|
||||
{ key: 'finished', label: '已完成', color: '#10B981' },
|
||||
];
|
||||
|
||||
const metricTypeGroups = [
|
||||
{ key: 'work', label: '工作', color: '#3B82F6' },
|
||||
{ key: 'life', label: '生活', color: '#10B981' },
|
||||
{ key: 'study', label: '学习', color: '#F97316' },
|
||||
{ key: 'other', label: '其他', color: '#8B5CF6' },
|
||||
];
|
||||
|
||||
let chartInstance: echarts.ECharts | null = null;
|
||||
let resizeObserver: ResizeObserver | null = null;
|
||||
let themeObserver: MutationObserver | null = null;
|
||||
|
||||
const metricCards = computed<MetricCard[]>(() => {
|
||||
return metricTypeGroups.map((group) => ({
|
||||
key: group.key,
|
||||
label: group.label,
|
||||
color: group.color,
|
||||
value: noteList.value.filter((item) => matchTypeGroup(item.type, group.label)).length,
|
||||
total: noteList.value.filter((item) => matchTypeGroup(item.type, group.label)).length,
|
||||
finished: noteList.value.filter((item) => matchTypeGroup(item.type, group.label) && item.ustatus === '1').length,
|
||||
}));
|
||||
});
|
||||
|
||||
function getDictLabel(dictList: DictData[], value?: string) {
|
||||
return dictList.find((item) => item.dictValue === value)?.dictLabelRaw || value || '-';
|
||||
}
|
||||
|
||||
function matchTypeGroup(typeValue: string | undefined, targetLabel: string) {
|
||||
return getDictLabel(typeDict.value, typeValue) === targetLabel;
|
||||
}
|
||||
|
||||
function getStatusGroup(item: MyNotes) {
|
||||
const label = getDictLabel(statusDict.value, item.ustatus);
|
||||
if (label.includes('完成')) return '已完成';
|
||||
if (label.includes('进行')) return '进行中';
|
||||
if (label.includes('开始')) return '待开始';
|
||||
if (item.ustatus === '1') return '已完成';
|
||||
if (item.ustatus === '2') return '进行中';
|
||||
return '待开始';
|
||||
}
|
||||
|
||||
function getMonthList() {
|
||||
return Array.from({ length: 12 }, (_, index) => `${index + 1}月`);
|
||||
}
|
||||
|
||||
function getNoteMonth(item: MyNotes) {
|
||||
const dateValue = item.createTime || item.startTime || item.deadline || item.updateTime;
|
||||
return dateValue ? dayjs(dateValue).format('M月') : '';
|
||||
}
|
||||
|
||||
async function getDict() {
|
||||
try {
|
||||
const [typeRes, statusRes] = await Promise.all([
|
||||
dictDataListData({ dictType: 'note_type' }),
|
||||
dictDataListData({ dictType: 'note_status' }),
|
||||
]);
|
||||
typeDict.value = typeRes || [];
|
||||
statusDict.value = statusRes || [];
|
||||
} catch (error) {
|
||||
typeDict.value = [];
|
||||
statusDict.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
async function getList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await myNotesListData({ pageNum: 1, pageSize: 999 });
|
||||
noteList.value = res?.list || [];
|
||||
} catch (error) {
|
||||
noteList.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
nextTick(() => {
|
||||
renderChart();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function buildChartData() {
|
||||
const months = getMonthList();
|
||||
const totals = months.map((month) => {
|
||||
return statusGroups.reduce((sum, status) => {
|
||||
return (
|
||||
sum +
|
||||
noteList.value.filter((item) => getNoteMonth(item) === month && getStatusGroup(item) === status.label).length
|
||||
);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
const series: echarts.BarSeriesOption[] = statusGroups.map((group) => {
|
||||
return {
|
||||
name: group.label,
|
||||
type: 'bar',
|
||||
stack: 'total',
|
||||
barWidth: '24%',
|
||||
emphasis: {
|
||||
focus: 'series',
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inside',
|
||||
formatter: ({ value }) => (Number(value) > 0 ? `${value}` : ''),
|
||||
color: '#ffffff',
|
||||
fontSize: 11,
|
||||
},
|
||||
itemStyle: {
|
||||
color: group.color,
|
||||
borderRadius: 0,
|
||||
},
|
||||
data: months.map((month) => {
|
||||
return noteList.value.filter((item) => getNoteMonth(item) === month && getStatusGroup(item) === group.label)
|
||||
.length;
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
series.push({
|
||||
name: '总数',
|
||||
type: 'bar',
|
||||
stack: 'total',
|
||||
barWidth: '24%',
|
||||
silent: true,
|
||||
legendHoverLink: false,
|
||||
itemStyle: {
|
||||
color: 'rgba(0,0,0,0)',
|
||||
borderRadius: 0,
|
||||
},
|
||||
tooltip: {
|
||||
show: false,
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
formatter: ({ dataIndex }) => (totals[dataIndex] > 0 ? `${totals[dataIndex]}` : ''),
|
||||
color: '#475569',
|
||||
fontSize: 11,
|
||||
},
|
||||
data: totals.map(() => 0),
|
||||
z: 10,
|
||||
});
|
||||
|
||||
return {
|
||||
categories: months,
|
||||
series,
|
||||
};
|
||||
}
|
||||
|
||||
function renderChart() {
|
||||
if (!chartRef.value) return;
|
||||
|
||||
if (!chartInstance) {
|
||||
chartInstance = echarts.init(chartRef.value);
|
||||
}
|
||||
|
||||
const { categories, series } = buildChartData();
|
||||
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
|
||||
|
||||
const totalSeries = series.find((item) => item.name === '总数');
|
||||
if (totalSeries?.label) {
|
||||
totalSeries.label.color = isDark ? '#cbd5e1' : '#475569';
|
||||
}
|
||||
|
||||
chartInstance.setOption({
|
||||
grid: {
|
||||
left: 12,
|
||||
right: 12,
|
||||
top: 40,
|
||||
bottom: 6,
|
||||
containLabel: true,
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
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',
|
||||
},
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
top: 4,
|
||||
left: 'center',
|
||||
selectedMode: true,
|
||||
itemGap: 16,
|
||||
data: statusGroups.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',
|
||||
margin: 8,
|
||||
rotate: 30,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '数量',
|
||||
nameTextStyle: {
|
||||
color: isDark ? '#94a3b8' : '#64748b',
|
||||
padding: [0, 0, 4, 0],
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: isDark ? 'rgba(71, 85, 105, 0.35)' : 'rgba(203, 213, 225, 0.55)',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: isDark ? '#94a3b8' : '#64748b',
|
||||
},
|
||||
},
|
||||
series,
|
||||
});
|
||||
}
|
||||
|
||||
function resizeChart() {
|
||||
chartInstance?.resize();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await getDict();
|
||||
await getList();
|
||||
|
||||
if (noteCardRef.value) {
|
||||
resizeObserver = new ResizeObserver(() => {
|
||||
resizeChart();
|
||||
});
|
||||
resizeObserver.observe(noteCardRef.value);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', resizeChart);
|
||||
|
||||
themeObserver = new MutationObserver(() => {
|
||||
nextTick(() => {
|
||||
renderChart();
|
||||
});
|
||||
});
|
||||
themeObserver.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['data-theme'],
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
resizeObserver?.disconnect();
|
||||
themeObserver?.disconnect();
|
||||
window.removeEventListener('resize', resizeChart);
|
||||
chartInstance?.dispose();
|
||||
chartInstance = null;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.note-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;
|
||||
|
||||
&__refresh {
|
||||
padding: 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.note-overview {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(220px, 0.9fr) minmax(0, 1.6fr);
|
||||
gap: 12px;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.note-metrics {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
grid-template-rows: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.metric-item,
|
||||
.note-chart-panel {
|
||||
border-radius: 12px;
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 0 8px 24px rgb(148 163 184 / 14%);
|
||||
}
|
||||
|
||||
.metric-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: stretch;
|
||||
padding: 8px;
|
||||
|
||||
&__main {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
min-height: 0;
|
||||
gap: 8px;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
&__pane {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 0 8px 24px rgb(148 163 184 / 14%);
|
||||
}
|
||||
|
||||
&__extra {
|
||||
margin-top: 8px;
|
||||
color: rgb(100 116 139);
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__value {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
|
||||
&--small {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
&__label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
min-height: 28px;
|
||||
margin-top: 2px;
|
||||
padding-top: 4px;
|
||||
border-top: 1px solid rgb(226 232 240);
|
||||
color: rgb(71 85 105);
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.note-chart-panel {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.note-chart {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .note-card {
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
border-bottom-color: rgb(51 65 85);
|
||||
|
||||
&__refresh:deep(.el-icon) {
|
||||
color: rgb(147 197 253);
|
||||
}
|
||||
}
|
||||
|
||||
.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%);
|
||||
}
|
||||
|
||||
.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%);
|
||||
}
|
||||
|
||||
&__extra {
|
||||
color: rgb(148 163 184);
|
||||
}
|
||||
|
||||
&__label {
|
||||
border-top-color: rgb(51 65 85);
|
||||
color: rgb(148 163 184);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.note-card {
|
||||
.note-overview {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.note-metrics {
|
||||
grid-template-rows: repeat(2, minmax(88px, 1fr));
|
||||
}
|
||||
|
||||
.note-chart {
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,18 +1,19 @@
|
||||
<template>
|
||||
<PageWrapper>
|
||||
<PageWrapper :contentFullHeight="true">
|
||||
<template #headerContent>
|
||||
<WorkbenchHeader />
|
||||
</template>
|
||||
<div class="jeesite-workbench">
|
||||
<div class="workbench-layout">
|
||||
<div class="workbench-top">10% 区域</div>
|
||||
<div class="workbench-row">
|
||||
<div class="workbench-col">30% 区域左侧</div>
|
||||
<div class="workbench-col">30% 区域右侧</div>
|
||||
<div class="workbench-col">
|
||||
<NoteInfo />
|
||||
</div>
|
||||
<div class="workbench-col">上右</div>
|
||||
</div>
|
||||
<div class="workbench-row">
|
||||
<div class="workbench-col">30% 区域左侧</div>
|
||||
<div class="workbench-col">30% 区域右侧</div>
|
||||
<div class="workbench-col">中左</div>
|
||||
<div class="workbench-col">中右</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -22,6 +23,7 @@
|
||||
import { ref } from 'vue';
|
||||
import { PageWrapper } from '@jeesite/core/components/Page';
|
||||
import WorkbenchHeader from './components/WorkbenchHeader.vue';
|
||||
import NoteInfo from './components/NoteInfo.vue';
|
||||
|
||||
const loading = ref(true);
|
||||
setTimeout(() => {
|
||||
@@ -37,7 +39,7 @@
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
margin: 0;
|
||||
background: #FFFFFF;
|
||||
background: rgb(255, 255, 255);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
@@ -48,34 +50,30 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 4px;
|
||||
padding: 2px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-top {
|
||||
flex: 0 0 10%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-row {
|
||||
display: flex;
|
||||
flex: 0 0 30%;
|
||||
flex: 1 1 0;
|
||||
gap: 12px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-col,
|
||||
.jeesite-workbench .workbench-top {
|
||||
.jeesite-workbench .workbench-col {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgb(226 232 240);
|
||||
background: #FFFFFF;
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
color: rgb(71 85 105);
|
||||
font-size: 16px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-col {
|
||||
@@ -89,10 +87,10 @@
|
||||
background: @dark-bg !important;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .jeesite-workbench .workbench-top,
|
||||
html[data-theme='dark'] .jeesite-workbench .workbench-col {
|
||||
border-color: rgb(51 65 85);
|
||||
background: @dark-bg !important;
|
||||
color: rgb(226 232 240);
|
||||
box-shadow: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user