Files
leaser_front/src/views/business/project/drawer/project-info-drawer.vue
T

278 lines
6.9 KiB
Vue
Raw Normal View History

2025-08-11 23:28:10 +08:00
<template>
<a-drawer
:width="1000"
:visible="visible"
title="项目详情"
:footer="false"
unmount-on-close
@cancel="handleCancel"
>
2026-01-23 01:14:47 +08:00
<div class="flex items-center justify-between">
<div>
<p>{{ detailInfo?.name }}</p>
<p class="mt-[10px]">
<a-tag :color="getTypeColor(detailInfo?.type)">{{
detailInfo?.typeName
}}</a-tag>
</p>
</div>
<div class="flex items-center gap-[10px]">
<p>{{ detailInfo?.updatedAt }}</p>
<div>
<a-button @click="handleEdit">
<template #icon>
<icon-edit />
</template>
{{ $t('edit') }}
</a-button>
</div>
<!-- <a-button type="primary" @click="handleDelete">删除</a-button> -->
</div>
</div>
<div class="mt-[10px] grid grid-cols-3 gap-[10px]">
<a-card title="面积信息">
<div class="ring-chart-container">
<Chart :options="ringChartOption" height="200px" />
</div>
</a-card>
<a-card title="房源统计">
<div class="grid grid-cols-3 gap-[10px] text-center">
<div>
<p class="text-[18px] font-bold">{{ detailInfo?.roomNum }}</p>
<p>房源总数</p>
</div>
<div>
<p class="text-[18px] font-bold">{{ detailInfo?.roomsRentNum }}</p>
<p>已出租</p>
</div>
<div>
<p class="text-[18px] font-bold">{{
detailInfo?.roomsUnRentNum
}}</p>
<p>空置</p>
</div>
</div>
</a-card>
<a-card title="租客信息"></a-card>
</div>
2025-08-11 23:28:10 +08:00
</a-drawer>
</template>
<script lang="ts" setup>
2026-01-23 01:14:47 +08:00
import { watch, onMounted, computed } from 'vue';
2025-08-11 23:28:10 +08:00
// import { Message } from '@arco-design/web-vue';
// import { projectTypeList } from '@/utils/constant';
import { ProjectItem } from '@/types/business';
2026-01-23 01:14:47 +08:00
import Chart from '@/components/chart/index.vue';
import type { EChartsOption } from 'echarts';
2025-08-11 23:28:10 +08:00
const props = defineProps<{
visible: boolean;
projectId: number | null;
detailInfo: ProjectItem | null;
2026-01-23 01:14:47 +08:00
projectTypeList: any[];
2025-08-11 23:28:10 +08:00
}>();
const emit = defineEmits<{
(e: 'update:visible', val: boolean): void;
}>();
watch(
() => props.visible,
async (val) => {
console.log(val, 'val');
},
{ immediate: true }
);
const handleCancel = () => {
emit('update:visible', false);
};
2026-01-23 01:14:47 +08:00
const handleEdit = () => {
emit('update:visible', false);
};
const getTypeColor = (type: number | undefined) => {
if (!type) return '';
const color = props.projectTypeList.find((item) => item.id === type)?.color;
return color || '';
};
// 格式化面积数值,保留2位小数
const formatArea = (value: number): number => {
return Math.round(value * 100) / 100;
};
// 格式化面积显示,添加千分位分隔符
const formatAreaDisplay = (value: number): string => {
if (!value && value !== 0) return '0';
return formatArea(value).toLocaleString('zh-CN', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
};
// 计算环形图数据
const ringChartData = computed(() => {
if (!props.detailInfo) {
return [];
}
const { roomArea = 0, rentArea = 0, keepArea = 0 } = props.detailInfo;
// 确保数值有效
const totalArea = Number(roomArea) || 0;
const rentedArea = Number(rentArea) || 0;
const reservedArea = Number(keepArea) || 0;
// 可租面积 = 计租面积 - 在租面积 - 保留面积
const availableArea = Math.max(0, totalArea - rentedArea - reservedArea);
// 构建图表数据,如果总面积大于0,显示所有三个部分(即使某些为0)
const data: Array<{ name: string; value: number }> = [];
// 如果总面积大于0,显示所有分类
if (totalArea > 0) {
// 在租面积
data.push({
name: '在租面积',
value: formatArea(rentedArea),
});
// 保留面积
data.push({
name: '保留面积',
value: formatArea(reservedArea),
});
// 可租面积
data.push({
name: '可租面积',
value: formatArea(availableArea),
});
} else {
// 如果所有数据都为0,显示占位数据
data.push({
name: '计租面积',
value: 0,
});
}
// 调试信息(开发时使用)
console.log('环形图数据:', {
roomArea: totalArea,
rentArea: rentedArea,
keepArea: reservedArea,
availableArea,
chartData: data,
});
return data;
});
// 环形图配置
const ringChartOption = computed<EChartsOption>(() => {
const data = ringChartData.value;
if (data.length === 0) {
return {
title: {
text: '暂无数据',
left: 'center',
top: 'middle',
textStyle: {
color: '#999',
fontSize: 14,
},
},
};
}
return {
tooltip: {
trigger: 'item',
formatter: (params: any) => {
const { name, value, percent } = params;
return `${name}<br/>${formatAreaDisplay(value)}㎡ (${percent}%)`;
},
},
legend: {
orient: 'vertical',
left: 'left',
top: 'middle',
itemWidth: 12,
itemHeight: 12,
textStyle: {
fontSize: 12,
},
},
series: [
{
name: '面积信息',
type: 'pie',
radius: ['40%', '70%'], // 环形图:内半径40%,外半径70%
center: ['60%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 4,
borderColor: '#fff',
borderWidth: 2,
},
label: {
show: true,
formatter: '{b}\n{d}%',
fontSize: 12,
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold',
},
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)',
},
},
data: data,
},
],
};
});
2025-08-11 23:28:10 +08:00
onMounted(() => {});
</script>
<style lang="less" scoped>
:deep(label.arco-form-item-label) {
width: 100% !important;
}
2026-01-23 01:14:47 +08:00
.ring-chart-container {
position: relative;
min-height: 300px;
.area-summary {
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid var(--color-border-2);
.summary-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
.summary-label {
color: var(--color-text-2);
font-size: 14px;
}
.summary-value {
color: var(--color-text-1);
font-size: 16px;
font-weight: 500;
}
}
}
}
2025-08-11 23:28:10 +08:00
</style>