Merge branch 'main' into dev-lilin

This commit is contained in:
lilin 2026-07-28 19:00:14 +08:00
commit 022bfeadd6
65 changed files with 40461 additions and 2153 deletions

View File

@ -0,0 +1,12 @@
package com.yfd.platform.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldChinese {
String value() default "";
}

View File

@ -61,6 +61,8 @@ public class SecurityConfig {
.requestMatchers("/tempFile/**").permitAll()
.requestMatchers("/system/user/auditUser").permitAll()
.requestMatchers("/register/accessToken").permitAll()
.requestMatchers("/sys/psbmodulelbb/**").permitAll()
.requestMatchers("/base/operationLog/**").permitAll()
// .requestMatchers("/eng/**").permitAll()
// .requestMatchers("/eq/**").permitAll()
// .requestMatchers("/env/**").permitAll()

View File

@ -0,0 +1,46 @@
package com.yfd.platform.qgc_base.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.qgc_base.domain.MsOperationLog;
import com.yfd.platform.qgc_base.domain.MsOperationLogDetail;
import com.yfd.platform.qgc_base.service.IMsOperationLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 操作日志控制器
*/
@Slf4j
@RestController
@RequestMapping("/base/operationLog")
@Tag(name = "操作日志管理")
public class MsOperationLogController {
@Resource
private IMsOperationLogService msOperationLogService;
@PostMapping("/GetKendoListCust")
@Operation(summary = "分页查询操作日志tableName必传recordId可选")
public ResponseResult getKendoList(@RequestBody DataSourceRequest dataSourceRequest) {
Page<MsOperationLog> page = msOperationLogService.queryPageList(dataSourceRequest);
return ResponseResult.successData(page);
}
@GetMapping("/getDetailByMainId")
@Operation(summary = "根据日志主表ID查询日志详情")
public ResponseResult getDetailByMainId(@RequestParam("mainId") String mainId) {
if (StringUtils.isBlank(mainId)) {
return ResponseResult.error("mainId 不能为空");
}
List<MsOperationLogDetail> list = msOperationLogService.getDetailByMainId(mainId);
return ResponseResult.successData(list);
}
}

View File

@ -2,6 +2,8 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.UserIdField;
import com.yfd.platform.annotation.UserNameField;
import lombok.Data;
import java.io.Serializable;
@ -64,8 +66,13 @@ public class MsWarnRuleB implements Serializable {
// ---------- 审计字段 ----------
@TableField("RECORD_USER")
@UserIdField
private String recordUser;
@TableField(exist = false)
@UserNameField
private String recordUserName;
@TableField("RECORD_TIME")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date recordTime;

View File

@ -2,6 +2,7 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -25,16 +26,19 @@ public class SdAiboxBH implements Serializable {
* 测站编码
*/
@TableId(type = IdType.INPUT)
@FieldChinese("测站编码")
private String stcd;
/**
* 测站名称
*/
@FieldChinese("测站名称")
private String stnm;
/**
* 测站类型
*/
@FieldChinese("测站类型")
private String sttp;
@TableField(exist = false)
@ -44,43 +48,51 @@ public class SdAiboxBH implements Serializable {
* 数据时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/**
* 位置经度
*/
@FieldChinese("位置经度")
private BigDecimal lgtd;
/**
* 位置纬度
*/
@FieldChinese("位置纬度")
private BigDecimal lttd;
/**
* 高程
*/
@FieldChinese("高程")
private BigDecimal elev;
/**
* 站址
*/
@FieldChinese("站址")
private String stlc;
/**
* 建成日期
*/
@FieldChinese("建成日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date jcdt;
/**
* 退役/拆除日期
*/
@FieldChinese("退役/拆除日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date wddt;
/**
* 建设状态代码
*/
@FieldChinese("建设状态代码")
private Integer bldsttCode;
@TableField(exist = false)
@ -89,11 +101,13 @@ public class SdAiboxBH implements Serializable {
/**
* 是否启用
*/
@FieldChinese("是否启用")
private Integer usfl;
/**
* 数据是否接入
*/
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
@ -102,12 +116,14 @@ public class SdAiboxBH implements Serializable {
/**
* 数据接入时间
*/
@FieldChinese("数据接入时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date dtinTm;
/**
* 监测方式
*/
@FieldChinese("监测方式")
private Integer mway;
@TableField(exist = false)
@ -116,16 +132,19 @@ public class SdAiboxBH implements Serializable {
/**
* 站索引
*/
@FieldChinese("站索引")
private String stindx;
/**
* 排序
*/
@FieldChinese("排序")
private Integer orderIndex;
/**
* 关联测站编码
*/
@FieldChinese("关联测站编码")
private String rstcd;
@TableField(exist = false)
@ -134,6 +153,7 @@ public class SdAiboxBH implements Serializable {
/**
* 所属基地编码
*/
@FieldChinese("所属基地编码")
private String baseId;
@TableField(exist = false)
@ -142,11 +162,13 @@ public class SdAiboxBH implements Serializable {
/**
* 所属基地流域编码
*/
@FieldChinese("所属基地流域编码")
private String hbrvcd;
/**
* 所属流域代码
*/
@FieldChinese("所属流域代码")
private String rvcd;
@TableField(exist = false)
@ -155,114 +177,136 @@ public class SdAiboxBH implements Serializable {
/**
* 简介
*/
@FieldChinese("简介")
private String introduce;
/**
* LOGO
*/
@FieldChinese("LOGO")
private String logo;
/**
* 介绍文件
*/
@FieldChinese("介绍文件")
private String inffile;
/**
* 服务对象
*/
@FieldChinese("服务对象")
private String fwdx;
/**
* 供电方式
*/
@FieldChinese("供电方式")
private String gdfs;
/**
* AI配置
*/
@FieldChinese("AI配置")
private String aipz;
/**
* 模型版本
*/
@FieldChinese("模型版本")
private String mxbb;
/**
* IP地址
*/
@FieldChinese("IP地址")
private String ipaddr;
/**
* SIM卡信息
*/
@FieldChinese("SIM卡信息")
private String siminfo;
/**
* 联系人
*/
@FieldChinese("联系人")
private String lxr;
/**
* 用途
*/
@FieldChinese("用途")
private String purpose;
/**
* 数据频率
*/
@FieldChinese("数据频率")
private String dtfrqcy;
/**
* 备注
*/
@FieldChinese("备注")
private String remark;
/**
* 植被覆盖类型
*/
@FieldChinese("植被覆盖类型")
private String vlsr;
/**
* 植被覆盖调查时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("植被覆盖调查时间")
private Date vlsrTm;
/**
* 创建人
*/
@FieldChinese("创建人")
private String recordUser;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("创建时间")
private Date recordTime;
/**
* 更新人
*/
@FieldChinese("更新人")
private String modifyUser;
/**
* 更新时间
*/
@FieldChinese("更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/**
* 是否已删除
*/
@FieldChinese("是否已删除")
private Integer isDeleted;
/**
* 删除人
*/
@FieldChinese("删除人")
private String deleteUser;
/**
* 删除时间
*/
@FieldChinese("删除时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date deleteTime;
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import java.io.Serializable;
@ -18,154 +19,233 @@ import java.util.Date;
public class SdAimonitorBH implements Serializable {
private static final long serialVersionUID = 1L;
/** 站码 */
@TableId(type = IdType.INPUT)
@FieldChinese("站码")
private String stcd;
/** 站名 */
@FieldChinese("站名")
private String stnm;
/** 站类 */
@FieldChinese("站类")
private String sttp;
@TableField(exist = false)
private String sttpName;
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/** 经度(单位:°) */
@FieldChinese("经度(单位:°)")
private BigDecimal lgtd;
/** 纬度(单位:°) */
@FieldChinese("纬度(单位:°)")
private BigDecimal lttd;
/** 高程单位m */
@FieldChinese("高程单位m")
private BigDecimal elev;
/** 站址/位置 */
@FieldChinese("站址/位置")
private String stlc;
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
/** 建设状态分类 */
@TableField("BLDSTT_CODE")
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/** 是否启用 */
@FieldChinese("是否启用")
private Integer usfl;
/** 数据是否接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField("DTIN_TM")
@FieldChinese("数据接入时间")
private Date dtinTm;
/** 监测方式 */
@FieldChinese("监测方式")
private Integer mway;
@TableField(exist = false)
private String mwayName;
/** 监测指标 */
@TableField("STINDX")
@FieldChinese("监测指标")
private String stindx;
/** 排序 */
@TableField("ORDER_INDEX")
@FieldChinese("排序")
private Integer orderIndex;
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
/** 所属水电基地编码 */
@TableField("BASE_ID")
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
/** 所属流域编码 */
@FieldChinese("所属流域编码")
private String rvcd;
@TableField(exist = false)
private String rvnm;
/** 简介 */
@FieldChinese("简介")
private String introduce;
/** LOGO图片 */
@FieldChinese("LOGO图片")
private String logo;
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/** 数据监测频次单位min */
@FieldChinese("数据监测频次单位min")
private Integer dtfrqcy;
/** 备注 */
@FieldChinese("备注")
private String remark;
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
/** 数据来源时间 */
@TableField("VLSR_TM")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
/** 服务对象 */
@TableField("FWDX")
@FieldChinese("服务对象")
private String fwdx;
/** 供电方式 */
@TableField("GDFS")
@FieldChinese("供电方式")
private String gdfs;
/** AI盒子配置 */
@TableField("AIPZ")
@FieldChinese("AI盒子配置")
private String aipz;
/** 模型版本 */
@TableField("MXBB")
@FieldChinese("模型版本")
private String mxbb;
/** IP地址 */
@TableField("IPADDR")
@FieldChinese("IP地址")
private String ipaddr;
/** SIM卡信息 */
@TableField("SIMINFO")
@FieldChinese("SIM卡信息")
private String siminfo;
/** 用途 */
@TableField("PURPOSE")
@FieldChinese("用途")
private String purpose;
/** 观察方式 */
@TableField("OBSERVE")
@FieldChinese("观察方式")
private String observe;
/** 地形裁剪范围 */
@TableField("BOX")
@FieldChinese("地形裁剪范围")
private String box;
// ---------- 审计字段 ----------
/** 创建人关联SYS_USER.ID */
@TableField("RECORD_USER")
@FieldChinese("创建人")
private String recordUser;
/** 创建时间 */
@TableField("RECORD_TIME")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("创建时间")
private Date recordTime;
/** 更新人关联SYS_USER.ID */
@TableField("MODIFY_USER")
@FieldChinese("更新人")
private String modifyUser;
/** 更新时间 */
@TableField("MODIFY_TIME")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("更新时间")
private Date modifyTime;
/** 是否已删除 */
@TableField("IS_DELETED")
@FieldChinese("是否已删除")
private Integer isDeleted;
/** 删除人关联SYS_USER.ID */
@TableField("DELETE_USER")
@FieldChinese("删除人")
private String deleteUser;
/** 删除时间 */
@TableField("DELETE_TIME")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("删除时间")
private Date deleteTime;
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -24,17 +25,20 @@ public class SdArtsgBH implements Serializable {
/**
* 测站编码
*/
@FieldChinese("测站编码")
@TableId(type = IdType.INPUT)
private String stcd;
/**
* 测站名称
*/
@FieldChinese("测站名称")
private String stnm;
/**
* 测站类型
*/
@FieldChinese("测站类型")
private String sttp;
@TableField(exist = false)
@ -43,37 +47,44 @@ public class SdArtsgBH implements Serializable {
/**
* 数据时间
*/
@FieldChinese("数据时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date tm;
/**
* 位置经度
*/
@FieldChinese("位置经度")
private BigDecimal lgtd;
/**
* 位置纬度
*/
@FieldChinese("位置纬度")
private BigDecimal lttd;
/**
* 高程
*/
@FieldChinese("高程")
private BigDecimal elev;
/**
* 站址
*/
@FieldChinese("站址")
private String stlc;
/**
* 是否启用
*/
@FieldChinese("是否启用")
private Integer usfl;
/**
* 数据是否接入
*/
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
@ -82,17 +93,20 @@ public class SdArtsgBH implements Serializable {
/**
* 数据接入时间
*/
@FieldChinese("数据接入时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date dtinTm;
/**
* 排序
*/
@FieldChinese("排序")
private Integer orderIndex;
/**
* 关联测站编码
*/
@FieldChinese("关联测站编码")
private String rstcd;
@TableField(exist = false)
@ -101,6 +115,7 @@ public class SdArtsgBH implements Serializable {
/**
* 所属基地编码
*/
@FieldChinese("所属基地编码")
private String baseId;
@TableField(exist = false)
@ -109,11 +124,13 @@ public class SdArtsgBH implements Serializable {
/**
* 所属基地流域编码
*/
@FieldChinese("所属基地流域编码")
private String hbrvcd;
/**
* 所属流域代码
*/
@FieldChinese("所属流域代码")
private String rvcd;
@ -123,47 +140,55 @@ public class SdArtsgBH implements Serializable {
/**
* 所属行政区编码
*/
@FieldChinese("所属行政区编码")
private String addvcd;
/**
* 规划设计日期
*/
@FieldChinese("规划设计日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date stdsdt;
/**
* 计划开工日期
*/
@FieldChinese("计划开工日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date pststdt;
/**
* 计划完工日期
*/
@FieldChinese("计划完工日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date pesstdt;
/**
* 开工日期
*/
@FieldChinese("开工日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date swdt;
/**
* 建成日期
*/
@FieldChinese("建成日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date jcdt;
/**
* 退役/拆除日期
*/
@FieldChinese("退役/拆除日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date wddt;
/**
* 建设状态代码
*/
@FieldChinese("建设状态代码")
private Integer bldsttCode;
@TableField(exist = false)
@ -172,71 +197,85 @@ public class SdArtsgBH implements Serializable {
/**
* 简介
*/
@FieldChinese("简介")
private String introduce;
/**
* LOGO
*/
@FieldChinese("LOGO")
private String logo;
/**
* 介绍文件
*/
@FieldChinese("介绍文件")
private String inffile;
/**
* 投资
*/
@FieldChinese("投资")
private BigDecimal inv;
/**
* 投资金额
*/
@FieldChinese("投资金额")
private Integer invinmn;
/**
* 保护措施
*/
@FieldChinese("保护措施")
private String prtcts;
/**
* 数量
*/
@FieldChinese("数量")
private Integer cnt;
/**
* 面积
*/
@FieldChinese("面积")
private BigDecimal ar;
/**
* 类型
*/
@FieldChinese("类型")
private String tp;
/**
* 附件
*/
@FieldChinese("附件")
private String attm;
/**
* 数据频率
*/
@FieldChinese("数据频率")
private String dtfrqcy;
/**
* 备注
*/
@FieldChinese("备注")
private String remark;
/**
* 植被覆盖类型
*/
@FieldChinese("植被覆盖类型")
private String vlsr;
/**
* 植被覆盖调查时间
*/
@FieldChinese("植被覆盖调查时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date vlsrTm;
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -21,341 +22,279 @@ public class SdDwBH implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 测站编码
*/
/** 低温水减缓设施编码 */
@TableId(type = IdType.INPUT)
@FieldChinese("低温水减缓设施编码")
private String stcd;
/**
* 数据时间
*/
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/**
* 测站名称
*/
/** 低温水减缓设施名称 */
@FieldChinese("低温水减缓设施名称")
private String stnm;
/**
* 测站类型
*/
/** 低温水减缓设施类型 */
@FieldChinese("低温水减缓设施类型")
private String sttp;
@TableField(exist = false)
private String sttpName;
/**
* 位置经度
*/
/** 经度(°) */
@FieldChinese("经度(°)")
private BigDecimal lgtd;
/**
* 位置纬度
*/
/** 纬度(°) */
@FieldChinese("纬度(°)")
private BigDecimal lttd;
/**
* 高程
*/
/** 高程(m) */
@FieldChinese("高程(m)")
private BigDecimal elev;
/**
* 站址
*/
/** 站址/位置 */
@FieldChinese("站址/位置")
private String stlc;
/**
* 是否启用
*/
/** 是否启用0=禁用 1=启用 */
@FieldChinese("是否启用")
private Integer usfl;
/**
* 数据是否接入
*/
/** 数据是否接入0=未接入 1=已接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
/**
* 数据接入时间
*/
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据接入时间")
private Date dtinTm;
/**
* 排序
*/
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/**
* 所属基地编码
*/
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/**
* 所属基地流域编码
*/
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
/**
* 关联测站编码
*/
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
/**
* 规划设计日期
*/
/** 规划设计日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("规划设计日期")
private Date stdsdt;
/**
* 计划开工日期
*/
/** 计划开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划开工日期")
private Date pststdt;
/**
* 计划完工日期
*/
/** 计划完工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划完工日期")
private Date pesstdt;
/**
* 开工日期
*/
/** 开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("开工日期")
private Date swdt;
/**
* 建成日期
*/
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
/**
* 退役/拆除日期
*/
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
/**
* 建设状态代码
*/
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/**
* 简介
*/
/** 简介 */
@FieldChinese("简介")
private String introduce;
/**
* LOGO
*/
/** LOGO图片 */
@FieldChinese("LOGO图片")
private String logo;
/**
* 介绍文件
*/
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/**
* 投资
*/
/** 总投资(亿元) */
@FieldChinese("总投资(亿元)")
private BigDecimal inv;
/**
* 投资金额
*/
/** 投资是否计入主体工程0=否 1=是 */
@FieldChinese("投资是否计入主体工程")
private Integer invinmn;
/**
* 调度方式
*/
/** 是否有调度规程分析0=无调度规程 1=有调度规程 */
@FieldChinese("是否有调度规程分析")
private Integer dispatch;
/**
* 调度描述
*/
/** 调度规程文字描述 */
@FieldChinese("调度规程文字描述")
private String dispatchDes;
/**
* 调度文件
*/
/** 调度规程文件 */
@FieldChinese("调度规程文件")
private String dispatchFile;
/**
* 叠梁门层数高度
*/
/** 多层式进水口-每层取水口高程(用"/"隔断) */
@FieldChinese("多层式进水口-每层取水口高程")
private String dcshg;
/**
* 叠梁门单层取水口个数
*/
/** 多层式进水口-取水口个数 */
@FieldChinese("多层式进水口-取水口个数")
private BigDecimal dcsqskgs;
/**
* 叠梁门层数
*/
/** 叠梁门/翻板门式进水口的门叶数量 */
@FieldChinese("叠梁门/翻板门式进水口的门叶数量")
private Integer dlmcnt;
/**
* 叠梁门高度
*/
/** 叠梁门/翻板门式进水口的单节门叶高度 */
@FieldChinese("叠梁门/翻板门式进水口的单节门叶高度")
private BigDecimal dlmhg;
/**
* 叠梁门底部高程
*/
/** 叠梁门/翻板门顶部高程 */
@FieldChinese("叠梁门/翻板门顶部高程")
private BigDecimal dlmdbgc;
/**
* 叠梁门最大温度梯度
*/
/** 叠梁门/翻板门式进水口的最大淹没水深 */
@FieldChinese("叠梁门/翻板门式进水口的最大淹没水深")
private BigDecimal dlmmxwdp;
/**
* 梯级电站台数
*/
/** 套筒式进水口的套筒数量 */
@FieldChinese("套筒式进水口的套筒数量")
private Integer ttscnt;
/**
* 梯级电站高度
*/
/** 套筒式进水口的单个套筒高度 */
@FieldChinese("套筒式进水口的单个套筒高度")
private BigDecimal ttshg;
/**
* 梯级电站最低死水位
*/
/** 套筒式进水口的最大淹没水深 */
@FieldChinese("套筒式进水口的最大淹没水深")
private BigDecimal ttszdss;
/**
* 取水口段结构
*/
/** 前置挡墙/隔水幕墙的结构形式 */
@FieldChinese("前置挡墙/隔水幕墙的结构形式")
private String qzdqjg;
/**
* 取水口段高度
*/
/** 前置挡墙的挡墙顶高程 */
@FieldChinese("前置挡墙的挡墙顶高程")
private BigDecimal qzdqhg;
/**
* 隔水幕墙长度
*/
/** 隔水幕墙的长度 */
@FieldChinese("隔水幕墙的长度")
private BigDecimal gsmqcd;
/**
* 隔水幕墙宽度
*/
/** 隔水幕墙的宽度 */
@FieldChinese("隔水幕墙的宽度")
private BigDecimal gsmqkd;
/**
* 隔水幕墙材料
*/
/** 隔水幕墙材料 */
@FieldChinese("隔水幕墙材料")
private BigDecimal gsmqcl;
/**
* 其他设施具体型式
*/
/** 其他设施具体型式 */
@FieldChinese("其他设施具体型式")
private String qtssjbtx;
/**
* 天然河流平均水温
*/
/** 天然河流平均水温 */
@FieldChinese("天然河流平均水温")
private BigDecimal nravwt;
/**
* 天然河流最高温月份多年平均水温
*/
/** 天然河流最高温月份多年平均水温 */
@FieldChinese("天然河流最高温月份多年平均水温")
private BigDecimal nrmxavwt;
/**
* 天然河流最低温月份多年平均水温
*/
/** 天然河流最低温月份多年平均水温 */
@FieldChinese("天然河流最低温月份多年平均水温")
private BigDecimal nrmnavwt;
/**
* 建成后坝下平均水温
*/
/** 建成后坝下平均水温 */
@FieldChinese("建成后坝下平均水温")
private BigDecimal dnavwt;
/**
* 建成后坝下最高温月份多年平均水温
*/
/** 建成后坝下最高温月份多年平均水温 */
@FieldChinese("建成后坝下最高温月份多年平均水温")
private BigDecimal dnmxavwt;
/**
* 建成后坝下最低温月份多年平均水温
*/
/** 建成后坝下最低温月份多年平均水温 */
@FieldChinese("建成后坝下最低温月份多年平均水温")
private BigDecimal dnmnavwt;
/**
* 数据频率
*/
/** 数据监测频次 */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/**
* 备注
*/
/** 备注 */
@FieldChinese("备注")
private String remark;
/**
* 植被覆盖类型
*/
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
/**
* 植被覆盖调查时间
*/
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
/**
* 创建人
*/
/** 创建人 */
@FieldChinese("创建人")
private String recordUser;
/**
* 创建时间
*/
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("创建时间")
private Date recordTime;
/**
* 更新人
*/
/** 更新人 */
@FieldChinese("更新人")
private String modifyUser;
/**
* 更新时间
*/
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("更新时间")
private Date modifyTime;
/**
* 是否已删除
*/
/** 是否已删除 */
@FieldChinese("是否已删除")
private Integer isDeleted;
/**
* 删除人
*/
/** 删除人 */
@FieldChinese("删除人")
private String deleteUser;
/**
* 删除时间
*/
/** 删除时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("删除时间")
private Date deleteTime;
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -21,296 +22,243 @@ public class SdEqBH implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 测站编码
*/
/** 生态流量泄放设施编码 */
@TableId(type = IdType.INPUT)
@FieldChinese("生态流量泄放设施编码")
private String stcd;
/**
* 测站名称
*/
/** 生态流量泄放设施名称 */
@FieldChinese("生态流量泄放设施名称")
private String stnm;
/**
* 数据时间
*/
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/**
* 测站类型
*/
/** 生态流量泄放设施类型 */
@FieldChinese("生态流量泄放设施类型")
private String sttp;
@TableField(exist = false)
private String sttpName;
/**
* 所属建设阶段
*/
/** 所属建设阶段 */
@FieldChinese("所属建设阶段")
private Integer blprd;
/**
* 位置经度
*/
/** 经度(单位:°) */
@FieldChinese("经度")
private BigDecimal lgtd;
/**
* 位置纬度
*/
/** 纬度(单位:°) */
@FieldChinese("纬度")
private BigDecimal lttd;
/**
* 高程
*/
/** 高程单位m */
@FieldChinese("高程")
private BigDecimal elev;
/**
* 站址
*/
/** 站址/位置 */
@FieldChinese("站址/位置")
private String stlc;
/**
* 是否启用
*/
/** 是否启用 */
@FieldChinese("是否启用")
private Integer usfl;
/**
* 数据是否接入
*/
/** 数据是否接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
/**
* 数据接入时间
*/
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据接入时间")
private Date dtinTm;
/**
* 排序
*/
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/**
* 关联测站编码
*/
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
/**
* 所属基地编码
*/
/** 所属基地编码 */
@FieldChinese("所属基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/**
* 所属基地流域编码
*/
/** 所属基地河段编码 */
@FieldChinese("所属基地河段编码")
private String hbrvcd;
/**
* 规划设计日期
*/
/** 规划设计日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("规划设计日期")
private Date stdsdt;
/**
* 计划开工日期
*/
/** 计划开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划开工日期")
private Date pststdt;
/**
* 计划完工日期
*/
/** 计划完工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划完工日期")
private Date pesstdt;
/**
* 开工日期
*/
/** 开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("开工日期")
private Date swdt;
/**
* 建成日期
*/
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
/**
* 退役/拆除日期
*/
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
/**
* 建设状态代码
*/
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/**
* 简介
*/
/** 简介 */
@FieldChinese("简介")
private String introduce;
/**
* LOGO
*/
/** LOGO图片 */
@FieldChinese("LOGO图片")
private String logo;
/**
* 介绍文件
*/
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/**
* 投资
*/
/** 投资(单位:亿元) */
@FieldChinese("投资")
private BigDecimal inv;
/**
* 投资金额
*/
/** 投资是否计入主体工程 */
@FieldChinese("投资是否计入主体工程")
private Integer invinmn;
/**
* 泄放孔结构
*/
/** 生态放流孔(闸、洞、管)-结构形式 */
@FieldChinese("生态放流孔(闸、洞、管)-结构形式")
private String flkjg;
/**
* 泄放孔尺寸
*/
/** 生态放流孔(闸、洞、管)-孔口尺寸单位m */
@FieldChinese("生态放流孔(闸、洞、管)-孔口尺寸")
private String flksz;
/**
* 单独泄放管渠
*/
/** 生态放流孔(闸、洞、管)-死水位时保证流量单位m³/s */
@FieldChinese("生态放流孔(闸、洞、管)-死水位时保证流量")
private String ddzgq;
/**
* 泄放孔口
*/
/** 生态放流孔(闸、洞、管)-最大泄放流量单位m³/s */
@FieldChinese("生态放流孔(闸、洞、管)-最大泄放流量")
private String flkq;
/**
* 进水口底板高程
*/
/** 生态放流孔(闸、洞、管)或生态机组-进水口地板高程单位m */
@FieldChinese("进水口底板高程")
private BigDecimal jskdbgc;
/**
* 出水口底板高程
*/
/** 生态放流孔(闸、洞、管)或生态机组-出水口地板高程单位m */
@FieldChinese("出水口底板高程")
private BigDecimal cskdbgc;
/**
* 检修放空管道
*/
/** 基荷发电工况单位MW */
@FieldChinese("基荷发电工况")
private String jhfdgk;
/**
* 泄放流量
*/
/** 基荷发电或生态机组-发电流量单位m³/s */
@FieldChinese("发电流量")
private BigDecimal fdll;
/**
* 生态机组装机容量
*/
/** 生态机组装机容量 */
@FieldChinese("生态机组装机容量")
private BigDecimal stjzzjrl;
/**
* 生态机组引水渠道
*/
/** 生态机组额定流量 */
@FieldChinese("生态机组额定流量")
private BigDecimal stjzysq;
/**
* 数据频率
*/
/** 数据监测频次单位min */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/**
* 评估方法
*/
/** 考核方式 */
@FieldChinese("考核方式")
private String assessMethod;
/**
* 是否计算器
*/
/** 是否建设期的考核要求 */
@FieldChinese("是否建设期的考核要求")
private Integer isJsq;
/**
* 是否流量
*/
/** 是否有下泄生态流量要求 */
@FieldChinese("是否有下泄生态流量要求")
private String isFlow;
/**
* 最小流量
*/
/** 最小保证下泄生态流量值单位m³/s */
@FieldChinese("最小保证下泄生态流量值")
private BigDecimal minFlow;
/**
* 备注
*/
/** 备注 */
@FieldChinese("备注")
private String remark;
/**
* 植被覆盖类型
*/
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
/**
* 植被覆盖调查时间
*/
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
/**
* 创建人
*/
/** 创建人 */
@FieldChinese("创建人")
private String recordUser;
/**
* 创建时间
*/
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("创建时间")
private Date recordTime;
/**
* 更新人
*/
/** 更新人 */
@FieldChinese("更新人")
private String modifyUser;
/**
* 更新时间
*/
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("更新时间")
private Date modifyTime;
/**
* 是否已删除
*/
/** 是否已删除 */
@FieldChinese("是否已删除")
private Integer isDeleted;
/**
* 删除人
*/
/** 删除人 */
@FieldChinese("删除人")
private String deleteUser;
/**
* 删除时间
*/
/** 删除时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("删除时间")
private Date deleteTime;
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -21,249 +22,205 @@ public class SdFbrdBH implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 测站编码
*/
/** 鱼类增殖站编码 */
@TableId(type = IdType.INPUT)
@FieldChinese("鱼类增殖站编码")
private String stcd;
/**
* 测站名称
*/
/** 鱼类增殖站名称 */
@FieldChinese("鱼类增殖站名称")
private String stnm;
/**
* 测站类型
*/
/** 站类 */
@FieldChinese("站类")
private String sttp;
@TableField(exist = false)
private String sttpName;
/**
* 数据时间
*/
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/**
* 所属建设阶段
*/
/** 所属建设阶段 */
@FieldChinese("所属建设阶段")
private Integer blprd;
/**
* 位置经度
*/
/** 经度(单位:°) */
@FieldChinese("经度")
private BigDecimal lgtd;
/**
* 位置纬度
*/
/** 纬度(单位:°) */
@FieldChinese("纬度")
private BigDecimal lttd;
/**
* 高程
*/
/** 高程单位m */
@FieldChinese("高程")
private BigDecimal elev;
/**
* 站址
*/
/** 站址/位置 */
@FieldChinese("站址/位置")
private String stlc;
/**
* 是否启用
*/
/** 是否启用 */
@FieldChinese("是否启用")
private Integer usfl;
/**
* 数据是否接入
*/
/** 数据是否接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
/**
* 数据接入时间
*/
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据接入时间")
private Date dtinTm;
/**
* 排序
*/
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/**
* 关联测站编码
*/
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
/**
* 所属基地编码
*/
/** 所属基地编码 */
@FieldChinese("所属基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/**
* 所属基地流域编码
*/
/** 所属基地河段编码 */
@FieldChinese("所属基地河段编码")
private String hbrvcd;
/**
* 环评单位
*/
/** 服务电站对象列表 */
@FieldChinese("服务电站对象列表")
private String rengcd;
/**
* 规划设计日期
*/
/** 规划设计日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("规划设计日期")
private Date stdsdt;
/**
* 计划开工日期
*/
/** 计划开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划开工日期")
private Date pststdt;
/**
* 计划完工日期
*/
/** 计划完工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划完工日期")
private Date pesstdt;
/**
* 开工日期
*/
/** 开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("开工日期")
private Date swdt;
/**
* 建成日期
*/
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
/**
* 退役/拆除日期
*/
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
/**
* 建设状态代码
*/
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/**
* 简介
*/
/** 简介 */
@FieldChinese("简介")
private String introduce;
/**
* LOGO
*/
/** LOGO图片 */
@FieldChinese("LOGO图片")
private String logo;
/**
* 介绍文件
*/
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/**
* 投资
*/
/** 投资(单位:亿元) */
@FieldChinese("投资")
private BigDecimal inv;
/**
* 投资金额
*/
/** 投资是否计入主体工程 */
@FieldChinese("投资是否计入主体工程")
private Integer invinmn;
/**
* 增殖放流面积
*/
/** 总占地面积单位km² */
@FieldChinese("总占地面积")
private BigDecimal zzflar;
/**
* 增殖放流工艺
*/
/** 生产工艺 */
@FieldChinese("生产工艺")
private String zzflgy;
/**
* 增殖放流鱼种描述
*/
/** 养殖模式 */
@FieldChinese("养殖模式")
private String zzflyzms;
/**
* 增殖放流标记方式
*/
/** 标记方式 */
@FieldChinese("标记方式")
private String zzflbjfs;
/**
* 增殖放流对象
*/
/** 放流对象 */
@FieldChinese("放流对象")
private String zzfldx;
/**
* 增殖放流数量
*/
/** 放流规模(单位:尾/年) */
@FieldChinese("放流规模")
private Integer zzflcnt;
/**
* 增殖放流放流流程
*/
/** 放流地点 */
@FieldChinese("放流地点")
private String zzflfllc;
/**
* 增殖放流时间
*/
/** 放流时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("放流时间")
private Date zzfltm;
/**
* 增殖放流任务
*/
/** 承担放流任务 */
@FieldChinese("承担放流任务")
private String zzflrw;
/**
* 设计单位
*/
/** 设计单位 */
@FieldChinese("设计单位")
private String dsun;
/**
* 基本特性参数
*/
/** 基本特性参数(文字描述) */
@FieldChinese("基本特性参数")
private String jbtxcs;
/**
* 数据频率
*/
/** 数据监测频次单位min */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/**
* 备注
*/
/** 备注 */
@FieldChinese("备注")
private String remark;
/**
* 植被覆盖类型
*/
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
/**
* 植被覆盖调查时间
*/
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -21,252 +22,206 @@ public class SdFhbtBH implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 测站编码
*/
/** 栖息地编码 */
@TableId(type = IdType.INPUT)
@FieldChinese("栖息地编码")
private String stcd;
/**
* 测站名称
*/
/** 栖息地名称 */
@FieldChinese("栖息地名称")
private String stnm;
/**
* 数据时间
*/
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/**
* 所属建设阶段
*/
/** 所属建设阶段 */
@FieldChinese("所属建设阶段")
private Integer blprd;
/**
* 位置经度
*/
/** 经度 */
@FieldChinese("经度")
private BigDecimal lgtd;
/**
* 位置纬度
*/
/** 纬度 */
@FieldChinese("纬度")
private BigDecimal lttd;
/**
* 高程
*/
/** 高程 */
@FieldChinese("高程")
private BigDecimal elev;
/**
* 站址
*/
/** 站址/位置 */
@FieldChinese("站址/位置")
private String stlc;
/**
* 是否启用
*/
/** 是否启用0=禁用 1=启用 */
@FieldChinese("是否启用")
private Integer usfl;
/**
* 数据是否接入
*/
/** 数据是否接入0=未接入 1=已接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
/**
* 数据接入时间
*/
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据接入时间")
private Date dtinTm;
/**
* 排序
*/
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/**
* 关联测站编码
*/
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
/**
* 所属基地编码
*/
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/**
* 所属基地流域编码
*/
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
/**
* 所属流域代码
*/
/** 所属流域编码 */
@FieldChinese("所属流域编码")
private String rvcd;
@TableField(exist = false)
private String rvnm;
/**
* 所属行政区编码
*/
/** 所属行政区编码 */
@FieldChinese("所属行政区编码")
private String addvcd;
/**
* 河段描述
*/
/** 河段描述 */
@FieldChinese("河段描述")
private String reachdes;
/**
* 经度纬度列表
*/
/** 栖息地范围经纬度列表 */
@FieldChinese("栖息地范围经纬度列表")
private String lglttd;
/**
* 简介
*/
/** 简介 */
@FieldChinese("简介")
private String introduce;
/**
* LOGO
*/
/** LOGO图片 */
@FieldChinese("LOGO图片")
private String logo;
/**
* 介绍文件
*/
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/**
* 投资
*/
/** 投资(单位:亿元) */
@FieldChinese("投资")
private BigDecimal inv;
/**
* 投资金额
*/
/** 投资是否计入主体工程 */
@FieldChinese("投资是否计入主体工程")
private Integer invinmn;
/**
* 保护对象
*/
/** 保护对象 */
@FieldChinese("保护对象")
private String bhdx;
/**
* 保护范围
*/
/** 保护范围 */
@FieldChinese("保护范围")
private String bhfw;
/**
* 保护措施
*/
/** 保护长度单位km */
@FieldChinese("保护长度")
private String bhcd;
/**
* 保护面积
*/
/** 保护面积单位km² */
@FieldChinese("保护面积")
private BigDecimal bhmj;
/**
* 保护河流
*/
/** 保护河流 */
@FieldChinese("保护河流")
private String bhhl;
/**
* 保护河道
*/
/** 保护河段 */
@FieldChinese("保护河段")
private String bhhd;
/**
* 保护措施
*/
/** 保护措施 */
@FieldChinese("保护措施")
private String bhcs;
/**
* 保护方式
*/
/** 保护方式 */
@FieldChinese("保护方式")
private String bhfs;
/**
* 附件
*/
/** 实施时间 */
@FieldChinese("实施时间")
private String attm;
/**
* 保护水文参数
*/
/** 保护外围长度单位km */
@FieldChinese("保护外围长度")
private String bhwwcd;
/**
* 保护河相关系
*/
/** 保护核心长度单位km */
@FieldChinese("保护核心长度")
private String bhhxcd;
/**
* 数据频率
*/
/** 数据监测频次单位min */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/**
* 备注
*/
/** 备注 */
@FieldChinese("备注")
private String remark;
/**
* 植被覆盖类型
*/
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
/**
* 植被覆盖调查时间
*/
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
/**
* 创建人
*/
/** 创建人 */
@FieldChinese("创建人")
private String recordUser;
/**
* 创建时间
*/
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("创建时间")
private Date recordTime;
/**
* 更新人
*/
/** 更新人 */
@FieldChinese("更新人")
private String modifyUser;
/**
* 更新时间
*/
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("更新时间")
private Date modifyTime;
/**
* 是否已删除
*/
/** 是否已删除 */
@FieldChinese("是否已删除")
private Integer isDeleted;
/**
* 删除人
*/
/** 删除人 */
@FieldChinese("删除人")
private String deleteUser;
/**
* 删除时间
*/
/** 删除时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("删除时间")
private Date deleteTime;
}

View File

@ -1,6 +1,7 @@
package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -19,278 +20,225 @@ public class SdFishDictoryB implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
/** 主键 */
@TableId(type = IdType.ASSIGN_UUID)
@FieldChinese("主键")
private String id;
/**
* 编码
*/
/** 编码 */
@FieldChinese("编码")
private String code;
/**
* 名称
*/
/** 名称 */
@FieldChinese("名称")
private String name;
/**
* 英文名称
*/
/** 英文名称 */
@FieldChinese("英文名称")
private String nameEn;
/**
* 俗名
*/
/** 俗名 */
@FieldChinese("俗名")
private String alias;
/**
* LOGO
*/
/** LOGO */
@FieldChinese("LOGO")
private String logo;
/**
* 介绍
*/
/** 介绍 */
@FieldChinese("介绍")
private String introduce;
/**
* 介绍弹窗图片
*/
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/**
*
*/
/** 目 */
@FieldChinese("")
private String orders;
/**
*
*/
/** 科 */
@FieldChinese("")
private String family;
/**
*
*/
/** 属 */
@FieldChinese("")
private String genus;
/**
*
*/
/** 种 */
@FieldChinese("")
private String species;
/**
* 分类1=淡水 2=海水
*/
/** 分类1=淡水 2=海水 */
@FieldChinese("分类")
private Integer type;
@TableField(exist = false)
private String typeName;
/**
* 成鱼大小单位cm
*/
/** 成鱼大小单位cm */
@FieldChinese("成鱼大小")
private String fsz;
/**
* 是否珍稀鱼类0= 1=
*/
/** 是否珍稀鱼类0=否 1=是 */
@FieldChinese("是否珍稀鱼类")
private Integer rare;
@TableField(exist = false)
private String rareName;
/**
* 物种来源1=本土物种 2=外来物种
*/
/** 物种来源1=本土物种 2=外来物种 */
@FieldChinese("物种来源")
private Integer specOrigin;
@TableField(exist = false)
private String specOriginName;
/**
* 保护类型1=濒危 2=极危 3=近危 4=易危 5=重点保护 6=无危 7=国家二级 8=市二级保护
*/
/** 保护类型 */
@FieldChinese("保护类型")
private Integer ptype;
@TableField(exist = false)
private String ptypeName;
/**
* 所属流域
*/
/** 所属流域 */
@FieldChinese("所属流域")
private String rvcd;
/**
* 洄游习性
*/
/** 洄游习性 */
@FieldChinese("洄游习性")
private String habitMigrat;
/**
* 摄食习性
*/
/** 摄食习性 */
@FieldChinese("摄食习性")
private String feedingHabit;
/**
* 产卵特性
*/
/** 产卵特性 */
@FieldChinese("产卵特性")
private String spawnCharact;
/**
* 主要食物
*/
/** 主要食物 */
@FieldChinese("主要食物")
private String food;
/**
* 觅食时段
*/
/** 觅食时段 */
@FieldChinese("觅食时段")
private String timeFeed;
/**
* 产地及产期
*/
/** 产地及产期 */
@FieldChinese("产地及产期")
private String orignDate;
/**
* 适宜温度单位
*/
/** 适宜温度:单位:℃ */
@FieldChinese("适宜温度")
private String pretemp;
/**
* 适宜流速单位m/s
*/
/** 适宜流速单位m/s */
@FieldChinese("适宜流速")
private String flowRate;
/**
* 适宜水深单位m
*/
/** 适宜水深单位m */
@FieldChinese("适宜水深")
private String depth;
/**
* 适宜底质
*/
/** 适宜底质 */
@FieldChinese("适宜底质")
private String botmMater;
/**
* 水质要求1= 2= 3= 4= 5= 6=劣质V
*/
/** 水质要求 */
@FieldChinese("水质要求")
private String wqtq;
// @TableField(exist = false)
// private String wqtqName;
/**
* 主要生活环境 1=流水生境 2=静缓流生境 3=洞穴生境
*/
/** 主要生活环境 1=流水生境 2=静缓流生境 3=洞穴生境 */
@FieldChinese("主要生活环境")
private Integer habitat;
@TableField(exist = false)
private String habitatName;
/**
* 种群现状 1=优势种 2=常见种 3=少见种 4=记录种
*/
/** 种群现状 1=优势种 2=常见种 3=少见种 4=记录种 */
@FieldChinese("种群现状")
private Integer situation;
@TableField(exist = false)
private String situationName;
/**
* 资源类型 1=保护鱼类 2=特有鱼类 3=重要经济鱼类 4=濒危状况
*/
/** 资源类型 1=保护鱼类 2=特有鱼类 3=重要经济鱼类 4=濒危状况 */
@FieldChinese("资源类型")
private Integer resourceType;
@TableField(exist = false)
private String resourceTypeName;
/**
* 形态描述
*/
/** 形态描述 */
@FieldChinese("形态描述")
private String shapedesc;
/**
* 保护级别
*/
/** 保护级别 */
@FieldChinese("保护级别")
private String protectlvl;
/**
* 栖息习性
*/
/** 栖息习性 */
@FieldChinese("栖息习性")
private String habitation;
/**
* 附件
*/
/** 附件 */
@FieldChinese("附件")
private String fid;
/**
* 描述
*/
/** 描述 */
@FieldChinese("描述")
private String description;
/**
* 是否启用0=禁用 1=启用
*/
/** 是否启用0=禁用 1=启用 */
@FieldChinese("是否启用")
private Integer enable;
/**
* 系统内置项0= 1=
*/
/** 系统内置项0=否 1=是 */
@FieldChinese("系统内置项")
private Integer internal;
/**
* 排序
*/
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/**
* 创建人关联SYS_USER.ID
*/
/** 创建人 */
@FieldChinese("创建人")
private String recordUser;
/**
* 创建时间
*/
/** 创建时间 */
@FieldChinese("创建时间")
private Date recordTime;
/**
* 更新人关联SYS_USER.ID
*/
/** 更新人 */
@FieldChinese("更新人")
private String modifyUser;
/**
* 更新时间
*/
/** 更新时间 */
@FieldChinese("更新时间")
private Date modifyTime;
/**
* 是否已删除0=未删除 1=已删除
*/
/** 是否已删除 */
@FieldChinese("是否已删除")
private Integer isDeleted;
/**
* 删除人关联SYS_USER.ID
*/
/** 删除人 */
@FieldChinese("删除人")
private String deleteUser;
/**
* 删除时间
*/
/** 删除时间 */
@FieldChinese("删除时间")
private Date deleteTime;
/**
* 产卵月份多个月份以逗号分隔
*/
/** 产卵月份:多个月份以逗号分隔 */
@FieldChinese("产卵月份")
private String spawnMonth;
/**
* 数据来源
*/
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
/**
* 数据来源时间
*/
/** 数据来源时间 */
@FieldChinese("数据来源时间")
private Date vlsrTm;
}

View File

@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import java.io.Serializable;
@ -22,455 +23,368 @@ public class SdFpssBH implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 过鱼设施编码
*/
/** 过鱼设施编码 */
@TableId(type = IdType.INPUT)
@FieldChinese("过鱼设施编码")
private String stcd;
/**
* 设施名称
*/
/** 过鱼设施名称 */
@FieldChinese("过鱼设施名称")
private String stnm;
/**
* 所属水电基地流域编码
*/
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
/**
* 数据时间
*/
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/**
* 过鱼设施类型字典编码sd_fpss_b_h.sttp
* FP_1=鱼道 FP_2=仿自然通道 FP_3=集运鱼系统 FP_4=升鱼机 FP_5=其它过鱼方式 FP_6=网捕过坝
*/
/** 过鱼设施类型 */
@FieldChinese("过鱼设施类型")
private String sttp;
@TableField(exist = false)
private String sttpName;
/**
* 所属基地编码
*/
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/**
* 所属建设阶段 字典编码common.blprd
* 1001000=规划 1002000=预可研 1003000=环评 1004000=可研 1005000=在建 1006000=招标设计
* 1007000=施工详图 1009000=建设 1010000=蓄水阶段环保验收 1011000=竣工 1012000=竣工环保验收 1013000=环境影响后评价
*/
/** 所属建设阶段 */
@FieldChinese("所属建设阶段")
private Integer blprd;
/**
* 经度单位(°)
*/
/** 经度,单位:(°) */
@FieldChinese("经度")
private BigDecimal lgtd;
/**
* 纬度单位(°)
*/
/** 纬度,单位:(°) */
@FieldChinese("纬度")
private BigDecimal lttd;
/**
* 高程单位m
*/
/** 高程单位m */
@FieldChinese("高程")
private BigDecimal elev;
/**
* 站址/位置
*/
/** 站址/位置 */
@FieldChinese("站址/位置")
private String stlc;
/**
* 是否启用 字典编码common.enabled 0=禁用 1=启用
*/
/** 是否启用 */
@FieldChinese("是否启用")
private Integer usfl;
/**
* 数据是否接入 字典编码common.yn 0= 1=
*/
/** 数据是否接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
/**
* 数据接入时间
*/
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据接入时间")
private Date dtinTm;
/**
* 排序按照业务规则"升序"
*/
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/**
* 所属电站编码关联SD_ENGINFO_B_H.STCD
*/
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
/**
* 规划设计日期
*/
/** 规划设计日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("规划设计日期")
private Date stdsdt;
/**
* 计划开工日期
*/
/** 计划开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划开工日期")
private Date pststdt;
/**
* 计划完工日期
*/
/** 计划完工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划完工日期")
private Date pesstdt;
/**
* 开工日期
*/
/** 开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("开工日期")
private Date swdt;
/**
* 建成日期
*/
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
/**
* 退役/拆除日期
*/
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
/**
* 建设状态分类0=未建/规划(3,4,5,6,为空) 1=在建(2,7,8) 2=已建(1,10,11)
*/
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/**
* 简介
*/
/** 简介 */
@FieldChinese("简介")
private String introduce;
/**
* LOGO
*/
/** LOGO */
@FieldChinese("LOGO")
private String logo;
/**
* 介绍弹窗图片
*/
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/**
* 投资单位亿元
*/
/** 投资,单位:亿元 */
@FieldChinese("投资")
private BigDecimal inv;
/**
* 鱼道型式
*/
/** 鱼道型式 */
@FieldChinese("鱼道型式")
private String ydxs;
/**
* 鱼道总长度单位m
*/
/** 鱼道总长度单位m */
@FieldChinese("鱼道总长度")
private BigDecimal ydzcd;
/**
* 鱼道进口运行设计水位单位m
*/
/** 鱼道进口运行设计水位单位m */
@FieldChinese("鱼道进口运行设计水位")
private BigDecimal ydjkz;
/**
* 鱼道进口数量单位
*/
/** 鱼道进口数量,单位:个 */
@FieldChinese("鱼道进口数量")
private Integer ydjkcnt;
/**
* 鱼道或仿自然通道-进口高程单位m
*/
/** 鱼道或仿自然通道-进口高程单位m */
@FieldChinese("鱼道或仿自然通道-进口高程")
private BigDecimal jkhg;
/**
* 鱼道进口诱鱼型式
*/
/** 鱼道进口诱鱼型式 */
@FieldChinese("鱼道进口诱鱼型式")
private String ydyyxs;
/**
* 鱼道出口运行设计水位单位m
*/
/** 鱼道出口运行设计水位单位m */
@FieldChinese("鱼道出口运行设计水位")
private BigDecimal ydckz;
/**
* 鱼道出口数量单位
*/
/** 鱼道出口数量,单位:个 */
@FieldChinese("鱼道出口数量")
private Integer ydckcnt;
/**
* 鱼道或仿自然通道-出口高程单位m
*/
/** 鱼道或仿自然通道-出口高程单位m */
@FieldChinese("鱼道或仿自然通道-出口高程")
private BigDecimal ckhg;
/**
* 鱼道池室设计流速单位m/s
*/
/** 鱼道池室设计流速单位m/s */
@FieldChinese("鱼道池室设计流速")
private BigDecimal ydcsv;
/**
* 鱼道每级池室长单位m
*/
/** 鱼道每级池室长单位m */
@FieldChinese("鱼道每级池室长")
private Integer ydcscd;
/**
* 鱼道每级池室宽单位m
*/
/** 鱼道每级池室宽单位m */
@FieldChinese("鱼道每级池室宽")
private Integer ydcskd;
/**
* 鱼道池室坡度
*/
/** 鱼道池室坡度 */
@FieldChinese("鱼道池室坡度")
private String ydcspd;
/**
* 鱼道池室数量单位
*/
/** 鱼道池室数量,单位:个 */
@FieldChinese("鱼道池室数量")
private Integer ydcscnt;
/**
* 鱼道休息池个数
*/
/** 鱼道休息池个数 */
@FieldChinese("鱼道休息池个数")
private Integer ydxxccnt;
/**
* 鱼道或仿自然通道-流速单位m/s
*/
/** 鱼道或仿自然通道-流速单位m/s */
@FieldChinese("鱼道或仿自然通道-流速")
private String flow;
/**
* 仿自然通道断面形状
*/
/** 仿自然通道断面形状 */
@FieldChinese("仿自然通道断面形状")
private String fzrdmxz;
/**
* 仿自然通道长度*宽度
*/
/** 仿自然通道长度*宽度 */
@FieldChinese("仿自然通道长度*宽度")
private String fzrtdsz;
/**
* 仿自然通道运行水深单位m
*/
/** 仿自然通道运行水深单位m */
@FieldChinese("仿自然通道运行水深")
private BigDecimal fzryxwdp;
/**
* 仿自然通道坡降
*/
/** 仿自然通道坡降 */
@FieldChinese("仿自然通道坡降")
private BigDecimal fzrpj;
/**
* 集运鱼系统或升鱼机-上游码头位置
*/
/** 集运鱼系统或升鱼机-上游码头位置 */
@FieldChinese("集运鱼系统或升鱼机-上游码头位置")
private String symtlc;
/**
* 集运鱼系统或升鱼机-上游码头型式
*/
/** 集运鱼系统或升鱼机-上游码头型式 */
@FieldChinese("集运鱼系统或升鱼机-上游码头型式")
private String symtxs;
/**
* 集运鱼系统或升鱼机-下游码头位置
*/
/** 集运鱼系统或升鱼机-下游码头位置 */
@FieldChinese("集运鱼系统或升鱼机-下游码头位置")
private String xymtlc;
/**
* 集运鱼系统或升鱼机-下游码头型式
*/
/** 集运鱼系统或升鱼机-下游码头型式 */
@FieldChinese("集运鱼系统或升鱼机-下游码头型式")
private String xymtxs;
/**
* 集运鱼系统或升鱼机-集诱鱼方式
*/
/** 集运鱼系统或升鱼机-集诱鱼方式 */
@FieldChinese("集运鱼系统或升鱼机-集诱鱼方式")
private String jyfs;
/**
* 集运鱼系统或升鱼机-运鱼设施方式
*/
/** 集运鱼系统或升鱼机-运鱼设施方式 */
@FieldChinese("集运鱼系统或升鱼机-运鱼设施方式")
private String yyfs;
/**
* 升鱼机集鱼槽数量单位
*/
/** 升鱼机集鱼槽数量,单位:个 */
@FieldChinese("升鱼机集鱼槽数量")
private Integer syjcnt;
/**
* 升鱼机集鱼槽进口高程单位m
*/
/** 升鱼机集鱼槽进口高程单位m */
@FieldChinese("升鱼机集鱼槽进口高程")
private BigDecimal syjhg;
/**
* 升鱼机集鱼槽流量单位m3/s
*/
/** 升鱼机集鱼槽流量单位m3/s */
@FieldChinese("升鱼机集鱼槽流量")
private String syjq;
/**
* 升鱼机断面尺寸**单位m
*/
/** 升鱼机断面尺寸(长*宽*高单位m */
@FieldChinese("升鱼机断面尺寸")
private String syjsz;
/**
* 升鱼机集鱼槽水深单位m
*/
/** 升鱼机集鱼槽水深单位m */
@FieldChinese("升鱼机集鱼槽水深")
private String syjwdp;
/**
* 设计过鱼规模单位
*/
/** 设计过鱼规模,单位:尾 */
@FieldChinese("设计过鱼规模")
private String sjgycnt;
/**
* 主要过鱼对象{[code:鱼编码1,name:鱼名称1数量],[code:鱼编码2,name:鱼名称2]...}
*/
/** 主要过鱼对象 */
@FieldChinese("主要过鱼对象")
private String zygydx;
/**
* 主要过鱼对象描述
*/
/** 主要过鱼对象描述 */
@FieldChinese("主要过鱼对象描述")
private String zygydxms;
/**
* 兼顾过鱼对象{[code:鱼编码1,name:鱼名称1数量],[code:鱼编码2,name:鱼名称2]...}
*/
/** 兼顾过鱼对象 */
@FieldChinese("兼顾过鱼对象")
private String jggydx;
/**
* 兼顾过鱼对象描述
*/
/** 兼顾过鱼对象描述 */
@FieldChinese("兼顾过鱼对象描述")
private String jggydxms;
/**
* 过鱼时间
*/
/** 过鱼时间 */
@FieldChinese("过鱼时间")
private String gytm;
/**
* 所属测站编码
*/
/** 所属测站编码 */
@FieldChinese("所属测站编码")
private String stCode;
/**
* 运行时间
*/
/** 运行时间 */
@FieldChinese("运行时间")
private String yxtm;
/**
* 主要过鱼月份多个月份用,隔开
*/
/** 主要过鱼月份(多个月份用,隔开) */
@FieldChinese("主要过鱼月份")
private String fpssmn;
/**
* 数据监测频次单位min
*/
/** 数据监测频次单位min */
@FieldChinese("数据监测频次")
private Integer dtfrqcy;
/**
* 基本特性参数文字描述
*/
/** 基本特性参数(文字描述) */
@FieldChinese("基本特性参数")
private String jbtxcs;
/**
* 设施是否实现鱼类上行 0= 1=
*/
/** 设施是否实现鱼类上行 0=否 1=是 */
@FieldChinese("设施是否实现鱼类上行")
private Integer isUp;
@TableField(exist = false)
private String isUpName;
/**
* 设施是否实现鱼类下行 0= 1=
*/
/** 设施是否实现鱼类下行 0=否 1=是 */
@FieldChinese("设施是否实现鱼类下行")
private Integer isDown;
@TableField(exist = false)
private String isDownName;
/**
* 监测方式1=人工 2=自动
*/
/** 监测方式1=人工 2=自动 */
@FieldChinese("监测方式")
private Integer mway;
@TableField(exist = false)
private String mwayName;
/**
* 备注
*/
/** 备注 */
@FieldChinese("备注")
private String remark;
/**
* 数据来源
*/
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
/**
* 数据来源时间
*/
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
/**
* 创建人
*/
/** 创建人 */
@FieldChinese("创建人")
private String recordUser;
/**
* 创建时间
*/
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("创建时间")
private Date recordTime;
/**
* 更新人
*/
/** 更新人 */
@FieldChinese("更新人")
private String modifyUser;
/**
* 更新时间
*/
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("更新时间")
private Date modifyTime;
/**
* 是否已删除
*/
/** 是否已删除 */
@FieldChinese("是否已删除")
private Integer isDeleted;
/**
* 删除人
*/
/** 删除人 */
@FieldChinese("删除人")
private String deleteUser;
/**
* 删除时间
*/
/** 删除时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("删除时间")
private Date deleteTime;
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import com.yfd.platform.annotation.UserIdField;
import com.yfd.platform.annotation.UserNameField;
import lombok.Data;
@ -15,210 +16,308 @@ import java.util.Date;
public class SdOpinfoBH implements Serializable {
private static final long serialVersionUID = 1L;
/** 倾斜摄影站点编码 */
@TableId(type = IdType.INPUT)
@FieldChinese("倾斜摄影站点编码")
private String stcd;
/** 站点名称 */
@FieldChinese("站点名称")
private String stnm;
/** 站类 */
@FieldChinese("站类")
private String sttp;
@TableField(exist = false)
private String sttpName;
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/** 所属建设阶段 */
@FieldChinese("所属建设阶段")
private Integer blprd;
/** 经度。单位:(°) */
@FieldChinese("经度")
private BigDecimal lgtd;
/** 纬度。单位:(°) */
@FieldChinese("纬度")
private BigDecimal lttd;
/** 高程。单位:(°) */
@FieldChinese("高程")
private BigDecimal elev;
/** 位置 */
@FieldChinese("位置")
private String stlc;
/** 是否启用 */
@FieldChinese("是否启用")
private Integer usfl;
/** 数据是否接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField("DTIN_TM")
@FieldChinese("数据接入时间")
private Date dtinTm;
@TableField("ORDER_INDEX")
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
@TableField("BASE_ID")
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
@TableField(exist = false)
private String hbrvcdName;
/** 所属流域代码 */
@FieldChinese("所属流域代码")
private String rvcd;
@TableField(exist = false)
private String rvnm;
/** 所属行政区编码 */
@FieldChinese("所属行政区编码")
private String addvcd;
@TableField("STDSDT")
/** 规划设计日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("规划设计日期")
private Date stdsdt;
@TableField("PSTSTDT")
/** 计划开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划开工日期")
private Date pststdt;
@TableField("PESSTDT")
/** 计划完工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划完工日期")
private Date pesstdt;
@TableField("SWDT")
/** 开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("开工日期")
private Date swdt;
@TableField("JCDT")
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
@TableField("WDDT")
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
@TableField("BLDSTT_CODE")
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/** 简介 */
@FieldChinese("简介")
private String introduce;
/** LOGO */
@FieldChinese("LOGO")
private String logo;
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/** 在线地址 */
@FieldChinese("在线地址")
private String url;
/** 自定义高程(前端) */
@FieldChinese("自定义高程")
private BigDecimal height;
/** 边界数据 */
@FieldChinese("边界数据")
private String boundary;
@TableField("CENTER_LGTD")
/** 中心点经度 */
@FieldChinese("中心点经度")
private BigDecimal centerLgtd;
@TableField("CENTER_LTTD")
/** 中心点纬度 */
@FieldChinese("中心点纬度")
private BigDecimal centerLttd;
@TableField("CENTER_ELEV")
/** 中心点高程 */
@FieldChinese("中心点高程")
private BigDecimal centerElev;
/** 说明 */
@FieldChinese("说明")
private String description;
@TableField("CENTER1_LGTD")
/** 中心点1经度 */
@FieldChinese("中心点1经度")
private BigDecimal center1Lgtd;
@TableField("CENTER1_LTTD")
/** 中心点1纬度 */
@FieldChinese("中心点1纬度")
private BigDecimal center1Lttd;
@TableField("CENTER1_ELEV")
/** 中心点1高程 */
@FieldChinese("中心点1高程")
private BigDecimal center1Elev;
@TableField("CLIPPING_PLANES")
/** 裁剪平面 */
@FieldChinese("裁剪平面")
private String clippingPlanes;
@TableField("DESTINATION_TYPE")
/** 相机位置坐标系类型 */
@FieldChinese("相机位置坐标系类型")
private String destinationType;
@TableField("DESTINATION_LGTD")
/** 相机位置经度X */
@FieldChinese("相机位置经度X")
private BigDecimal destinationLgtd;
@TableField("DESTINATION_LTTD")
/** 相机位置纬度Y */
@FieldChinese("相机位置纬度Y")
private BigDecimal destinationLttd;
@TableField("DESTINATION_ELEV")
/** 相机位置高度Z */
@FieldChinese("相机位置高度Z")
private BigDecimal destinationElev;
@TableField("ORIENTATION_ROLL")
/** 摄像头滚转角X */
@FieldChinese("摄像头滚转角X")
private BigDecimal orientationRoll;
@TableField("ORIENTATION_HEADING")
/** 摄像头偏航角Z(左右旋转) */
@FieldChinese("摄像头偏航角Z")
private BigDecimal orientationHeading;
@TableField("ORIENTATION_PITCH")
/** 摄像头俯仰角Y(上下旋转) */
@FieldChinese("摄像头俯仰角Y")
private BigDecimal orientationPitch;
@TableField("REVISE_SITE_ELEV")
/** 前端校正站点高程 */
@FieldChinese("前端校正站点高程")
private BigDecimal reviseSiteElev;
@TableField("REVISE_SITE_ELEV_FACTOR")
/** 前端校正站点高程系数 */
@FieldChinese("前端校正站点高程系数")
private BigDecimal reviseSiteElevFactor;
@TableField("DESTINATION_LGTD_WCS")
/** 相机位置经度X世界坐标系 */
@FieldChinese("相机位置经度X世界坐标系")
private BigDecimal destinationLgtdWcs;
@TableField("DESTINATION_LTTD_WCS")
/** 相机位置纬度Y世界坐标系 */
@FieldChinese("相机位置纬度Y世界坐标系")
private BigDecimal destinationLttdWcs;
@TableField("DESTINATION_ELEV_WCS")
/** 相机位置高度Z世界坐标系 */
@FieldChinese("相机位置高度Z世界坐标系")
private BigDecimal destinationElevWcs;
@TableField("DESTINATION_LGTD_WGS84")
/** 相机位置经度X WGS-84坐标系 */
@FieldChinese("相机位置经度X WGS-84坐标系")
private BigDecimal destinationLgtdWgs84;
@TableField("DESTINATION_LTTD_WGS84")
/** 相机位置纬度Y WGS-84坐标系 */
@FieldChinese("相机位置纬度Y WGS-84坐标系")
private BigDecimal destinationLttdWgs84;
@TableField("DESTINATION_ELEV_WGS84")
/** 相机位置高度Z WGS-84坐标系 */
@FieldChinese("相机位置高度Z WGS-84坐标系")
private BigDecimal destinationElevWgs84;
/** 倾斜摄影电站坐标json串 */
@FieldChinese("倾斜摄影电站坐标json串")
private String location;
/** 倾斜摄影模型精度 */
@FieldChinese("倾斜摄影模型精度")
private String accuracy;
@TableField("STNM_ALIAS")
/** 别名 */
@FieldChinese("别名")
private String stnmAlias;
/** 备注 */
@FieldChinese("备注")
private String remark;
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
@TableField("VLSR_TM")
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
/** 创建时间 */
@TableField("RECORD_TIME")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("创建时间")
private Date recordTime;
/** 更新人 */
@TableField("MODIFY_USER")
@FieldChinese("更新人")
private String modifyUser;
/** 更新时间 */
@TableField("MODIFY_TIME")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("更新时间")
private Date modifyTime;
/** 是否已删除 */
@TableField("IS_DELETED")
@FieldChinese("是否已删除")
private Integer isDeleted;
/** 删除人 */
@TableField("DELETE_USER")
@FieldChinese("删除人")
private String deleteUser;
/** 删除时间 */
@TableField("DELETE_TIME")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("删除时间")
private Date deleteTime;
/** 所属站类全路径(非数据库字段) */
@ -232,6 +331,7 @@ public class SdOpinfoBH implements Serializable {
/** 创建人 */
@TableField("RECORD_USER")
@UserIdField
@FieldChinese("创建人")
private String recordUser;
/** 创建人名称(非数据库字段) */

View File

@ -2,124 +2,185 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 其他陆生生态保护工程信息表
*/
@Data
@TableName("SD_OTTE_B_H")
public class SdOtteBH implements Serializable {
private static final long serialVersionUID = 1L;
/** 其他陆生生态保护工程编码 */
@TableId(type = IdType.INPUT)
@FieldChinese("其他陆生生态保护工程编码")
private String stcd;
/** 其他陆生生态保护工程名称 */
@FieldChinese("其他陆生生态保护工程名称")
private String stnm;
/** 站类 */
@FieldChinese("站类")
private String sttp;
@TableField(exist = false)
private String sttpName;
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/** 所属建设阶段 */
@FieldChinese("所属建设阶段")
private Integer blprd;
/** 经度(单位:°) */
@FieldChinese("经度")
private BigDecimal lgtd;
/** 纬度(单位:°) */
@FieldChinese("纬度")
private BigDecimal lttd;
/** 高程单位m */
@FieldChinese("高程")
private BigDecimal elev;
/** 站址/位置 */
@FieldChinese("站址/位置")
private String stlc;
/** 是否启用 */
@FieldChinese("是否启用")
private Integer usfl;
@TableField(exist = false)
private String usflName;
/** 数据是否接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField("DTIN_TM")
@FieldChinese("数据接入时间")
private Date dtinTm;
@TableField("ORDER_INDEX")
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
@TableField("BASE_ID")
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
/** 所属流域编码 */
@FieldChinese("所属流域编码")
private String rvcd;
@TableField(exist = false)
private String rvnm;
/** 所属行政区划编码 */
@FieldChinese("所属行政区划编码")
private String addvcd;
@TableField("STDSDT")
/** 规划设计日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("规划设计日期")
private Date stdsdt;
@TableField("PSTSTDT")
/** 计划开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划开工日期")
private Date pststdt;
@TableField("PESSTDT")
/** 计划完工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划完工日期")
private Date pesstdt;
@TableField("SWDT")
/** 开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("开工日期")
private Date swdt;
@TableField("JCDT")
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
@TableField("WDDT")
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
@TableField("BLDSTT_CODE")
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/** 简介 */
@FieldChinese("简介")
private String introduce;
/** LOGO图片 */
@FieldChinese("LOGO图片")
private String logo;
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/** 投资(单位:亿元) */
@FieldChinese("投资")
private BigDecimal inv;
/** 基本特性参数(文字描述) */
@FieldChinese("基本特性参数")
private String jbtxcs;
/** 数据监测频次单位min */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/** 备注 */
@FieldChinese("备注")
private String remark;
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
@TableField("VLSR_TM")
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
}

View File

@ -2,126 +2,189 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 其他水生生态保护工程信息表
*/
@Data
@TableName("SD_OTWE_B_H")
public class SdOtweBH implements Serializable {
private static final long serialVersionUID = 1L;
/** 其他水生生态保护工程编码 */
@TableId(type = IdType.INPUT)
@FieldChinese("其他水生生态保护工程编码")
private String stcd;
/** 其他水生生态保护工程名称 */
@FieldChinese("其他水生生态保护工程名称")
private String stnm;
/** 站类 */
@FieldChinese("站类")
private String sttp;
@TableField(exist = false)
private String sttpName;
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/** 所属建设阶段 */
@FieldChinese("所属建设阶段")
private Integer blprd;
/** 经度(单位:°) */
@FieldChinese("经度")
private BigDecimal lgtd;
/** 纬度(单位:°) */
@FieldChinese("纬度")
private BigDecimal lttd;
/** 高程单位m */
@FieldChinese("高程")
private BigDecimal elev;
/** 站址/位置 */
@FieldChinese("站址/位置")
private String stlc;
/** 是否启用 */
@FieldChinese("是否启用")
private Integer usfl;
@TableField(exist = false)
private String usflName;
/** 数据是否接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField("DTIN_TM")
@FieldChinese("数据接入时间")
private Date dtinTm;
@TableField("ORDER_INDEX")
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
@TableField("BASE_ID")
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
/** 所属流域编码 */
@FieldChinese("所属流域编码")
private String rvcd;
@TableField(exist = false)
private String rvnm;
/** 所属行政区划编码 */
@FieldChinese("所属行政区划编码")
private String addvcd;
@TableField("STDSDT")
/** 规划设计日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("规划设计日期")
private Date stdsdt;
@TableField("PSTSTDT")
/** 计划开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划开工日期")
private Date pststdt;
@TableField("PESSTDT")
/** 计划完工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划完工日期")
private Date pesstdt;
@TableField("SWDT")
/** 开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("开工日期")
private Date swdt;
@TableField("JCDT")
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
@TableField("WDDT")
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
@TableField("BLDSTT_CODE")
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/** 简介 */
@FieldChinese("简介")
private String introduce;
/** LOGO图片 */
@FieldChinese("LOGO图片")
private String logo;
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/** 投资(单位:亿元) */
@FieldChinese("投资")
private BigDecimal inv;
/** 投资是否计入主体工程 */
@FieldChinese("投资是否计入主体工程")
private Integer invinmn;
/** 基本特性参数(文字描述) */
@FieldChinese("基本特性参数")
private String jbtxcs;
/** 数据监测频次单位min */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/** 备注 */
@FieldChinese("备注")
private String remark;
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
@TableField("VLSR_TM")
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
}

View File

@ -2,142 +2,211 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 声呐及水下摄像头基本属性表
*/
@Data
@TableName("SD_SONAR_B_H")
public class SdSonarBH implements Serializable {
private static final long serialVersionUID = 1L;
/** 站码 */
@TableId(type = IdType.INPUT)
@FieldChinese("站码")
private String stcd;
/** 站名 */
@FieldChinese("站名")
private String stnm;
/** 监控类型 */
@FieldChinese("监控类型")
private String mntp;
/** 监控类别 */
@FieldChinese("监控类别")
private String sttp;
@TableField(exist = false)
private String sttpName;
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/** 经度(单位:°) */
@FieldChinese("经度")
private BigDecimal lgtd;
/** 纬度(单位:°) */
@FieldChinese("纬度")
private BigDecimal lttd;
/** 高程单位m */
@FieldChinese("高程")
private BigDecimal elev;
/** 站址/位置 */
@FieldChinese("站址/位置")
private String stlc;
@TableField("JCDT")
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
@TableField("WDDT")
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
@TableField("BLDSTT_CODE")
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/** 是否启用 */
@FieldChinese("是否启用")
private Integer usfl;
@TableField(exist = false)
private String usflName;
/** 数据是否接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField("DTIN_TM")
@FieldChinese("数据接入时间")
private Date dtinTm;
/** 监测方式 */
@FieldChinese("监测方式")
private Integer mway;
@TableField(exist = false)
private String mwayName;
/** 监测指标 */
@FieldChinese("监测指标")
private String stindx;
@TableField("ORDER_INDEX")
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
@TableField("BASE_ID")
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
/** 所属流域编码 */
@FieldChinese("所属流域编码")
private String rvcd;
@TableField(exist = false)
private String rvnm;
/** 所属行政区编码 */
@FieldChinese("所属行政区编码")
private String addvcd;
/** 简介 */
@FieldChinese("简介")
private String introduce;
/** LOGO图片 */
@FieldChinese("LOGO图片")
private String logo;
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/** 服务对象 */
@FieldChinese("服务对象")
private String fwdx;
/** 观察方式 */
@FieldChinese("观察方式")
private String gcfs;
/** 数据监测频次单位min */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/** 备注 */
@FieldChinese("备注")
private String remark;
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
@TableField("VLSR_TM")
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
@TableField("RECORD_USER")
/** 创建人 */
@FieldChinese("创建人")
private String recordUser;
@TableField("RECORD_TIME")
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("创建时间")
private Date recordTime;
@TableField("MODIFY_USER")
/** 更新人 */
@FieldChinese("更新人")
private String modifyUser;
@TableField("MODIFY_TIME")
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("更新时间")
private Date modifyTime;
@TableField("IS_DELETED")
/** 是否已删除 */
@FieldChinese("是否已删除")
private Integer isDeleted;
@TableField("DELETE_USER")
/** 删除人 */
@FieldChinese("删除人")
private String deleteUser;
@TableField("DELETE_TIME")
/** 删除时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("删除时间")
private Date deleteTime;
@TableField("WARN_STATE")
/** 告警状态 */
@FieldChinese("告警状态")
private String warnState;
}

View File

@ -2,119 +2,178 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 陆生生态调查断面工程信息表
*/
@Data
@TableName("SD_TE_B_H")
public class SdTeBH implements Serializable {
private static final long serialVersionUID = 1L;
/** 陆生生态调查断面编码 */
@TableId(type = IdType.INPUT)
@FieldChinese("陆生生态调查断面编码")
private String stcd;
/** 陆生生态调查断面名称 */
@FieldChinese("陆生生态调查断面名称")
private String stnm;
/** 站类 */
@FieldChinese("站类")
private String sttp;
@TableField(exist = false)
private String sttpName;
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/** 经度(单位:°) */
@FieldChinese("经度")
private BigDecimal lgtd;
/** 纬度(单位:°) */
@FieldChinese("纬度")
private BigDecimal lttd;
/** 高程单位m */
@FieldChinese("高程")
private BigDecimal elev;
/** 站址/位置 */
@FieldChinese("站址/位置")
private String stlc;
/** 是否启用 */
@FieldChinese("是否启用")
private Integer usfl;
/** 数据是否接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField("DTIN_TM")
@FieldChinese("数据接入时间")
private Date dtinTm;
@TableField("ORDER_INDEX")
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
@TableField("BASE_ID")
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
/** 所属流域编码 */
@FieldChinese("所属流域编码")
private String rvcd;
@TableField(exist = false)
private String rvnm;
/** 所属行政区划编码 */
@FieldChinese("所属行政区划编码")
private String addvcd;
@TableField("STDSDT")
/** 规划设计日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("规划设计日期")
private Date stdsdt;
@TableField("PSTSTDT")
/** 计划开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划开工日期")
private Date pststdt;
@TableField("PESSTDT")
/** 计划完工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划完工日期")
private Date pesstdt;
@TableField("SWDT")
/** 开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("开工日期")
private Date swdt;
@TableField("JCDT")
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
@TableField("WDDT")
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
@TableField("BLDSTT_CODE")
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/** 简介 */
@FieldChinese("简介")
private String introduce;
/** LOGO图片 */
@FieldChinese("LOGO图片")
private String logo;
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/** 投资(单位:亿元) */
@FieldChinese("投资")
private BigDecimal inv;
/** 投资是否计入主体工程 */
@FieldChinese("投资是否计入主体工程")
private Integer invinmn;
/** 数据监测频次单位min */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/** 备注 */
@FieldChinese("备注")
private String remark;
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
@TableField("VLSR_TM")
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
}

View File

@ -2,152 +2,229 @@ package com.yfd.platform.qgc_base.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 动物救助站工程信息表
*/
@Data
@TableName("SD_VA_B_H")
public class SdVaBH implements Serializable {
private static final long serialVersionUID = 1L;
/** 动物救助站编码 */
@TableId(type = IdType.INPUT)
@FieldChinese("动物救助站编码")
private String stcd;
/** 动物救助站名称 */
@FieldChinese("动物救助站名称")
private String stnm;
/** 站类 */
@FieldChinese("站类")
private String sttp;
@TableField(exist = false)
private String sttpName;
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/** 所属建设阶段 */
@FieldChinese("所属建设阶段")
private Integer blprd;
/** 经度(单位:°) */
@FieldChinese("经度")
private BigDecimal lgtd;
/** 纬度(单位:°) */
@FieldChinese("纬度")
private BigDecimal lttd;
/** 高程单位m */
@FieldChinese("高程")
private BigDecimal elev;
/** 站址/位置 */
@FieldChinese("站址/位置")
private String stlc;
/** 是否启用 */
@FieldChinese("是否启用")
private Integer usfl;
@TableField(exist = false)
private String usflName;
/** 数据是否接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField("DTIN_TM")
@FieldChinese("数据接入时间")
private Date dtinTm;
@TableField("ORDER_INDEX")
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
@TableField("BASE_ID")
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
/** 服务电站编码列表 */
@FieldChinese("服务电站编码列表")
private String rstcdmap;
@TableField("STDSDT")
/** 规划设计日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("规划设计日期")
private Date stdsdt;
@TableField("PSTSTDT")
/** 计划开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划开工日期")
private Date pststdt;
@TableField("PESSTDT")
/** 计划完工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划完工日期")
private Date pesstdt;
@TableField("SWDT")
/** 开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("开工日期")
private Date swdt;
@TableField("JCDT")
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
@TableField("WDDT")
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
@TableField("BLDSTT_CODE")
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/** 简介 */
@FieldChinese("简介")
private String introduce;
/** LOGO图片 */
@FieldChinese("LOGO图片")
private String logo;
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/** 投资(单位:亿元) */
@FieldChinese("投资")
private BigDecimal inv;
/** 面积单位km² */
@FieldChinese("面积")
private BigDecimal area;
/** 地点 */
@FieldChinese("地点")
private String place;
/** 保护方式 */
@FieldChinese("保护方式")
private String bhfs;
/** 保护原因 */
@FieldChinese("保护原因")
private String bhyy;
/** 保护对象文字描述 */
@FieldChinese("保护对象文字描述")
private String bhdx;
/** 保护对象列表 */
@FieldChinese("保护对象列表")
private String bhdxlb;
/** 数据监测频次单位min */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/** 备注 */
@FieldChinese("备注")
private String remark;
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
@TableField("VLSR_TM")
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
@TableField("RECORD_USER")
/** 创建人 */
@FieldChinese("创建人")
private String recordUser;
@TableField("RECORD_TIME")
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("创建时间")
private Date recordTime;
@TableField("MODIFY_USER")
/** 更新人 */
@FieldChinese("更新人")
private String modifyUser;
@TableField("MODIFY_TIME")
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("更新时间")
private Date modifyTime;
@TableField("IS_DELETED")
/** 是否已删除 */
@FieldChinese("是否已删除")
private Integer isDeleted;
@TableField("DELETE_USER")
/** 删除人 */
@FieldChinese("删除人")
private String deleteUser;
@TableField("DELETE_TIME")
/** 删除时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("删除时间")
private Date deleteTime;
}

View File

@ -5,196 +5,302 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 视频站基本属性表
*/
@Data
@TableName("SD_VDINFO_B")
public class SdVdinfoB implements Serializable {
private static final long serialVersionUID = 1L;
/** 视频站站码 */
@TableId(type = IdType.INPUT)
@FieldChinese("视频站站码")
private String stcd;
/** 视频站名称 */
@FieldChinese("视频站名称")
private String stnm;
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/** 视频站监控类型 */
@FieldChinese("视频站监控类型")
private String mntp;
/** 视频站子站类 */
@FieldChinese("视频站子站类")
private String sttp;
@TableField(exist = false)
private String sttpName;
/** 经度 */
@FieldChinese("经度")
private BigDecimal lgtd;
/** 纬度 */
@FieldChinese("纬度")
private BigDecimal lttd;
/** 高程/海拔 */
@FieldChinese("高程/海拔")
private BigDecimal elev;
/** 地址 */
@FieldChinese("地址")
private String stlc;
/** 监测指标 */
@FieldChinese("监测指标")
private String stindx;
/** 备注 */
@FieldChinese("备注")
private String description;
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
/** 所属测站编码 */
@FieldChinese("所属测站编码")
private String cstcd;
/** 所属流域编码 */
@FieldChinese("所属流域编码")
private String rvcd;
@TableField(exist = false)
private String rvnm;
/** 所属行政编码 */
@FieldChinese("所属行政编码")
private String addvcd;
@TableField(exist = false)
private String addvcdName;
/** 所属公司编码 */
@FieldChinese("所属公司编码")
private String hycd;
@TableField("BASE_ID")
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
/** 所属栖息地编码 */
@FieldChinese("所属栖息地编码")
private String fhstcd;
/** 开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("开工日期")
private Date swdt;
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
/** 撤站日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("撤站日期")
private Date wddt;
@TableField("BLDSTT_CODE")
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/** 是否启用 */
@FieldChinese("是否启用")
private Integer usfl;
/** 数据是否接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
@TableField("DTIN_SRC")
/** 数据接入来源 */
@FieldChinese("数据接入来源")
private String dtinSrc;
@TableField("DTIN_TM")
/** 数据接入开始时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据接入开始时间")
private Date dtinTm;
@TableField("DEVICE_INFO")
/** 设备关键信息 */
@FieldChinese("设备关键信息")
private String deviceInfo;
@TableField("ACCESS_WAY")
/** 视频站接入方式 */
@FieldChinese("视频站接入方式")
private String accessWay;
@TableField("DEVICE_SERIAL")
/** 视频站设备序列号 */
@FieldChinese("视频站设备序列号")
private String deviceSerial;
@TableField("CHANNEL_NO")
/** 视频站通道号 */
@FieldChinese("视频站通道号")
private String channelNo;
@TableField("CHANNEL_NAME")
/** 视频站通道名 */
@FieldChinese("视频站通道名")
private String channelName;
/** 国标设备的通道编号 */
@FieldChinese("国标设备的通道编号")
private String gbchannel;
/** 视频站流播放协议 */
@FieldChinese("视频站流播放协议")
private String protocol;
/** 视频站码流类型 */
@FieldChinese("视频站码流类型")
private String quality;
/** 视频站传输协议 */
@FieldChinese("视频站传输协议")
private String transmode;
@TableField("IS_VD_CONTROL")
/** 视频站是否支持远程控制 */
@FieldChinese("视频站是否支持远程控制")
private Integer isVdControl;
@TableField("CONTROL_MODE")
/** 获取视频站支持远程控制范围 */
@FieldChinese("获取视频站支持远程控制范围")
private String controlMode;
/** 视频站直播地址 */
@FieldChinese("视频站直播地址")
private String url;
@TableField("INTRANET_URL")
/** 视频站直播内网地址 */
@FieldChinese("视频站直播内网地址")
private String intranetUrl;
/** 视频站用户名 */
@FieldChinese("视频站用户名")
private String vduser;
/** 视频站密码 */
@FieldChinese("视频站密码")
private String vdpwd;
@TableField("STORAGE_WAY")
/** 视频站定时截取存储方式 */
@FieldChinese("视频站定时截取存储方式")
private String storageWay;
/** 视频站定时截取频率cron表达式 */
@FieldChinese("视频站定时截取频率")
private String frequency;
@TableField("CUT_TIME")
/** 视频站定时截取时长 */
@FieldChinese("视频站定时截取时长")
private String cutTime;
@TableField("FRAME_RATE")
/** 视频站定时截取压缩每秒多少帧 */
@FieldChinese("视频站定时截取压缩每秒多少帧")
private String frameRate;
@TableField("TS_DURATION")
/** ts文件的时长 */
@FieldChinese("ts文件的时长")
private String tsDuration;
@TableField("OCR_WAY")
/** ocr方式 */
@FieldChinese("ocr方式")
private String ocrWay;
/** 是否是生态流量泄放复核 */
@FieldChinese("是否是生态流量泄放复核")
private String eqreviewm;
/** 视频站设备机位变更日期 */
@FieldChinese("视频站设备机位变更日期")
private Integer jwupdate;
@TableField("AI_ENABLED")
/** 视频站AI识别是否启用 */
@FieldChinese("视频站AI识别是否启用")
private Integer aiEnabled;
@TableField("AI_FREQUENCY")
/** 视频站AI识别频率cron表达式 */
@FieldChinese("视频站AI识别频率")
private String aiFrequency;
@TableField("AI_EXT_CODE")
/** 视频站AI识别外部站码 */
@FieldChinese("视频站AI识别外部站码")
private String aiExtCode;
@TableField("AI_EXT_NAME")
/** 视频站AI识别外部站名 */
@FieldChinese("视频站AI识别外部站名")
private String aiExtName;
@TableField("LIVE_ADDRESS")
/** 平台提供的直接列表 */
@FieldChinese("平台提供的直接列表")
private String liveAddress;
/** 视频录像数据保留天数 */
@FieldChinese("视频录像数据保留天数")
private Integer vdhisday;
@TableField("DELAY_TIME")
/** 视频截取失败多少秒重试 */
@FieldChinese("视频截取失败多少秒重试")
private String delayTime;
@TableField("DELAY_NUM")
/** 视频截取失败最大重试次数 */
@FieldChinese("视频截取失败最大重试次数")
private Integer delayNum;
/** 依托项目 */
@FieldChinese("依托项目")
private String project;
/** 数据监测频次单位min */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/** 备注 */
@FieldChinese("备注")
private String remark;
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
@TableField("VLSR_TM")
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
@TableField("WARN_STATE")
/** 告警状态 */
@FieldChinese("告警状态")
private String warnState;
}

View File

@ -5,147 +5,230 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 珍稀植物保护工程信息表
*/
@Data
@TableName("SD_VP_B_H")
public class SdVpBH implements Serializable {
private static final long serialVersionUID = 1L;
/** 珍稀植物园编码 */
@TableId(type = IdType.INPUT)
@FieldChinese("珍稀植物园编码")
private String stcd;
/** 珍稀植物园名称 */
@FieldChinese("珍稀植物园名称")
private String stnm;
/** 站类 */
@FieldChinese("站类")
private String sttp;
@TableField(exist = false)
private String sttpName;
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/** 所属建设阶段 */
@FieldChinese("所属建设阶段")
private Integer blprd;
/** 经度(单位:°) */
@FieldChinese("经度")
private BigDecimal lgtd;
/** 纬度(单位:°) */
@FieldChinese("纬度")
private BigDecimal lttd;
/** 高程单位m */
@FieldChinese("高程")
private BigDecimal elev;
/** 站址/位置 */
@FieldChinese("站址/位置")
private String stlc;
/** 是否启用 */
@FieldChinese("是否启用")
private Integer usfl;
/** 数据是否接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
@TableField("DTIN_TM")
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据接入时间")
private Date dtinTm;
@TableField("ORDER_INDEX")
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
@TableField("BASE_ID")
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
/** 规划设计日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("规划设计日期")
private Date stdsdt;
/** 计划开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划开工日期")
private Date pststdt;
/** 计划完工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划完工日期")
private Date pesstdt;
/** 开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("开工日期")
private Date swdt;
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
@TableField("BLDSTT_CODE")
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/** 简介 */
@FieldChinese("简介")
private String introduce;
/** LOGO图片 */
@FieldChinese("LOGO图片")
private String logo;
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/** 投资(单位:亿元) */
@FieldChinese("投资")
private BigDecimal inv;
/** 总工期(单位:天) */
@FieldChinese("总工期")
private Integer aptl;
/** 面积单位km² */
@FieldChinese("面积")
private BigDecimal area;
/** 地点 */
@FieldChinese("地点")
private String place;
/** 保护对象文字描述 */
@FieldChinese("保护对象文字描述")
private String bhdx;
/** 保护对象列表 */
@FieldChinese("保护对象列表")
private String bhdxlb;
/** 保护方式 */
@FieldChinese("保护方式")
private String bhfs;
/** 保护原因 */
@FieldChinese("保护原因")
private String bhyy;
/** 是否业主营地公用 */
@FieldChinese("是否业主营地公用")
private Integer iscaec;
/** 数据监测频次单位min */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/** 备注 */
@FieldChinese("备注")
private String remark;
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
@TableField("VLSR_TM")
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
@TableField("RECORD_USER")
/** 创建人 */
@FieldChinese("创建人")
private String recordUser;
@TableField("RECORD_TIME")
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("创建时间")
private Date recordTime;
@TableField("MODIFY_USER")
/** 更新人 */
@FieldChinese("更新人")
private String modifyUser;
@TableField("MODIFY_TIME")
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("更新时间")
private Date modifyTime;
@TableField("IS_DELETED")
/** 是否已删除 */
@FieldChinese("是否已删除")
private Integer isDeleted;
@TableField("DELETE_USER")
/** 删除人 */
@FieldChinese("删除人")
private String deleteUser;
@TableField("DELETE_TIME")
/** 删除时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("删除时间")
private Date deleteTime;
}

View File

@ -5,113 +5,178 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 水生生态调查断面工程信息表
*/
@Data
@TableName("SD_WE_B_H")
public class SdWeBH implements Serializable {
private static final long serialVersionUID = 1L;
/** 水生生态调查断面编码 */
@TableId(type = IdType.INPUT)
@FieldChinese("水生生态调查断面编码")
private String stcd;
/** 水生生态调查断面名称 */
@FieldChinese("水生生态调查断面名称")
private String stnm;
/** 站类 */
@FieldChinese("站类")
private String sttp;
@TableField(exist = false)
private String sttpName;
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/** 经度(单位:°) */
@FieldChinese("经度")
private BigDecimal lgtd;
/** 纬度(单位:°) */
@FieldChinese("纬度")
private BigDecimal lttd;
/** 高程单位m */
@FieldChinese("高程")
private BigDecimal elev;
/** 站址/位置 */
@FieldChinese("站址/位置")
private String stlc;
/** 是否启用 */
@FieldChinese("是否启用")
private Integer usfl;
/** 数据是否接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
@TableField("DTIN_TM")
/** 数据接入时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据接入时间")
private Date dtinTm;
@TableField("ORDER_INDEX")
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
@TableField("BASE_ID")
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
/** 所属流域编码 */
@FieldChinese("所属流域编码")
private String rvcd;
@TableField(exist = false)
private String rvnm;
/** 所属行政区划编码 */
@FieldChinese("所属行政区划编码")
private String addvcd;
/** 规划设计日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("规划设计日期")
private Date stdsdt;
/** 计划开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划开工日期")
private Date pststdt;
/** 计划完工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("计划完工日期")
private Date pesstdt;
/** 开工日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("开工日期")
private Date swdt;
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
@TableField("BLDSTT_CODE")
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/** 简介 */
@FieldChinese("简介")
private String introduce;
/** LOGO图片 */
@FieldChinese("LOGO图片")
private String logo;
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/** 投资(单位:亿元) */
@FieldChinese("投资")
private BigDecimal inv;
/** 投资是否计入主体工程 */
@FieldChinese("投资是否计入主体工程")
private Integer invinmn;
/** 数据监测频次单位min */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/** 备注 */
@FieldChinese("备注")
private String remark;
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
@TableField("VLSR_TM")
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
}

View File

@ -5,144 +5,215 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 水质站基本属性表
*/
@Data
@TableName("SD_WQ_B_H")
public class SdWqBH implements Serializable {
private static final long serialVersionUID = 1L;
/** 站码 */
@TableId(type = IdType.INPUT)
@FieldChinese("站码")
private String stcd;
/** 站名 */
@FieldChinese("站名")
private String stnm;
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/** 站类 */
@FieldChinese("站类")
private String sttp;
@TableField(exist = false)
private String sttpName;
/** 经度(°) */
@FieldChinese("经度")
private BigDecimal lgtd;
/** 纬度(°) */
@FieldChinese("纬度")
private BigDecimal lttd;
/** 高程/海拔(m) */
@FieldChinese("高程/海拔")
private BigDecimal elev;
/** 站址 */
@FieldChinese("站址")
private String stlc;
/** 水质目标 */
@FieldChinese("水质目标")
private String wwqtg;
@TableField(exist = false)
private String wwqtgName;
/** 水质建设类型 */
@FieldChinese("水质建设类型")
private String wqtype;
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
/** 退役/拆除日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("退役/拆除日期")
private Date wddt;
@TableField("BLDSTT_CODE")
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/** 简介 */
@FieldChinese("简介")
private String introduce;
/** LOGO图片 */
@FieldChinese("LOGO图片")
private String logo;
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/** 是否启用0=禁用 1=启用 */
@FieldChinese("是否启用")
private Integer usfl;
/** 数据是否接入0=未接入 1=已接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
@TableField("DTIN_SRC")
/** 数据接入来源 */
@FieldChinese("数据接入来源")
private String dtinSrc;
@TableField("DTIN_TYPE")
/** 数据接入类型0=自建 1=国家建 2=人工建 */
@FieldChinese("数据接入类型")
private Integer dtinType;
@TableField(exist = false)
private String dtinTypeName;
@TableField("DTIN_TM")
/** 数据接入开始时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据接入开始时间")
private Date dtinTm;
/** 监测方式1=人工 2=自动 */
@FieldChinese("监测方式")
private Integer mway;
@TableField(exist = false)
private String mwayName;
/** 监测指标 */
@FieldChinese("监测指标")
private String stindx;
@TableField("ORDER_INDEX")
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
@TableField("BASE_ID")
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
/** 所属栖息地编码 */
@FieldChinese("所属栖息地编码")
private String fhstcd;
/** 是否关联断面 */
@FieldChinese("是否关联断面")
private Integer ispro;
/** 数据监测频次(min) */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/** 备注 */
@FieldChinese("备注")
private String remark;
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
@TableField("VLSR_TM")
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
@TableField("RECORD_USER")
/** 创建人 */
@FieldChinese("创建人")
private String recordUser;
@TableField("RECORD_TIME")
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("创建时间")
private Date recordTime;
@TableField("MODIFY_USER")
/** 更新人 */
@FieldChinese("更新人")
private String modifyUser;
@TableField("MODIFY_TIME")
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("更新时间")
private Date modifyTime;
@TableField("IS_DELETED")
/** 是否已删除 */
@FieldChinese("是否已删除")
private Integer isDeleted;
@TableField("DELETE_USER")
/** 删除人 */
@FieldChinese("删除人")
private String deleteUser;
@TableField("DELETE_TIME")
/** 删除时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("删除时间")
private Date deleteTime;
@TableField("WARN_STATE")
/** 告警状态 */
@FieldChinese("告警状态")
private String warnState;
}

View File

@ -5,167 +5,252 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.FieldChinese;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 水温站基本属性表
*/
@Data
@TableName("SD_WT_B_H")
public class SdWtBH implements Serializable {
private static final long serialVersionUID = 1L;
/** 水温站站码 */
@TableId(type = IdType.INPUT)
@FieldChinese("水温站站码")
private String stcd;
/** 数据时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据时间")
private Date tm;
/** 水温站站名 */
@FieldChinese("水温站站名")
private String stnm;
/** 站类 */
@FieldChinese("站类")
private String sttp;
@TableField(exist = false)
private String sttpName;
/** 经度 */
@FieldChinese("经度")
private BigDecimal lgtd;
/** 纬度 */
@FieldChinese("纬度")
private BigDecimal lttd;
/** 高程 */
@FieldChinese("高程")
private BigDecimal elev;
/** 站址 */
@FieldChinese("站址")
private String stlc;
/** 测站来源 */
@FieldChinese("测站来源")
private String stsr;
@TableField("WT_DEVICE_TYPE")
/** 水温监测断面设备类型1=浮动式 2=固定式 */
@FieldChinese("水温监测断面设备类型")
private Integer wtDeviceType;
@TableField("WT_TYPE")
/** 水温监测断面类型 */
@FieldChinese("水温监测断面类型")
private String wtType;
/** 电站水温结构类型 */
@FieldChinese("电站水温结构类型")
private String wts;
@TableField("WT_HGT_TYPE")
/** 固定垂向水温类型1=相对位置 2=高程 */
@FieldChinese("固定垂向水温类型")
private Integer wtHgtType;
@TableField("WT_FIRST_HGT")
/** 固定垂向水温第1个探头高程 */
@FieldChinese("固定垂向水温第1个探头高程")
private BigDecimal wtFirstHgt;
@TableField("WT_DIST")
/** 垂向水温探头分布 */
@FieldChinese("垂向水温探头分布")
private String wtDist;
/** 建成日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("建成日期")
private Date jcdt;
/** 撤站日期 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("撤站日期")
private Date wddt;
@TableField("BLDSTT_CODE")
/** 建设状态分类 */
@FieldChinese("建设状态分类")
private Integer bldsttCode;
@TableField(exist = false)
private String bldsttCodeName;
/** 总投资 */
@FieldChinese("总投资")
private BigDecimal inv;
/** 投资是否计入主体工程 */
@FieldChinese("投资是否计入主体工程")
private Integer invinmn;
/** 简介 */
@FieldChinese("简介")
private String introduce;
/** 测站logo */
@FieldChinese("测站logo")
private String logo;
/** 介绍弹窗图片 */
@FieldChinese("介绍弹窗图片")
private String inffile;
/** 是否启用0=禁用 1=启用 */
@FieldChinese("是否启用")
private Integer usfl;
/** 数据是否接入0=未接入 1=已接入 */
@FieldChinese("数据是否接入")
private Integer dtin;
@TableField(exist = false)
private String dtinName;
@TableField("DTIN_SRC")
/** 数据接入来源 */
@FieldChinese("数据接入来源")
private String dtinSrc;
@TableField("DTIN_TYPE")
/** 数据接入类型0=自建 1=国家建 2=人工建 */
@FieldChinese("数据接入类型")
private Integer dtinType;
@TableField(exist = false)
private String dtinTypeName;
@TableField("DTIN_TM")
/** 数据接入开始时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据接入开始时间")
private Date dtinTm;
/** 监测方式1=人工 2=自动 */
@FieldChinese("监测方式")
private Integer mway;
@TableField(exist = false)
private String mwayName;
/** 监测指标 */
@FieldChinese("监测指标")
private String stindx;
@TableField("ORDER_INDEX")
/** 排序 */
@FieldChinese("排序")
private Integer orderIndex;
/** 所属断面编码 */
@FieldChinese("所属断面编码")
private String dmstcd;
/** 所属电站编码 */
@FieldChinese("所属电站编码")
private String rstcd;
@TableField(exist = false)
private String ennm;
/** 所属栖息地编码 */
@FieldChinese("所属栖息地编码")
private String fhstcd;
/** 是否属于测站0=否 1=是 */
@FieldChinese("是否属于测站")
private Integer ispro;
/** 依托项目 */
@FieldChinese("依托项目")
private String project;
/** 数据监测频次 */
@FieldChinese("数据监测频次")
private String dtfrqcy;
/** 备注说明 */
@FieldChinese("备注说明")
private String remark;
/** 数据来源 */
@FieldChinese("数据来源")
private String vlsr;
@TableField("VLSR_TM")
/** 数据来源时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("数据来源时间")
private Date vlsrTm;
@TableField("RECORD_USER")
/** 创建人 */
@FieldChinese("创建人")
private String recordUser;
@TableField("RECORD_TIME")
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("创建时间")
private Date recordTime;
@TableField("MODIFY_USER")
/** 更新人 */
@FieldChinese("更新人")
private String modifyUser;
@TableField("MODIFY_TIME")
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("更新时间")
private Date modifyTime;
@TableField("IS_DELETED")
/** 是否已删除 */
@FieldChinese("是否已删除")
private Integer isDeleted;
@TableField("DELETE_USER")
/** 删除人 */
@FieldChinese("删除人")
private String deleteUser;
@TableField("DELETE_TIME")
/** 删除时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@FieldChinese("删除时间")
private Date deleteTime;
@TableField("BASE_ID")
/** 所属水电基地编码 */
@FieldChinese("所属水电基地编码")
private String baseId;
@TableField(exist = false)
private String baseName;
/** 所属水电基地流域编码 */
@FieldChinese("所属水电基地流域编码")
private String hbrvcd;
@TableField("WARN_STATE")
/** 告警状态 */
@FieldChinese("告警状态")
private String warnState;
@TableField("IS_PUSH")
/** 是否纳入推送0=否 1=是 */
@FieldChinese("是否纳入推送")
private Integer isPush;
}

View File

@ -38,7 +38,7 @@ public interface MsWarnRuleBMapper extends BaseMapper<MsWarnRuleB> {
@Select("SELECT t1.ID, RULE_NAME AS ruleName, RULE_CODE AS ruleCode, t2.LVL AS lvl " +
"FROM MS_WARN_RULE_B t1 INNER JOIN MS_WARN_RULE_DETAIL_B t2 ON t1.ID = t2.RULE_ID " +
"WHERE 1=1 AND t1.STCD = #{stcd} " +
"WHERE 1=1 AND (t1.RULE_CODE ='common' OR (t1.RULE_CODE ='custom' AND t1.STCD=#{stcd})) " +
"AND t1.RULE_TYPE = #{ruleType} AND t1.IS_DELETED = 0 AND t2.IS_DELETED = 0 " +
"GROUP BY t1.ID, RULE_NAME, RULE_CODE, lvl")
List<WarnRuleVo> getRuleListByStcd(@Param("stcd") String stcd, @Param("ruleType") String ruleType);
@ -46,7 +46,7 @@ public interface MsWarnRuleBMapper extends BaseMapper<MsWarnRuleB> {
@Update("UPDATE MS_WARN_RULE_B SET STCD = #{stcd} WHERE ID = #{id}")
void updateStcd(@Param("stcd") String stcd, @Param("id") String id);
@Select("SELECT t2.STTP_NAME FROM V_MS_STBPRP_T t1 INNER JOIN SD_STTP_B t2 ON t1.STTP = t2.ID WHERE t1.STCD = #{stcd}")
@Select("SELECT t2.STTP_NAME FROM V_MS_STBPRP_T t1 INNER JOIN SD_STTP_B t2 ON t1.STTP = t2.STTP_CODE WHERE t1.STCD = #{stcd}")
String getSttpCodeNameByStcd(@Param("stcd") String stcd);
@Select("SELECT COUNT(t1.ID) FROM MS_WARN_RULE_B t1 INNER JOIN MS_WARN_RULE_DETAIL_B t2 ON t1.ID = t2.RULE_ID " +

View File

@ -1,8 +1,15 @@
package com.yfd.platform.qgc_base.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.qgc_base.domain.MsOperationLog;
import com.yfd.platform.qgc_base.domain.MsOperationLogDetail;
import com.yfd.platform.qgc_base.domain.SdEngInfoBH;
public interface IMsOperationLogService {
import java.util.List;
public interface IMsOperationLogService extends IService<MsOperationLog> {
void recordEngAddLog(SdEngInfoBH engInfo, String source);
@ -58,4 +65,20 @@ public interface IMsOperationLogService {
* @param <T> 实体类型
*/
<T> void recordDeleteDetailLog(String recordId,String tableName, T entity, String source);
/**
* 分页查询操作日志
*
* @param request 请求参数tableName 必传在 filter recordId 可选
* @return 分页结果
*/
Page<MsOperationLog> queryPageList(DataSourceRequest request);
/**
* 根据日志主表ID查询日志详情
*
* @param mainId 日志主表ID
* @return 日志详情列表
*/
List<MsOperationLogDetail> getDetailByMainId(String mainId);
}

View File

@ -3,6 +3,7 @@ package com.yfd.platform.qgc_base.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.qgc_base.domain.MsWarnRuleB;
import com.yfd.platform.qgc_sys.warnRule.vo.MsWarnRuleBVo;
import com.yfd.platform.qgc_sys.warnRule.vo.WarnRuleVo;
@ -23,7 +24,7 @@ public interface IMsWarnRuleBService extends IService<MsWarnRuleB> {
/**
* 获取告警类型对应的要素列表
*/
List<WarnYsVo> getAllYs(String ruleType);
List<WarnYsVo> getAllYs(String ruleId,String ruleType);
/**
* 新增或修改预警规则
@ -58,7 +59,7 @@ public interface IMsWarnRuleBService extends IService<MsWarnRuleB> {
/**
* 查询测站和预警规则绑定列表
*/
Page<MsWarnRuleBVo> getRuleBindList(DataSourceRequest request);
DataSourceResult<MsWarnRuleBVo> getRuleBindList(DataSourceRequest request);
/**
* 根据id查询规则配置详情

View File

@ -4,28 +4,29 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.annotation.FieldChinese;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.qgc_base.domain.MsOperationLog;
import com.yfd.platform.qgc_base.domain.MsOperationLogDetail;
import com.yfd.platform.qgc_base.domain.SdEngInfoBH;
import com.yfd.platform.qgc_base.mapper.MsOperationLogDetailMapper;
import com.yfd.platform.qgc_base.mapper.MsOperationLogMapper;
import com.yfd.platform.qgc_base.service.IMsOperationLogService;
import com.yfd.platform.utils.DataSourceRequestUtil;
import com.yfd.platform.utils.SecurityUtils;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
@Service
public class MsOperationLogServiceImpl implements IMsOperationLogService {
public class MsOperationLogServiceImpl extends ServiceImpl<MsOperationLogMapper, MsOperationLog> implements IMsOperationLogService {
private static final String ENG_TABLE_NAME = "SD_ENGINFO_B_H";
@ -275,7 +276,7 @@ public class MsOperationLogServiceImpl implements IMsOperationLogService {
if (engInfo == null) {
return;
}
MsOperationLog mainLog = buildMainLog(null,"新增电站", source);
MsOperationLog mainLog = buildMainLog(engInfo.getStcd(),"新增电站", source);
msOperationLogMapper.insert(mainLog);
List<MsOperationLogDetail> details = new ArrayList<>();
@ -421,6 +422,7 @@ public class MsOperationLogServiceImpl implements IMsOperationLogService {
if (processedColumns.contains(columnName)) {
continue;
}
String fieldMeaning = resolveFieldChinese(field);
Object oldValue = getFieldValue(field, before);
Object newValue = getFieldValue(field, after);
@ -432,7 +434,7 @@ public class MsOperationLogServiceImpl implements IMsOperationLogService {
continue;
}
details.add(buildGenericDetail(mainLog.getId(), tableName, recordId, columnName,
oldValue, newValue, "修改字段值"));
fieldMeaning,oldValue, newValue, "修改字段值"));
processedColumns.add(columnName);
}
batchInsertDetails(details);
@ -460,8 +462,9 @@ public class MsOperationLogServiceImpl implements IMsOperationLogService {
if (processedColumns.contains(columnName)) {
continue;
}
String fieldMeaning = resolveFieldChinese(field);
Object newValue = getFieldValue(field, entity);
details.add(buildGenericDetail(mainLog.getId(), tableName, recordId, columnName,
details.add(buildGenericDetail(mainLog.getId(), tableName, recordId, columnName,fieldMeaning,
null, newValue, "新增字段值"));
processedColumns.add(columnName);
}
@ -490,12 +493,13 @@ public class MsOperationLogServiceImpl implements IMsOperationLogService {
if (processedColumns.contains(columnName)) {
continue;
}
String fieldMeaning = resolveFieldChinese(field);
Object oldValue = getFieldValue(field, entity);
// if (oldValue == null) {
// continue;
// }
details.add(buildGenericDetail(mainLog.getId(), tableName, recordId, columnName,
oldValue, null, "删除字段值"));
fieldMeaning,oldValue, null, "删除字段值"));
processedColumns.add(columnName);
}
batchInsertDetails(details);
@ -545,14 +549,14 @@ public class MsOperationLogServiceImpl implements IMsOperationLogService {
* 构建通用的操作日志详情不含字典名称解析
*/
private MsOperationLogDetail buildGenericDetail(String mainId, String tableName,
String stationCode, String fieldCode,
String stationCode, String fieldCode,String fieldMeaning,
Object oldValue, Object newValue, String remark) {
MsOperationLogDetail detail = new MsOperationLogDetail();
detail.setMainId(mainId);
detail.setTableName(tableName);
detail.setStationCode(stationCode);
detail.setFieldCode(fieldCode);
detail.setFieldMeaning(fieldCode);
detail.setFieldMeaning(fieldMeaning);
detail.setOldValueCode(formatValue(oldValue));
detail.setNewValueCode(formatValue(newValue));
detail.setRemark(remark);
@ -582,6 +586,23 @@ public class MsOperationLogServiceImpl implements IMsOperationLogService {
return camelToUpperUnderline(field.getName());
}
// private String resolveColumnName(Field field) {
// FieldChinese chinese = field.getAnnotation(FieldChinese.class);
// if (chinese != null && StringUtils.isNotBlank(chinese.value())) {
// return chinese.value();
// }
// return resolveFieldColumnName(field);
// }
private String resolveFieldChinese(Field field) {
FieldChinese chinese = field.getAnnotation(FieldChinese.class);
if (chinese != null && StringUtils.isNotBlank(chinese.value())) {
return chinese.value();
}
return resolveColumnName(field);
}
private Object getFieldValue(Field field, Object target) {
try {
return field.get(target);
@ -685,4 +706,48 @@ public class MsOperationLogServiceImpl implements IMsOperationLogService {
}
return builder.toString();
}
@Override
public Page<MsOperationLog> queryPageList(DataSourceRequest request) {
Page<MsOperationLog> msOperationLogPage = DataSourceRequestUtil.executeQuery(request, MsOperationLog.class, this);
return msOperationLogPage;
}
@Override
public List<MsOperationLogDetail> getDetailByMainId(String mainId) {
if (StringUtils.isBlank(mainId)) {
return new ArrayList<>();
}
LambdaQueryWrapper<MsOperationLogDetail> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(MsOperationLogDetail::getMainId, mainId);
return msOperationLogDetailMapper.selectList(wrapper);
}
/**
* DataSourceRequest 过滤条件中提取指定字段的值
*/
private String getFilterFieldValue(DataSourceRequest request, String fieldName) {
if (request == null || request.getFilter() == null) {
return null;
}
return findFilterValue(request.getFilter(), fieldName);
}
private String findFilterValue(DataSourceRequest.FilterDescriptor filter, String fieldName) {
if (filter == null) {
return null;
}
if (fieldName.equals(filter.getField()) && filter.getValue() != null) {
return filter.getValue().toString();
}
if (filter.getFilters() != null) {
for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) {
String value = findFilterValue(child, fieldName);
if (value != null) {
return value;
}
}
}
return null;
}
}

View File

@ -2,12 +2,16 @@ package com.yfd.platform.qgc_base.service.impl;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.common.DataSourceLoadOptionsBase;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.common.MicroservicDynamicSQLMapper;
import com.yfd.platform.common.utils.UserNameFillHelper;
import com.yfd.platform.qgc_base.domain.MsWarnRuleB;
import com.yfd.platform.qgc_base.domain.MsWarnRuleDetailB;
import com.yfd.platform.qgc_base.domain.MsWarnRuleStbprpB;
@ -20,16 +24,15 @@ import com.yfd.platform.qgc_sys.warnRule.vo.MsWarnRuleBVo;
import com.yfd.platform.qgc_sys.warnRule.vo.MsWarnRuleDetailVo;
import com.yfd.platform.qgc_sys.warnRule.vo.WarnRuleVo;
import com.yfd.platform.qgc_sys.warnRule.vo.WarnYsVo;
import com.yfd.platform.utils.DataSourceRequestUtil;
import com.yfd.platform.utils.DictCodeToNameConverter;
import com.yfd.platform.utils.CodeToNameMetadataBo;
import com.yfd.platform.utils.SecurityUtils;
import com.yfd.platform.utils.*;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@ -68,9 +71,13 @@ public class MsWarnRuleBServiceImpl extends ServiceImpl<MsWarnRuleBMapper, MsWar
@Resource
private MsWarnRuleStbprpBMapper msWarnRuleStbprpBMapper;
@Resource
private UserNameFillHelper userNameFillHelper;
@Override
public Page<MsWarnRuleB> queryPageList(DataSourceRequest request) {
Page<MsWarnRuleB> page = DataSourceRequestUtil.executeQuery(request, MsWarnRuleB.class, this);
userNameFillHelper.fillUserNames(page.getRecords());
dictCodeToNameConverter.convertCodeToName(page, CODE_TO_NAME_META_LIST);
return page;
}
@ -79,9 +86,9 @@ public class MsWarnRuleBServiceImpl extends ServiceImpl<MsWarnRuleBMapper, MsWar
@Transactional(rollbackFor = Exception.class)
public boolean add(MsWarnRuleB entity, String source) {
boolean result = this.save(entity);
if (result) {
msOperationLogService.recordAddDetailLog(entity.getId(), TABLE_NAME, entity, source);
}
// if (result) {
// msOperationLogService.recordAddDetailLog(entity.getId(), TABLE_NAME, entity, source);
// }
return result;
}
@ -90,9 +97,9 @@ public class MsWarnRuleBServiceImpl extends ServiceImpl<MsWarnRuleBMapper, MsWar
public boolean update(MsWarnRuleB entity, String source) {
MsWarnRuleB before = this.getById(entity.getId());
boolean result = this.updateById(entity);
if (result && before != null) {
msOperationLogService.recordModifyDetailLog(entity.getId(), TABLE_NAME, before, entity, source);
}
// if (result && before != null) {
// msOperationLogService.recordModifyDetailLog(entity.getId(), TABLE_NAME, before, entity, source);
// }
return result;
}
@ -109,25 +116,68 @@ public class MsWarnRuleBServiceImpl extends ServiceImpl<MsWarnRuleBMapper, MsWar
wrapper.set(MsWarnRuleB::getDeleteUser, SecurityUtils.getCurrentUsername());
wrapper.set(MsWarnRuleB::getDeleteTime, new Date());
if (this.update(wrapper)) {
msOperationLogService.recordDeleteDetailLog(id, TABLE_NAME, entity, source);
// msOperationLogService.recordDeleteDetailLog(id, TABLE_NAME, entity, source);
count++;
}
}
return count > 0;
}
/**
* 最小值
*/
private BigDecimal minVal;
/**
* 最大值
*/
private BigDecimal maxVal;
@Override
public List<WarnYsVo> getAllYs(String ruleType) {
public List<WarnYsVo> getAllYs(String ruleId, String ruleType) {
String dbRuleType = getOldRuleType(ruleType);
String sql = "SELECT t2.TB_ID AS tbId, t2.YS, t3.YS_SHOW_NAME AS ysName\n" +
"FROM MS_WARN_RULE_B t1\n" +
"INNER JOIN MS_WARN_RULE_DETAIL_B t2 ON t1.ID = t2.RULE_ID\n" +
"INNER JOIN ST_YS_B t3 ON t2.YS = t3.YS\n" +
"WHERE t1.RULE_TYPE ='" + dbRuleType + "'\n" +
" AND t1.IS_DELETED = 0\n" +
" AND t2.IS_DELETED = 0\n" +
"GROUP BY t2.TB_ID, t2.YS, t3.YS_SHOW_NAME";
boolean hasRuleId = (ruleId != null && !ruleId.isEmpty());
// 动态构建 SELECT 子句
StringBuilder selectClause = new StringBuilder(
"SELECT t2.TB_ID AS tbId, t2.YS, t3.YS_SHOW_NAME AS ysName"
);
// ruleId 时额外查询 MIN_VAL MAX_VAL
if (hasRuleId) {
selectClause.append(",t2.WARN_LEVEL,t2.MARK,t2.LVL, t2.MIN_VAL, t2.MAX_VAL");
}
// 动态构建 GROUP BY 子句 SELECT 对应
StringBuilder groupByClause = new StringBuilder(
"GROUP BY t2.TB_ID, t2.YS, t3.YS_SHOW_NAME"
);
if (hasRuleId) {
groupByClause.append(",t2.WARN_LEVEL,t2.MARK,t2.LVL, t2.MIN_VAL, t2.MAX_VAL");
}
// 基础 FROM / JOIN 和固定过滤条件删除标志
String fromJoin = "\nFROM MS_WARN_RULE_B t1" +
"\nINNER JOIN MS_WARN_RULE_DETAIL_B t2 ON t1.ID = t2.RULE_ID" +
"\nINNER JOIN ST_YS_B t3 ON t2.YS = t3.YS" +
"\nWHERE t1.IS_DELETED = 0" +
"\n AND t2.IS_DELETED = 0";
// 动态条件使用占位符
String condition;
Map<String, Object> paramMap = new HashMap<>();
if (hasRuleId) {
condition = "\n AND t1.ID = #{map.ruleId}";
paramMap.put("ruleId", ruleId);
} else {
condition = "\n AND t1.RULE_TYPE = #{map.ruleType}";
paramMap.put("ruleType", dbRuleType);
}
String orderBy="\nORDER BY t2.TB_ID";
// 组装完整 SQL
String sql = selectClause + fromJoin + condition + "\n" + groupByClause + orderBy;
return microservicDynamicSQLMapper.getAllListWithResultType(sql, paramMap, WarnYsVo.class);
}
@ -140,11 +190,11 @@ public class MsWarnRuleBServiceImpl extends ServiceImpl<MsWarnRuleBMapper, MsWar
org.springframework.beans.BeanUtils.copyProperties(vo, entity);
entity.setId(vo.getId());
entity.setModifyTime(new Date());
// entity.setRuleType(getOldRuleType(entity.getRuleType()));
List<MsWarnRuleDetailVo> detail = vo.getDetail();
Integer lvl = null;
if (!CollectionUtils.isEmpty(detail) && detail.get(0) != null && detail.get(0).getLvl() != null) {
lvl = Integer.parseInt(detail.get(0).getLvl());
if (!CollectionUtils.isEmpty(detail) && detail.getFirst() != null && detail.getFirst().getLvl() != null) {
lvl = Integer.parseInt(detail.getFirst().getLvl());
}
List<MsWarnRuleDetailB> detailBList = new ArrayList<>();
@ -157,10 +207,13 @@ public class MsWarnRuleBServiceImpl extends ServiceImpl<MsWarnRuleBMapper, MsWar
i.getAndIncrement();
MsWarnRuleDetailB detailB = new MsWarnRuleDetailB();
detailB.setRuleId(vo.getId());
detailB.setTbId(ysVo.getTbId());
detailB.setYs(ysVo.getYs());
detailB.setWarnLevel(detailVo.getWarnLevel());
detailB.setLvl(detailVo.getLvl() != null ? Integer.parseInt(detailVo.getLvl()) : null);
detailB.setTbId(ysVo.getTbId());
detailB.setYs(ysVo.getYs());
detailB.setMinVal(ysVo.getMinVal());
detailB.setMaxVal(ysVo.getMaxVal());
detailB.setMark(ysVo.getMark());
DateTime dateTime = DateUtil.offsetSecond(new Date(), i.get());
detailB.setTm(dateTime);
detailB.setRecordUser(SecurityUtils.getCurrentUsername());
@ -174,7 +227,7 @@ public class MsWarnRuleBServiceImpl extends ServiceImpl<MsWarnRuleBMapper, MsWar
if (StringUtils.isBlank(vo.getId())) {
// ---- 新增 ----
entity.setRecordUser(SecurityUtils.getCurrentUsername());
entity.setRecordUser(SecurityUtils.getUserId());
if ("common".equals(vo.getRuleCode())) {
boolean exist = checkRuleExist(vo.getRuleType(), lvl);
if (exist) {
@ -323,17 +376,18 @@ public class MsWarnRuleBServiceImpl extends ServiceImpl<MsWarnRuleBMapper, MsWar
}
@Override
public Page<MsWarnRuleBVo> getRuleBindList(DataSourceRequest request) {
public DataSourceResult<MsWarnRuleBVo> getRuleBindList(DataSourceRequest request) {
DataSourceResult<MsWarnRuleBVo> dataSourceResult = new DataSourceResult<>();
StringBuilder sql = new StringBuilder();
sql.append("SELECT id AS bindId, STCD, STNM, STTP_CODE AS sttpCode, RULE_NAME AS ruleName, ")
sql.append("SELECT id AS bindId, STCD,RULE_ID, STNM, STTP_CODE AS sttpCode, RULE_NAME AS ruleName, ")
.append("RULE_TYPE AS ruleType, recordUser, MODIFY_TIME AS modifyTime, isShow, RULE_CODE AS ruleCode ")
.append("FROM (\n")
.append("SELECT t1.ID, t1.STCD, t3.STNM, t3.STTP_CODE, t2.RULE_NAME, t2.RULE_TYPE, ")
.append("SELECT t1.ID,t2.ID RULE_ID, t1.STCD, t3.STNM, t3.STTP_CODE, t2.RULE_NAME, t2.RULE_TYPE, ")
.append("t2.RECORD_USER AS recordUser, t2.MODIFY_TIME, t2.DESCRIPTION, t2.IS_SHOW AS isShow, t2.RULE_CODE ")
.append("FROM MS_WARN_RULE_STBPRP_B t1\n")
.append("INNER JOIN MS_WARN_RULE_B t2 ON t1.RULE_ID = t2.ID\n")
.append("INNER JOIN V_MS_STBPRP_T t3 ON t1.STCD = t3.STCD\n")
.append("WHERE t2.RULE_CODE IN ('common','custom')\n")
.append("WHERE t2.RULE_CODE IN ('common','custom') AND t2.IS_DELETED=0 AND t3.IS_DELETED=0 AND t1.IS_DELETED=0 ORDER BY t1.RECORD_TIME DESC \n")
.append(") WHERE 1=1");
Map<String, Object> params = new HashMap<>();
@ -342,18 +396,14 @@ public class MsWarnRuleBServiceImpl extends ServiceImpl<MsWarnRuleBMapper, MsWar
// 处理排序
appendOrderBy(request, sql);
Page<MsWarnRuleBVo> page;
if (request.getPage() > 0 && request.getPageSize() > 0) {
page = new Page<>(request.getPage(), request.getPageSize());
} else if (request.getTake() > 0) {
long pageNum = (request.getSkip() / request.getTake()) + 1;
page = new Page<>(pageNum, request.getTake());
} else {
page = new Page<>(1, 20);
}
microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), params, MsWarnRuleBVo.class);
return page;
DataSourceLoadOptionsBase loadOptions = request.toDevRequest();
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
List<MsWarnRuleBVo> list = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), params, MsWarnRuleBVo.class);
dictCodeToNameConverter.convertCodeToName(list, CODE_TO_NAME_META_LIST);
userNameFillHelper.fillUserNames(list);
dataSourceResult.setData(list);
dataSourceResult.setTotal(page == null ? list.size() : page.getTotal());
return dataSourceResult;
}
@Override
@ -408,11 +458,16 @@ public class MsWarnRuleBServiceImpl extends ServiceImpl<MsWarnRuleBMapper, MsWar
MsWarnRuleDetailVo detailVo = new MsWarnRuleDetailVo();
List<MsWarnRuleDetailB> detailGroup = warnLevelMap.get(warnLevel);
List<WarnYsVo> ysVoList = new ArrayList<>();
MsWarnRuleDetailB first = detailGroup.get(0);
org.springframework.beans.BeanUtils.copyProperties(first, detailVo);
MsWarnRuleDetailB first = detailGroup.getFirst();
if (first != null && first.getLvl() != null) {
detailVo.setLvl(first.getLvl().toString());
}
detailVo.setWarnLevel(first.getWarnLevel());
// detailVo.setLvlName(first.n);
// BeanUtils.copyProperties(first, detailVo);
for (MsWarnRuleDetailB db : detailGroup) {
WarnYsVo ysVo = new WarnYsVo();
org.springframework.beans.BeanUtils.copyProperties(db, ysVo);
BeanUtils.copyProperties(db, ysVo);
ysVoList.add(ysVo);
}
detailVo.setYsList(ysVoList);

View File

@ -170,7 +170,7 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
wrapper.eq(StringUtils.hasText(baseId), SdEngInfoBH::getBaseId, baseId)
.eq(StringUtils.hasText(hbrvcd), SdEngInfoBH::getHbrvcd, hbrvcd)
.eq(StrUtil.isNotBlank(reachcd), SdEngInfoBH::getReachcd, reachcd)
.eq(StrUtil.isNotBlank(rvcd), SdEngInfoBH::getReachcd, rvcd)
.eq(StrUtil.isNotBlank(rvcd), SdEngInfoBH::getRvcd, rvcd)
.in(rvcds != null && !rvcds.isEmpty(), SdEngInfoBH::getReachcd, rvcds)
.in(hbrvcds != null && !hbrvcds.isEmpty(), SdEngInfoBH::getHbrvcd, hbrvcds)
.like(StringUtils.hasText(ennm), SdEngInfoBH::getEnnm, ennm)
@ -2096,6 +2096,8 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
return switch (field) {
case "id" -> "t.id";
case "sttp" -> "t.sttp";
case "hycd" -> "t.hycd";
case "topHycd" -> "t.topHycd";
case "sttpCode" -> "t.sttpCode";
case "runState" -> "t.runState";
case "sttpName" -> "t.sttpName";

View File

@ -52,6 +52,7 @@ public class OverviewVmsstbprptVo implements Serializable {
private BigDecimal inv;
private Integer invinmn;
private Date stdsdt;
private String precis;
private Date pststdt;
private Date pesstdt;
private Date swdt;

View File

@ -477,7 +477,7 @@ public class VdMonitorServiceImpl implements VdMonitorService {
private DataSourceResult<VdRunDataVo> queryLatestRunDataDetailList(DataSourceRequest dataSourceRequest,
DataSourceLoadOptionsBase loadOptions) {
return queryRunDataDetailList(dataSourceRequest, loadOptions, buildLatestRunDataCoreSql());
return queryRunDataDetailList(dataSourceRequest, loadOptions, buildRunDataCoreSql());
}
private DataSourceResult<VdRunDataVo> queryRunDataDetailList(DataSourceRequest dataSourceRequest,
@ -513,7 +513,7 @@ public class VdMonitorServiceImpl implements VdMonitorService {
private DataSourceResult<VdRunDataVo> queryLatestRunDataGroupList(DataSourceRequest dataSourceRequest,
DataSourceLoadOptionsBase loadOptions) {
return queryRunDataGroupList(dataSourceRequest, loadOptions, buildLatestRunDataCoreSql());
return queryRunDataGroupList(dataSourceRequest, loadOptions, buildRunDataCoreSql());
}
private DataSourceResult<VdPointVo> queryVdPointDetailList(DataSourceRequest dataSourceRequest,
@ -843,103 +843,137 @@ public class VdMonitorServiceImpl implements VdMonitorService {
"AND src.LGTD IS NOT NULL " +
"AND src.LTTD IS NOT NULL ";
}
private String buildRunDataCoreSql() {
return "SELECT " +
"run.ID AS id, " +
"run.STCD AS stcd, " +
"run.TM AS tm, " +
"NVL(run.FLNM, base.STNM || ' ' || TO_CHAR(run.TM, 'yyyy-mm-dd hh24')) AS flnm, " +
"run.IMG_PATH AS imgPath, " +
"run.FLPTH AS flpth, " +
"run.DEVICEINFO AS deviceinfo, " +
"run.DESCRIBE AS describe, " +
"run.FID AS fid, " +
"run.THUMBNAIL AS thumbnail, " +
"base.RSTCD AS rstcd, " +
"base.STNM AS stnm, " +
"eng.ENNM AS ennm, " +
"base.FHSTCD AS fhstcd, " +
"fh.STNM AS fhstnm, " +
"base.CSTCD AS stCode, " +
"cst.STNM AS stName, " +
"NVL(eng.BASE_ID, base.BASE_ID) AS baseId, " +
"hb.BASENAME AS baseName, " +
"base.STTP AS sttpCode, " +
"sttp.STTP_NAME AS sttpName, " +
"base.STNM AS titleName, " +
"NVL(hb.ORDER_INDEX, 999999) AS baseStepSort, " +
"NVL(hbrv.ORDER_INDEX, 999999) AS rvcdStepSort, " +
"NVL(eng.ORDER_INDEX, 999999) AS rstcdStepSort, " +
"NVL(base.ORDER_INDEX, 999999) AS siteStepSort, " +
"NVL(eng.HBRVCD, base.HBRVCD) AS hbrvcd, " +
"hbrv.HBRVNM AS hbrvcdName " +
"FROM SD_VDINFO_R run " +
"INNER JOIN (" + buildVdDeviceBaseSql() + ") base ON run.STCD = base.STCD " +
"LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = base.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " +
"LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = NVL(eng.BASE_ID, base.BASE_ID) " +
" AND NVL(hb.IS_DELETED, 0) = 0 AND NVL(hb.ENABLED, 1) = 1 " +
"LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = NVL(eng.HBRVCD, base.HBRVCD) " +
" AND hbrv.BASEID = NVL(eng.BASE_ID, base.BASE_ID) " +
" AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1 " +
"LEFT JOIN SD_FHBT_B_H fh ON fh.STCD = base.FHSTCD AND NVL(fh.IS_DELETED, 0) = 0 " +
"LEFT JOIN (" + buildStationBaseSql() + ") cst ON cst.STCD = base.CSTCD " +
"LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = base.STTP " +
" AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 " +
"WHERE NVL(run.IS_DELETED, 0) = 0 ";
return " SELECT\n" +
" a.ID,\n" +
" a.STCD,\n" +
" a.TM,\n" +
" b.stnm || ' ' || to_char(a.TM, 'yyyy-mm-dd hh24') AS FLNM,\n" +
" a.IMG_PATH,\n" +
" a.FLPTH,\n" +
" a.DEVICEINFO,\n" +
" a.DESCRIBE,\n" +
" a.FID,\n" +
" a.THUMBNAIL,\n" +
" b.RSTCD,\n" +
" b.stnm,\n" +
" b.ennm,\n" +
" b.FHSTCD,\n" +
" b.FHSTNM,\n" +
" b.STCODE AS stCode,\n" +
" b.STNAME AS stName,\n" +
" b.BASE_ID AS baseId,\n" +
" b.BASE_NAME AS baseName,\n" +
" b.sttp_code AS sttpCode,\n" +
" b.sttp_name AS sttpName,\n" +
" b.stnm AS titleName,\n" +
" b.basestepsort,\n" +
" b.rvcdstepsort,\n" +
" b.rstcdstepsort,\n" +
" b.hbrvcd,\n" +
" b.hbrvcd_name\n" +
" FROM SD_VDINFO_R a\n" +
" INNER JOIN V_MS_STBPRP_T b\n" +
" ON a.STCD = b.STCD\n" +
" AND b.IS_DELETED = 0";
}
private String buildLatestRunDataCoreSql() {
return "SELECT " +
"run.ID AS id, " +
"run.STCD AS stcd, " +
"run.TM AS tm, " +
"NVL(run.FLNM, base.STNM || ' ' || TO_CHAR(run.TM, 'yyyy-mm-dd hh24')) AS flnm, " +
"run.IMG_PATH AS imgPath, " +
"run.FLPTH AS flpth, " +
"run.DEVICEINFO AS deviceinfo, " +
"run.DESCRIBE AS describe, " +
"run.FID AS fid, " +
"run.THUMBNAIL AS thumbnail, " +
"base.RSTCD AS rstcd, " +
"base.STNM AS stnm, " +
"eng.ENNM AS ennm, " +
"base.FHSTCD AS fhstcd, " +
"fh.STNM AS fhstnm, " +
"base.CSTCD AS stCode, " +
"cst.STNM AS stName, " +
"NVL(eng.BASE_ID, base.BASE_ID) AS baseId, " +
"hb.BASENAME AS baseName, " +
"base.STTP AS sttpCode, " +
"sttp.STTP_NAME AS sttpName, " +
"base.STNM AS titleName, " +
"NVL(hb.ORDER_INDEX, 999999) AS baseStepSort, " +
"NVL(hbrv.ORDER_INDEX, 999999) AS rvcdStepSort, " +
"NVL(eng.ORDER_INDEX, 999999) AS rstcdStepSort, " +
"NVL(base.ORDER_INDEX, 999999) AS siteStepSort, " +
"NVL(eng.HBRVCD, base.HBRVCD) AS hbrvcd, " +
"hbrv.HBRVNM AS hbrvcdName " +
"FROM ( " +
"SELECT detail.ID, detail.STCD, detail.TM, detail.FLNM, detail.IMG_PATH, detail.FLPTH, detail.DEVICEINFO, " +
"detail.DESCRIBE, detail.FID, detail.THUMBNAIL " +
"FROM SD_VDINFO_R detail " +
"INNER JOIN ( " +
"SELECT STCD, MAX(TM) AS TM FROM SD_VDINFO_R WHERE NVL(IS_DELETED, 0) = 0 GROUP BY STCD " +
") latest ON detail.STCD = latest.STCD AND detail.TM = latest.TM " +
"WHERE NVL(detail.IS_DELETED, 0) = 0 " +
") run " +
"INNER JOIN (" + buildVdDeviceBaseSql() + ") base ON run.STCD = base.STCD " +
"LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = base.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " +
"LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = NVL(eng.BASE_ID, base.BASE_ID) " +
" AND NVL(hb.IS_DELETED, 0) = 0 AND NVL(hb.ENABLED, 1) = 1 " +
"LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = NVL(eng.HBRVCD, base.HBRVCD) " +
" AND hbrv.BASEID = NVL(eng.BASE_ID, base.BASE_ID) " +
" AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1 " +
"LEFT JOIN SD_FHBT_B_H fh ON fh.STCD = base.FHSTCD AND NVL(fh.IS_DELETED, 0) = 0 " +
"LEFT JOIN (" + buildStationBaseSql() + ") cst ON cst.STCD = base.CSTCD " +
"LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = base.STTP " +
" AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 ";
}
// private String buildRunDataCoreSql() {
// return "SELECT " +
// "run.ID AS id, " +
// "run.STCD AS stcd, " +
// "run.TM AS tm, " +
// "NVL(run.FLNM, base.STNM || ' ' || TO_CHAR(run.TM, 'yyyy-mm-dd hh24')) AS flnm, " +
// "run.IMG_PATH AS imgPath, " +
// "run.FLPTH AS flpth, " +
// "run.DEVICEINFO AS deviceinfo, " +
// "run.DESCRIBE AS describe, " +
// "run.FID AS fid, " +
// "run.THUMBNAIL AS thumbnail, " +
// "base.RSTCD AS rstcd, " +
// "base.STNM AS stnm, " +
// "eng.ENNM AS ennm, " +
// "base.FHSTCD AS fhstcd, " +
// "fh.STNM AS fhstnm, " +
// "base.CSTCD AS stCode, " +
// "cst.STNM AS stName, " +
// "NVL(eng.BASE_ID, base.BASE_ID) AS baseId, " +
// "hb.BASENAME AS baseName, " +
// "base.STTP AS sttpCode, " +
// "sttp.STTP_NAME AS sttpName, " +
// "base.STNM AS titleName, " +
// "NVL(hb.ORDER_INDEX, 999999) AS baseStepSort, " +
// "NVL(hbrv.ORDER_INDEX, 999999) AS rvcdStepSort, " +
// "NVL(eng.ORDER_INDEX, 999999) AS rstcdStepSort, " +
// "NVL(base.ORDER_INDEX, 999999) AS siteStepSort, " +
// "NVL(eng.HBRVCD, base.HBRVCD) AS hbrvcd, " +
// "hbrv.HBRVNM AS hbrvcdName " +
// "FROM SD_VDINFO_R run " +
// "INNER JOIN (" + buildVdDeviceBaseSql() + ") base ON run.STCD = base.STCD " +
// "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = base.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " +
// "LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = NVL(eng.BASE_ID, base.BASE_ID) " +
// " AND NVL(hb.IS_DELETED, 0) = 0 AND NVL(hb.ENABLED, 1) = 1 " +
// "LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = NVL(eng.HBRVCD, base.HBRVCD) " +
// " AND hbrv.BASEID = NVL(eng.BASE_ID, base.BASE_ID) " +
// " AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1 " +
// "LEFT JOIN SD_FHBT_B_H fh ON fh.STCD = base.FHSTCD AND NVL(fh.IS_DELETED, 0) = 0 " +
// "LEFT JOIN (" + buildStationBaseSql() + ") cst ON cst.STCD = base.CSTCD " +
// "LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = base.STTP " +
// " AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 " +
// "WHERE NVL(run.IS_DELETED, 0) = 0 ";
// }
// private String buildLatestRunDataCoreSql() {
// return "SELECT " +
// "run.ID AS id, " +
// "run.STCD AS stcd, " +
// "run.TM AS tm, " +
// "NVL(run.FLNM, base.STNM || ' ' || TO_CHAR(run.TM, 'yyyy-mm-dd hh24')) AS flnm, " +
// "run.IMG_PATH AS imgPath, " +
// "run.FLPTH AS flpth, " +
// "run.DEVICEINFO AS deviceinfo, " +
// "run.DESCRIBE AS describe, " +
// "run.FID AS fid, " +
// "run.THUMBNAIL AS thumbnail, " +
// "base.RSTCD AS rstcd, " +
// "base.STNM AS stnm, " +
// "eng.ENNM AS ennm, " +
// "base.FHSTCD AS fhstcd, " +
// "fh.STNM AS fhstnm, " +
// "base.CSTCD AS stCode, " +
// "cst.STNM AS stName, " +
// "NVL(eng.BASE_ID, base.BASE_ID) AS baseId, " +
// "hb.BASENAME AS baseName, " +
// "base.STTP AS sttpCode, " +
// "sttp.STTP_NAME AS sttpName, " +
// "base.STNM AS titleName, " +
// "NVL(hb.ORDER_INDEX, 999999) AS baseStepSort, " +
// "NVL(hbrv.ORDER_INDEX, 999999) AS rvcdStepSort, " +
// "NVL(eng.ORDER_INDEX, 999999) AS rstcdStepSort, " +
// "NVL(base.ORDER_INDEX, 999999) AS siteStepSort, " +
// "NVL(eng.HBRVCD, base.HBRVCD) AS hbrvcd, " +
// "hbrv.HBRVNM AS hbrvcdName " +
// "FROM ( " +
// "SELECT detail.ID, detail.STCD, detail.TM, detail.FLNM, detail.IMG_PATH, detail.FLPTH, detail.DEVICEINFO, " +
// "detail.DESCRIBE, detail.FID, detail.THUMBNAIL " +
// "FROM SD_VDINFO_R detail " +
// "INNER JOIN ( " +
// "SELECT STCD, MAX(TM) AS TM FROM SD_VDINFO_R WHERE NVL(IS_DELETED, 0) = 0 GROUP BY STCD " +
// ") latest ON detail.STCD = latest.STCD AND detail.TM = latest.TM " +
// "WHERE NVL(detail.IS_DELETED, 0) = 0 " +
// ") run " +
// "INNER JOIN (" + buildVdDeviceBaseSql() + ") base ON run.STCD = base.STCD " +
// "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = base.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " +
// "LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = NVL(eng.BASE_ID, base.BASE_ID) " +
// " AND NVL(hb.IS_DELETED, 0) = 0 AND NVL(hb.ENABLED, 1) = 1 " +
// "LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = NVL(eng.HBRVCD, base.HBRVCD) " +
// " AND hbrv.BASEID = NVL(eng.BASE_ID, base.BASE_ID) " +
// " AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1 " +
// "LEFT JOIN SD_FHBT_B_H fh ON fh.STCD = base.FHSTCD AND NVL(fh.IS_DELETED, 0) = 0 " +
// "LEFT JOIN (" + buildStationBaseSql() + ") cst ON cst.STCD = base.CSTCD " +
// "LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = base.STTP " +
// " AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 ";
// }
private String buildStationBaseSql() {
return "SELECT river.STCD AS STCD, river.STNM AS STNM FROM SD_RIVER_B_H river WHERE NVL(river.IS_DELETED, 0) = 0 " +
@ -959,7 +993,7 @@ public class VdMonitorServiceImpl implements VdMonitorService {
selectMap.put("stcd", "t.stcd AS stcd");
selectMap.put("tm", "t.tm AS tm");
selectMap.put("flnm", "t.flnm AS flnm");
selectMap.put("imgPath", "t.imgPath AS imgPath");
selectMap.put("imgPath", "t.IMG_PATH AS imgPath");
selectMap.put("flpth", "t.flpth AS flpth");
selectMap.put("deviceinfo", "t.deviceinfo AS deviceinfo");
selectMap.put("describe", "t.describe AS describe");
@ -979,9 +1013,9 @@ public class VdMonitorServiceImpl implements VdMonitorService {
selectMap.put("baseStepSort", "t.baseStepSort AS baseStepSort");
selectMap.put("rvcdStepSort", "t.rvcdStepSort AS rvcdStepSort");
selectMap.put("rstcdStepSort", "t.rstcdStepSort AS rstcdStepSort");
selectMap.put("siteStepSort", "t.siteStepSort AS siteStepSort");
// selectMap.put("siteStepSort", "t.siteStepSort AS siteStepSort");
selectMap.put("hbrvcd", "t.hbrvcd AS hbrvcd");
selectMap.put("hbrvcdName", "t.hbrvcdName AS hbrvcdName");
selectMap.put("hbrvcdName", "t.hbrvcd_name AS hbrvcdName");
if (CollUtil.isEmpty(selectFields)) {
return String.join(", ", selectMap.values());

View File

@ -1,9 +1,11 @@
package com.yfd.platform.qgc_sys.warnRule.controller;
import com.yfd.platform.common.DataSourceLoadOptionsBase;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.qgc_base.service.IMsWarnRuleBService;
import com.yfd.platform.qgc_sys.warnRule.vo.MsWarnRuleBVo;
import com.yfd.platform.utils.QgcQueryWrapperUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
@ -33,11 +35,13 @@ public class MsWarnRuleBController {
@PostMapping("/ysList")
@Operation(summary = "获取告警类型对应的要素")
public ResponseResult getAllYs(@RequestBody DataSourceRequest dataSourceRequest) {
String ruleType = getFilterFieldValue(dataSourceRequest, "ruleType");
DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest();
String ruleType = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "ruleType");
String ruleId = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "ruleId");
if (ruleType == null || ruleType.isEmpty()) {
return ResponseResult.error("ruleType 不能为空");
}
return ResponseResult.successData(msWarnRuleBService.getAllYs(ruleType));
return ResponseResult.successData(msWarnRuleBService.getAllYs(ruleId,ruleType));
}
@PostMapping("/addOrUpdate")
@ -108,31 +112,31 @@ public class MsWarnRuleBController {
return ResponseResult.successData(msWarnRuleBService.getRuleListByStcd(stcd, ruleType, lvl));
}
/**
* DataSourceRequest 过滤条件中提取指定字段的值
*/
private String getFilterFieldValue(DataSourceRequest request, String fieldName) {
if (request == null || request.getFilter() == null) {
return null;
}
return findFilterValue(request.getFilter(), fieldName);
}
private String findFilterValue(DataSourceRequest.FilterDescriptor filter, String fieldName) {
if (filter == null) {
return null;
}
if (fieldName.equals(filter.getField()) && filter.getValue() != null) {
return filter.getValue().toString();
}
if (filter.getFilters() != null) {
for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) {
String value = findFilterValue(child, fieldName);
if (value != null) {
return value;
}
}
}
return null;
}
// /**
// * DataSourceRequest 过滤条件中提取指定字段的值
// */
// private String getFilterFieldValue(DataSourceRequest request, String fieldName) {
// if (request == null || request.getFilter() == null) {
// return null;
// }
// return findFilterValue(request.getFilter(), fieldName);
// }
//
// private String findFilterValue(DataSourceRequest.FilterDescriptor filter, String fieldName) {
// if (filter == null) {
// return null;
// }
// if (fieldName.equals(filter.getField()) && filter.getValue() != null) {
// return filter.getValue().toString();
// }
// if (filter.getFilters() != null) {
// for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) {
// String value = findFilterValue(child, fieldName);
// if (value != null) {
// return value;
// }
// }
// }
// return null;
// }
}

View File

@ -1,6 +1,9 @@
package com.yfd.platform.qgc_sys.warnRule.vo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.UserIdField;
import com.yfd.platform.annotation.UserNameField;
import lombok.Data;
import java.util.Date;
@ -18,6 +21,8 @@ public class MsWarnRuleBVo {
/** 设施与规则绑定id */
private String bindId;
/** 告警规则名称 */
private String ruleId;
/** 告警规则名称 */
private String ruleName;
@ -58,11 +63,17 @@ public class MsWarnRuleBVo {
private List<MsWarnRuleDetailVo> detail;
/** 创建人 */
@UserIdField
private String recordUser;
/** 创建人名称 */
/** 创建人 */
@UserNameField
@TableField(exist = false)
private String recordUserName;
// /** 创建人名称 */
// private String recordUserName;
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;

View File

@ -15,6 +15,12 @@ public class WarnYsVo {
/** 要素编码 */
private String ys;
/** 等级 */
private Integer lvl;
/** 告警等级 */
private String warnLevel;
/** 要素名称 */
private String ysName;

View File

@ -129,4 +129,4 @@ attachment:
token: ${ATTACHMENT_TOKEN:qgcBkod25ngBa4wu8BtfCPYsJ7lQGVDoexH}
upload-url: ${ATTACHMENT_UPLOAD_URL:http://172.16.31.185:18200/upload}
video-url: ${ATTACHMENT_VIDEO_URL:http://172.16.31.185:18200/upload}
delete-url: ${ATTACHMENT_DELETE_URL:http://172.16.31.185:18200/delete}
delete-url: ${ATTACHMENT_DELETE_URL:http://172.16.31.185:18200/FileDelete}

View File

@ -285,4 +285,4 @@ attachment:
token: ${ATTACHMENT_TOKEN:qgcBkod25ngBa4wu8BtfCPYsJ7lQGVDoexH}
upload-url: ${ATTACHMENT_UPLOAD_URL:http://172.16.31.185:18200/upload}
video-url: ${ATTACHMENT_VIDEO_URL:http://172.16.31.185:18200/upload}
delete-url: ${ATTACHMENT_DELETE_URL:http://172.16.31.185:18200/delete}
delete-url: ${ATTACHMENT_DELETE_URL:http://172.16.31.185:18200/FileDelete}

View File

@ -7,13 +7,13 @@ VITE_APP_TITLE = '水电水利建设项目全过程环境管理信息平台'
VITE_APP_PORT = 3000
VITE_APP_BASE_API = '/dev-api'
# 本地环境
# VITE_APP_BASE_URL = 'http://localhost:8093'
VITE_APP_BASE_URL = 'http://localhost:8093'
# 测试环境
# VITE_APP_BASE_URL = 'http://172.16.21.142:8093'
# 汤伟
VITE_APP_BASE_URL = 'http://10.84.111.235:8093'
# VITE_APP_BASE_URL = 'http://10.84.111.235:8093'
# 李林
# VITE_APP_BASE_URL = 'http://10.84.111.25:8093'
VITE_APP_BASE_URL = 'http://10.84.111.25:8093'
## 开发环境 附件服务地址
VITE_APP_ATTACHMENT_URL = 'https://211.99.26.225:12125'

View File

@ -0,0 +1,343 @@
# 地图可视化配置平台MapStudio技术实现说明文档
## 1. 项目概述
本项目是一个基于 **Vue3** + **Ant Design Vue 4.0** + **OpenLayers (ol ^10.8.0)** 的独立地图配图功能模块。 **核心定位**:用于流域水电场景的地图配图工具,支持多类型底图切换、基础图层叠加、业务锚点管理(含样式编辑)。 **关键特性**:作为一个高内聚、低耦合的独立模块,支持整体复制迁移至其他 Vue3 项目。
## 2. 技术栈与环境
- **框架**Vue 3 (Composition API)
- **UI 组件库**Ant Design Vue 4.0 (`a-drawer`, `a-tabs`, `a-popover`, `a-modal` 等)
- **地图引擎**OpenLayers (`ol@^10.8.0`)
- **状态管理**Vue `reactive` + `provide`/`inject` 模式(`useMapStudioState.ts`
- **辅助库**`html2canvas`(配图截图预览,待接入)
- **图标资源**`/src/assets/legend/*.svg`Vite glob 批量导入)
## 3. 页面布局结构
整体采用 **“左侧固定工具栏 + 中央地图容器 + 右侧可收抽屉 + 左下悬浮图例”** 的布局方案。
| 区域 | 组件/实现 | 交互说明 |
| :--------------------- | :--------------------- | :------------------------------------------------------------------------------------------- |
| **工具栏** | `LeftToolbar.vue` | 垂直排列【放大】、【缩小】、【全屏】、【导入(占位)】、【保存配图】。独立于抽屉,抽屉收起时依然显示。目前按钮均为静态占位,无实际交互逻辑。 |
| **中央地图容器** | `index.vue` 内联 div | 承载 OL Map 实例,直接在 `index.vue` 中通过 `ref` 挂载地图,无独立 `MapContainer.vue` 组件。 |
| **右侧抽屉** | `RightDrawer.vue` | `a-drawer` 组件,支持收起/展开。内部嵌套 `a-tabs`,包含【基础底图】、【图例/标题管理】、【锚点样式】三个 Tab。 |
| **左下悬浮图例** | `Legend.vue` | 动态显示当前可见锚点分类的图标和标签,支持图例标题/子级样式配置,位置可通过配置调整(左上/左下/右上/右下)。 |
## 4. 功能模块详细说明
### 4.1 底图切换
- **支持类型**:【影像图】、【矢量图】、【地形图】、【等高线图】。通过替换 `ol/layer/Tile``source` 实现。
- 影像图ArcGIS World Imagery
- 矢量图:内网 GeoServer WMTS`qgc_qsj_arcgistiles_l13`
- 地形图:天地图地形 `ter_w`
- 等高线图Thunderforest Cycle
- **边界图层**:可通过 `a-checkbox` 控制显示/隐藏内网 GeoServer 提供的流域边界线。切换到矢量图时强制隐藏边界。
- **空间范围限定**:未实现(后续可扩展)。
### 4.2 叠加基础图层(显隐控制)
通过 `useOverlayLayers.ts` 管理,右侧抽屉"基础底图"Tab 中的 Checkbox 勾选控制图层显隐(取消勾选时仅 `setVisible(false)`,不删除图层)。
支持以下图层(部分为 WMTS/ArcGIS/GeoServer 服务):
| 图层 | 类型 | 数据来源 |
| :----------- | :---------- | :------------------------------- |
| 行政标注 | TileLayer | 天地图矢量标注 `cia_w` |
| 区域服务 | ImageLayer | ArcGIS REST `ZH_QUYU` |
| 九段线 | ImageLayer | ArcGIS REST `九段线服务1` |
| 岛屿 | ImageLayer | GeoServer WMS `cite:dy` |
| 流域注记 | ImageLayer | ArcGIS REST `zh_LiuYu_annotation` |
| 流域线 | ImageLayer | ArcGIS REST `zh_LiuYu_line` |
| 轮渡 | ImageLayer | ArcGIS REST `jiaotong_ferry` |
| 铁路 | ImageLayer | ArcGIS REST `jiaotong_railway` |
| 地铁 | ImageLayer | ArcGIS REST `jiaotong_metro` |
| 行政区面状 | ImageLayer | ArcGIS REST `zh_XingZhengQu_Polygon` |
| 行政区 | ImageLayer | ArcGIS REST `ZH_XINGZHEGNQU` |
### 4.3 业务锚点系统
锚点类型4 类):电站、过鱼设施、鱼类增殖站、低温水减缓设施。页面初始化时即并行加载所有分类的接口数据,勾选子类型后渲染到地图上,同时图例自动显示。
#### 4.3.1 数据模型
锚点核心接口定义在 `useMapStudioState.ts` 中:
```typescript
interface AnchorCategory {
key: string; // 分类 keypowerStation / fishPassage / fishFarm / coldWater
label: string; // 分类名称
icon: string; // 分类图标 key
children: AnchorItem[];
}
interface AnchorItem {
key: string; // 子类型 key如 large_eng_built
label: string; // 子类型名称
icon: string; // 子类型图标 key
checked: boolean; // 是否勾选
}
```
每个锚点 Feature 的 properties 包含:
- `_iconUrl` - 当前图标 URL
- `_label` - 显示文字
- `_stnm` - 站点名称
- `_lng`, `_lat` - 经纬度
- `_categoryKey`, `_subTypeKey` - 分类/子类型标识
- `_iconSource` - 图标来源inherit / custom
- `_customIconUrl` - 自定义图标 URL
- `_customTypeLabel` - 自定义类型名称(更换图标时可自定义)
- `_ov_*` - 样式覆盖字段(字体、字号、颜色、加粗、图标大小、描边、文字位置/边距、显示文字)
#### 4.3.2 样式继承与优先级
- **全局样式**:存储在 `anchorGlobalStyle` ref 中,修改时全局锚点刷新。
- **单个覆盖**:存储在 feature properties 的 `_ov_*` 字段中。`null` 表示继承全局。
- **渲染合并**:在 `createStyleFunction()` 中执行:`getOv(feature, key, globalValue)` - 有覆盖用覆盖值,否则回退到全局。
- **恢复默认**:将所有 `_ov_*` 置为 `null`
#### 4.3.3 锚点交互
- **勾选显示**:右侧抽屉"基础底图"Tab 提供四类锚点的 Checkbox 组,勾选子类型后地图渲染对应锚点,图例自动更新。
- **选中与编辑**
- **点击地图锚点**:触发选中事件,右侧抽屉自动切换到"锚点样式"Tab 并展开该锚点的详情编辑区域。
- **右侧面板编辑**:可编辑当前选中锚点的:
- **经纬度**(支持直接修改并更新地图位置)
- **显示文字**(修改锚点显示的文本)
- **更换图标**(上传自定义图标,支持两个选项)
- **样式覆盖**(每个样式字段独立覆盖全局,支持一键恢复继承)
- **无气泡 popover**:目前不弹出地图气泡。
- **更换图标**
- **选项 A - 应用于此锚点**:仅替换当前选中锚点的图标。可选择"添加到图例",输入父级名称和当前名称,若图例中不存在则自动添加。
- **选项 B - 应用于所有同类型**:替换当前分类下所有锚点的图标,同时图例中该分类的图标也会更新。
- **碰撞检测**:不做碰撞检测与抽稀(`declutterMode: 'none'`)。
#### 4.3.4 锚点导入(暂为占位)
左侧工具栏【导入】按钮为静态占位,无实际交互逻辑。
#### 4.3.5 图标资源映射
图标 SVG 文件存放于 `/src/assets/legend/`,通过 `ICON_SVG_MAP``useMapStudioState.ts`)建立 icon key 到文件名不含扩展名的映射Vite glob 批量导入获取 URL。
### 4.4 图例/标题管理
右侧抽屉"图例/标题管理"Tab
#### 4.4.1 图例配置
- **显示控制**`a-checkbox` 控制图例和标题的显隐
- **图例属性**:位置(左上/左下/右上/右下)、宽度、高度、左边距/右边距、上边距/下边距
- **图例标题**:对齐方式(左/中/右)、字体、字号、颜色、加粗
- **子级样式**:字体、字号、颜色、加粗、图标大小
#### 4.4.2 标题配置
- 标题内容、X/Y 位置、宽度、高度(通过 `BasicControlOptions[1].checked` 控制显隐)
### 4.5 锚点全局样式管理
右侧抽屉"锚点样式"Tab在无选中锚点时仅显示"全局样式"配置区:
- 字体、字号、颜色、加粗
- 图标大小
- 文字描边宽度、描边颜色
- 文字位置(上/下/左/右)、水平边距、垂直边距
- 是否显示文字标注
- **恢复默认**:一键重置为 `DEFAULT_ANCHOR_STYLE`
有选中锚点时,顶部显示"当前选中"区域,包含:
- 分类标签(含自定义类型名称)
- 站点名称
- 经纬度编辑
- 显示文字编辑
- 当前图标预览 + 更换图标按钮
- **样式覆盖**区:每个样式字段独立可调,带"恢复为继承"按钮(×)
- **恢复默认**:一键清空所有覆盖
### 4.6 自定义图形绘制(未实现)
预留功能,尚未开发。
### 4.7 自定义图片叠加(未实现)
预留功能,尚未开发。
### 4.8 配图方案管理(未实现)
预留功能,尚未开发。
## 5. 目录结构与实际代码
```
src/modules/MapStudio/
├── index.vue # 主入口组件
├── api/
│ └── index.ts # 4 类锚点 API 接口
├── components/
│ ├── LeftToolbar.vue # 左侧工具栏
│ ├── RightDrawer.vue # 右侧抽屉
│ └── Legend.vue # 左下悬浮图例
├── composables/
│ ├── useMapStudioState.ts # 共享状态创建/注入
│ ├── useMapInit.ts # 地图初始化与底图切换
│ ├── useOverlayLayers.ts # 基础图层叠加管理
│ └── useAnchorLayers.ts # 锚点图层管理
└── styles/
└── index.scss # 模块样式
```
## 6. 核心数据流
- **状态管理**`useMapStudioState.ts` 通过 `createMapStudioState()` 创建所有响应式状态,`provideMapStudioState()` 注入,子组件通过 `injectMapStudioState()` 获取。
- **锚点图层**`useAnchorLayers.ts` 管理 4 类锚点的 API 数据加载、OL 图层创建/显隐、样式函数、地图点击选中、样式覆盖同步。
- **基础图层**`useOverlayLayers.ts` 管理基础底图的叠加,通过 `LAYER_MAP` 定义各图层的创建工厂,响应式同步勾选状态。
- **API 层**`api/index.ts` 定义 4 类锚点的请求参数和接口函数,使用项目通用 `request` 工具(基于 axios
## 7. 开发注意事项与难点规避
- **性能优化**:锚点数量较多(>500务必开启 VectorSource 的 `renderMode: 'vector'`,并批量添加 Features`source.addFeatures()`)。
- **样式刷新**:覆盖字段写入 feature 后,必须重新 `setStyle(styleFn)` 触发重绘。
- **交互冲突**:左侧工具栏按钮需阻止点击事件冒泡,避免触发地图的 `singleclick` 事件。
- **底图切换**:切换时将新底图 `insertAt(0)` 插入最底层,避免覆盖上层叠加图层。
- **边界图层**:切换到底图"矢量图"时强制移除边界图层(因矢量图 WMTS 已包含边界信息)。
- **图标覆盖**:选项 B 替换图标时,通过 `categoryIconOverrides` 存储覆盖 URL图例组件会读取该字段更新显示。
## 8. 未实现功能列表与推荐优先级
### 功能完成度概览
| 功能模块 | 状态 | 说明 |
| :--------------------- | :----------- | :------------------------------------------- |
| 底图切换 | ✅ 已完成 | 4 种底图,边界图层显隐控制 |
| 基础图层叠加 | ✅ 已完成 | 11 个子图层,分组 Checkbox 勾选控制 |
| 锚点数据加载与展示 | ✅ 已完成 | 4 类接口初始化加载,勾选渲染,图例自动更新 |
| 锚点全局样式控制 | ✅ 已完成 | 字体/字号/颜色/加粗/图标大小/描边/位置/边距 |
| 锚点选中与编辑 | ✅ 已完成 | 点击选中,右侧面板编辑经纬度/文字/样式 |
| 更换图标(单锚点) | ✅ 已完成 | 上传+添加到图例,自定义类型名称 |
| 更换图标(同分类) | ✅ 已完成 | 替换全部分类图标,更新图例 |
| 图例/标题配置 | ✅ 已完成 | 位置/尺寸/对齐/字体/颜色/加粗 |
| 配图方案管理 | ❌ 未实现 | 保存/加载/历史配图 |
| 工具栏按钮功能 | ❌ 未实现 | 放大/缩小/全屏/导入/保存按钮均为静态占位 |
| 自定义图形绘制 | ❌ 未实现 | 线条/箭头/矩形/圆圈 |
| 自定义图片叠加 | ❌ 未实现 | PNG 上传叠加,调整位置/大小 |
| 空间范围限定 | ❌ 未实现 | 选择区域并裁切地图 |
| 锚点拖拽 | ❌ 未实现 | Translate 交互拖动锚点位置 |
| 选中锚点 popover 气泡 | ❌ 未实现 | 点击锚点在地图弹出小气泡 |
| 锚点导入功能 | ❌ 未实现 | Excel/CSV 批量导入 |
### 推荐开发优先级
**P0 - 核心功能(建议优先完成)**
1. **配图方案管理** - 这是配图工具的核心闭环功能。左侧【保存】按钮应弹出命名输入框保存当前所有状态底图类型、图层显隐、锚点数据与样式覆盖、图例配置、标题配置为JSON配图方案并支持历史记录查看、加载、删除。
- 涉及文件:`LeftToolbar.vue`(接入保存/导入按钮逻辑)、`RightDrawer.vue`(新增加载方案界面)、新建 `useSerializer.ts`(序列化/反序列化)
- 依赖:需要后端存储接口或本地 localStorage
2. **工具栏按钮功能** - 放大/缩小/全屏/导入/保存按钮目前均为静态。放大缩小应绑定 `map.getView().zoom`,全屏应调用 `FullScreen` API导入按钮应弹出功能弹框。
- 涉及文件:`LeftToolbar.vue`(接入 mapInstance
**P1 - 重要功能(配图方案之后)**
3. **自定义图形绘制** - 利用 `ol/interaction/Draw` 实现线条、矩形、圆圈,以及箭头(起点终点+终点三角头)。图形存入独立 `VectorSource`,支持选中删除。保存配图时需包含图形坐标数据。
- 涉及文件:新建 `useDrawTools.ts`、`RightDrawer.vue`新增绘制Tab或面板
4. **自定义图片叠加** - 上传 PNG 图片以绝对定位 div 覆盖在地图上,支持鼠标拖拽移动位置。保存配图时记录 CSS 位置数据。
- 涉及文件:新建 `CustomImageOverlay.vue`、`RightDrawer.vue`(新增图片管理面板)
**P2 - 增强功能(基础功能稳定后)**
5. **空间范围限定** - 下拉选择水电基地/流域/省份,地图 fit 至对应边界,并可调用 `clippingPolygons` 实现区域外变灰的裁切效果。
- 涉及文件:`useMapInit.ts`(扩展)、`RightDrawer.vue`(新增下拉选择)
6. **选中锚点气泡 popover** - 点击锚点时在地图弹出轻量 `a-popover` 气泡,显示站点名称和"删除"按钮。
- 涉及文件:`useAnchorLayers.ts`(点击事件扩展)
7. **锚点拖拽** - 启用 `ol/interaction/Translate` 允许拖动锚点改变地理位置,拖拽结束自动更新选中面板的经纬度。
- 涉及文件:`useAnchorLayers.ts`(添加 Translate 交互)
8. **锚点导入** - 左侧【导入】按钮弹出 a-modal 弹框,支持 Excel/CSV 批量导入经纬度数据。
- 涉及文件:`LeftToolbar.vue`(接入导入弹框)、新建导入逻辑 composable
**P3 - 工程优化(可逐步完善)**
9. **迁移为 Pinia 状态管理** - 当前使用 `provide`/`inject`,迁移到 Pinia 可更好地支持 Vue Devtools 调试和模块隔离。
- 涉及文件:新建 `store/mapStudioStore.ts`,调整 `useMapStudioState.ts`
10. **目录结构调整** - 将类型定义迁移到 `types/index.ts`,新建 `MapContainer.vue` 独立组件,对外暴露 `index.ts`app.use 安装)。
## 9. 与现有底层地图的集成方案(接入指南)
### 9.1 核心原则(禁止叠放)
在集成至已有地图项目时,**严禁**使用 `z-index` 将本模块地图叠放于底层地图之上。
**原因**
1. **事件冲突**:鼠标滚轮缩放、点击拖拽等事件会同时触发两层地图,导致画面闪烁、缩放倍数混乱。
2. **性能浪费**:被遮盖的底层地图仍在持续进行瓦片请求和渲染,消耗 CPU/GPU 与网络资源。
**正确策略**:必须将底层地图**隐藏/销毁**后,再加载本模块地图。
### 9.2 推荐集成方案(二选一)
#### 方案 A隐藏底层容器推荐保留底层状态
适用于底层地图涉及复杂的业务交互状态(如选中的点位、高亮区域),退出模块后需无缝恢复。
- **进入模块时**:设置底层地图容器的 CSS 样式为 `display: none``visibility: hidden`
- **模块内部**:在底层地图容器同级位置,新建一个绝对定位的 `div` 作为本模块地图的挂载点,初始化 `ol.Map`
- **退出模块时**
1. 调用本模块地图实例的 `map.dispose()` 销毁地图。
2. 移除新建的挂载 `div` 元素。
3. 恢复底层地图容器的显示样式。
#### 方案 B销毁底层地图更彻底
适用于底层地图仅作展示、无复杂临时状态的场景。
- **进入模块时**:直接获取底层地图容器,销毁原有 `ol.Map` 实例(`targetElement.innerHTML = ''`),并复用该容器作为本模块地图的挂载点。
- **退出模块时**:销毁本模块地图实例,根据业务需求决定是否重新初始化底层地图。
### 9.3 解耦约定(确保模块可迁移)
由于本模块设计为**独立可迁移**,模块内部代码**严禁**直接操作父级项目的 DOM 元素或地图实例。
**正确的通信方式**:本模块 `MapStudio/index.vue` 通过暴露生命周期事件,由父级项目自行控制底层地图的显隐与销毁。
```vue
<!-- 父级项目使用示例 -->
<template>
<div id="app">
<!-- 原有底层地图容器 -->
<div id="old-map-container" v-show="!showMapStudio"></div>
<!-- MapStudio 模块 -->
<MapStudio
v-if="showMapStudio"
@before-mount="handleBeforeMount" <!-- 进入模块时触发 -->
@after-destroy="handleAfterDestroy" <!-- 退出模块时触发 -->
/>
</div>
</template>
<script setup>
const showMapStudio = ref(false);
const handleBeforeMount = () => {
// 父级在此处执行:隐藏底层地图或销毁其实例
// 例如document.getElementById('old-map-container').style.display = 'none';
};
const handleAfterDestroy = () => {
// 父级在此处执行:恢复底层地图显示或重新初始化
// 例如document.getElementById('old-map-container').style.display = 'block';
};
</script>
```

View File

@ -34,6 +34,7 @@
"esri-leaflet": "^3.0.19",
"exceljs": "^4.4.0",
"file-saver": "^2.0.5",
"html2canvas": "^1.4.1",
"js-base64": "^3.7.5",
"js-cookie": "^3.0.1",
"jsencrypt": "^3.3.2",
@ -57,6 +58,7 @@
"vue-ant-modal-enhance": "^1.2.2",
"vue-i18n": "^9.1.9",
"vue-router": "^4.1.6",
"vue3-draggable-resizable": "^1.6.5",
"vuedraggable": "^2.24.3",
"wujie": "^1.0.24",
"wujie-vue3": "^1.0.24",

View File

@ -80,6 +80,9 @@ importers:
file-saver:
specifier: ^2.0.5
version: 2.0.5
html2canvas:
specifier: ^1.4.1
version: 1.4.1
js-base64:
specifier: ^3.7.5
version: 3.7.8
@ -149,6 +152,9 @@ importers:
vue-router:
specifier: ^4.1.6
version: 4.6.4(vue@3.5.33(typescript@6.0.3))
vue3-draggable-resizable:
specifier: ^1.6.5
version: 1.6.5
vuedraggable:
specifier: ^2.24.3
version: 2.24.3
@ -2720,6 +2726,10 @@ packages:
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
base64-arraybuffer@1.0.2:
resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
engines: {node: '>= 0.6.0'}
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@ -3016,6 +3026,9 @@ packages:
css-box-model@1.2.1:
resolution: {integrity: sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==}
css-line-break@2.1.0:
resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
css-select@4.3.0:
resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
@ -3772,6 +3785,10 @@ packages:
html-void-elements@2.0.1:
resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==}
html2canvas@1.4.1:
resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
engines: {node: '>=8.0.0'}
htmlparser2@3.10.1:
resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==}
@ -5462,6 +5479,9 @@ packages:
resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==}
engines: {node: '>=0.10'}
text-segmentation@1.0.3:
resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==}
text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
@ -5714,6 +5734,9 @@ packages:
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
utrie@1.0.2:
resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
uuid@13.0.2:
resolution: {integrity: sha512-vzi9uRZ926x4XV73S/4qQaTwPXM2JBj6/6lI/byHH1jOpCzb0zDbfytgA9LcN/hzb2l7WQSQnxITOVx5un/wGw==}
hasBin: true
@ -5858,6 +5881,9 @@ packages:
peerDependencies:
vue: ^3.0.0
vue3-draggable-resizable@1.6.5:
resolution: {integrity: sha512-31142E31fGNnq3HKqvmFLSsqIbhck7TyGuQWhUKrDw6DOcGAuRx4ddRjaxvT6fe7dgeKH53qAh+i0ZlWtPLl2g==}
vue@3.5.33:
resolution: {integrity: sha512-1AgChhx5w3ALgT4oK3acm2Es/7jyZhWSVUfs3rOBlGQC0rjEDkS7G4lWlJJGGNQD+BV3reCwbQrOe1mPNwKHBQ==}
peerDependencies:
@ -10304,6 +10330,8 @@ snapshots:
balanced-match@1.0.2: {}
base64-arraybuffer@1.0.2: {}
base64-js@1.5.1: {}
base@0.11.2:
@ -10654,6 +10682,10 @@ snapshots:
dependencies:
tiny-invariant: 1.3.3
css-line-break@2.1.0:
dependencies:
utrie: 1.0.2
css-select@4.3.0:
dependencies:
boolbase: 1.0.0
@ -11558,6 +11590,11 @@ snapshots:
html-void-elements@2.0.1: {}
html2canvas@1.4.1:
dependencies:
css-line-break: 2.1.0
text-segmentation: 1.0.3
htmlparser2@3.10.1:
dependencies:
domelementtype: 1.3.1
@ -13279,6 +13316,10 @@ snapshots:
text-extensions@1.9.0: {}
text-segmentation@1.0.3:
dependencies:
utrie: 1.0.2
text-table@0.2.0: {}
thenify-all@1.6.0:
@ -13533,6 +13574,10 @@ snapshots:
util-deprecate@1.0.2: {}
utrie@1.0.2:
dependencies:
base64-arraybuffer: 1.0.2
uuid@13.0.2: {}
uuid@8.3.2: {}
@ -13695,6 +13740,8 @@ snapshots:
is-plain-object: 3.0.1
vue: 3.5.33(typescript@6.0.3)
vue3-draggable-resizable@1.6.5: {}
vue@3.5.33(typescript@6.0.3):
dependencies:
'@vue/compiler-dom': 3.5.33

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -11,11 +11,16 @@ const modelStore = useModelStore();
const tagsViewStore = useTagsViewStore();
const router = useRoute();
const routeKey = computed(() => router.path + Math.random());
// GisView
const isZhiNengPeiTu = computed(() => {
return router.path === '/zhiNengFenXi/zhiNengPeiTu/index';
});
</script>
<template>
<section class="app-main">
<GisView />
<GisView v-if="!isZhiNengPeiTu" />
<div class="gi-panels">
<router-view v-slot="{ Component, route }" :key="routeKey">
<transition name="router-fade" mode="out-in">

View File

@ -0,0 +1,210 @@
import request from '@/utils/request';
/** Kendo UI 列表接口通用响应结构 */
export interface KendoListResponse<T = any> {
Data: T[];
Total: number;
AggregateResults?: any[];
Errors?: any;
}
/** 锚点基础字段 */
export interface AnchorPointItem {
baseId?: string;
ennm?: string;
lgtd?: number;
lttd?: number;
anchoPointState?: string;
sttp?: string;
[key: string]: any;
}
// ───────────────────────── 1. 电站 ─────────────────────────
export interface EngPointFilter {
filter: {
logic: string;
filters: Array<{
field: string;
operator: string;
dataType: string;
value?: string;
}>;
};
sort: Array<{
field: string;
dir: string;
}>;
}
/** 电站 - 请求体 */
export function getEngPointList(data: EngPointFilter) {
return request({
url: '/eng/base/point/GetKendoListCust',
method: 'post',
data
});
}
/** 电站 - 默认参数 */
export const ENG_POINT_DEFAULT_PARAMS: EngPointFilter = {
filter: {
logic: 'and',
filters: [
{
field: 'anchoPointState',
operator: 'isnotnull',
dataType: 'string'
}
]
},
sort: [
{ field: 'baseId', dir: 'asc' },
{ field: 'rvcdStepSort', dir: 'asc' },
{ field: 'siteStepSort', dir: 'asc' },
{ field: 'ennm', dir: 'asc' }
]
};
// ───────────────────────── 2. 过鱼设施 ─────────────────────────
export interface FpPointFilter {
filter: {
logic: string;
filters: Array<{
field: string;
operator: string;
dataType: string;
value?: string;
}>;
};
}
/** 过鱼设施 - 请求体 */
export function getFpPointList(data: FpPointFilter) {
return request({
url: '/fp/point/qgc/GetKendoListCust',
method: 'post',
data
});
}
/** 过鱼设施 - 默认参数 */
export const FP_POINT_DEFAULT_PARAMS: FpPointFilter = {
filter: {
logic: 'and',
filters: [
{
field: 'lgtd',
operator: 'isnotnull',
dataType: 'string'
}
]
}
};
// ───────────────────────── 3. 鱼类增殖站 ─────────────────────────
export interface FbPointFilter {
filter: {
logic: string;
filters: Array<{
field: string;
operator: string;
dataType: string;
value?: string;
}>;
};
}
/** 鱼类增殖站 - 请求体 */
export function getFbPointList(data: FbPointFilter) {
return request({
url: '/fb/point/GetKendoListCust',
method: 'post',
data
});
}
/** 鱼类增殖站 - 默认参数 */
export const FB_POINT_DEFAULT_PARAMS: FbPointFilter = {
filter: {
logic: 'and',
filters: [
{
field: 'sttp',
operator: 'eq',
dataType: 'string',
value: 'FB'
},
{
field: 'lgtd',
operator: 'isnotnull',
dataType: 'string'
}
]
}
};
// ───────────────────────── 4. 低温水减缓设施 ─────────────────────────
export interface WtPointFilter {
filter: {
logic: string;
filters: Array<{
field: string;
operator: string;
dataType: string;
value?: string;
}>;
};
}
/** 低温水减缓设施 - 请求体 */
export function getWtPointList(data: WtPointFilter) {
return request({
url: '/wt/getFacilityPointList/GetKendoListCust',
method: 'post',
data
});
}
/** 低温水减缓设施 - 默认参数 */
export const WT_POINT_DEFAULT_PARAMS: WtPointFilter = {
filter: {
logic: 'and',
filters: [
{
field: 'lgtd',
operator: 'isnotnull',
dataType: 'string'
}
]
}
};
// 保存配图
export function saveImage(data: any) {
return request({
url: '/smartImage/save',
method: 'post',
data
});
}
// 删除配图
export function deleteImage(data: any) {
return request({
url: '/smartImage/delete',
method: 'post',
data
});
}
// 获取配图列表
export function getImageList(data: any) {
return request({
url: '/smartImage/GetKendoList',
method: 'post',
data
});
}

View File

@ -0,0 +1,251 @@
<template>
<a-modal
:open="visible"
title="历史记录"
width="700px"
:footer="null"
:get-container="getModalContainer"
@cancel="handleCancel"
>
<!-- 搜索栏 -->
<div class="history-modal__search">
<a-input
v-model:value="searchKeyword"
placeholder="输入配图名称"
style="width: 260px"
allowClear
@press-enter="handleQuery"
/>
<a-button type="primary" :loading="loading" @click="handleQuery">
查询
</a-button>
</div>
<!-- 表格 -->
<a-table
:data-source="list"
:columns="columns"
:loading="loading"
:pagination="pagination"
row-key="id"
size="small"
@change="onTableChange"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'actions'">
<a-button type="link" size="small" @click="handleEdit(record)"
>编辑</a-button
>
<a-button type="link" size="small" @click="handlePreview(record)"
>预览</a-button
>
<a-popconfirm
title="确定删除该配图?"
@confirm="handleDelete(record)"
>
<a-button type="link" size="small" danger>删除</a-button>
</a-popconfirm>
</template>
</template>
</a-table>
</a-modal>
<!-- 隐藏的图片预览使用 Ant Design Image 组件 -->
<a-image
:src="previewImageSrc"
:preview="{
visible: previewVisible,
onVisibleChange: (v: boolean) => { previewVisible = v; },
getContainer: getModalContainer
}"
style="width: 0; height: 0; overflow: hidden"
/>
</template>
<script setup lang="ts">
import { ref, reactive, watch, nextTick } from 'vue';
import { Modal, message } from 'ant-design-vue';
import { useMapStudioStore } from '../stores/mapStudioStore';
import { getImageList, deleteImage } from '../api';
const props = defineProps<{ visible: boolean }>();
const emit = defineEmits<{
'update:visible': [val: boolean];
}>();
const store = useMapStudioStore();
//
function getModalContainer() {
return document.querySelector('.map-studio') || document.body;
}
//
const searchKeyword = ref('');
const loading = ref(false);
const list = ref<any[]>([]);
const total = ref(0);
const pagination = reactive({
current: 1,
pageSize: 10,
showSizeChanger: false,
showTotal: (t: number) => `${t}`,
total: 0
});
const columns = [
{ title: '配图名称', dataIndex: 'peituName', key: 'peituName' },
{ title: '操作', key: 'actions', width: 200 }
];
//
async function fetchList() {
loading.value = true;
try {
const skip = (pagination.current - 1) * pagination.pageSize;
const params: any = {
skip,
take: pagination.pageSize
};
if (searchKeyword.value.trim()) {
params.filter = {
logic: 'and',
filters: [
{
field: 'peituName',
dataType: 'string',
operator: 'contains',
value: searchKeyword.value.trim()
}
]
};
}
const res = await getImageList(params);
const data = res.data;
//
if (data) {
list.value = data.records || data.data || [];
total.value = data.total ?? data.total ?? 0;
} else {
list.value = data.items || [];
total.value = data.total ?? 0;
}
pagination.total = total.value;
} catch (err) {
console.error('[HistoryModal] 查询失败:', err);
message.error('查询失败');
} finally {
loading.value = false;
}
}
function handleQuery() {
pagination.current = 1;
fetchList();
}
function onTableChange(pag: { current: number; pageSize: number }) {
pagination.current = pag.current;
pagination.pageSize = pag.pageSize;
fetchList();
}
//
function handleEdit(record: any) {
//
const hasUnsaved =
store.importedImages.length > 0 ||
store.anchorCategories.some(cat =>
cat.children.some(child => child.checked)
);
const applyEdit = () => {
try {
// config
const config =
typeof record.config === 'string'
? JSON.parse(record.config)
: record.config;
//
store.editConfigId = record.id || '';
store.editPeituName = record.peituName || '';
// store index.vue
store.restorePayload = config;
store.restoreVersion++;
message.success('配置已恢复');
handleCancel();
} catch (err) {
console.error('[HistoryModal] 编辑恢复失败:', err);
message.error('配置恢复失败');
}
};
if (hasUnsaved) {
Modal.confirm({
title: '当前地图有未保存的内容',
content: '应用历史配置将覆盖当前地图的所有内容,确定继续?',
okText: '确定覆盖',
cancelText: '取消',
onOk: applyEdit
});
} else {
applyEdit();
}
}
//
const previewImageSrc = ref('');
const previewVisible = ref(false);
function handlePreview(record: any) {
previewImageSrc.value =
import.meta.env.VITE_APP_ATTACHMENT_URL + '/?' + record.imageKey;
nextTick(() => {
previewVisible.value = true;
});
}
//
async function handleDelete(record: any) {
try {
let res = await deleteImage([record.id]);
if (res.code == 0) {
message.success('删除成功');
fetchList();
} else {
message.error('删除失败');
}
} catch (err) {
console.error('[HistoryModal] 删除失败:', err);
message.error('删除失败');
}
}
//
watch(
() => props.visible,
val => {
if (val) {
searchKeyword.value = '';
pagination.current = 1;
fetchList();
}
}
);
function handleCancel() {
emit('update:visible', false);
}
</script>
<style scoped>
.history-modal__search {
display: flex;
gap: 8px;
margin-bottom: 16px;
}
</style>

View File

@ -0,0 +1,456 @@
<template>
<a-modal
:open="visible"
title="导入锚点"
width="620px"
:footer="null"
:destroyOnClose="true"
@update:open="emit('update:visible', $event)"
>
<!-- ====== Step 1: 上传图标 ====== -->
<div v-if="step === 1" class="import-modal-step">
<div class="import-step-header">第一步上传图标</div>
<div class="import-icon-upload-area">
<!-- 图标上传框 -->
<div
class="import-icon-upload-box"
:class="{ 'has-preview': uploadIconUrl }"
@click="iconFileInput?.click()"
>
<img
v-if="uploadIconUrl"
:src="uploadIconUrl"
class="import-icon-upload-img"
/>
<div v-else class="import-icon-upload-placeholder">
<span class="import-icon-upload-plus">+</span>
<span>点击上传图标</span>
</div>
</div>
<input
ref="iconFileInput"
type="file"
accept="image/*"
style="display: none"
@change="onIconFileSelected"
/>
<div v-if="uploadIconUrl" class="import-icon-upload-hint">
点击上方图片可重新选择
</div>
<div v-else class="import-icon-upload-hint">
支持 PNG / JPG / SVG 等格式自动缩放到 64x64
</div>
</div>
<div class="import-modal-actions">
<a-button type="primary" :disabled="!uploadIconUrl" @click="step = 2">
下一步
</a-button>
<a-button @click="emit('update:visible', false)">取消</a-button>
</div>
</div>
<!-- ====== Step 2: 填写信息 + 上传 xlsx ====== -->
<div v-if="step === 2" class="import-modal-step">
<div class="import-step-header">第二步填写信息并上传文件</div>
<div class="import-form-row">
<label class="import-form-label">父级名称</label>
<a-input
v-model:value="parentName"
placeholder="请输入父级名称"
style="width: 240px"
/>
</div>
<div class="import-form-row">
<label class="import-form-label">图例名称</label>
<a-input
v-model:value="legendName"
placeholder="选填,默认使用父级名称"
style="width: 240px"
/>
</div>
<a-divider />
<div class="import-upload-area">
<div class="import-upload-label">上传 xlsx 文件</div>
<a-upload
:beforeUpload="handleBeforeUpload"
:showUploadList="false"
accept=".xlsx,.xls"
>
<a-button type="dashed">
<template #icon><span>📂</span></template>
选择文件
</a-button>
</a-upload>
<span v-if="fileName" class="import-file-name">{{ fileName }}</span>
</div>
<!-- 解析结果预览 -->
<div v-if="parsedData.length > 0" class="import-preview">
<div class="import-preview-title">
已解析 <strong>{{ parsedData.length }}</strong> 条锚点数据
</div>
<div class="import-preview-table-wrap">
<table class="import-preview-table">
<thead>
<tr>
<th>#</th>
<th>锚点名称</th>
<th>经度</th>
<th>纬度</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, idx) in parsedData" :key="idx">
<td>{{ idx + 1 }}</td>
<td>{{ item.name || '(空)' }}</td>
<td>{{ item.lng }}</td>
<td>{{ item.lat }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- 解析错误 -->
<div v-if="parseError" class="import-parse-error">{{ parseError }}</div>
<div class="import-modal-actions">
<a-button @click="step = 1">上一步</a-button>
<a-button
type="primary"
:disabled="parsedData.length === 0"
@click="confirmImport"
>
确定
</a-button>
<a-button @click="emit('update:visible', false)">取消</a-button>
</div>
</div>
</a-modal>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import * as XLSX from 'xlsx';
import { anchorActions } from '../composables/useAnchorLayers';
const props = defineProps<{
visible: boolean;
}>();
const emit = defineEmits<{
(e: 'update:visible', val: boolean): void;
}>();
const addUserImportAnchors = anchorActions.addUserImportAnchors;
// Step 1:
const iconFileInput = ref<HTMLInputElement | null>(null);
const uploadIconUrl = ref('');
function onIconFileSelected(e: Event) {
const input = e.target as HTMLInputElement;
const file = input.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = () => {
// 64x64
const img = new Image();
img.onload = () => {
const maxSize = 64;
let w = img.naturalWidth;
let h = img.naturalHeight;
if (w > maxSize || h > maxSize) {
const ratio = Math.min(maxSize / w, maxSize / h);
w = Math.round(w * ratio);
h = Math.round(h * ratio);
}
const canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
if (ctx) {
ctx.clearRect(0, 0, w, h);
ctx.drawImage(img, 0, 0, w, h);
uploadIconUrl.value = canvas.toDataURL('image/png');
} else {
uploadIconUrl.value = reader.result as string;
}
};
img.onerror = () => {
uploadIconUrl.value = reader.result as string;
};
img.src = reader.result as string;
};
reader.readAsDataURL(file);
}
//
const step = ref(1);
const parentName = ref('');
const legendName = ref('');
const fileName = ref('');
const parsedData = ref<{ name: string; lng: number; lat: number }[]>([]);
const parseError = ref('');
//
watch(
() => props.visible,
(val: boolean) => {
if (!val) {
step.value = 1;
uploadIconUrl.value = '';
parentName.value = '';
legendName.value = '';
fileName.value = '';
parsedData.value = [];
parseError.value = '';
}
}
);
// xlsx
function handleBeforeUpload(file: File): boolean {
fileName.value = file.name;
parseError.value = '';
parsedData.value = [];
const reader = new FileReader();
reader.onload = (e: ProgressEvent<FileReader>) => {
try {
const data = new Uint8Array(e.target!.result as ArrayBuffer);
const workbook = XLSX.read(data, { type: 'array' });
const sheetName = workbook.SheetNames[0];
const sheet = workbook.Sheets[sheetName];
const json = XLSX.utils.sheet_to_json<(string | number)[][]>(sheet, {
header: 1
});
if (json.length === 0) {
parseError.value = '文件为空,请检查';
return;
}
const results: { name: string; lng: number; lat: number }[] = [];
for (let i = 0; i < json.length; i++) {
const row = json[i];
if (!row || row.length < 3) continue;
const name = String(row[0] ?? '').trim();
const lng = parseFloat(String(row[1]).trim());
const lat = parseFloat(String(row[2]).trim());
if (!isNaN(lng) && !isNaN(lat)) {
results.push({ name, lng, lat });
}
}
if (results.length === 0) {
parseError.value =
'未解析到有效数据,请确保第一列为锚点名称,第二列为经度,第三列为纬度';
return;
}
parsedData.value = results;
} catch (err) {
parseError.value = '文件解析失败:' + (err as Error).message;
}
};
reader.onerror = () => {
parseError.value = '文件读取失败';
};
reader.readAsArrayBuffer(file);
return false;
}
// useAnchorLayers
function confirmImport() {
if (parsedData.value.length === 0 || !addUserImportAnchors) return;
addUserImportAnchors({
parentName: parentName.value || '未命名',
legendName: legendName.value || parentName.value || '未命名',
iconUrl: uploadIconUrl.value,
items: parsedData.value
});
//
emit('update:visible', false);
}
</script>
<style scoped>
.import-modal-step {
min-height: 300px;
}
.import-step-header {
font-size: 15px;
font-weight: 600;
color: #262626;
margin-bottom: 16px;
padding-left: 10px;
border-left: 3px solid #0c72c5;
line-height: 1;
}
/* ── 图标上传 ── */
.import-icon-upload-area {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
padding: 20px 0;
}
.import-icon-upload-box {
width: 160px;
height: 160px;
border: 2px dashed #d9d9d9;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s;
background: #fafafa;
overflow: hidden;
}
.import-icon-upload-box:hover {
border-color: #1890ff;
background: #f0f9ff;
}
.import-icon-upload-box.has-preview {
border-style: solid;
border-color: #d9d9d9;
}
.import-icon-upload-img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.import-icon-upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
color: #bbb;
user-select: none;
}
.import-icon-upload-plus {
font-size: 36px;
line-height: 1;
color: #d9d9d9;
}
.import-icon-upload-hint {
font-size: 13px;
color: #999;
}
/* ── 表单 ── */
.import-form-row {
display: flex;
align-items: center;
margin-bottom: 14px;
}
.import-form-label {
width: 90px;
font-size: 14px;
color: #262626;
flex-shrink: 0;
text-align: right;
margin-right: 12px;
}
/* ── 上传区域 ── */
.import-upload-area {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
}
.import-upload-label {
font-size: 14px;
color: #262626;
flex-shrink: 0;
}
.import-file-name {
font-size: 13px;
color: #1890ff;
}
/* ── 预览表格 ── */
.import-preview {
margin-top: 16px;
}
.import-preview-title {
font-size: 14px;
color: #262626;
margin-bottom: 10px;
}
.import-preview-table-wrap {
max-height: 220px;
overflow-y: auto;
border: 1px solid #f0f0f0;
border-radius: 4px;
}
.import-preview-table {
width: 100%;
border-collapse: collapse;
font-size: 13px;
}
.import-preview-table th,
.import-preview-table td {
padding: 6px 10px;
text-align: left;
border-bottom: 1px solid #f0f0f0;
}
.import-preview-table th {
background: #fafafa;
font-weight: 600;
color: #262626;
position: sticky;
top: 0;
}
.import-preview-table td {
color: #595959;
}
/* ── 错误提示 ── */
.import-parse-error {
margin-top: 12px;
padding: 8px 12px;
background: #fff2f0;
border: 1px solid #ffccc7;
border-radius: 4px;
color: #ff4d4f;
font-size: 13px;
}
/* ── 操作按钮 ── */
.import-modal-actions {
display: flex;
justify-content: center;
gap: 12px;
margin-top: 24px;
padding-top: 16px;
border-top: 1px solid #f0f0f0;
}
</style>

View File

@ -0,0 +1,416 @@
<template>
<div class="map-studio__toolbar">
<button class="map-studio__toolbar-btn" title="放大" @click="zoomIn">
<span class="btn-icon text-[16px]"><PlusOutlined /></span>
<span class="btn-label">放大</span>
</button>
<button class="map-studio__toolbar-btn" title="缩小" @click="zoomOut">
<span class="btn-icon text-[16px]"><MinusOutlined /></span>
<span class="btn-label">缩小</span>
</button>
<div class="map-studio__toolbar-divider" />
<button
class="map-studio__toolbar-btn"
title="全屏"
@click="toggleFullScreen"
>
<span class="btn-icon text-[20px]"></span>
<span class="btn-label">全屏</span>
</button>
<div class="map-studio__toolbar-divider" />
<button class="map-studio__toolbar-btn" title="重置" @click="resetMap">
<span class="btn-icon text-[16px]"></span>
<span class="btn-label">重置</span>
</button>
<div class="map-studio__toolbar-divider" />
<button
class="map-studio__toolbar-btn"
title="撤回"
:disabled="!canUndo"
@click="undo"
>
<span class="btn-icon text-[16px]"></span>
<span class="btn-label">撤回</span>
</button>
<button
class="map-studio__toolbar-btn"
title="取消撤回"
:disabled="!canRedo"
@click="redo"
>
<span class="btn-icon text-[16px]"></span>
<span class="btn-label">取消</span>
</button>
<div class="map-studio__toolbar-divider" />
<a-dropdown
v-model:open="importDropdownOpen"
placement="rightTop"
:trigger="['click']"
:getPopupContainer="getPopupContainer"
>
<button class="map-studio__toolbar-btn" title="导入">
<span class="btn-icon text-[16px]">📁</span>
<span class="btn-label">导入</span>
</button>
<template #overlay>
<a-menu>
<a-menu-item @click="triggerImportAnchors">
<span>导入锚点</span>
</a-menu-item>
<a-menu-item @click="triggerImportImage">
<span>导入图片</span>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
<!-- 隐藏的文件输入用于导入 PNG 图片 -->
<input
ref="importFileInput"
type="file"
accept="image/png"
style="display: none"
@change="onImageFileSelected"
/>
<!-- 导入锚点 Modal -->
<ImportAnchorModal v-model:visible="importAnchorModalVisible" />
<!-- 添加表格按钮 -->
<button
class="map-studio__toolbar-btn"
title="添加表格"
@click="triggerAddTable"
>
<span class="btn-icon text-[16px]"></span>
<span class="btn-label">表格</span>
</button>
<!-- 保存配图 Modal -->
<SaveModal v-model:visible="saveVisible" @saved="onSaved" />
<!-- 历史记录 Modal -->
<HistoryModal v-model:visible="historyVisible" />
<div class="map-studio__toolbar-divider" />
<!-- 绘制工具下拉 -->
<a-dropdown
v-model:open="drawDropdownOpen"
placement="rightTop"
:trigger="['click']"
:getPopupContainer="getPopupContainer"
>
<button
class="map-studio__toolbar-btn"
:class="{ 'is-active': drawToolActive !== null }"
title="绘制"
>
<span class="btn-icon text-[16px]"></span>
<span class="btn-label">{{
drawToolActive ? drawToolLabel : '绘制'
}}</span>
</button>
<template #overlay>
<a-menu @click="onDrawToolSelect" :selectedKeys="menuSelectedKeys">
<a-menu-item key="point">📍 标记点</a-menu-item>
<a-menu-item key="line"> 折线</a-menu-item>
<a-menu-item key="polygon"> 多边形</a-menu-item>
<a-menu-item key="rect"> 矩形</a-menu-item>
<a-menu-item key="circle"> 圆形</a-menu-item>
<a-menu-item key="freehand"> 自由手绘</a-menu-item>
<a-menu-item key="text">A 文字标注</a-menu-item>
</a-menu>
</template>
</a-dropdown>
<!-- 若当前有绘制的工具激活显示删除按钮 -->
<button
v-if="drawToolActive !== null"
class="map-studio__toolbar-btn"
title="删除选中"
@click="deleteSelected"
>
<span class="btn-icon text-[16px]">🗑</span>
<span class="btn-label">删除</span>
</button>
<div class="map-studio__toolbar-divider" />
<button
class="map-studio__toolbar-btn"
title="保存配图"
@click="saveVisible = true"
>
<span class="btn-icon text-[16px]">💾</span>
<span class="btn-label">保存</span>
</button>
<button
class="map-studio__toolbar-btn"
title="历史记录"
@click="historyVisible = true"
>
<span class="btn-icon text-[16px]">🔄</span>
<span class="btn-label">历史</span>
</button>
</div>
</template>
<script setup lang="ts">
import { ref, computed, h } from 'vue';
import { storeToRefs } from 'pinia';
import { Modal, Input } from 'ant-design-vue';
import { PlusOutlined, MinusOutlined } from '@ant-design/icons-vue';
import { useMapStudioStore } from '../stores/mapStudioStore';
import type { DrawToolType } from '../types';
import type { TableOverlayData } from '../types';
import { useUndoRedo } from '../composables/useUndoRedo';
import ImportAnchorModal from './ImportAnchorModal.vue';
import SaveModal from './SaveModal.vue';
import HistoryModal from './HistoryModal.vue';
const store = useMapStudioStore();
const {
mapInstance,
importedImages,
selectedImageId,
activeTab,
drawToolActive
} = storeToRefs(store);
const { canUndo, canRedo, undo, redo } = useUndoRedo();
const { drawCheckpoint } = useUndoRedo();
const importDropdownOpen = ref(false);
const importFileInput = ref<HTMLInputElement | null>(null);
const importAnchorModalVisible = ref(false);
const saveVisible = ref(false);
const historyVisible = ref(false);
const drawDropdownOpen = ref(false);
function getPopupContainer() {
return document.querySelector('.map-studio') || document.body;
}
const DRAW_TOOL_LABELS: Record<DrawToolType, string> = {
point: '标记点',
line: '折线',
polygon: '多边形',
rect: '矩形',
circle: '圆形',
freehand: '自由手绘',
text: '文字标注',
select: '选中/编辑'
};
const drawToolLabel = computed(() =>
drawToolActive.value ? DRAW_TOOL_LABELS[drawToolActive.value] ?? '绘制' : ''
);
/** 菜单选中项,当前激活的工具高亮显示 */
const menuSelectedKeys = computed(() =>
drawToolActive.value ? [drawToolActive.value] : []
);
let imageIdCounter = 0;
let tableIdCounter = 0;
function triggerAddTable() {
const defaultRows = 3;
const defaultCols = 4;
let tempRows = defaultRows;
let tempCols = defaultCols;
Modal.confirm({
title: '添加表格',
content: () =>
h(
'div',
{ style: 'display:flex;flex-direction:column;gap:16px;padding:8px 0;' },
[
h('div', { style: 'display:flex;align-items:center;gap:8px;' }, [
h('span', { style: 'white-space:nowrap;' }, '行数:'),
h(Input, {
style: 'width:120px',
placeholder: '行数',
value: String(tempRows),
type: 'number',
min: 1,
max: 50,
onInput: (e: any) => {
const v = parseInt(e.target?.value ?? '');
if (!isNaN(v) && v > 0) tempRows = v;
}
})
]),
h('div', { style: 'display:flex;align-items:center;gap:8px;' }, [
h('span', { style: 'white-space:nowrap;' }, '列数:'),
h(Input, {
style: 'width:120px',
placeholder: '列数',
value: String(tempCols),
type: 'number',
min: 1,
max: 50,
onInput: (e: any) => {
const v = parseInt(e.target?.value ?? '');
if (!isNaN(v) && v > 0) tempCols = v;
}
})
])
]
),
onOk: () => {
const rows = Math.max(tempRows, 1);
const cols = Math.max(tempCols, 1);
//
const cellData: string[][] = [];
for (let r = 0; r < rows; r++) {
const row: string[] = [];
for (let c = 0; c < cols; c++) {
row.push('');
}
cellData.push(row);
}
tableIdCounter++;
const table: TableOverlayData = {
id: `table_${Date.now()}_${tableIdCounter}`,
x: 30,
y: 30,
width: 400,
height: 60 + rows * 30,
rows,
cols,
cellData,
fontSize: 14,
fontFamily: 'Microsoft YaHei',
textColor: '#333333',
borderColor: '#000000',
borderWidth: 1,
fillColor: '#ffffff',
fillTransparent: false,
fontBold: false,
hAlign: 'center',
vAlign: 'middle',
rowHeights: Array(rows).fill(30),
colWidths: Array(cols).fill(80)
};
store.tableOverlays.push(table);
store.selectedTableId = table.id;
store.activeTab = 'table';
//
drawCheckpoint();
}
});
}
function triggerImportImage() {
importDropdownOpen.value = false;
importFileInput.value?.click();
}
function triggerImportAnchors() {
importDropdownOpen.value = false;
importAnchorModalVisible.value = true;
}
function onImageFileSelected(e: Event) {
const input = e.target as HTMLInputElement;
const file = input.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = () => {
const src = reader.result as string;
imageIdCounter++;
// 200x200
importedImages.value.push({
id: `img_${Date.now()}_${imageIdCounter}`,
src,
x: 10,
y: 10,
width: 200,
height: 200
});
// tab
selectedImageId.value =
importedImages.value[importedImages.value.length - 1].id;
activeTab.value = 'images';
};
reader.readAsDataURL(file);
// input
input.value = '';
}
//
function onDrawToolSelect(ev: { key: string }) {
drawDropdownOpen.value = false;
const key = ev.key as DrawToolType;
if (key === drawToolActive.value) {
//
drawToolActive.value = null;
} else {
drawToolActive.value = key;
}
// tab
if (key === 'select' && drawToolActive.value === 'select') {
activeTab.value = 'draw';
}
}
function deleteSelected() {
// useDrawTools
window.dispatchEvent(new CustomEvent('map-studio:delete-draw'));
}
function zoomIn() {
if (!mapInstance.value) return;
const view = mapInstance.value.getView();
const zoom = view.getZoom() ?? 1;
view.setZoom(zoom + 0.2);
}
function zoomOut() {
if (!mapInstance.value) return;
const view = mapInstance.value.getView();
const zoom = view.getZoom() ?? 1;
view.setZoom(zoom - 0.2);
}
function toggleFullScreen() {
if (!document.fullscreenElement) {
// MapStudio
const studioEl = document.querySelector('.map-studio') as HTMLElement;
if (!studioEl) return;
studioEl.requestFullscreen().catch(err => {
console.error('进入全屏失败:', err);
});
} else {
document.exitFullscreen().catch(err => {
console.error('退出全屏失败:', err);
});
}
}
function resetMap() {
//
if (store.clipMode !== 'none' && store.fitClipView) {
store.fitClipView();
return;
}
if (store.resetView) {
store.resetView();
}
}
function onSaved() {
// modal
console.log('[LeftToolbar] 配图保存成功');
}
</script>

View File

@ -0,0 +1,291 @@
<template>
<div
v-if="
BasicControlOptions[0].checked &&
(checkedAnchorData.length > 0 || customLegendGroups.length > 0)
"
class="map-studio__legend"
:style="legendStyle"
>
<div class="map-studio__legend-title-row" :style="titleStyle">
<span class="map-studio__legend-title">图例</span>
</div>
<div class="map-studio__legend-scroll">
<div
v-for="category in checkedAnchorData"
:key="category.key"
class="map-studio__legend-group"
>
<div class="map-studio__legend-group-title" :style="subtitleStyle">
{{ category.label }}
</div>
<div class="map-studio__legend-group-content">
<div
v-for="item in category.children"
:key="item.key"
class="map-studio__legend-item"
>
<img
v-if="item.iconSrc"
:src="item.iconSrc"
:style="childIconStyle"
class="map-studio__legend-icon"
/>
<span class="map-studio__legend-label" :style="childLabelStyle">{{
item.label
}}</span>
</div>
</div>
</div>
<!-- 自定义图例分组 -->
<div
v-for="group in customLegendGroups"
:key="group.key"
class="map-studio__legend-group"
>
<div class="map-studio__legend-group-title" :style="subtitleStyle">
{{ group.label }}
</div>
<div class="map-studio__legend-group-content">
<div
v-for="(item, idx) in group.children"
:key="idx"
class="map-studio__legend-item"
>
<img
v-if="item.iconUrl"
:src="item.iconUrl"
:style="childIconStyle"
class="map-studio__legend-icon"
/>
<span class="map-studio__legend-label" :style="childLabelStyle">{{
item.label
}}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { storeToRefs } from 'pinia';
import { useMapStudioStore } from '../stores/mapStudioStore';
import { ICON_SVG_MAP } from '../types';
const store = useMapStudioStore();
const {
anchorCategories,
BasicControlOptions,
legendConfig,
anchorGlobalStyle,
categoryIconOverrides,
customLegendGroups,
categoryChildExtensions
} = storeToRefs(store);
// Vite glob SVG
const legendIconModules = import.meta.glob('/src/assets/legend/*.svg', {
eager: true,
query: '?url',
import: 'default'
}) as Record<string, string>;
function getIconSrc(iconKey: string): string {
const filename = ICON_SVG_MAP[iconKey];
if (!filename) return '';
const modulePath = `/src/assets/legend/${filename}.svg`;
return legendIconModules[modulePath] || '';
}
/** 所有被勾选的锚点 + 自定义扩展,按大类分组 */
const checkedAnchorData = computed(() => {
return anchorCategories.value
.map(cat => {
const checked = cat.children.filter(c => c.checked);
const extensions = categoryChildExtensions.value[cat.label] || [];
if (checked.length === 0 && extensions.length === 0) return null;
const catOverrideIconUrl = categoryIconOverrides.value[cat.key];
const children: {
key: string;
label: string;
iconSrc: string;
}[] = [];
// 使 customIconUrl
for (const c of checked) {
children.push({
key: c.key,
label: c.label,
iconSrc:
c.customIconUrl ||
catOverrideIconUrl ||
(ICON_SVG_MAP[c.icon] ? getIconSrc(c.icon) : '')
});
}
//
const checkedLabels = new Set(checked.map(c => c.label));
for (let i = 0; i < extensions.length; i++) {
const ext = extensions[i];
if (checkedLabels.has(ext.label)) continue;
children.push({
key: `ext-${cat.key}-${i}`,
label: ext.label,
iconSrc: ext.iconUrl
});
}
return { key: cat.key, label: cat.label, children };
})
.filter(Boolean) as {
key: string;
label: string;
children: { key: string; label: string; iconSrc: string }[];
}[];
});
/** 图例容器样式(位置、宽高、偏移) */
const legendStyle = computed(() => {
const cfg = legendConfig.value;
const pos: Record<string, string> = {};
if (cfg.position.includes('top')) pos.top = `${cfg.offsetY}px`;
else pos.bottom = `${cfg.offsetY}px`;
if (cfg.position.includes('left')) pos.left = `${cfg.offsetX}px`;
else pos.right = `${cfg.offsetX}px`;
return {
width: `${cfg.width}px`,
maxHeight: `${cfg.height}px`,
...pos
};
});
/** 图标尺寸样式 */
const iconSizeStyle = computed(() => ({
width: `${anchorGlobalStyle.value.iconWidth}px`,
height: `${anchorGlobalStyle.value.iconHeight}px`
}));
/** 文字样式 */
const labelStyle = computed(() => ({
fontSize: `${anchorGlobalStyle.value.fontSize}px`,
color: anchorGlobalStyle.value.color,
fontWeight: anchorGlobalStyle.value.bold
? ('bold' as const)
: ('normal' as const)
}));
/** 图例标题样式 */
const titleStyle = computed(() => ({
fontSize: `${legendConfig.value.titleFontSize}px`,
fontFamily: legendConfig.value.titleFontFamily,
fontWeight: legendConfig.value.titleBold
? ('bold' as const)
: ('normal' as const),
textAlign: legendConfig.value.titleAlign as 'left' | 'center' | 'right',
color: legendConfig.value.titleColor
}));
/** 一级大类标题样式(比图例标题小 2px */
const subtitleStyle = computed(() => ({
fontSize: `${Math.max(legendConfig.value.titleFontSize - 2, 10)}px`,
fontWeight: legendConfig.value.titleBold
? ('bold' as const)
: ('normal' as const),
fontFamily: legendConfig.value.titleFontFamily,
color: legendConfig.value.titleColor
}));
/** 图例子级文字样式 */
const childLabelStyle = computed(() => ({
fontSize: `${legendConfig.value.childFontSize}px`,
fontFamily: legendConfig.value.childFontFamily,
color: legendConfig.value.childColor,
fontWeight: legendConfig.value.childBold
? ('bold' as const)
: ('normal' as const)
}));
/** 图例子级图标尺寸 */
const childIconStyle = computed(() => ({
width: `${legendConfig.value.childIconSize}px`,
height: `${legendConfig.value.childIconSize}px`
}));
</script>
<style lang="scss" scoped>
.map-studio__legend {
position: absolute;
background: #fff;
padding: 8px 10px;
z-index: 10;
overflow: hidden;
}
.map-studio__legend-title-row {
margin-bottom: 6px;
padding-bottom: 4px;
border-bottom: 1px solid #eee;
}
.map-studio__legend-scroll {
overflow-y: auto;
max-height: calc(100% - 24px);
display: flex;
gap: 6px 16px;
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-thumb {
background: #d9d9d9;
border-radius: 2px;
}
}
.map-studio__legend-group {
display: inline-block;
vertical-align: top;
margin-left: 4px;
}
.map-studio__legend-group-title {
font-size: 12px;
font-weight: 600;
color: #262626;
margin-bottom: 8px;
}
.map-studio__legend-group-content {
display: flex;
flex-wrap: wrap;
gap: 2px 6px;
margin-left: 4px;
}
.map-studio__legend-item {
width: 100%;
display: flex;
align-items: center;
gap: 8px;
padding: 4px 0;
white-space: nowrap;
margin-bottom: 2px;
span {
margin-top: -2px;
}
}
.map-studio__legend-icon {
flex-shrink: 0;
object-fit: contain;
}
.map-studio__legend-label {
line-height: 1.2;
}
</style>

View File

@ -0,0 +1,13 @@
<template>
<div ref="containerRef" class="map-studio__map-area">
<slot />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const containerRef = ref<HTMLElement | null>(null);
defineExpose({ containerRef });
</script>

View File

@ -0,0 +1,224 @@
<template>
<div
ref="containerRef"
class="map-studio__image-overlay-container"
@keydown.delete="onDeleteKey"
tabindex="0"
>
<template v-for="img in importedImages" :key="img.id">
<vue3-draggable-resizable
style="pointer-events: all"
:init-w="img.width"
:init-h="img.height"
:x="img.x"
:y="img.y"
:w="img.width"
:h="img.height"
:parent="true"
:active="selectedImageId === img.id"
:min-w="20"
:min-h="20"
:handles="['tl', 'tm', 'tr', 'ml', 'mr', 'bl', 'bm', 'br']"
@update:x="onUpdateX(img, $event)"
@update:y="onUpdateY(img, $event)"
@update:w="onUpdateW(img, $event)"
@update:h="onUpdateH(img, $event)"
@activated="onActivated(img)"
@drag-start="onDragStart(img)"
@drag-end="onDragEnd"
@resize-start="onResizeStart(img)"
@resize-end="onResizeEnd"
>
<img
:src="img.src"
class="map-studio__overlay-image"
draggable="false"
/>
<!-- 删除按钮左上角不遮挡右上角缩放手柄 -->
<div
v-if="selectedImageId === img.id"
class="map-studio__overlay-delete"
@mousedown.stop
@click.stop="onDeleteImage(img)"
>
×
</div>
</vue3-draggable-resizable>
</template>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { storeToRefs } from 'pinia';
import Vue3DraggableResizable from 'vue3-draggable-resizable';
import 'vue3-draggable-resizable/dist/Vue3DraggableResizable.css';
import { useMapStudioStore } from '../stores/mapStudioStore';
import type { ImportedImage } from '../types';
const store = useMapStudioStore();
const { importedImages, selectedImageId, activeTab } = storeToRefs(store);
const containerRef = ref<HTMLElement | null>(null);
const isInteracting = ref(false);
// activated
function onActivated(img: ImportedImage) {
selectedImageId.value = img.id;
}
//
function handleDocumentClick(e: MouseEvent) {
if (!selectedImageId.value || isInteracting.value) return;
const target = e.target as Node;
// .vdr
const vdrs = document.querySelectorAll('.vdr');
for (const vdr of vdrs) {
if (vdr.contains(target)) return;
}
//
const delBtns = document.querySelectorAll('.map-studio__overlay-delete');
for (const btn of delBtns) {
if (btn.contains(target)) return;
}
// X/Y
const drawers = document.querySelectorAll('.map-studio__drawer-section');
for (const drawer of drawers) {
if (drawer.contains(target)) return;
}
// ant-modal
const modals = document.querySelectorAll('.ant-modal');
for (const modal of modals) {
if (modal.contains(target)) return;
}
selectedImageId.value = null;
}
// /
function onDragStart(img: ImportedImage) {
selectedImageId.value = img.id;
isInteracting.value = true;
activeTab.value = 'images';
}
function onDragEnd() {
isInteracting.value = false;
}
function onResizeStart(img: ImportedImage) {
selectedImageId.value = img.id;
isInteracting.value = true;
activeTab.value = 'images';
}
function onResizeEnd() {
isInteracting.value = false;
}
// /
function onUpdateX(img: ImportedImage, val: number) {
img.x = Math.floor(val);
}
function onUpdateY(img: ImportedImage, val: number) {
img.y = Math.floor(val);
}
function onUpdateW(img: ImportedImage, val: number) {
img.width = Math.floor(val);
}
function onUpdateH(img: ImportedImage, val: number) {
img.height = Math.floor(val);
}
//
function onDeleteImage(img: ImportedImage) {
const idx = importedImages.value.indexOf(img);
if (idx !== -1) {
importedImages.value.splice(idx, 1);
}
if (selectedImageId.value === img.id) {
selectedImageId.value = null;
}
// tab
if (importedImages.value.length === 0 && activeTab.value === 'images') {
activeTab.value = 'baseMap';
}
}
function onDeleteKey(e: KeyboardEvent) {
// container Delete
if (e.key === 'Delete' && selectedImageId.value) {
const img = importedImages.value.find(i => i.id === selectedImageId.value);
if (img) {
onDeleteImage(img);
}
}
}
//
function handleKeyDown(e: KeyboardEvent) {
if (
e.key === 'Delete' &&
selectedImageId.value &&
containerRef.value?.contains(e.target as Node)
) {
const img = importedImages.value.find(i => i.id === selectedImageId.value);
if (img) {
onDeleteImage(img);
}
}
}
onMounted(() => {
document.addEventListener('keydown', handleKeyDown);
document.addEventListener('mousedown', handleDocumentClick, true);
});
onUnmounted(() => {
document.removeEventListener('keydown', handleKeyDown);
document.removeEventListener('mousedown', handleDocumentClick, true);
});
</script>
<style scoped>
.map-studio__image-overlay-container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 5;
pointer-events: none;
outline: none;
}
.map-studio__image-overlay-container > :deep(.vdr) {
pointer-events: auto;
}
.map-studio__overlay-image {
width: 100%;
height: 100%;
object-fit: contain;
user-select: none;
pointer-events: none;
}
.map-studio__overlay-delete {
position: absolute;
top: 0px;
right: -30px;
width: 20px;
height: 20px;
border-radius: 50%;
background: #ff4d4f;
color: #fff;
font-size: 14px;
line-height: 20px;
text-align: center;
cursor: pointer;
z-index: 10;
pointer-events: auto;
user-select: none;
box-shadow: 0 1px 4px rgba(255, 77, 79, 0.5);
}
.map-studio__overlay-delete:hover {
transform: scale(1.15);
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,363 @@
<template>
<a-modal
:open="visible"
title="保存配图"
width="520px"
:confirm-loading="saving"
:ok-button-props="{ disabled: !peituName.trim() }"
:get-container="getModalContainer"
@ok="handleSave"
@cancel="handleCancel"
>
<div class="save-modal__body">
<!-- 配图名称 -->
<div class="save-modal__field">
<label class="save-modal__label">
<span class="save-modal__required">*</span>配图名称
</label>
<a-input
v-model:value="peituName"
placeholder="请输入配图名称"
:maxlength="50"
:status="nameError ? 'error' : undefined"
/>
<span v-if="nameError" class="save-modal__error">请输入配图名称</span>
</div>
<!-- 预览图 -->
<div class="save-modal__field">
<label class="save-modal__label">预览图</label>
<div class="save-modal__preview-wrapper">
<a-image
v-if="previewBase64"
:src="previewBase64"
class="save-modal__preview"
alt="预览图"
:preview="{ getContainer: getModalContainer }"
/>
<div v-else class="save-modal__preview-empty">
<span v-if="capturing">正在截图...</span>
<span v-else>截取预览图中...</span>
</div>
</div>
<div class="save-modal__preview-actions">
<a-button
size="small"
:disabled="!previewBase64"
@click="downloadPreview"
>
下载预览图
</a-button>
</div>
</div>
</div>
</a-modal>
</template>
<script setup lang="ts">
import { ref, watch, nextTick } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { storeToRefs } from 'pinia';
import { useMapStudioStore } from '../stores/mapStudioStore';
import { useUserStore } from '@/store/modules/user';
import { saveImage } from '../api';
import { drawActions } from '../composables/useDrawTools';
import { anchorActions } from '../composables/useAnchorLayers';
const props = defineProps<{ visible: boolean }>();
const emit = defineEmits<{
'update:visible': [val: boolean];
saved: [];
}>();
const store = useMapStudioStore();
const {
selectedBaseMap,
showBoundary,
clipMode,
clipBasin,
clipDistrict,
layerOptions,
BasicControlOptions,
legendConfig,
anchorGlobalStyle,
anchorCategories,
customLegendEntries,
customLegendGroups,
categoryChildExtensions,
categoryIconOverrides,
importedImages,
drawStyle,
tableOverlays
} = storeToRefs(store);
/** 获取 modal 挂载容器,全屏时挂载到 .map-studio 内 */
function getModalContainer() {
return document.querySelector('.map-studio') || document.body;
}
const peituName = ref('');
const previewBase64 = ref('');
const saving = ref(false);
const capturing = ref(false);
const nameError = ref(false);
// modal
watch(
() => props.visible,
async val => {
if (val) {
// store
peituName.value = store.editPeituName || '';
previewBase64.value = '';
nameError.value = false;
await nextTick();
takeScreenshot();
}
}
);
/** 截图:使用 html2canvas 捕获地图区域 */
async function takeScreenshot() {
capturing.value = true;
previewBase64.value = '';
await nextTick();
try {
const html2canvas = (await import('html2canvas')).default;
const el = document.querySelector('.map-studio__map-area') as HTMLElement;
if (!el) {
console.warn('[SaveModal] 未找到 .map-studio__map-area 元素');
return;
}
const canvas = await html2canvas(el, {
useCORS: true,
allowTaint: false,
backgroundColor: '#ffffff',
scale: 1
});
previewBase64.value = canvas.toDataURL('image/png');
} catch (err) {
console.error('[SaveModal] 截图失败:', err);
} finally {
capturing.value = false;
}
}
/** 下载预览图 */
function downloadPreview() {
if (!previewBase64.value) return;
const link = document.createElement('a');
link.download = `${peituName.value || '预览图'}.png`;
link.href = previewBase64.value;
link.click();
}
/** 收集全部配置状态 */
function collectConfig(): any {
// checked
const flattenLayers = (items: any[]): string[] => {
const keys: string[] = [];
for (const item of items) {
if (item.children) {
for (const child of item.children) {
if (child.checked) keys.push(child.key);
}
} else if (item.checked) {
keys.push(item.key);
}
}
return keys;
};
// +
const anchorChecked: string[] = [];
const anchorIcons: Record<string, string> = {};
for (const cat of anchorCategories.value) {
for (const child of cat.children) {
if (child.checked) anchorChecked.push(child.key);
if (child.customIconUrl) anchorIcons[child.key] = child.customIconUrl;
}
}
//
const drawFeatures = drawActions.getSerializedFeatures
? drawActions.getSerializedFeatures()
: [];
//
const anchorOverrides = anchorActions.getSerializedOverrides
? anchorActions.getSerializedOverrides()
: [];
// anchorDeletedIds + importedAnchors
const serializedAnchors = anchorActions.getSerializedAnchors
? anchorActions.getSerializedAnchors()
: [];
return {
version: '1.0',
baseMap: {
source: selectedBaseMap.value,
showBoundary: showBoundary.value,
clip: {
mode: clipMode.value,
basin: clipBasin.value,
district: clipDistrict.value
}
},
overlayLayers: {
checkedKeys: flattenLayers(layerOptions.value)
},
legend: {
visible: BasicControlOptions.value[0]?.checked ?? true,
config: { ...legendConfig.value },
customEntries: customLegendEntries.value,
customGroups: customLegendGroups.value,
categoryChildExtensions: categoryChildExtensions.value,
categoryIconOverrides: categoryIconOverrides.value
},
anchorCategories: {
checkedKeys: anchorChecked,
customIcons: anchorIcons
},
anchorGlobalStyle: { ...anchorGlobalStyle.value },
anchorOverrides,
anchors: serializedAnchors,
drawFeatures,
drawStyle: { ...drawStyle.value },
importedImages: importedImages.value.map(img => ({
id: img.id,
src: img.src,
x: img.x,
y: img.y,
width: img.width,
height: img.height
})),
tableOverlays: tableOverlays.value.map(tbl => ({ ...tbl }))
};
}
/** 保存到后端 */
async function handleSave() {
if (!peituName.value.trim()) {
nameError.value = true;
return;
}
nameError.value = false;
// id
if (store.editConfigId) {
await new Promise<void>((resolve, reject) => {
Modal.confirm({
title: '确认覆盖',
content: '该配图已存在,确定覆盖原配图?',
okText: '确定覆盖',
cancelText: '取消',
onOk: () => resolve(),
onCancel: () => reject(new Error('cancel'))
});
}).catch(() => {
return; //
});
}
saving.value = true;
try {
//
if (!previewBase64.value) {
await takeScreenshot();
}
const config = collectConfig();
const userStore = useUserStore();
// JSON
const payload = {
id: store.editConfigId || '',
peituName: peituName.value,
operator: userStore.username || '',
config: JSON.stringify(config),
bsfile: previewBase64.value || ''
};
let res = await saveImage(payload);
if (res.code == 0) {
message.success('保存成功');
//
store.editConfigId = '';
store.editPeituName = '';
emit('saved');
handleCancel();
} else {
message.error(res.msg || '保存失败');
}
} catch (err) {
console.error('[SaveModal] 保存失败:', err);
} finally {
saving.value = false;
}
}
function handleCancel() {
emit('update:visible', false);
}
</script>
<style scoped>
.save-modal__body {
display: flex;
flex-direction: column;
gap: 16px;
}
.save-modal__field {
display: flex;
flex-direction: column;
gap: 6px;
}
.save-modal__label {
font-size: 13px;
color: #333;
font-weight: 500;
}
.save-modal__required {
color: #ff4d4f;
margin-right: 2px;
}
.save-modal__error {
color: #ff4d4f;
font-size: 12px;
line-height: 1;
}
.save-modal__preview-wrapper {
width: 100%;
height: 200px;
border: 1px solid #d9d9d9;
border-radius: 4px;
overflow: hidden;
background: #fafafa;
display: flex;
align-items: center;
justify-content: center;
}
.save-modal__preview {
width: 100%;
height: 100%;
object-fit: contain;
}
.save-modal__preview-empty {
color: #999;
font-size: 13px;
}
.save-modal__preview-actions {
display: flex;
gap: 8px;
}
</style>

View File

@ -0,0 +1,299 @@
<template>
<div
ref="containerRef"
class="map-studio__table-overlay-container"
@keydown.delete="onDeleteKey"
tabindex="0"
>
<template v-for="tbl in tableOverlays" :key="tbl.id">
<vue3-draggable-resizable
style="pointer-events: all"
:init-w="tbl.width"
:init-h="tbl.height"
:x="tbl.x"
:y="tbl.y"
:w="tbl.width"
:h="tbl.height"
:parent="true"
:active="selectedTableId === tbl.id"
:min-w="100"
:min-h="50"
:handles="['tl', 'tm', 'tr', 'ml', 'mr', 'bl', 'bm', 'br']"
@update:x="onUpdateX(tbl, $event)"
@update:y="onUpdateY(tbl, $event)"
@update:w="onUpdateW(tbl, $event)"
@update:h="onUpdateH(tbl, $event)"
@activated="onActivated(tbl)"
@drag-start="onDragStart(tbl)"
@drag-end="onDragEnd"
@resize-start="onResizeStart(tbl)"
@resize-end="onResizeEnd"
>
<div class="map-studio__table-overlay" :style="tableStyle(tbl)">
<table
class="map-studio__table-element"
:style="tableInnerStyle(tbl)"
>
<colgroup v-if="tbl.colWidths && tbl.colWidths.length > 0">
<col
v-for="(cw, ci) in tbl.colWidths"
:key="ci"
:style="{ width: cw + 'px' }"
/>
</colgroup>
<tr
v-for="(row, ri) in tbl.cellData"
:key="ri"
:style="trStyle(tbl, ri)"
>
<td
v-for="(cell, ci) in row"
:key="`${ri}-${ci}`"
class="map-studio__table-cell"
:style="cellStyle(tbl, ri, ci)"
>
{{ cell }}
</td>
</tr>
</table>
</div>
<!-- 删除按钮 -->
<div
v-if="selectedTableId === tbl.id"
class="map-studio__table-delete"
@mousedown.stop
@click.stop="onDeleteTable(tbl)"
>
×
</div>
</vue3-draggable-resizable>
</template>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { storeToRefs } from 'pinia';
import Vue3DraggableResizable from 'vue3-draggable-resizable';
import 'vue3-draggable-resizable/dist/Vue3DraggableResizable.css';
import { useMapStudioStore } from '../stores/mapStudioStore';
import { useUndoRedo } from '../composables/useUndoRedo';
import type { TableOverlayData } from '../types';
const store = useMapStudioStore();
const { tableOverlays, selectedTableId, activeTab } = storeToRefs(store);
const { drawCheckpoint } = useUndoRedo();
const containerRef = ref<HTMLElement | null>(null);
const isInteracting = ref(false);
function onActivated(tbl: TableOverlayData) {
selectedTableId.value = tbl.id;
}
//
function handleDocumentClick(e: MouseEvent) {
if (!selectedTableId.value || isInteracting.value) return;
const target = e.target as Node;
const vdrs = document.querySelectorAll('.vdr');
for (const vdr of vdrs) {
if (vdr.contains(target)) return;
}
const delBtns = document.querySelectorAll('.map-studio__table-delete');
for (const btn of delBtns) {
if (btn.contains(target)) return;
}
const drawers = document.querySelectorAll('.map-studio__drawer-section');
for (const drawer of drawers) {
if (drawer.contains(target)) return;
}
// ant-design-vue a-select body
const dropdowns = document.querySelectorAll('.ant-select-dropdown');
for (const dd of dropdowns) {
if (dd.contains(target)) return;
}
const modals = document.querySelectorAll('.ant-modal');
for (const modal of modals) {
if (modal.contains(target)) return;
}
selectedTableId.value = null;
}
function onDragStart(tbl: TableOverlayData) {
selectedTableId.value = tbl.id;
isInteracting.value = true;
activeTab.value = 'table';
}
function onDragEnd() {
isInteracting.value = false;
drawCheckpoint();
}
function onResizeStart(tbl: TableOverlayData) {
selectedTableId.value = tbl.id;
isInteracting.value = true;
activeTab.value = 'table';
}
function onResizeEnd() {
isInteracting.value = false;
drawCheckpoint();
}
function onUpdateX(tbl: TableOverlayData, val: number) {
tbl.x = Math.floor(val);
}
function onUpdateY(tbl: TableOverlayData, val: number) {
tbl.y = Math.floor(val);
}
function onUpdateW(tbl: TableOverlayData, val: number) {
tbl.width = Math.floor(val);
}
function onUpdateH(tbl: TableOverlayData, val: number) {
tbl.height = Math.floor(val);
}
function onDeleteTable(tbl: TableOverlayData) {
//
drawCheckpoint();
const idx = tableOverlays.value.indexOf(tbl);
if (idx !== -1) tableOverlays.value.splice(idx, 1);
if (selectedTableId.value === tbl.id) selectedTableId.value = null;
if (tableOverlays.value.length === 0 && activeTab.value === 'table') {
activeTab.value = 'baseMap';
}
}
function onDeleteKey(e: KeyboardEvent) {
if (e.key === 'Delete' && selectedTableId.value) {
const tbl = tableOverlays.value.find(t => t.id === selectedTableId.value);
if (tbl) onDeleteTable(tbl);
}
}
function handleKeyDown(e: KeyboardEvent) {
if (
e.key === 'Delete' &&
selectedTableId.value &&
containerRef.value?.contains(e.target as Node)
) {
const tbl = tableOverlays.value.find(t => t.id === selectedTableId.value);
if (tbl) onDeleteTable(tbl);
}
}
//
function tableStyle(tbl: TableOverlayData) {
return {
width: '100%',
height: '100%',
overflow: 'auto',
background: tbl.fillTransparent ? 'transparent' : tbl.fillColor,
border: `${tbl.borderWidth}px solid ${tbl.borderColor}`,
boxSizing: 'border-box' as const
};
}
function tableInnerStyle(tbl: TableOverlayData) {
const hasCustomRows = tbl.rowHeights && tbl.rowHeights.some(h => h > 0);
return {
width: '100%',
height: hasCustomRows ? 'auto' : '100%',
borderCollapse: 'collapse' as const,
tableLayout: (tbl.colWidths && tbl.colWidths.length > 0 ? 'auto' : 'fixed') as any
};
}
function trStyle(tbl: TableOverlayData, ri: number) {
if (tbl.rowHeights && tbl.rowHeights[ri] != null && tbl.rowHeights[ri] > 0) {
return { height: tbl.rowHeights[ri] + 'px' };
}
return {};
}
function cellStyle(tbl: TableOverlayData, ri: number, ci: number) {
const vAlignMap: Record<string, string> = {
top: 'top',
middle: 'middle',
bottom: 'bottom'
};
const style: Record<string, any> = {
border: `${tbl.borderWidth}px solid ${tbl.borderColor}`,
padding: '4px 6px',
fontSize: `${tbl.fontSize}px`,
fontFamily: tbl.fontFamily,
color: tbl.textColor,
fontWeight: tbl.fontBold ? ('bold' as const) : ('normal' as const),
textAlign: tbl.hAlign as any,
verticalAlign: (vAlignMap[tbl.vAlign] || 'middle') as any,
wordBreak: 'break-all' as const,
boxSizing: 'border-box' as const,
height: '100%'
};
//
if (tbl.colWidths && tbl.colWidths[ci] != null && tbl.colWidths[ci] > 0) {
style.width = tbl.colWidths[ci] + 'px';
}
return style;
}
onMounted(() => {
document.addEventListener('keydown', handleKeyDown);
document.addEventListener('mousedown', handleDocumentClick, true);
});
onUnmounted(() => {
document.removeEventListener('keydown', handleKeyDown);
document.removeEventListener('mousedown', handleDocumentClick, true);
});
</script>
<style scoped>
.map-studio__table-overlay-container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 5;
pointer-events: none;
outline: none;
}
.map-studio__table-overlay-container > :deep(.vdr) {
pointer-events: auto;
}
.map-studio__table-overlay {
user-select: none;
pointer-events: none;
}
.map-studio__table-element {
pointer-events: none;
}
.map-studio__table-cell {
white-space: pre-wrap;
overflow: hidden;
}
.map-studio__table-delete {
position: absolute;
top: 0px;
right: -30px;
width: 20px;
height: 20px;
border-radius: 50%;
background: #ff4d4f;
color: #fff;
font-size: 14px;
line-height: 20px;
text-align: center;
cursor: pointer;
z-index: 10;
pointer-events: auto;
user-select: none;
box-shadow: 0 1px 4px rgba(255, 77, 79, 0.5);
}
.map-studio__table-delete:hover {
transform: scale(1.15);
}
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,250 @@
import { ref, watch, onMounted, onBeforeUnmount, type Ref } from 'vue';
import { useMapStudioStore } from '../stores/mapStudioStore';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import XYZ from 'ol/source/XYZ';
import { fromLonLat } from 'ol/proj';
/** 天地图 token */
const TDT_TOKEN = 'e90d56e5a09d1767899ad45846b0cefd';
/** 天地图墨卡托投影标识 */
const TDT_MAP_TYPE = 'w';
/** 中国中心点(经纬度) */
const CENTER_CHINA: [number, number] = [105, 38.5];
const INITIAL_ZOOM = 4.5;
const MIN_ZOOM = 4;
const MAX_ZOOM = 19;
/** 边界图层 WMTS URL */
const BOUNDARY_URL =
'https://211.99.26.225:18085/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=qgc_sx_gjjdx_arcgistiles_l13&STYLE=&TILEMATRIX=EPSG:3857_qgc_sx_gjjdx_arcgistiles_l13:{z}&TILEMATRIXSET=EPSG:3857_qgc_sx_gjjdx_arcgistiles_l13&FORMAT=image/png&TILECOL={x}&TILEROW={y}';
/** 底图源配置 */
export const BASE_MAP_SOURCES: Record<
string,
{ label: string; createSource: () => XYZ }
> = {
satellite: {
label: '影像图',
createSource: () =>
new XYZ({
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
maxZoom: 19,
crossOrigin: 'anonymous',
wrapX: true
})
},
vector: {
label: '矢量图',
createSource: () =>
new XYZ({
url: 'https://211.99.26.225:18085/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=qgc_qsj_arcgistiles_l13&STYLE=&TILEMATRIX=EPSG:3857_qgc_qsj_arcgistiles_l13:{z}&TILEMATRIXSET=EPSG:3857_qgc_qsj_arcgistiles_l13&FORMAT=image/png&TILECOL={x}&TILEROW={y}',
maxZoom: 18,
crossOrigin: 'anonymous',
wrapX: true
})
},
terrain: {
label: '地形图',
createSource: () =>
new XYZ({
url: `https://t0.tianditu.gov.cn/ter_${TDT_MAP_TYPE}/wmts?tk=${TDT_TOKEN}&SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=${TDT_MAP_TYPE}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=tiles`,
maxZoom: 18,
crossOrigin: 'anonymous',
wrapX: true
})
},
contour: {
label: '等高线',
createSource: () =>
new XYZ({
url: 'https://c.tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=6170aad10dfd42a38d4d8c709a536f38',
maxZoom: 18,
crossOrigin: 'anonymous',
wrapX: true
})
}
};
export function useMapInit(
mapContainerRef: Ref<HTMLElement | null>,
selectedBaseMap: Ref<string>,
showBoundary: Ref<boolean>
) {
const mapInstance = ref<Map | null>(null);
/** 当前底图图层 */
const baseLayer = ref<TileLayer<XYZ> | null>(null);
/** 边界图层 */
const boundaryLayer = ref<TileLayer<XYZ> | null>(null);
function createBaseLayer(key: string): TileLayer<XYZ> {
const config = BASE_MAP_SOURCES[key];
if (!config) {
console.warn(`未知底图类型: ${key},使用默认矢量图`);
return createBaseLayer('vector');
}
return new TileLayer({
source: config.createSource(),
properties: { baseMapKey: key }
});
}
function createBoundaryLayer(): TileLayer<XYZ> {
return new TileLayer({
source: new XYZ({
url: BOUNDARY_URL,
maxZoom: 18,
crossOrigin: 'anonymous',
wrapX: true
}),
properties: { isBoundary: true }
});
}
/** 勾选/取消边界图层(矢量图时禁止加载) */
function toggleBoundaryLayer(show: boolean) {
if (!mapInstance.value) return;
// 矢量图时永远不加载边界
if (selectedBaseMap.value === 'vector') {
removeBoundaryLayer();
return;
}
if (show) {
// 勾选 → 创建并添加
if (!boundaryLayer.value) {
boundaryLayer.value = createBoundaryLayer();
}
if (
!mapInstance.value.getLayers().getArray().includes(boundaryLayer.value)
) {
// 插入到底图上方index 1确保在锚点图层下方
mapInstance.value.getLayers().insertAt(1, boundaryLayer.value);
}
} else {
removeBoundaryLayer();
}
}
/** 移除边界图层 */
function removeBoundaryLayer() {
if (
boundaryLayer.value &&
mapInstance.value &&
mapInstance.value.getLayers().getArray().includes(boundaryLayer.value)
) {
mapInstance.value.removeLayer(boundaryLayer.value);
boundaryLayer.value = null;
}
}
function initMap() {
if (!mapContainerRef.value) return;
// 只创建底图
const layer = createBaseLayer(selectedBaseMap.value);
baseLayer.value = layer;
const map = new Map({
target: mapContainerRef.value,
layers: [layer],
view: new View({
center: fromLonLat(CENTER_CHINA),
zoom: INITIAL_ZOOM,
minZoom: MIN_ZOOM,
maxZoom: MAX_ZOOM,
constrainOnlyCenter: false,
smoothExtentConstraint: false
}),
controls: []
});
mapInstance.value = map;
// 如果默认勾选且不是矢量图,则添加边界图层
if (showBoundary.value && selectedBaseMap.value !== 'vector') {
toggleBoundaryLayer(true);
}
}
function switchBaseMap(key: string) {
if (!mapInstance.value) return;
const newLayer = createBaseLayer(key);
if (baseLayer.value) {
mapInstance.value.removeLayer(baseLayer.value);
}
// 底图插入到最底层,避免覆盖边界等上层图层
mapInstance.value.getLayers().insertAt(0, newLayer);
baseLayer.value = newLayer;
// 如果边界图层存在重新插入到底图上方index 1避免覆盖锚点
if (
boundaryLayer.value &&
mapInstance.value.getLayers().getArray().includes(boundaryLayer.value)
) {
mapInstance.value.removeLayer(boundaryLayer.value);
mapInstance.value.getLayers().insertAt(1, boundaryLayer.value);
}
// 切换到矢量图时强制移除边界;切出矢量图时如果勾选了则重新加载
if (key === 'vector') {
removeBoundaryLayer();
} else if (showBoundary.value && !boundaryLayer.value) {
toggleBoundaryLayer(true);
}
}
/** 监听底图切换 */
watch(
() => selectedBaseMap.value,
newKey => {
switchBaseMap(newKey);
}
);
/** 监听边界显隐 */
watch(
() => showBoundary.value,
show => {
toggleBoundaryLayer(show);
}
);
onMounted(() => {
initMap();
});
onBeforeUnmount(() => {
if (mapInstance.value) {
mapInstance.value.setTarget(undefined);
mapInstance.value.dispose();
}
});
/** 重置地图视图到初始状态 */
function resetView() {
if (!mapInstance.value) return;
const view = mapInstance.value.getView();
view.setCenter(fromLonLat(CENTER_CHINA));
view.setZoom(INITIAL_ZOOM);
}
// 将地图实例同步到 Pinia store
const store = useMapStudioStore();
watch(
mapInstance,
val => {
store.mapInstance = val;
},
{ immediate: true }
);
return {
mapInstance,
switchBaseMap,
boundaryLayer,
resetView
};
}

View File

@ -0,0 +1,238 @@
import { watch, onBeforeUnmount, type Ref } from 'vue';
import OlMap from 'ol/Map';
import TileLayer from 'ol/layer/Tile';
import ImageLayer from 'ol/layer/Image';
import XYZ from 'ol/source/XYZ';
import ImageArcGISRest from 'ol/source/ImageArcGISRest';
import ImageWMS from 'ol/source/ImageWMS';
/** 单个图层项定义 */
export interface LayerItem {
key: string;
label: string;
checked: boolean;
children?: LayerItem[];
}
/** 扁平 key → OL 图层映射 */
const LAYER_MAP: Record<
string,
() => TileLayer<XYZ> | ImageLayer<ImageArcGISRest | ImageWMS>
> = {
// 行政标注 - 天地图矢量标注
adminLabel: () =>
new TileLayer({
source: new XYZ({
url: 'http://t4.tianditu.gov.cn/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=9884c7460528e32e3bbf3d1a233d7fea',
maxZoom: 18,
crossOrigin: 'anonymous',
wrapX: true
})
}),
// 区域服务 - ArcGIS
regionService: () =>
new ImageLayer({
source: new ImageArcGISRest({
url: 'https://211.99.26.225:18085/arcgis/rest/services/ZH_QUYU/MapServer',
crossOrigin: 'anonymous'
})
}),
// 九段线 - ArcGIS
nineDashLine: () =>
new ImageLayer({
source: new ImageArcGISRest({
url: 'https://211.99.26.225:18085/arcgis/rest/services/%E4%B9%9D%E6%AE%B5%E7%BA%BF%E6%9C%8D%E5%8A%A11/MapServer',
crossOrigin: 'anonymous'
})
}),
// 岛屿 - GeoServer WMS需确认 layer 名称)
island: () =>
new ImageLayer({
source: new ImageWMS({
url: 'https://211.99.26.225:18085/geoserver/cite/wms',
params: { LAYERS: 'cite:dy' },
crossOrigin: 'anonymous'
})
}),
// 流域注记 - ArcGIS
basinLabel: () =>
new ImageLayer({
source: new ImageArcGISRest({
url: 'https://211.99.26.225:18085/arcgis/rest/services/zh_LiuYu_annotation/MapServer',
crossOrigin: 'anonymous'
})
}),
// 流域线 - ArcGIS
basinLine: () =>
new ImageLayer({
source: new ImageArcGISRest({
url: 'https://211.99.26.225:18085/arcgis/rest/services/zh_LiuYu_line/MapServer',
crossOrigin: 'anonymous'
})
}),
// 轮渡 - ArcGIS
ferry: () =>
new ImageLayer({
source: new ImageArcGISRest({
url: 'https://211.99.26.225:18085/arcgis/rest/services/jiaotong_ferry/MapServer',
crossOrigin: 'anonymous'
})
}),
// 铁路 - ArcGIS
railway: () =>
new ImageLayer({
source: new ImageArcGISRest({
url: 'https://211.99.26.225:18085/arcgis/rest/services/jiaotong_railway/MapServer',
crossOrigin: 'anonymous'
})
}),
// 地铁 - ArcGIS
metro: () =>
new ImageLayer({
source: new ImageArcGISRest({
url: 'https://211.99.26.225:18085/arcgis/rest/services/jiaotong_metro/MapServer',
crossOrigin: 'anonymous'
})
}),
// 行政区面状 - ArcGIS
adminAreaPolygon: () =>
new ImageLayer({
source: new ImageArcGISRest({
url: 'https://211.99.26.225:18085/arcgis/rest/services/zh_XingZhengQu_Polygon/MapServer',
crossOrigin: 'anonymous'
})
}),
// 行政区 - ArcGIS
adminArea: () =>
new ImageLayer({
source: new ImageArcGISRest({
url: 'https://211.99.26.225:18085/arcgis/rest/services/ZH_XINGZHEGNQU/MapServer',
crossOrigin: 'anonymous'
})
})
};
export function useOverlayLayers(
mapInstance: Ref<OlMap | null>,
layerOptions: Ref<LayerItem[]>
) {
// 已创建的 OL 图层映射
const activeLayers = new Map<
string,
TileLayer<XYZ> | ImageLayer<ImageArcGISRest | ImageWMS>
>();
/** 收集所有扁平 key */
function getLeafKeys(items: LayerItem[]): string[] {
const keys: string[] = [];
for (const item of items) {
if (item.children) {
keys.push(...getLeafKeys(item.children));
} else {
keys.push(item.key);
}
}
return keys;
}
/** 同步单个 key 的显隐 */
function syncLayer(key: string, checked: boolean) {
if (!mapInstance.value) return;
const factory = LAYER_MAP[key];
if (!factory) return;
let layer = activeLayers.get(key);
if (checked) {
// 勾选 → 创建并显示
if (!layer) {
layer = factory();
activeLayers.set(key, layer);
mapInstance.value.addLayer(layer);
}
layer.setVisible(true);
} else {
// 取消勾选 → 仅隐藏,不删除
if (layer) {
layer.setVisible(false);
}
}
}
/** 深度遍历所有叶子节点并同步 */
function syncAll(items: LayerItem[]) {
for (const item of items) {
if (item.children) {
syncAll(item.children);
} else {
syncLayer(item.key, item.checked);
}
}
}
// 深度 watch 所有叶子节点的 checked 变化
watch(
layerOptions,
() => {
if (!mapInstance.value) return;
syncAll(layerOptions.value);
},
{ deep: true }
);
// 地图就绪后同步初始状态
watch(
() => mapInstance.value,
map => {
if (map) {
syncAll(layerOptions.value);
}
},
{ immediate: true }
);
onBeforeUnmount(() => {
// 清理所有图层
for (const [key, layer] of activeLayers.entries()) {
layer.getSource()?.dispose();
activeLayers.delete(key);
}
});
return { activeLayers };
}
/** 默认基础图层选项(分组结构) */
export const DEFAULT_LAYER_OPTIONS: LayerItem[] = [
{ key: 'adminLabel', label: '行政标注', checked: false },
{ key: 'regionService', label: '区域服务', checked: false },
{ key: 'nineDashLine', label: '九段线', checked: false },
// { key: 'island', label: '岛屿', checked: false },
{
key: 'basin',
label: '流域',
checked: false,
children: [
{ key: 'basinLabel', label: '流域注记', checked: false },
{ key: 'basinLine', label: '流域线', checked: false }
]
},
{
key: 'traffic',
label: '交通',
checked: false,
children: [
{ key: 'ferry', label: '轮渡', checked: false },
{ key: 'railway', label: '铁路', checked: false },
{ key: 'metro', label: '地铁', checked: false }
]
},
{
key: 'adminArea',
label: '行政区',
checked: false,
children: [
{ key: 'adminAreaPolygon', label: '行政区面状', checked: false },
{ key: 'adminArea', label: '行政区', checked: false }
]
}
];

View File

@ -0,0 +1,445 @@
/**
* undo / redo
*
*
* - RightDrawer legend / anchors / images / draw
* -
* drawSource addfeature/removefeature drawCheckpoint()
*
* store ref deep watchflush:'sync' + 沿 200ms
* checkpoint200ms
* - suppressUntil drawCheckpoint store watcher 50ms
* - drawToolActive watcher restore
*
* - restore isRestoring
* - MAX_STEPS50
* - Ctrl+Z / Ctrl+Shift+Z
*/
import { ref, watch, onMounted, onUnmounted } from 'vue';
import { storeToRefs } from 'pinia';
import { useMapStudioStore } from '../stores/mapStudioStore';
import { drawActions } from './useDrawTools';
import { anchorActions } from './useAnchorLayers';
import type {
LegendConfig,
AnchorGlobalStyle,
SelectedAnchorInfo,
ImportedImage,
DrawStyle,
DrawToolType,
TableOverlayData
} from '../types';
const MAX_STEPS = 50;
const COOLDOWN_MS = 200;
interface UndoSnapshot {
legendConfig: LegendConfig;
anchorGlobalStyle: AnchorGlobalStyle;
selectedAnchor: SelectedAnchorInfo | null;
importedImages: ImportedImage[];
selectedImageId: string | null;
tableOverlays: TableOverlayData[];
selectedTableId: string | null;
drawStyle: DrawStyle;
// selectedDrawStyle / selectedDrawInfo / selectedDrawText 不参与快照
drawFeatures: any[];
drawToolActive: DrawToolType | null;
activeTab: string;
/** 锚点 features 序列化数据(位置、图标、标签等) */
anchorFeatures: any[];
/** 锚点样式覆盖序列化数据 */
anchorOverrides: any[];
}
const undoStack: UndoSnapshot[] = [];
const redoStack: UndoSnapshot[] = [];
/** 上一次 checkpoint 时的状态(下一次 checkpoint 时 push 到 undoStack */
let previousSnapshot: UndoSnapshot | null = null;
/** 正在 restore 中,阻止一切快照 */
let isRestoring = false;
/** store watcher 前沿节流定时器null = 可发起 checkpoint */
let cooldownTimer: ReturnType<typeof setTimeout> | null = null;
/**
* drawCheckpoint
* drawSource drawCheckpoint store watcher
* drawend store checkpoint
*/
let suppressUntil = 0;
/**
* store watcher checkpoint
* clearSelection selectedAnchor
*/
let suppressWatcher = false;
const canUndo = ref(false);
const canRedo = ref(false);
function updateButtons() {
canUndo.value = undoStack.length > 0;
canRedo.value = redoStack.length > 0;
}
/** 深拷贝当前 store 状态 + 绘制图形序列化数据 */
function takeSnapshot(): UndoSnapshot {
const store = useMapStudioStore();
const s = storeToRefs(store);
return {
legendConfig: JSON.parse(JSON.stringify(s.legendConfig.value)),
anchorGlobalStyle: JSON.parse(JSON.stringify(s.anchorGlobalStyle.value)),
selectedAnchor: (() => {
if (!s.selectedAnchor.value) return null;
const cloned = JSON.parse(JSON.stringify(s.selectedAnchor.value));
// 不保存 displayLabel锚点名称名称修改应独立于样式/位置撤回问题2/3修复
delete cloned.displayLabel;
return cloned;
})(),
importedImages: JSON.parse(JSON.stringify(s.importedImages.value)),
selectedImageId: s.selectedImageId.value,
tableOverlays: JSON.parse(JSON.stringify(s.tableOverlays.value)),
selectedTableId: s.selectedTableId.value,
drawStyle: JSON.parse(JSON.stringify(s.drawStyle.value)),
// selectedDrawInfo / selectedDrawStyle / selectedDrawText 不参与快照—
// 右侧绘制面板跟随地图选中状态自然变化不应产生撤回步骤问题8修复
drawFeatures: drawActions.getSerializedFeatures
? drawActions.getSerializedFeatures()
: [],
drawToolActive: s.drawToolActive.value,
activeTab: s.activeTab.value,
anchorFeatures: anchorActions.getSerializedAnchors
? anchorActions.getSerializedAnchors()
: [],
anchorOverrides: anchorActions.getSerializedOverrides
? anchorActions.getSerializedOverrides()
: []
};
}
/** 将快照恢复到 store + 绘制图层 */
function restoreSnapshot(snapshot: UndoSnapshot) {
isRestoring = true;
const store = useMapStudioStore();
const s = storeToRefs(store);
// 保存当前锚点名称恢复后重新覆盖displayLabel 不参与快照问题2/3修复
const currentDisplayLabel = s.selectedAnchor.value?.displayLabel ?? '';
s.legendConfig.value = JSON.parse(JSON.stringify(snapshot.legendConfig));
s.anchorGlobalStyle.value = JSON.parse(
JSON.stringify(snapshot.anchorGlobalStyle)
);
s.selectedAnchor.value = snapshot.selectedAnchor
? JSON.parse(JSON.stringify(snapshot.selectedAnchor))
: null;
// 恢复后保留当前锚点名称displayLabel 不参与快照问题2/3修复
if (s.selectedAnchor.value && currentDisplayLabel) {
s.selectedAnchor.value.displayLabel = currentDisplayLabel;
}
s.importedImages.value = JSON.parse(JSON.stringify(snapshot.importedImages));
s.selectedImageId.value = snapshot.selectedImageId;
s.tableOverlays.value = JSON.parse(JSON.stringify(snapshot.tableOverlays));
s.selectedTableId.value = snapshot.selectedTableId;
s.drawStyle.value = JSON.parse(JSON.stringify(snapshot.drawStyle));
// 若表格 tab 但无选中表格,切到别处避免空内容闪烁
if (s.activeTab.value === 'table' && !s.selectedTableId.value) {
s.activeTab.value = 'baseMap';
}
// 恢复绘制图形selectedDrawStyle / selectedDrawInfo / selectedDrawText 不参与恢复—
// 右侧绘制面板的自然状态不应被撤回覆盖问题8修复
// ⚠ 不恢复 drawToolActive / activeTab —— 撤回不应切换工具或标签页
// s.drawToolActive.value = snapshot.drawToolActive;
// s.activeTab.value = snapshot.activeTab;
// 恢复绘制图形
if (drawActions.clearAllDrawings && drawActions.restoreDrawingsFromSave) {
drawActions.clearAllDrawings();
if (snapshot.drawFeatures.length > 0) {
drawActions.restoreDrawingsFromSave(snapshot.drawFeatures, {});
}
}
// 撤回后清除绘制选中状态让右侧面板自然跟随地图状态问题8修复
s.selectedDrawInfo.value = null;
// 恢复锚点 features位置、图标、标签等
// 注意:如果 snapshot 没有锚点数据anchorFeatures.length === 0
// 不清除当前锚点避免撤回初始状态锚点加载前时丢失所有已加载的锚点问题6修复
if (snapshot.anchorFeatures.length > 0) {
if (
anchorActions.clearAllAnchors &&
anchorActions.restoreAnchorsFromSave &&
anchorActions.restoreAnchorOverridesFromSave
) {
anchorActions.clearAllAnchors();
anchorActions.restoreAnchorsFromSave(snapshot.anchorFeatures);
if (snapshot.anchorOverrides.length > 0) {
anchorActions.restoreAnchorOverridesFromSave(snapshot.anchorOverrides);
}
}
// 重新关联选中的锚点 featureclearAllAnchors 后旧引用已失效问题4修复
if (anchorActions.reselectSelectedAnchor) {
anchorActions.reselectSelectedAnchor();
}
// 同步选中锚点的覆盖样式回 OL feature
if (anchorActions.syncSelectedOverrides) {
anchorActions.syncSelectedOverrides();
}
// 将保留的锚点名称同步回 featurerestoreAnchorsFromSave 的 _label = stnm 会覆盖自定义名称)
if (
anchorActions.updateSelectedLabel &&
s.selectedAnchor.value?.displayLabel
) {
anchorActions.updateSelectedLabel(s.selectedAnchor.value.displayLabel);
}
}
// 恢复后刷新 previousSnapshot
previousSnapshot = takeSnapshot();
// 所有同步操作完成后再恢复 watcher避免中间状态触发不必要的 checkpoint
isRestoring = false;
}
/**
* store watcher checkpoint suppressWatcher
*/
function checkpoint() {
if (isRestoring) return;
if (suppressWatcher) return;
if (previousSnapshot) {
const current = takeSnapshot();
// 去重:如果前后快照完全一致,不产生撤回步骤
if (JSON.stringify(previousSnapshot) !== JSON.stringify(current)) {
undoStack.push(previousSnapshot);
if (undoStack.length > MAX_STEPS) {
undoStack.shift();
}
redoStack.length = 0; // 新操作 → 清空 redo
updateButtons();
}
previousSnapshot = current;
} else {
previousSnapshot = takeSnapshot();
}
}
/**
* checkpoint
* suppressUntil store watcher checkpoint
*/
function drawCheckpoint() {
if (isRestoring) return;
// 设置抑制窗口,阻止紧随其后的 store ref 变更再次 checkpoint
suppressUntil = performance.now() + 50;
if (previousSnapshot) {
const current = takeSnapshot();
// 如果唯一变化是 drawToolActive/activeTab 且图形数未变,则跳过(不产生虚假撤回步骤)
if (
(previousSnapshot.drawFeatures?.length ?? 0) ===
(current.drawFeatures?.length ?? 0)
) {
const changedKeys: string[] = [];
for (const key of Object.keys(current) as (keyof UndoSnapshot)[]) {
if (
JSON.stringify(previousSnapshot[key]) !== JSON.stringify(current[key])
) {
changedKeys.push(key);
}
}
const nonDisplayKeys = changedKeys.filter(
k => k !== 'drawToolActive' && k !== 'activeTab'
);
if (nonDisplayKeys.length === 0) {
previousSnapshot = current;
return;
}
}
// 去重:如果前后快照完全一致,不产生撤回步骤
if (JSON.stringify(previousSnapshot) !== JSON.stringify(current)) {
undoStack.push(previousSnapshot);
if (undoStack.length > MAX_STEPS) {
undoStack.shift();
}
redoStack.length = 0;
updateButtons();
}
previousSnapshot = current;
} else {
previousSnapshot = takeSnapshot();
}
}
/**
* previousSnapshot
*
*/
function syncSnapshot() {
if (isRestoring) return;
previousSnapshot = takeSnapshot();
}
/** 临时抑制 store watcher checkpoint用于锚点显隐切换等不应产生撤回步骤的场景 */
function setSuppressWatcher(val: boolean) {
suppressWatcher = val;
}
/**
* drawend storeupdateSelectedDrawInfo
* store watcher checkpoint
* setSuppressWatcher cooldownTimerwatcher
* cooldownTimer watcher
*/
function beginDrawBatch() {
suppressUntil = performance.now() + 50;
}
// ── 公开 API ──
function undo() {
if (undoStack.length === 0) return;
// 清除可能的抑制窗口,避免 restore 后 watcher 被意外跳过
suppressUntil = 0;
suppressWatcher = false;
const snapshot = undoStack.pop()!;
const currentSnapshot = takeSnapshot();
redoStack.push(currentSnapshot);
restoreSnapshot(snapshot);
updateButtons();
}
function redo() {
if (redoStack.length === 0) return;
suppressUntil = 0;
suppressWatcher = false;
undoStack.push(previousSnapshot || takeSnapshot());
if (undoStack.length > MAX_STEPS) {
undoStack.shift();
}
const snapshot = redoStack.pop()!;
restoreSnapshot(snapshot);
updateButtons();
}
/** 在 RightDrawer setup 中调用,启动对 store 状态变更的 deep watch */
function initUndoWatch() {
const store = useMapStudioStore();
const {
legendConfig,
anchorGlobalStyle,
selectedAnchor,
importedImages,
selectedImageId,
drawStyle
// selectedDrawStyle / selectedDrawInfo / selectedDrawText 不参与 watcher —
// 右侧绘制面板状态变更不应产生撤回步骤问题8修复
// drawToolActive 不在 watcher 中 — 单纯切换工具不产生撤回步骤
} = storeToRefs(store);
// 初始化 previousSnapshot
previousSnapshot = takeSnapshot();
watch(
[
legendConfig,
anchorGlobalStyle,
selectedAnchor,
importedImages,
selectedImageId,
drawStyle
],
() => {
if (isRestoring) return;
// drawCheckpoint 已处理 → 跳过,避免重复
if (performance.now() < suppressUntil) return;
// 前沿节流:冷却中 → 仅重置定时器
if (cooldownTimer !== null) {
clearTimeout(cooldownTimer);
cooldownTimer = setTimeout(() => {
cooldownTimer = null;
}, COOLDOWN_MS);
return;
}
// 冷却结束 → 立即 checkpoint启动新冷却
checkpoint();
cooldownTimer = setTimeout(() => {
cooldownTimer = null;
}, COOLDOWN_MS);
},
{ deep: true, flush: 'sync' }
);
}
// ── 键盘快捷键 ──
function onKeyDown(e: KeyboardEvent) {
if (
e.target instanceof HTMLInputElement ||
e.target instanceof HTMLTextAreaElement
) {
return;
}
if (e.ctrlKey || e.metaKey) {
if (e.shiftKey && (e.key === 'z' || e.key === 'Z')) {
e.preventDefault();
redo();
return;
}
if (e.key === 'z' || e.key === 'Z') {
e.preventDefault();
undo();
return;
}
}
}
function registerShortcuts() {
onMounted(() => {
document.addEventListener('keydown', onKeyDown);
});
onUnmounted(() => {
document.removeEventListener('keydown', onKeyDown);
});
}
export function useUndoRedo() {
return {
canUndo,
canRedo,
undo,
redo,
initUndoWatch,
registerShortcuts,
drawCheckpoint,
setSuppressWatcher,
beginDrawBatch,
syncSnapshot
};
}

View File

@ -0,0 +1,268 @@
<template>
<div class="map-studio">
<!-- 中央地图容器 -->
<MapContainer ref="mapContainerComp">
<Legend />
<MapImageOverlay />
<TableOverlay />
</MapContainer>
<!-- 右侧区域工具栏 + 抽屉展开按钮 + 抽屉 -->
<div class="map-studio__right-area">
<LeftToolbar />
<!-- 抽屉收起时的展开按钮 -->
<button
class="map-studio__drawer-toggle"
@click="drawerOpen = true"
v-show="!drawerOpen"
title="展开"
>
<img src="@/assets/components/arrow-left.png" alt="" />
</button>
<RightDrawer v-model:open="drawerOpen" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch, computed } from 'vue';
import { storeToRefs } from 'pinia';
import MapContainer from './components/MapContainer.vue';
import LeftToolbar from './components/LeftToolbar.vue';
import RightDrawer from './components/RightDrawer.vue';
import Legend from './components/Legend.vue';
import MapImageOverlay from './components/MapImageOverlay.vue';
import TableOverlay from './components/TableOverlay.vue';
import { useMapStudioStore } from './stores/mapStudioStore';
import { useMapInit } from './composables/useMapInit';
import { useOverlayLayers } from './composables/useOverlayLayers';
import { useAnchorLayers, anchorActions } from './composables/useAnchorLayers';
import { useDrawTools, drawActions } from './composables/useDrawTools';
import './styles/index.scss';
const drawerOpen = ref(true);
// 使 Pinia store
const store = useMapStudioStore();
if (!store) {
throw new Error('[MapStudio] Pinia store 未正确初始化');
}
const { selectedBaseMap, showBoundary, layerOptions } = storeToRefs(store);
// MapContainer
const mapContainerComp = ref<InstanceType<typeof MapContainer> | null>(null);
// MapContainer containerRef
const mapContainerRef = computed(
() => mapContainerComp.value?.containerRef ?? null
);
// mapInstance store
const { mapInstance, resetView } = useMapInit(
mapContainerRef as any,
selectedBaseMap,
showBoundary
);
// resetView store LeftToolbar / RightDrawer 使
store.resetView = resetView as any;
//
useOverlayLayers(mapInstance, layerOptions as any);
// Pinia store
useAnchorLayers(mapInstance);
// Pinia store
const { deleteSelectedDraw } = useDrawTools(mapInstance);
//
function onDeleteDrawEvent() {
deleteSelectedDraw();
}
window.addEventListener('map-studio:delete-draw', onDeleteDrawEvent);
// tab
watch(
() => store.selectedAnchor,
anchor => {
if (anchor) {
store.activeTab = 'anchors';
}
},
{ deep: true }
);
//
watch(
() => store.restoreVersion,
() => {
const payload = store.restorePayload;
if (!payload) return;
console.log('[MapStudio] 开始恢复配置', payload.version);
const map = mapInstance.value;
if (!map) return;
// 1.
//
store.selectedAnchor = null;
store.selectedDrawInfo = null;
store.drawToolActive = null;
//
if (anchorActions.clearAllAnchors) {
anchorActions.clearAllAnchors();
}
//
if (drawActions.clearAllDrawings) {
drawActions.clearAllDrawings();
}
//
store.importedImages = [];
//
store.tableOverlays = [];
store.selectedTableId = null;
// 2.
if (payload.baseMap) {
store.selectedBaseMap = payload.baseMap.source || 'vector';
store.showBoundary = payload.baseMap.showBoundary ?? true;
store.clipMode = payload.baseMap.clip?.mode || 'none';
store.clipBasin = payload.baseMap.clip?.basin || '';
store.clipDistrict = payload.baseMap.clip?.district || '';
}
// 3.
if (payload.overlayLayers?.checkedKeys) {
const checkedKeys = payload.overlayLayers.checkedKeys as string[];
const setChecked = (items: any[]) => {
for (const item of items) {
if (item.children) {
for (const child of item.children) {
child.checked = checkedKeys.includes(child.key);
}
} else {
item.checked = checkedKeys.includes(item.key);
}
}
};
setChecked(store.layerOptions);
// layerOptions
store.layerOptions = [...store.layerOptions];
}
// 4.
if (payload.legend) {
store.BasicControlOptions[0].checked = payload.legend.visible ?? true;
if (payload.legend.config) {
Object.assign(store.legendConfig, payload.legend.config);
}
store.customLegendEntries = payload.legend.customEntries || [];
store.customLegendGroups = payload.legend.customGroups || [];
store.categoryChildExtensions =
payload.legend.categoryChildExtensions || {};
store.categoryIconOverrides = payload.legend.categoryIconOverrides || {};
}
// 5.
if (payload.anchorGlobalStyle) {
Object.assign(store.anchorGlobalStyle, payload.anchorGlobalStyle);
}
// 6. 使 checkedKeys
const savedCheckedKeys: string[] =
payload.anchorCategories?.checkedKeys || [];
for (const cat of store.anchorCategories) {
for (const child of cat.children) {
child.checked = savedCheckedKeys.includes(child.key);
}
}
// 7.
if (payload.anchors && anchorActions.restoreAnchorsFromSave) {
anchorActions.restoreAnchorsFromSave(payload.anchors);
}
// 8.
if (
payload.anchorOverrides?.length &&
anchorActions.restoreAnchorOverridesFromSave
) {
anchorActions.restoreAnchorOverridesFromSave(payload.anchorOverrides);
}
// 8.
store.drawStyle = payload.drawStyle || store.drawStyle;
console.log(
'[MapStudio] drawFeatures 数据:',
payload.drawFeatures?.length,
'条'
);
console.log(
'[MapStudio] drawActions.restoreDrawingsFromSave 是否存在:',
!!drawActions.restoreDrawingsFromSave
);
if (payload.drawFeatures?.length && drawActions.restoreDrawingsFromSave) {
drawActions.restoreDrawingsFromSave(
payload.drawFeatures,
payload.drawStyle
);
} else {
console.warn(
'[MapStudio] 跳过绘制恢复: drawFeatures=',
payload.drawFeatures?.length,
'restoreFn=',
!!drawActions.restoreDrawingsFromSave
);
}
// 9.
if (payload.importedImages) {
store.importedImages = payload.importedImages.map((img: any) => ({
...img
}));
}
// 10.
if (payload.tableOverlays) {
store.tableOverlays = payload.tableOverlays.map((t: any) => ({ ...t }));
}
//
store.selectedAnchor = null;
// 10.
store.restorePayload = null;
console.log('[MapStudio] 配置恢复完成');
}
);
</script>
<style lang="scss" scoped>
.map-studio {
width: 100%;
height: 100%;
position: relative;
display: flex;
overflow: hidden;
:deep(.map-studio__map-area) {
flex: 1;
position: relative;
overflow: hidden;
}
.map-studio__right-area {
position: relative;
display: flex;
flex-direction: column;
flex-shrink: 0;
}
}
</style>

View File

@ -0,0 +1,263 @@
import { defineStore } from 'pinia';
import { ref } from 'vue';
import type OlMap from 'ol/Map';
import { DEFAULT_LAYER_OPTIONS } from '../composables/useOverlayLayers';
import {
DEFAULT_ANCHOR_STYLE,
DEFAULT_DRAW_STYLE,
DEFAULT_LEGEND_CONFIG,
type AnchorCategory,
type AnchorGlobalStyle,
type CustomLegendEntry,
type CustomLegendGroup,
type DrawStyle,
type DrawToolType,
type ImportedImage,
type LayerItem,
type LegendConfig,
type SelectedAnchorInfo,
type SelectedDrawInfo,
type TableOverlayData
} from '../types';
export const useMapStudioStore = defineStore('mapStudio', () => {
// ── 锚点分类 ──
const anchorCategories = ref<AnchorCategory[]>([
{
key: 'powerStation',
label: '电站',
icon: 'power-station',
children: [
{
key: 'large_eng_built',
label: '大型水电站-已建',
icon: 'large-built',
checked: false
},
{
key: 'large_eng_ubuilt',
label: '大型水电站-在建',
icon: 'large-building',
checked: false
},
{
key: 'large_eng_nbuilt',
label: '大型水电站-未建',
icon: 'large-unbuilt',
checked: false
},
{
key: 'mid_eng_built',
label: '中型水电站-已建',
icon: 'medium-built',
checked: false
},
{
key: 'mid_eng_ubuilt',
label: '中型水电站-在建',
icon: 'medium-building',
checked: false
},
{
key: 'mid_eng_nbuilt',
label: '中型水电站-未建',
icon: 'medium-unbuilt',
checked: false
}
]
},
{
key: 'fishPassage',
label: '过鱼设施',
icon: 'fish-passage',
children: [
{ key: 'gy_1', label: '鱼道', icon: 'fishway', checked: false },
{
key: 'gy_2',
label: '仿自然通道',
icon: 'nature-channel',
checked: false
},
{
key: 'GY_3_INCOMPLETE',
label: '集运鱼系统',
icon: 'collect-system',
checked: false
},
{ key: 'gy_4', label: '升鱼机', icon: 'fish-lift', checked: false },
{ key: 'gy_5', label: '其他', icon: 'other-fish', checked: false }
]
},
{
key: 'fishFarm',
label: '鱼类增殖站',
icon: 'fish-farm',
children: [
{
key: 'FB',
label: '鱼类增殖站',
icon: 'fish-farm-station',
checked: false
}
]
},
{
key: 'coldWater',
label: '低温水减缓设施',
icon: 'cold-water',
children: [
{ key: 'dws_1', label: '叠梁门', icon: 'closing-gate', checked: false },
{ key: 'dws_2', label: '前置挡墙', icon: 'front-wall', checked: false },
{
key: 'dws_3',
label: '隔水幕墙',
icon: 'curtain-wall',
checked: false
},
{ key: 'dws_4', label: '其他', icon: 'other-cold', checked: false },
{
key: 'dws_1_incomplete',
label: '叠梁门-未完成',
icon: 'closing-gate-unfinished',
checked: false
},
{
key: 'dws_2_incomplete',
label: '前置挡墙-未完成',
icon: 'front-wall-unfinished',
checked: false
},
{
key: 'dws_3_incomplete',
label: '隔水幕墙-未完成',
icon: 'curtain-wall-unfinished',
checked: false
},
{
key: 'dws_4_incomplete',
label: '其他-未完成',
icon: 'other-cold-unfinished',
checked: false
}
]
}
]);
// ── 基础控制选项 ──
const BasicControlOptions = ref<
{ key: string; label: string; checked: boolean }[]
>([{ key: 'legend', label: '是否显示图例', checked: true }]);
// ── 图例配置 ──
const legendConfig = ref<LegendConfig>({ ...DEFAULT_LEGEND_CONFIG });
// ── 锚点全局样式 ──
const anchorGlobalStyle = ref<AnchorGlobalStyle>({ ...DEFAULT_ANCHOR_STYLE });
// ── 底图 / 边界 ──
const selectedBaseMap = ref('vector');
const showBoundary = ref(true);
// ── 裁切设置 ──
const clipMode = ref<'none' | 'basin' | 'district'>('none');
const clipBasin = ref<string>('');
const clipDistrict = ref<string>('');
// ── 右侧抽屉 ──
const activeTab = ref('baseMap');
// ── 基础图层叠加 ──
const layerOptions = ref<LayerItem[]>(
JSON.parse(JSON.stringify(DEFAULT_LAYER_OPTIONS))
);
// ── 选中锚点 ──
const selectedAnchor = ref<SelectedAnchorInfo | null>(null);
// ── 自定义图例 ──
const customLegendEntries = ref<CustomLegendEntry[]>([]);
const customLegendGroups = ref<CustomLegendGroup[]>([]);
const categoryChildExtensions = ref<
Record<string, { label: string; iconUrl: string }[]>
>({});
const categoryIconOverrides = ref<Record<string, string>>({});
// ── 图片叠加 ──
const importedImages = ref<ImportedImage[]>([]);
const selectedImageId = ref<string | null>(null);
// ── 表格叠加 ──
const tableOverlays = ref<TableOverlayData[]>([]);
const selectedTableId = ref<string | null>(null);
// ── 导入锚点记录(用于保存) ──
const importedAnchors = ref<
{
parentName: string;
legendName: string;
iconUrl: string;
items: { lng: number; lat: number; name: string }[];
}[]
>([]);
// ── 绘制工具 ──
const drawToolActive = ref<DrawToolType>(null);
const drawStyle = ref<DrawStyle>({ ...DEFAULT_DRAW_STYLE });
const selectedDrawInfo = ref<SelectedDrawInfo | null>(null);
const selectedDrawStyle = ref<DrawStyle>({ ...DEFAULT_DRAW_STYLE });
const selectedDrawText = ref<string>('');
// ── 地图实例(由 useMapInit 自动同步) ──
const mapInstance = ref<OlMap | null>(null);
// 由 useMapInit 的 resetView 填充,供子组件调用
const resetView = ref<(() => void) | null>(null);
// 由 RightDrawer 裁切时填充,供 LeftToolbar 重置视角到裁切区域使用
const fitClipView = ref<(() => void) | null>(null);
// ── 恢复配置(从历史记录编辑时使用) ──
const restorePayload = ref<any>(null);
const restoreVersion = ref(0);
// ── 当前编辑的配图信息(历史记录编辑 → 保存时复用) ──
const editConfigId = ref('');
const editPeituName = ref('');
return {
// 状态
anchorCategories,
BasicControlOptions,
legendConfig,
anchorGlobalStyle,
selectedBaseMap,
showBoundary,
clipMode,
clipBasin,
clipDistrict,
activeTab,
layerOptions,
selectedAnchor,
customLegendEntries,
customLegendGroups,
categoryChildExtensions,
categoryIconOverrides,
importedImages,
selectedImageId,
tableOverlays,
selectedTableId,
importedAnchors,
drawToolActive,
drawStyle,
selectedDrawInfo,
selectedDrawStyle,
selectedDrawText,
mapInstance,
resetView,
fitClipView,
// 恢复
restorePayload,
restoreVersion,
// 编辑
editConfigId,
editPeituName
};
});

View File

@ -0,0 +1,191 @@
.map-studio {
width: 100%;
height: 100%;
display: flex;
position: relative;
pointer-events: all;
background-color: #fafafa;
}
/* 中央地图容器 */
.map-studio__map-area {
flex: 1;
position: relative;
overflow: hidden;
min-height: 0;
min-width: 0;
}
/* 工具栏(位于抽屉左侧) */
.map-studio__toolbar {
position: absolute;
left: -50px;
top: 4px;
width: 44px;
display: flex;
flex-direction: column;
align-items: center;
padding: 8px 0;
gap: 4px;
z-index: 10;
background: #fff;
border-radius: 4px;
}
.map-studio__toolbar-btn {
width: 36px;
display: flex;
align-items: center;
justify-content: center;
border: none;
background: transparent;
border-radius: 6px;
cursor: pointer;
color: #595959;
font-size: 12px;
transition: all 0.2s;
flex-direction: column;
gap: 4px;
padding: 4px 0;
}
.map-studio__toolbar-btn:hover {
background: #e6f7ff;
color: #1890ff;
}
.map-studio__toolbar-btn:disabled {
opacity: 0.35;
cursor: not-allowed;
}
.map-studio__toolbar-btn:disabled:hover {
background: transparent;
color: inherit;
}
.map-studio__toolbar-btn.is-active {
background: #bae7ff;
color: #1890ff;
font-weight: 600;
}
.map-studio__toolbar-btn .btn-icon {
line-height: 1;
}
.map-studio__toolbar-btn .btn-label {
font-size: 12px;
line-height: 1;
white-space: nowrap;
}
.map-studio__toolbar-divider {
width: 28px;
height: 1px;
background: #e8e8e8;
margin: 4px 0;
}
/* 抽屉外层容器(控制宽度过渡,配合工具栏滑动) */
.map-studio__drawer-section {
transition: width 0.3s ease;
position: relative;
}
.map-studio__drawer-section.is-closed {
width: 0;
}
.map-studio__drawer-section:not(.is-closed) {
width: 450px;
height: 100%;
}
/* 抽屉收起时,右侧的展开按钮(在 right-area 层级定位) */
.map-studio__drawer-toggle {
width: 18px;
position: absolute;
right: -2px;
cursor: pointer;
z-index: 10;
height: 88px;
line-height: 88px;
top: 45%;
vertical-align: middle;
background-image: url('@/assets/components/bg-toggle.e1dabcf3.svg');
background-repeat: no-repeat;
display: flex;
justify-content: center;
align-items: center;
}
/* 抽屉展开时,左侧的收起按钮(在 a-drawer 内容区定位) */
.map-studio__drawer-trigger {
width: 18px;
position: absolute;
cursor: pointer;
z-index: 10;
height: 88px;
line-height: 88px;
top: 45%;
left: -17px;
vertical-align: middle;
background-image: url('@/assets/components/bg-toggle.e1dabcf3.svg');
background-repeat: no-repeat;
display: flex;
justify-content: center;
align-items: center;
}
/* Drawer body */
.map-studio__drawer-body {
padding: 4px 20px 20px;
}
/* 覆盖 a-drawer 默认 body padding */
.map-studio .ant-drawer-body {
padding: 0 !important;
}
/* Tabs 内容区 */
.map-studio__tab-content {
padding-top: 16px;
}
/* Tabs 样式覆盖 - tabs 标签紧贴顶部 */
.map-studio .ant-tabs-nav {
margin-bottom: 0 !important;
}
.placeholder-desc {
font-size: 12px;
color: #999;
}
/* ── 锚点删除弹窗 ── */
.map-studio__delete-popup {
background: #ff4d4f;
border-radius: 50%;
width: 26px;
height: 26px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 8px rgba(255, 77, 79, 0.5);
cursor: pointer;
transition: transform 0.15s;
z-index: 1000;
}
.map-studio__delete-popup:hover {
transform: scale(1.15);
}
.map-studio__delete-btn {
color: #fff;
font-size: 15px;
font-weight: bold;
line-height: 1;
background: none;
border: none;
cursor: pointer;
padding: 0;
margin: 0;
}

View File

@ -0,0 +1,359 @@
// ── 锚点分类 ──
export interface AnchorItem {
key: string;
label: string;
icon: string;
checked: boolean;
/** 自定义图标 URL导入锚点用优先级高于 SVG icon key */
customIconUrl?: string;
}
export interface AnchorCategory {
key: string;
label: string;
icon: string;
children: AnchorItem[];
}
// ── 图例配置 ──
export interface LegendConfig {
position: string;
width: number;
height: number;
offsetX: number;
offsetY: number;
title: string;
showTitle: boolean;
/** 图例标题字号 */
titleFontSize: number;
/** 图例标题字体 */
titleFontFamily: string;
/** 图例标题加粗 */
titleBold: boolean;
/** 图例标题对齐方式 */
titleAlign: 'left' | 'center' | 'right';
/** 图例标题颜色 */
titleColor: string;
/** 图例子级文字字号 */
childFontSize: number;
/** 图例子级文字字体 */
childFontFamily: string;
/** 图例子级文字颜色 */
childColor: string;
/** 图例子级文字加粗 */
childBold: boolean;
/** 图例子级图标大小 */
childIconSize: number;
}
// ── 标题配置 ──
export interface TitleConfig {
x: number;
y: number;
width: number;
height: number;
text: string;
}
// ── 锚点全局样式 ──
export interface AnchorGlobalStyle {
fontSize: number;
fontFamily: string;
color: string;
bold: boolean;
/** 图标大小(宽=高),默认 16 */
iconSize: number;
/** 文字描边颜色 */
strokeColor: string;
/** 文字描边宽度 */
strokeWidth: number;
/** 文字相对于图标的位置: top / bottom / left / right */
textPosition: 'top' | 'bottom' | 'left' | 'right';
/** 文字水平方向与图标的间距 */
textMarginX: number;
/** 文字垂直方向与图标的间距 */
textMarginY: number;
/** 是否显示文字标注 */
showText: boolean;
}
/** 锚点样式覆盖(单个锚点可覆盖全局样式中的任意字段) */
export interface AnchorStyleOverride {
fontSize: number | null;
fontFamily: string | null;
color: string | null;
bold: boolean | null;
iconSize: number | null;
strokeColor: string | null;
strokeWidth: number | null;
textPosition: 'top' | 'bottom' | 'left' | 'right' | null;
textMarginX: number | null;
textMarginY: number | null;
showText: boolean | null;
}
/** 当前选中的锚点信息 */
export interface SelectedAnchorInfo {
/** 站点名称 */
stnm: string;
/** 当前显示的文字(可编辑) */
displayLabel: string;
/** 当前图标 URL */
iconUrl: string;
/** 图标来源 */
iconSource: 'inherit' | 'custom';
/** 自定义图标 URL */
customIconUrl: string;
/** 所属分类 key */
categoryKey: string;
/** 所属分类 label */
categoryLabel: string;
/** 所属子类型 key */
subTypeKey: string;
/** 所属子类型 label */
subTypeLabel: string;
/** 经度 */
lng: number;
/** 纬度 */
lat: number;
/** 样式覆盖值null 表示继承全局) */
overrides: AnchorStyleOverride;
}
// ── 自定义图例 ──
export interface CustomLegendEntry {
id: string;
label: string;
iconUrl: string;
}
export interface CustomLegendGroup {
key: string;
label: string;
children: {
label: string;
iconUrl: string;
}[];
}
// ── 绘制工具 ──
/** 绘制图形样式 */
export interface DrawStyle {
/** 线条/描边颜色 */
strokeColor: string;
/** 线条/描边宽度 */
strokeWidth: number;
/** 填充颜色(仅面) */
fillColor: string;
/** 点半径 */
pointRadius: number;
/** 点颜色 */
pointColor: string;
/** 线条类型 */
lineType: 'solid' | 'dashed' | 'dotted' | 'dash-dot';
/** 是否显示箭头 */
showArrow: boolean;
/** 箭头位置 */
arrowPosition: 'end' | 'both';
/** 箭头大小 */
arrowSize: 'small' | 'medium' | 'large';
/** 字号 */
fontSize: number;
/** 字体 */
fontFamily: string;
/** 文字颜色 */
textColor: string;
/** 文字描边颜色 */
textStrokeColor: string;
/** 文字描边宽度 */
textStrokeWidth: number;
/** 文字是否加粗 */
fontBold: boolean;
}
export const DEFAULT_DRAW_STYLE: DrawStyle = {
strokeColor: '#000000',
strokeWidth: 2,
fillColor: '#000000',
pointRadius: 6,
pointColor: '#000000',
lineType: 'solid',
showArrow: true,
arrowPosition: 'end',
arrowSize: 'medium',
fontSize: 14,
fontFamily: 'Microsoft YaHei',
textColor: '#ffffff',
textStrokeColor: '#000000',
textStrokeWidth: 3,
fontBold: false
};
/** 绘制工具类型 */
export type DrawToolType =
| 'point'
| 'line'
| 'polygon'
| 'rect'
| 'circle'
| 'freehand'
| 'text'
| 'select'
| null;
/** 绘制图形的选中信息 */
export interface SelectedDrawInfo {
id: string;
type: 'Point' | 'LineString' | 'Polygon' | 'Circle';
/** 原始绘制工具类型,用于区分 point / text / line / freehand 等 */
drawTypeKey: string;
/** 坐标(经度/纬度) */
coords: number[];
/** 对线的长度(米) */
length?: number;
/** 对面/圆的面积(平方米) */
area?: number;
}
// ── 图片叠加 ──
export interface ImportedImage {
id: string;
src: string;
x: number;
y: number;
width: number;
height: number;
}
// ── 表格叠加 ──
export interface TableOverlayData {
id: string;
x: number;
y: number;
width: number;
height: number;
rows: number;
cols: number;
/** 单元格文本数据 [row][col] */
cellData: string[][];
/** 字号 */
fontSize: number;
/** 字体 */
fontFamily: string;
/** 文字颜色 */
textColor: string;
/** 边框颜色 */
borderColor: string;
/** 边框宽度 */
borderWidth: number;
/** 填充颜色 */
fillColor: string;
/** 是否透明背景(为 true 时忽略 fillColor */
fillTransparent: boolean;
/** 文字加粗 */
fontBold: boolean;
/** 水平对齐 */
hAlign: 'left' | 'center' | 'right';
/** 垂直对齐 */
vAlign: 'top' | 'middle' | 'bottom';
/** 自定义行高px空数组=自适应 */
rowHeights: number[];
/** 自定义列宽px空数组=自适应 */
colWidths: number[];
}
// ── 基础图层 ──
/** 单个图层项定义 */
export interface LayerItem {
key: string;
label: string;
checked: boolean;
children?: LayerItem[];
}
// ── 常量 ──
export const FONT_OPTIONS = [
{ value: 'SimSun', label: '宋体' },
{ value: 'Microsoft YaHei', label: '微软雅黑' },
{ value: 'SimHei', label: '黑体' },
{ value: 'KaiTi', label: '楷体' },
{ value: 'FangSong', label: '仿宋' },
{ value: 'PingFang SC', label: '苹方' },
{ value: 'Source Han Sans SC', label: '思源黑体' }
];
export const DEFAULT_LEGEND_CONFIG: LegendConfig = {
position: 'bottom-left',
width: 200,
height: 200,
offsetX: 20,
offsetY: 20,
title: '图例',
showTitle: true,
titleFontSize: 14,
titleFontFamily: 'Microsoft YaHei',
titleBold: true,
titleAlign: 'center',
titleColor: '#000000',
childFontSize: 12,
childFontFamily: 'Microsoft YaHei',
childColor: '#000000',
childBold: false,
childIconSize: 16
};
export const DEFAULT_TITLE_CONFIG: TitleConfig = {
x: 30,
y: 20,
width: 300,
height: 60,
text: '主标题'
};
export const DEFAULT_ANCHOR_STYLE: AnchorGlobalStyle = {
fontSize: 10,
fontFamily: 'Microsoft YaHei',
color: '#ffffff',
bold: false,
iconSize: 22,
strokeColor: '#000000',
strokeWidth: 2,
textPosition: 'top',
textMarginX: 0,
textMarginY: 8,
showText: true
};
/** icon key → SVG 文件名映射 */
export const ICON_SVG_MAP: Record<string, string> = {
'large-built': 'map-dxsdzYijian',
'large-building': 'map-dxsdzZaijian',
'large-unbuilt': 'map-dxsdzGuihua',
'medium-built': 'map-zxsdzYijian',
'medium-building': 'map-zxsdzZaijian',
'medium-unbuilt': 'map-zxsdzGuihua',
fishway: 'map-gyssYudao',
'nature-channel': 'map-gyssFangzirantongdao',
'collect-system': 'map-gyssJiyunyuxitong',
'fish-lift': 'map-gyssShengyuji',
'other-fish': 'map-gyssQita',
'fish-farm-station': 'map-yuleizengzhizhan',
'closing-gate': 'map-dwsjhDieliangmenshi',
'front-wall': 'map-dwsjhQianzhidangqiang',
'curtain-wall': 'map-dwsjhGeshuimuqiang',
'other-cold': 'map-dwsjhQita',
'closing-gate-unfinished': 'map-dwsjhDieliangmenshiZWeijian',
'front-wall-unfinished': 'map-dwsjhQianzhidangqiangZWeijian',
'curtain-wall-unfinished': 'map-dwsjhGeshuimuqiangZWeijian',
'other-cold-unfinished': 'map-dwsjhQitaZWeijian'
};

View File

@ -0,0 +1,7 @@
<template>
<MapStudio />
</template>
<script setup lang="ts">
import MapStudio from '@/modules/MapStudio/index.vue';
</script>