From 77891bf4f297ee25f4a86349f9e546f0e8ffd822 Mon Sep 17 00:00:00 2001
From: wangkai <10903508@qq.com>
Date: Thu, 8 Oct 2026 16:49:56 +0800
Subject: [PATCH] =?UTF-8?q?feat(topology):=20=E5=BB=BA=E7=AD=91=E6=94=AF?=
=?UTF-8?q?=E6=8C=81=E5=9C=B0=E4=B8=8B=E6=A5=BC=E5=B1=82=E6=95=B0=EF=BC=8C?=
=?UTF-8?q?=E6=88=BF=E9=97=B4=E6=89=80=E5=9C=A8=E6=A5=BC=E5=B1=82=E4=B8=8B?=
=?UTF-8?q?=E6=8B=89=E8=87=AA=E5=8A=A8=E6=8C=89=E5=9C=B0=E4=B8=8A+?=
=?UTF-8?q?=E5=9C=B0=E4=B8=8B=E7=94=9F=E6=88=90=20-=20=E5=BB=BA=E7=AD=91?=
=?UTF-8?q?=E8=A1=A8=E6=96=B0=E5=A2=9Efloordown=5Fcount=EF=BC=8C=E5=BB=BA?=
=?UTF-8?q?=E7=AD=91=E8=A1=A8=E5=8D=95=E6=8B=86=E5=88=86=E5=9C=B0=E4=B8=8A?=
=?UTF-8?q?/=E5=9C=B0=E4=B8=8B=E6=A5=BC=E5=B1=82=E6=95=B0=EF=BC=9B?=
=?UTF-8?q?=E6=88=BF=E9=97=B4=E6=89=80=E5=9C=A8=E6=A5=BC=E5=B1=82=E6=94=B9?=
=?UTF-8?q?=E4=B8=8B=E6=8B=89=EF=BC=8C=E6=8C=89=E5=9C=B0=E4=B8=8A(1?=
=?UTF-8?q?=E5=B1=82/2=E5=B1=82)=E4=B8=8E=E5=9C=B0=E4=B8=8B(=E8=B4=9F1?=
=?UTF-8?q?=E5=B1=82/=E8=B4=9F2=E5=B1=82)=E8=87=AA=E5=8A=A8=E7=94=9F?=
=?UTF-8?q?=E6=88=90=E3=80=81=E8=B4=9F=E6=A5=BC=E5=B1=82=E5=9C=A8=E5=89=8D?=
=?UTF-8?q?=EF=BC=8C=E9=80=89=E9=A1=B9=E9=87=87=E7=94=A8=E6=95=B0=E5=AD=97?=
=?UTF-8?q?=E6=A0=BC=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
client/src/api/customerBuilding.ts | 3 ++
client/src/views/customer/topology/index.vue | 48 +++++++++++++++----
.../20261008_building_floordown_count.sql | 5 ++
server/src/dto/customer_building.dto.ts | 2 +
server/src/entity/customer_building.entity.ts | 5 +-
5 files changed, 52 insertions(+), 11 deletions(-)
create mode 100644 database/migrations/20261008_building_floordown_count.sql
diff --git a/client/src/api/customerBuilding.ts b/client/src/api/customerBuilding.ts
index f89a5b7..eb3e215 100644
--- a/client/src/api/customerBuilding.ts
+++ b/client/src/api/customerBuilding.ts
@@ -7,6 +7,7 @@ export interface CustomerBuildingInfo {
basicInfo?: string;
purpose?: string;
floorCount?: number;
+ floorDownCount?: number;
createdAt: string;
}
@@ -30,6 +31,7 @@ export interface CustomerBuildingCreateParams {
basicInfo?: string;
purpose?: string;
floorCount?: number;
+ floorDownCount?: number;
}
export interface CustomerBuildingUpdateParams {
@@ -38,6 +40,7 @@ export interface CustomerBuildingUpdateParams {
basicInfo?: string;
purpose?: string;
floorCount?: number;
+ floorDownCount?: number;
}
export const customerBuildingApi = {
diff --git a/client/src/views/customer/topology/index.vue b/client/src/views/customer/topology/index.vue
index 091afb4..6d96d1d 100644
--- a/client/src/views/customer/topology/index.vue
+++ b/client/src/views/customer/topology/index.vue
@@ -145,8 +145,11 @@
-
-
+
+
+
+
+
@@ -176,7 +179,12 @@
-
+
@@ -237,6 +245,7 @@ const formData = reactive({
buildingName: '',
purpose: '',
floorCount: undefined as number | undefined,
+ floorDownCount: undefined as number | undefined,
basicInfo: '',
roomCode: '',
roomName: '',
@@ -263,6 +272,21 @@ const buildingOptions = computed<{ label: string; value: number }[]>(() => {
const departmentOptions = ref<{ label: string; value: number }[]>([]);
const departmentLoading = ref(false);
+const floorOptions = computed<{ label: string; value: string }[]>(() => {
+ const root = treeData.value[0];
+ const building = root?.children?.find((n) => n.type === 'building' && n.data.id === formData.buildingId);
+ const up = building?.data?.floorCount ?? 0;
+ const down = building?.data?.floorDownCount ?? 0;
+ const opts: { label: string; value: string }[] = [];
+ for (let i = down; i >= 1; i--) {
+ opts.push({ label: `负${i}层`, value: String(-i) });
+ }
+ for (let i = 1; i <= up; i++) {
+ opts.push({ label: `${i}层`, value: String(i) });
+ }
+ return opts;
+});
+
const formRules = computed(() => {
if (modalType.value === 'building') {
return {
@@ -293,7 +317,8 @@ function descFor(data: TreeNode): string {
if (data.type === 'building') {
const b: CustomerBuildingInfo = data.data;
if (b.purpose) parts.push(b.purpose);
- if (b.floorCount != null) parts.push(`共${b.floorCount}层`);
+ if (b.floorCount != null) parts.push(`地上${b.floorCount}层`);
+ if (b.floorDownCount != null && b.floorDownCount > 0) parts.push(`地下${b.floorDownCount}层`);
if (b.basicInfo) parts.push(b.basicInfo);
} else if (data.type === 'room') {
const r: CustomerRoomInfo = data.data;
@@ -407,6 +432,7 @@ function handleEditBuilding(node: TreeNode) {
formData.buildingName = b.buildingName;
formData.purpose = b.purpose || '';
formData.floorCount = b.floorCount;
+ formData.floorDownCount = b.floorDownCount;
formData.basicInfo = b.basicInfo || '';
modalVisible.value = true;
}
@@ -451,6 +477,7 @@ function resetForm() {
formData.buildingName = '';
formData.purpose = '';
formData.floorCount = undefined;
+ formData.floorDownCount = undefined;
formData.basicInfo = '';
formData.roomCode = '';
formData.roomName = '';
@@ -474,12 +501,13 @@ async function handleSubmit() {
let res: any;
if (modalType.value === 'building') {
const payload = {
- customerId: formData.customerId,
- buildingName: formData.buildingName,
- purpose: formData.purpose,
- floorCount: formData.floorCount,
- basicInfo: formData.basicInfo,
- };
+ customerId: formData.customerId,
+ buildingName: formData.buildingName,
+ purpose: formData.purpose,
+ floorCount: formData.floorCount,
+ floorDownCount: formData.floorDownCount,
+ basicInfo: formData.basicInfo,
+ };
if (isEdit.value && editId.value != null) {
res = await customerBuildingApi.update(editId.value, payload);
} else {
diff --git a/database/migrations/20261008_building_floordown_count.sql b/database/migrations/20261008_building_floordown_count.sql
new file mode 100644
index 0000000..9ae197f
--- /dev/null
+++ b/database/migrations/20261008_building_floordown_count.sql
@@ -0,0 +1,5 @@
+-- 客户建筑信息表增加地下楼层数 floordown_count(INT,默认0)
+-- 语义:floor_count 为地上楼层数,floordown_count 为地下楼层数
+-- 幂等:ADD COLUMN IF NOT EXISTS 重复执行安全
+ALTER TABLE customer_building
+ ADD COLUMN IF NOT EXISTS floordown_count INT DEFAULT 0;
\ No newline at end of file
diff --git a/server/src/dto/customer_building.dto.ts b/server/src/dto/customer_building.dto.ts
index 45ec416..7141101 100644
--- a/server/src/dto/customer_building.dto.ts
+++ b/server/src/dto/customer_building.dto.ts
@@ -13,6 +13,7 @@ export class CustomerBuildingCreateDTO {
@IsOptional() @IsString() @MaxLength(2000) @Matches(/^[^<>]*$/) basicInfo?: string;
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) purpose?: string;
@IsOptional() @IsInt() @Min(0) floorCount?: number;
+ @IsOptional() @IsInt() @Min(0) floorDownCount?: number;
}
export class CustomerBuildingUpdateDTO {
@@ -21,4 +22,5 @@ export class CustomerBuildingUpdateDTO {
@IsOptional() @IsString() @MaxLength(2000) @Matches(/^[^<>]*$/) basicInfo?: string;
@IsOptional() @IsString() @MaxLength(128) @Matches(/^[^<>]*$/) purpose?: string;
@IsOptional() @IsInt() @Min(0) floorCount?: number;
+ @IsOptional() @IsInt() @Min(0) floorDownCount?: number;
}
\ No newline at end of file
diff --git a/server/src/entity/customer_building.entity.ts b/server/src/entity/customer_building.entity.ts
index 1fa5b13..9c3f500 100644
--- a/server/src/entity/customer_building.entity.ts
+++ b/server/src/entity/customer_building.entity.ts
@@ -26,9 +26,12 @@ export default class CustomerBuilding extends Model {
@Column({ type: DataType.STRING(128), comment: "用途" })
purpose!: string;
- @Column({ type: DataType.INTEGER, field: "floor_count", comment: "层数" })
+ @Column({ type: DataType.INTEGER, field: "floor_count", comment: "地上楼层数" })
floorCount!: number;
+ @Column({ type: DataType.INTEGER, field: "floordown_count", comment: "地下楼层数", defaultValue: 0 })
+ floorDownCount!: number;
+
@BelongsTo(() => Customer)
customer!: Customer;