This commit is contained in:
扈兆增 2026-06-17 14:52:46 +08:00
commit 3d4c400ade
104 changed files with 11682 additions and 1324 deletions

View File

@ -65,6 +65,7 @@ public class SecurityConfig {
// .requestMatchers("/eq/**").permitAll()
// .requestMatchers("/env/**").permitAll()
// .requestMatchers("/wt/**").permitAll()
// .requestMatchers("/fb/**").permitAll()
// .requestMatchers("/zq/**").permitAll()
// .requestMatchers("/wq/**").permitAll()
// .requestMatchers("/vd/**").permitAll()

View File

@ -122,11 +122,19 @@ public class SwaggerConfig {
@Bean
public GroupedOpenApi groupEnvFprApi() {
return GroupedOpenApi.builder()
.group("3.5 全过程-生态环保数据服务-鱼类调查")
.group("3.6 全过程-生态环保数据服务-鱼类调查")
.packagesToScan("com.yfd.platform.qgc_env.fpr.controller")
.build();
}
@Bean
public GroupedOpenApi groupEnvFbApi() {
return GroupedOpenApi.builder()
.group("3.7 全过程-生态环保数据服务-增殖放流")
.packagesToScan("com.yfd.platform.qgc_env.fb.controller")
.build();
}

View File

@ -4,6 +4,7 @@ import com.yfd.platform.common.DataSourceLoadOptionsBase;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqDrtpDataVo;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqIntervalVo;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqMsstbprptVo;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqRuleVo;
@ -42,6 +43,13 @@ public class EngEqDataController {
return ResponseResult.successData(engEqDataService.getDayKendoListCust(dataSourceRequest));
}
@PostMapping("/data/drtp/GetKendoListCust")
@Operation(summary = "生态流量周旬月季年数据")
public ResponseResult getDrtpKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {
DataSourceResult<EngEqDrtpDataVo> result = engEqDataService.getDrtpKendoListCust(dataSourceRequest);
return ResponseResult.successData(result);
}
@PostMapping("/interval/GetKendoListCust")
@Operation(summary = "生态流量达标情况")
public ResponseResult getIntervalKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {

View File

@ -0,0 +1,126 @@
package com.yfd.platform.qgc_eng.eq.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@Schema(description = "生态流量周旬月季年数据")
public class EngEqDrtpDataVo {
@Schema(description = "主键")
private String id;
@Schema(description = "电站编码")
private String stcd;
@Schema(description = "电站名称")
private String stnm;
@Schema(description = "工程名称")
private String ennm;
@Schema(description = "基地编码")
private String baseId;
@Schema(description = "基地名称")
private String baseName;
@Schema(description = "基地流域编码")
private String hbrvcd;
@Schema(description = "基地流域名称")
private String hbrvcdName;
@Schema(description = "流域编码")
private String rvcd;
@Schema(description = "流域名称")
private String rvcdName;
@Schema(description = "行政区名称")
private String addvcdName;
@Schema(description = "入库流量")
private BigDecimal qi;
@Schema(description = "出库流量")
private BigDecimal qo;
@Schema(description = "坝上水位")
private BigDecimal rz;
@Schema(description = "坝下水位")
private BigDecimal dz;
@Schema(description = "生态流量限值(环保部)")
private BigDecimal qecLimit;
@Schema(description = "生态流量")
private BigDecimal qec;
@Schema(description = "生态流量限值(水利部)")
private BigDecimal mwrLimit;
@Schema(description = "生态流量限值(多年平均)")
private BigDecimal avqLimit;
@Schema(description = "生态流量系数(环保部)")
private BigDecimal qecC;
@Schema(description = "生态流量系数(水利部)")
private BigDecimal mwrC;
@Schema(description = "生态流量系数(多年平均)")
private BigDecimal avqC;
@Schema(description = "生态流量是否达标")
private Integer sfdb;
@Schema(description = "生态流量是否达标中文")
private String sfdbName;
@Schema(description = "生态流量是否达标(环保部)")
private Integer qecSfdb;
@Schema(description = "生态流量是否达标(水利部)")
private Integer mwrSfdb;
@Schema(description = "生态流量是否达标(水利部)中文")
private String mwrSfdbName;
@Schema(description = "生态流量是否达标(多年平均)")
private Integer avqSfdb;
@Schema(description = "生态流量是否达标(多年平均)中文")
private String avqSfdbName;
@Schema(description = "数据时间")
private Date tm;
@Schema(description = "")
private Integer month;
@Schema(description = "")
private Integer year;
@Schema(description = "维度类型")
private String drtp;
@Schema(description = "时段")
private Integer dr;
@Schema(description = "基地排序")
private Integer baseStepSort;
@Schema(description = "流域排序")
private Integer rvcdStepSort;
@Schema(description = "电站排序")
private Integer rstcdStepSort;
@Schema(description = "站点排序")
private Integer siteStepSort;
}

View File

@ -3,6 +3,7 @@ package com.yfd.platform.qgc_eng.eq.service;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqDayDataVo;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqDrtpDataVo;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqDayIntervalVo;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqHourIntervalVo;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqIntervalVo;
@ -21,6 +22,8 @@ public interface EngEqDataService {
DataSourceResult<EngEqDayDataVo> getDayKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<EngEqDrtpDataVo> getDrtpKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<EngEqIntervalVo> getIntervalKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<EngEqMsstbprptVo> getMsstbprptList(DataSourceRequest dataSourceRequest);

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.common.DataSourceLoadOptionsBase;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.common.Group;
import com.yfd.platform.common.GroupHelper;
import com.yfd.platform.common.GroupingInfo;
import com.yfd.platform.common.MicroservicDynamicSQLMapper;
@ -13,6 +14,7 @@ import com.yfd.platform.common.enums.QecIntervalEnum;
import com.yfd.platform.common.enums.ShowEnum;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqDataVo;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqDayDataVo;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqDrtpDataVo;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqDayIntervalVo;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngFidVo;
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqHourIntervalVo;
@ -70,6 +72,15 @@ public class EngEqDataServiceImpl implements EngEqDataService {
return queryDayGroupList(dataSourceRequest, loadOptions);
}
@Override
public DataSourceResult<EngEqDrtpDataVo> getDrtpKendoListCust(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
if (CollUtil.isEmpty(dataSourceRequest == null ? null : dataSourceRequest.getGroup())) {
return queryDrtpDetailList(dataSourceRequest, loadOptions);
}
return queryDrtpGroupList(dataSourceRequest, loadOptions);
}
@Override
public DataSourceResult<EngEqIntervalVo> getIntervalKendoListCust(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
@ -742,7 +753,9 @@ public class EngEqDataServiceImpl implements EngEqDataService {
if (Boolean.TRUE.equals(dataSourceRequest.getGroupResultFlat())) {
result.setData((List<EngEqHourIntervalVo>) (List<?>) new GroupHelper().faltGroup(rows, Arrays.asList(groupInfos)));
} else {
result.setData((List<EngEqHourIntervalVo>) (List<?>) new GroupHelper().group(rows, Arrays.asList(groupInfos)));
List<Group> grouped = new GroupHelper().group(rows, Arrays.asList(groupInfos));
populateHourDayGroupKeyNames(grouped);
result.setData((List<EngEqHourIntervalVo>) (List<?>) grouped);
}
result.setTotal(0L);
result.setAggregates(new HashMap<>());
@ -897,7 +910,9 @@ public class EngEqDataServiceImpl implements EngEqDataService {
if (Boolean.TRUE.equals(dataSourceRequest.getGroupResultFlat())) {
result.setData((List<EngEqDayIntervalVo>) (List<?>) new GroupHelper().faltGroup(rows, Arrays.asList(groupInfos)));
} else {
result.setData((List<EngEqDayIntervalVo>) (List<?>) new GroupHelper().group(rows, Arrays.asList(groupInfos)));
List<Group> grouped = new GroupHelper().group(rows, Arrays.asList(groupInfos));
populateHourDayGroupKeyNames(grouped);
result.setData((List<EngEqDayIntervalVo>) (List<?>) grouped);
}
result.setTotal(0L);
result.setAggregates(new HashMap<>());
@ -951,6 +966,169 @@ public class EngEqDataServiceImpl implements EngEqDataService {
}
}
private void populateHourDayGroupKeyNames(List<Group> groups) {
if (CollUtil.isEmpty(groups)) {
return;
}
Map<String, String> baseNameCache = new HashMap<>();
Map<String, String> hbrvNameCache = new HashMap<>();
populateHourDayGroupKeyNames(groups, baseNameCache, hbrvNameCache);
}
private void populateHourDayGroupKeyNames(List<Group> groups,
Map<String, String> baseNameCache,
Map<String, String> hbrvNameCache) {
for (Group group : groups) {
if (group == null) {
continue;
}
if (StrUtil.isBlank(group.getKeyName())) {
group.setKeyName(resolveHourDayGroupKeyName(group.getField(), group.getKey(), baseNameCache, hbrvNameCache));
}
if (CollUtil.isNotEmpty(group.getItems()) && group.getItems().get(0) instanceof Group) {
populateHourDayGroupKeyNames((List<Group>) group.getItems(), baseNameCache, hbrvNameCache);
}
}
}
private String resolveHourDayGroupKeyName(Object field,
Object key,
Map<String, String> baseNameCache,
Map<String, String> hbrvNameCache) {
if (field == null || key == null) {
return null;
}
String fieldName = String.valueOf(field);
String keyValue = String.valueOf(key);
if (StrUtil.isBlank(keyValue)) {
return null;
}
return switch (fieldName) {
case "stnm", "ennm", "titleName", "baseName", "hbrvcdName", "addvcdName" -> keyValue;
case "sttp", "sttpCode" -> "ENG".equalsIgnoreCase(keyValue) ? "电站" : keyValue;
case "baseId" -> StrUtil.blankToDefault(resolveBaseName(keyValue, baseNameCache), keyValue);
case "hbrvcd" -> StrUtil.blankToDefault(resolveHbrvName(keyValue, hbrvNameCache), keyValue);
case "dtin" -> resolveDtinName(keyValue);
case "dtinEnv" -> resolveDtinEnvName(keyValue);
case "prsc" -> resolvePrscName(keyValue);
case "bldstt", "bldsttCcode" -> resolveBldsttName(keyValue);
case "qecInterval", "mwrInterval", "avqInterval" -> resolveQecIntervalName(keyValue);
case "anchoPointState", "mwrPointState", "avqPointState" -> resolvePointStateName(keyValue);
default -> keyValue;
};
}
private String resolveBaseName(String baseId, Map<String, String> cache) {
if (StrUtil.isBlank(baseId)) {
return null;
}
if (cache.containsKey(baseId)) {
return cache.get(baseId);
}
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("code", baseId);
List<Map<String, Object>> rows = microservicDynamicSQLMapper.pageAllList(null,
"SELECT hb.BASENAME AS name FROM SD_HYDROBASE hb " +
"WHERE hb.BASEID = #{map.code} AND NVL(hb.IS_DELETED, 0) = 0 AND ROWNUM = 1",
paramMap);
String name = extractName(rows);
cache.put(baseId, name);
return name;
}
private String resolveHbrvName(String hbrvcd, Map<String, String> cache) {
if (StrUtil.isBlank(hbrvcd)) {
return null;
}
if (cache.containsKey(hbrvcd)) {
return cache.get(hbrvcd);
}
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("code", hbrvcd);
List<Map<String, Object>> rows = microservicDynamicSQLMapper.pageAllList(null,
"SELECT dic.HBRVNM AS name FROM SD_HBRV_DIC dic " +
"WHERE dic.HBRVCD = #{map.code} AND NVL(dic.IS_DELETED, 0) = 0 AND NVL(dic.ENABLED, 1) = 1 AND ROWNUM = 1",
paramMap);
String name = extractName(rows);
cache.put(hbrvcd, name);
return name;
}
private String extractName(List<Map<String, Object>> rows) {
if (CollUtil.isEmpty(rows)) {
return null;
}
Object name = rows.get(0).get("NAME");
if (name == null) {
name = rows.get(0).get("name");
}
return name == null ? null : String.valueOf(name);
}
private String resolveDtinName(String keyValue) {
return switch (keyValue) {
case "1" -> "";
case "0" -> "";
default -> keyValue;
};
}
private String resolveDtinEnvName(String keyValue) {
return switch (keyValue) {
case "2" -> "已全部接入";
case "1" -> "部分接入";
case "0" -> "未接入";
default -> keyValue;
};
}
private String resolvePrscName(String keyValue) {
return switch (keyValue) {
case "1" -> "大型1";
case "2" -> "大型2";
case "3" -> "中型";
case "4" -> "小型";
default -> keyValue;
};
}
private String resolveBldsttName(String keyValue) {
return switch (keyValue) {
case "0" -> "未建/规划";
case "1" -> "在建";
case "2" -> "已建";
default -> keyValue;
};
}
private String resolveQecIntervalName(String keyValue) {
for (QecIntervalEnum item : QecIntervalEnum.values()) {
if (Objects.equals(item.getCode(), keyValue)) {
return item.getDesc();
}
}
return keyValue;
}
private String resolvePointStateName(String keyValue) {
String prefix;
if (keyValue.startsWith("eef_1_")) {
prefix = "大型1";
} else if (keyValue.startsWith("eef_2_")) {
prefix = "大型2/中型";
} else {
return keyValue;
}
return switch (keyValue.substring("eef_".length())) {
case "1_none", "2_none" -> prefix + "_无生态流量数据或要求";
case "1_1", "2_1" -> prefix + "_>=95%";
case "1_2", "2_2" -> prefix + "_90%~95%";
case "1_3", "2_3" -> prefix + "_80%~90%";
case "1_4", "2_4" -> prefix + "_<80%";
default -> keyValue;
};
}
private String buildDayIntervalViewSql(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
@ -1590,6 +1768,101 @@ public class EngEqDataServiceImpl implements EngEqDataService {
return result;
}
private DataSourceResult<EngEqDrtpDataVo> queryDrtpDetailList(DataSourceRequest dataSourceRequest,
DataSourceLoadOptionsBase loadOptions) {
StringBuilder sql = new StringBuilder();
sql.append("SELECT ")
.append(buildDrtpDetailSelectSql(dataSourceRequest == null ? null : dataSourceRequest.getSelect()))
.append(" FROM (")
.append(buildDrtpViewSql())
.append(") t WHERE 1 = 1 ");
Map<String, Object> paramMap = new HashMap<>();
String filterSql = buildDrtpFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), paramMap, new int[]{0});
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql).append(" ");
}
sql.append(buildDrtpDetailOrderBySql(dataSourceRequest == null ? null : dataSourceRequest.getSort()));
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
List<EngEqDrtpDataVo> list = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), paramMap, EngEqDrtpDataVo.class);
DataSourceResult<EngEqDrtpDataVo> result = new DataSourceResult<>();
result.setData(list);
result.setTotal(page != null ? page.getTotal() : list.size());
result.setAggregates(new HashMap<>());
return result;
}
private DataSourceResult<EngEqDrtpDataVo> queryDrtpGroupList(DataSourceRequest dataSourceRequest,
DataSourceLoadOptionsBase loadOptions) {
List<DataSourceRequest.GroupDescriptor> groups = dataSourceRequest.getGroup();
GroupingInfo[] groupInfos = loadOptions == null ? new GroupingInfo[0] : loadOptions.getGroup();
List<String> selectItems = new ArrayList<>();
for (DataSourceRequest.GroupDescriptor descriptor : groups) {
if (descriptor == null || StrUtil.isBlank(descriptor.getField())) {
continue;
}
String column = mapDrtpColumn(descriptor.getField());
if (StrUtil.isBlank(column)) {
continue;
}
selectItems.add(column + " AS " + descriptor.getField().toUpperCase());
selectItems.add("COUNT(*) AS COUNT_" + descriptor.getField().toUpperCase());
if (CollUtil.isNotEmpty(descriptor.getAggregates())) {
for (DataSourceRequest.AggregateDescriptor aggregate : descriptor.getAggregates()) {
String aggregateColumn = mapDrtpColumn(aggregate.getField());
if (StrUtil.isBlank(aggregateColumn) || StrUtil.isBlank(aggregate.getAggregate())) {
continue;
}
selectItems.add(buildAggregateSql(aggregate.getAggregate(), aggregateColumn, aggregate.getField()));
}
}
}
if (selectItems.isEmpty()) {
selectItems.add("t.STCD AS STCD");
selectItems.add("COUNT(*) AS COUNT_STCD");
}
StringBuilder sql = new StringBuilder();
sql.append("SELECT ")
.append(String.join(", ", selectItems))
.append(" FROM (")
.append(buildDrtpViewSql())
.append(") t WHERE 1 = 1 ");
Map<String, Object> paramMap = new HashMap<>();
String filterSql = buildDrtpFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), paramMap, new int[]{0});
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql).append(" ");
}
List<String> groupByColumns = new ArrayList<>();
for (DataSourceRequest.GroupDescriptor descriptor : groups) {
if (descriptor == null || StrUtil.isBlank(descriptor.getField())) {
continue;
}
String column = mapDrtpColumn(descriptor.getField());
if (StrUtil.isNotBlank(column)) {
groupByColumns.add(column);
}
}
if (!groupByColumns.isEmpty()) {
sql.append(" GROUP BY ").append(String.join(", ", groupByColumns)).append(" ");
}
sql.append(buildDrtpGroupOrderBySql(groups));
List<Map<String, Object>> rows = microservicDynamicSQLMapper.pageAllList(null, sql.toString(), paramMap);
DataSourceResult<EngEqDrtpDataVo> result = new DataSourceResult<>();
if (Boolean.TRUE.equals(dataSourceRequest.getGroupResultFlat())) {
result.setData((List<EngEqDrtpDataVo>) (List<?>) new GroupHelper().faltGroup(rows, Arrays.asList(groupInfos)));
} else {
result.setData((List<EngEqDrtpDataVo>) (List<?>) new GroupHelper().group(rows, Arrays.asList(groupInfos)));
}
result.setTotal((long) rows.size());
result.setAggregates(new HashMap<>());
return result;
}
private DataSourceResult<EngEqIntervalVo> queryIntervalDetailList(DataSourceRequest dataSourceRequest,
DataSourceLoadOptionsBase loadOptions) {
Map<String, Object> paramMap = new HashMap<>();
@ -2683,6 +2956,75 @@ public class EngEqDataServiceImpl implements EngEqDataService {
"WHERE NVL(day.IS_DELETED, 0) = 0";
}
private String buildDrtpViewSql() {
return "SELECT " +
"drtp.ID AS id, " +
"eng.STCD AS stcd, " +
"eng.ENNM AS stnm, " +
"eng.ENNM AS ennm, " +
"eng.BASE_ID AS baseId, " +
"hb.BASENAME AS baseName, " +
"eng.HBRVCD AS hbrvcd, " +
"hbrv.HBRVNM AS hbrvcdName, " +
"eng.RVCD AS rvcd, " +
"rv.RVNM AS rvcdName, " +
"addv.ADDVNM AS addvcdName, " +
"runDrtp.QI AS qi, " +
"runDrtp.QO AS qo, " +
"runDrtp.RZ AS rz, " +
"runDrtp.DZ AS dz, " +
"drtp.QEC_LIMIT AS qecLimit, " +
"drtp.QEC AS qec, " +
"drtp.MWR_LIMIT AS mwrLimit, " +
"drtp.AVQ_LIMIT AS avqLimit, " +
"drtp.QEC_C AS qecC, " +
"drtp.MWR_C AS mwrC, " +
"drtp.AVQ_C AS avqC, " +
"drtp.SFDB AS sfdb, " +
"CASE NVL(drtp.SFDB, -1) WHEN 0 THEN '不达标' WHEN 1 THEN '达标' WHEN 2 THEN '无生态流量数据' WHEN 3 THEN '无生态流量限值要求' ELSE NULL END AS sfdbName, " +
"drtp.SFDB AS qecSfdb, " +
"drtp.MWR_SFDB AS mwrSfdb, " +
"CASE NVL(drtp.MWR_SFDB, -1) WHEN 0 THEN '不达标' WHEN 1 THEN '达标' WHEN 2 THEN '无生态流量数据' WHEN 3 THEN '无生态流量限值要求' ELSE NULL END AS mwrSfdbName, " +
"drtp.AVQ_SFDB AS avqSfdb, " +
"CASE NVL(drtp.AVQ_SFDB, -1) WHEN 0 THEN '不达标' WHEN 1 THEN '达标' WHEN 2 THEN '无生态流量数据' WHEN 3 THEN '无生态流量限值要求' ELSE NULL END AS avqSfdbName, " +
"drtp.TM AS tm, " +
"drtp.YEAR AS year, " +
"drtp.MONTH AS month, " +
"drtp.DRTP AS drtp, " +
"drtp.DR AS dr, " +
"NVL(hb.ORDER_INDEX, 999999) AS baseStepSort, " +
"NVL(along.ORDER_INDEX, 999999) AS rvcdStepSort, " +
"NVL(rstSort.SORT, 999999) AS rstcdStepSort, " +
"NVL(siteSort.SORT, 999999) AS siteStepSort " +
"FROM SD_QECDRTP_S drtp " +
"INNER JOIN SD_ENGINFO_B_H eng ON eng.STCD = drtp.STCD AND NVL(eng.IS_DELETED, 0) = 0 " +
"LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = eng.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 " +
"LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = eng.HBRVCD AND hbrv.BASEID = eng.BASE_ID " +
" AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1 " +
"LEFT JOIN SD_RVCD_DIC rv ON rv.RVCD = eng.RVCD " +
"LEFT JOIN SD_ADDVCD_DIC addv ON addv.ADDVCD = eng.ADDVCD " +
"LEFT JOIN MS_ALONG_B along ON along.RVCD = eng.HBRVCD AND along.CODE = 'common' AND NVL(along.IS_DELETED, 0) = 0 " +
"LEFT JOIN ( " +
" SELECT det.SORT, cfg.RVCD, det.STCD " +
" FROM MS_ALONGDET_B det " +
" INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID " +
" WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common' " +
") rstSort ON rstSort.RVCD = eng.HBRVCD AND rstSort.STCD = eng.STCD " +
"LEFT JOIN ( " +
" SELECT det.SORT, cfg.RVCD, det.STCD " +
" FROM MS_ALONGDET_B det " +
" INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID " +
" WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common' " +
") siteSort ON siteSort.RVCD = eng.HBRVCD AND siteSort.STCD = eng.STCD " +
"LEFT JOIN SD_HYDROPWDRTP_S runDrtp ON drtp.STCD = runDrtp.STCD " +
" AND drtp.DRTP = runDrtp.DRTP " +
" AND NVL(drtp.DR, -1) = NVL(runDrtp.DR, -1) " +
" AND NVL(drtp.MONTH, -1) = NVL(runDrtp.MONTH, -1) " +
" AND drtp.YEAR = runDrtp.YEAR " +
" AND NVL(runDrtp.IS_DELETED, 0) = 0 " +
"WHERE NVL(drtp.IS_DELETED, 0) = 0";
}
private String buildDayRunDaySql() {
return "SELECT run.STCD, TRUNC(run.TM) AS DT, " +
"AVG(run.QI) AS QI, AVG(run.QO) AS QO, AVG(run.RZ) AS RZ, AVG(run.DZ) AS DZ " +
@ -2729,6 +3071,25 @@ public class EngEqDataServiceImpl implements EngEqDataService {
return String.join(", ", selected);
}
private String buildDrtpDetailSelectSql(List<String> selectFields) {
Map<String, String> columns = drtpFieldColumns();
List<String> selected = new ArrayList<>();
if (CollUtil.isEmpty(selectFields)) {
selected.addAll(columns.values());
} else {
for (String field : selectFields) {
String column = columns.get(field);
if (StrUtil.isNotBlank(column)) {
selected.add(column);
}
}
if (selected.isEmpty()) {
selected.addAll(columns.values());
}
}
return String.join(", ", selected);
}
private Map<String, String> detailFieldColumns() {
Map<String, String> columns = new LinkedHashMap<>();
columns.put("id", "sqr.ID AS id");
@ -2815,6 +3176,49 @@ public class EngEqDataServiceImpl implements EngEqDataService {
return columns;
}
private Map<String, String> drtpFieldColumns() {
Map<String, String> columns = new LinkedHashMap<>();
columns.put("id", "t.id AS id");
columns.put("stcd", "t.stcd AS stcd");
columns.put("stnm", "t.stnm AS stnm");
columns.put("ennm", "t.ennm AS ennm");
columns.put("baseId", "t.baseId AS baseId");
columns.put("baseName", "t.baseName AS baseName");
columns.put("hbrvcd", "t.hbrvcd AS hbrvcd");
columns.put("hbrvcdName", "t.hbrvcdName AS hbrvcdName");
columns.put("rvcd", "t.rvcd AS rvcd");
columns.put("rvcdName", "t.rvcdName AS rvcdName");
columns.put("addvcdName", "t.addvcdName AS addvcdName");
columns.put("qi", "t.qi AS qi");
columns.put("qo", "t.qo AS qo");
columns.put("rz", "t.rz AS rz");
columns.put("dz", "t.dz AS dz");
columns.put("qecLimit", "t.qecLimit AS qecLimit");
columns.put("qec", "t.qec AS qec");
columns.put("mwrLimit", "t.mwrLimit AS mwrLimit");
columns.put("avqLimit", "t.avqLimit AS avqLimit");
columns.put("qecC", "t.qecC AS qecC");
columns.put("mwrC", "t.mwrC AS mwrC");
columns.put("avqC", "t.avqC AS avqC");
columns.put("sfdb", "t.sfdb AS sfdb");
columns.put("sfdbName", "t.sfdbName AS sfdbName");
columns.put("qecSfdb", "t.qecSfdb AS qecSfdb");
columns.put("mwrSfdb", "t.mwrSfdb AS mwrSfdb");
columns.put("mwrSfdbName", "t.mwrSfdbName AS mwrSfdbName");
columns.put("avqSfdb", "t.avqSfdb AS avqSfdb");
columns.put("avqSfdbName", "t.avqSfdbName AS avqSfdbName");
columns.put("tm", "t.tm AS tm");
columns.put("year", "t.year AS year");
columns.put("month", "t.month AS month");
columns.put("drtp", "t.drtp AS drtp");
columns.put("dr", "t.dr AS dr");
columns.put("baseStepSort", "t.baseStepSort AS baseStepSort");
columns.put("rvcdStepSort", "t.rvcdStepSort AS rvcdStepSort");
columns.put("rstcdStepSort", "t.rstcdStepSort AS rstcdStepSort");
columns.put("siteStepSort", "t.siteStepSort AS siteStepSort");
return columns;
}
private String buildDetailOrderBySql(List<DataSourceRequest.SortDescriptor> sortList) {
if (CollUtil.isEmpty(sortList)) {
return " ORDER BY baseStepSort ASC, rvcdStepSort ASC, rstcdStepSort ASC, siteStepSort ASC, tm DESC";
@ -3596,6 +4000,10 @@ public class EngEqDataServiceImpl implements EngEqDataService {
return "dt".equalsIgnoreCase(field) || "tm".equalsIgnoreCase(field);
}
private boolean isEqDrtpDateField(String field) {
return "tm".equalsIgnoreCase(field);
}
private String buildEqValueExpr(String paramKey, boolean dateField, Object value) {
if (!dateField || value == null) {
return "#{map." + paramKey + "}";
@ -3684,6 +4092,83 @@ public class EngEqDataServiceImpl implements EngEqDataService {
return orders.isEmpty() ? "" : " ORDER BY " + String.join(", ", orders);
}
private String buildDrtpFilterCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
if (filter == null) {
return "";
}
if (StrUtil.isNotBlank(filter.getField())) {
return buildDrtpLeafCondition(filter, paramMap, indexHolder);
}
if (CollUtil.isEmpty(filter.getFilters())) {
return "";
}
List<String> conditions = new ArrayList<>();
for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) {
String childSql = buildDrtpFilterCondition(child, paramMap, indexHolder);
if (StrUtil.isNotBlank(childSql)) {
conditions.add("(" + childSql + ")");
}
}
if (conditions.isEmpty()) {
return "";
}
String logic = "or".equalsIgnoreCase(filter.getLogic()) ? " OR " : " AND ";
return String.join(logic, conditions);
}
private String buildDrtpLeafCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
String column = mapDrtpColumn(filter.getField());
if (StrUtil.isBlank(column)) {
return "";
}
return buildGenericCondition(column, filter, paramMap, indexHolder, isEqDrtpDateField(filter.getField()));
}
private String buildDrtpDetailOrderBySql(List<DataSourceRequest.SortDescriptor> sortList) {
if (CollUtil.isEmpty(sortList)) {
return " ORDER BY baseStepSort ASC, rvcdStepSort ASC, rstcdStepSort ASC, siteStepSort ASC, year DESC, month DESC, drtp ASC, dr ASC";
}
List<String> orders = new ArrayList<>();
for (DataSourceRequest.SortDescriptor sort : sortList) {
if (sort == null || StrUtil.isBlank(sort.getField())) {
continue;
}
String column = mapDrtpOrderColumn(sort.getField());
if (StrUtil.isBlank(column)) {
continue;
}
String dir = "desc".equalsIgnoreCase(sort.getDir()) || "des".equalsIgnoreCase(sort.getDir()) ? "DESC" : "ASC";
orders.add(column + " " + dir);
}
if (orders.isEmpty()) {
return " ORDER BY baseStepSort ASC, rvcdStepSort ASC, rstcdStepSort ASC, siteStepSort ASC, year DESC, month DESC, drtp ASC, dr ASC";
}
return " ORDER BY " + String.join(", ", orders);
}
private String buildDrtpGroupOrderBySql(List<DataSourceRequest.GroupDescriptor> groups) {
if (CollUtil.isEmpty(groups)) {
return "";
}
List<String> orders = new ArrayList<>();
for (DataSourceRequest.GroupDescriptor descriptor : groups) {
if (descriptor == null || StrUtil.isBlank(descriptor.getField())) {
continue;
}
String column = mapDrtpColumn(descriptor.getField());
if (StrUtil.isBlank(column)) {
continue;
}
String dir = "desc".equalsIgnoreCase(descriptor.getDir()) || "des".equalsIgnoreCase(descriptor.getDir()) ? "DESC" : "ASC";
orders.add(column + " " + dir);
}
return orders.isEmpty() ? "" : " ORDER BY " + String.join(", ", orders);
}
@ -4247,4 +4732,66 @@ public class EngEqDataServiceImpl implements EngEqDataService {
default -> null;
};
}
private String mapDrtpColumn(String field) {
if (StrUtil.isBlank(field)) {
return null;
}
return switch (field) {
case "id" -> "t.id";
case "stcd" -> "t.stcd";
case "stnm", "ennm" -> "t.ennm";
case "baseId" -> "t.baseId";
case "baseName" -> "t.baseName";
case "hbrvcd" -> "t.hbrvcd";
case "hbrvcdName" -> "t.hbrvcdName";
case "rvcd" -> "t.rvcd";
case "rvcdName" -> "t.rvcdName";
case "addvcdName" -> "t.addvcdName";
case "qi" -> "t.qi";
case "qo" -> "t.qo";
case "rz" -> "t.rz";
case "dz" -> "t.dz";
case "qecLimit" -> "t.qecLimit";
case "qec" -> "t.qec";
case "mwrLimit" -> "t.mwrLimit";
case "avqLimit" -> "t.avqLimit";
case "qecC" -> "t.qecC";
case "mwrC" -> "t.mwrC";
case "avqC" -> "t.avqC";
case "sfdb" -> "t.sfdb";
case "sfdbName" -> "t.sfdbName";
case "qecSfdb" -> "t.qecSfdb";
case "mwrSfdb" -> "t.mwrSfdb";
case "mwrSfdbName" -> "t.mwrSfdbName";
case "avqSfdb" -> "t.avqSfdb";
case "avqSfdbName" -> "t.avqSfdbName";
case "tm" -> "t.tm";
case "year" -> "t.year";
case "month" -> "t.month";
case "drtp" -> "t.drtp";
case "dr" -> "t.dr";
case "baseStepSort" -> "NVL(t.baseStepSort, 999999)";
case "rvcdStepSort" -> "NVL(t.rvcdStepSort, 999999)";
case "rstcdStepSort" -> "NVL(t.rstcdStepSort, 999999)";
case "siteStepSort" -> "NVL(t.siteStepSort, 999999)";
default -> null;
};
}
private String mapDrtpOrderColumn(String field) {
if (StrUtil.isBlank(field)) {
return null;
}
return switch (field) {
case "id", "baseId", "hbrvcd", "rvcd", "qecC", "mwrC", "avqC",
"sfdbName", "qecSfdb", "mwrSfdb", "mwrSfdbName", "avqSfdb",
"avqSfdbName", "baseStepSort", "rvcdStepSort", "rstcdStepSort",
"siteStepSort", "tm", "year", "month", "drtp", "dr", "stcd",
"stnm", "ennm", "qi", "qo", "qec", "sfdb", "rz", "dz",
"qecLimit", "mwrLimit", "avqLimit", "baseName", "rvcdName",
"hbrvcdName", "addvcdName" -> field;
default -> null;
};
}
}

View File

@ -0,0 +1,35 @@
package com.yfd.platform.qgc_env.fb.controller;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.qgc_env.fb.service.FbStationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/fb/bsmfr")
@Tag(name = "亲鱼选配与培育-亲鱼信息")
@Validated
public class FbBsmfrController {
@Resource
private FbStationService fbStationService;
@PostMapping("/qgc/GetKendoListCust")
@Operation(summary = "(全过程)增殖站二级页面: 亲鱼选配与培育->亲鱼信息")
public ResponseResult getQgcKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fbStationService.getQgcBsmfRKendoListCust(dataSourceRequest));
}
@PostMapping("/fish/GetKendoListCust")
@Operation(summary = "(全过程)增殖站二级页面: 过程图-亲鱼")
public ResponseResult getFishKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fbStationService.getBsmfRFishKendoListCust(dataSourceRequest));
}
}

View File

@ -0,0 +1,30 @@
package com.yfd.platform.qgc_env.fb.controller;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.qgc_env.fb.service.FbStationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/fb/fbrdmr")
@Tag(name = "鱼类增殖站年度鱼类标记数据")
@Validated
public class FbFbrdmrController {
@Resource
private FbStationService fbStationService;
@GetMapping("/getFbRelatedYrByStcd")
@Operation(summary = "根据增殖站编码查询相关业务年份")
public ResponseResult getFbRelatedYrByStcd(@Parameter(description = "增殖站编码")
@RequestParam("stcd") String stcd) {
return ResponseResult.successData(fbStationService.getFbRelatedYrByStcd(stcd));
}
}

View File

@ -0,0 +1,29 @@
package com.yfd.platform.qgc_env.fb.controller;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.qgc_env.fb.service.FbStationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/fb/msfbrdm")
@Tag(name = "鱼类增殖站增殖情况")
@Validated
public class FbMsfbrdmController {
@Resource
private FbStationService fbStationService;
@PostMapping("/fbFlData/GetKendoListCust")
@Operation(summary = "增殖站增殖情况(app)")
public ResponseResult getFbFlData(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fbStationService.getFbFlDataKendoListCust(dataSourceRequest));
}
}

View File

@ -0,0 +1,62 @@
package com.yfd.platform.qgc_env.fb.controller;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.qgc_env.fb.service.FbStationService;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/fb/station")
@Tag(name = "鱼类增殖站概况")
@Validated
public class FbStationController {
@Resource
private FbStationService fbStationService;
@PostMapping("/qgcoverview/getOverviewSecond")
@Operation(summary = "全流域增殖站概况二级页面")
public ResponseResult getQgcOverviewSecond(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fbStationService.getQgcOverviewSecond(dataSourceRequest));
}
@PostMapping("/overview/getOverviewSecond")
@Operation(summary = "增殖站概况二级页面")
public ResponseResult getOverviewSecond(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fbStationService.getOverviewSecond(dataSourceRequest));
}
@PostMapping("/overview/GetKendoListCust")
@Operation(summary = "全流域增殖站概况")
public ResponseResult getOverviewKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fbStationService.getOverviewKendoListCust(dataSourceRequest));
}
@PostMapping("/qgc/getFbStaticsData")
@Operation(summary = "增殖站放流数据统计")
public ResponseResult getQgcFbStaticsData(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fbStationService.getQgcFbStaticsData(dataSourceRequest));
}
@GetMapping("/msstbprpt/getStInfoByStcd")
@Operation(summary = "增殖站单站基础信息")
public ResponseResult getStInfoByStcd(@Parameter(description = "站点编码") @RequestParam("stcd") String stcd) {
return ResponseResult.successData(fbStationService.getStInfoByStcd(stcd));
}
@GetMapping("/rpimnr/qgc/year/GetYearRpStatistics")
@Operation(summary = "全过程放流统计总数,根据基地流域分组")
public ResponseResult getYearRpStatistics(@Parameter(description = "年份") @RequestParam("year") String year) {
return ResponseResult.successData(fbStationService.getYearRpStatistics(year));
}
}

View File

@ -0,0 +1,68 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@Accessors(chain = true)
@AllArgsConstructor
@Schema(description = "亲鱼过程图表头")
public class FbBsmfRFishHeadColumnVo {
@Schema(description = "字段名")
private String dataIndex;
@Schema(description = "标题")
private String title;
@Schema(description = "是否展示")
private Boolean visible = true;
@Schema(description = "唯一键")
private String key;
@Schema(description = "单位")
private String unit;
@Schema(description = "是否合并")
private boolean merge;
@Schema(description = "数据类型")
private String dataType;
@Schema(description = "数据格式")
private String dataFormat;
@Schema(description = "子节点")
private List<FbBsmfRFishHeadColumnVo> children;
public FbBsmfRFishHeadColumnVo(String title, String dataIndex) {
this.title = title;
this.dataIndex = dataIndex;
this.key = dataIndex;
}
public FbBsmfRFishHeadColumnVo(String title, String dataIndex, String key) {
this.title = title;
this.dataIndex = dataIndex;
this.key = key;
}
public FbBsmfRFishHeadColumnVo(String dataIndex,
String title,
Boolean visible,
String key,
boolean merge,
List<FbBsmfRFishHeadColumnVo> children) {
this.title = title;
this.dataIndex = dataIndex;
this.visible = visible;
this.merge = merge;
this.children = children;
this.key = key;
}
}

View File

@ -0,0 +1,15 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import lombok.Data;
@Data
public class FbBsmfRFishSummaryVo {
private String tm;
private String ftp;
private String ftpName;
private String value;
}

View File

@ -0,0 +1,22 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@Accessors(chain = true)
@Schema(description = "亲鱼过程图表格")
public class FbBsmfRFishTableVo {
@Schema(description = "表头")
private List<FbBsmfRFishHeadColumnVo> columns;
@Schema(description = "表格数据")
private Object dataSource;
@Schema(description = "总数")
private Long total;
}

View File

@ -0,0 +1,72 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class FbBsmfRQgcVo {
private String id;
private String stcd;
private Date tm;
private String ftp;
private String ftpName;
private String bssr;
private String bssrName;
private BigDecimal length;
private BigDecimal weight;
private BigDecimal age;
private Integer sex;
private String sexName;
private String signnum;
private String recorder;
private Long value;
private String fid;
private String recordUser;
private Date recordTime;
private String modifyUser;
private Date modifyTime;
private Integer isDeleted;
private String deleteUser;
private Date deleteTime;
private String platformId;
private String departmentId;
private String taskId;
private String taskStatus;
private String rstcd;
private String ennm;
private String baseId;
private String baseName;
}

View File

@ -0,0 +1,39 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "增殖站增殖情况")
public class FbFlDataVo {
@Schema(description = "增殖站编码")
private String stcd;
@Schema(description = "增殖站名称")
private String stnm;
@Schema(description = "电站编码")
private String rstcd;
@Schema(description = "电站名称")
private String ennm;
@Schema(description = "基地编码")
private String baseId;
@Schema(description = "基地名称")
private String baseName;
@Schema(description = "年份")
private String yr;
@Schema(description = "鱼类名称")
private String ftpName;
@Schema(description = "目标放鱼数量")
private Long targetFcnt;
@Schema(description = "实际放鱼数量")
private Long realFcnt;
}

View File

@ -0,0 +1,24 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "放流鱼种统计")
public class FbFtpStatisticsVo {
@Schema(description = "基地编码")
private String baseId;
@Schema(description = "基地名称")
private String baseName;
@Schema(description = "鱼类编码")
private String ftp;
@Schema(description = "鱼类名称")
private String fishName;
@Schema(description = "数量")
private Integer fcnt;
}

View File

@ -0,0 +1,13 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import lombok.Data;
@Data
public class FbRelatedYrVo {
private String type;
private String subType;
private String yr;
}

View File

@ -0,0 +1,51 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "鱼类增殖站单站基础信息")
public class FbStBaseInfoVo {
@Schema(description = "站点编码")
private String stcd;
@Schema(description = "站点名称")
private String stnm;
@Schema(description = "站类编码")
private String sttpCode;
@Schema(description = "站类名称")
private String sttpName;
@Schema(description = "站类全路径")
private String sttpFullPath;
@Schema(description = "站类层级")
private Integer sttpTreeLevel;
@Schema(description = "关联站点编码")
private String stCode;
@Schema(description = "关联站点名称")
private String stName;
@Schema(description = "所属基地编码")
private String baseId;
@Schema(description = "所属基地名称")
private String baseName;
@Schema(description = "所属基地流域编码")
private String hbrvcd;
@Schema(description = "所属基地流域名称")
private String hbrvcdName;
@Schema(description = "所属流域编码")
private String rvcd;
@Schema(description = "所属流域名称")
private String rvcdName;
}

View File

@ -0,0 +1,26 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Data
@Schema(description = "鱼类增殖站详情返回")
public class FbStInfoResultVo {
@Schema(description = "主信息兼容对象")
private Map<String, Object> msStbprpT = new LinkedHashMap<>();
@Schema(description = "测值列表")
private List<Object> stcdValVoList = new ArrayList<>();
@Schema(description = "关联列表")
private List<Object> relList = new ArrayList<>();
@Schema(description = "站点基础信息")
private FbStBaseInfoVo stBaseInfo;
}

View File

@ -0,0 +1,53 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Data
@Schema(description = "全流域增殖站概况二级页面")
public class FbStationOverviewSecondVo {
@Schema(description = "增殖站编码")
private String stcd;
@Schema(description = "增殖站名称")
private String stnm;
@Schema(description = "服务电站")
private String ennm;
@Schema(description = "增殖站总数")
private Integer count;
@Schema(description = "鱼种类数")
private Integer ftpCount;
@Schema(description = "总投资")
private BigDecimal totalInv;
@Schema(description = "计划放流鱼种类")
private String planFtp;
@Schema(description = "计划放流尾数")
private BigDecimal fcntjh;
@Schema(description = "实际鱼种类数")
private Integer realftpCount;
@Schema(description = "实际鱼种类")
private String realftp;
@Schema(description = "实际放流尾数")
private BigDecimal realfcnt;
@Schema(description = "实际放流尾数字符串")
private String realfcntStr;
@Schema(description = "年份")
private String year;
@Schema(description = "累计放鱼数量")
private Long totalFtpCount;
}

View File

@ -0,0 +1,35 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
@Schema(description = "增殖站放流统计结果")
public class FbStationStaticsDataVo {
@Schema(description = "流域编码")
private String hbrvcd;
@Schema(description = "流域名称")
private String hbrvcdName;
@Schema(description = "基地编码")
private String baseId;
@Schema(description = "基地名称")
private String baseName;
@Schema(description = "鱼类种数")
private Integer ftp;
@Schema(description = "放流数量")
private Long fcnt;
@Schema(description = "增殖站数量")
private Integer stcdCnt;
@Schema(description = "增殖站编码列表")
private List<String> stcdList;
}

View File

@ -0,0 +1,36 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "增殖站放流统计明细")
public class FbStationStaticsRawVo {
@Schema(description = "流域编码")
private String hbrvcd;
@Schema(description = "流域名称")
private String hbrvcdName;
@Schema(description = "基地编码")
private String baseId;
@Schema(description = "基地名称")
private String baseName;
@Schema(description = "增殖站编码")
private String stcd;
@Schema(description = "增殖站名称")
private String stnm;
@Schema(description = "鱼类编码")
private String ftp;
@Schema(description = "鱼类名称")
private String ftpName;
@Schema(description = "放流数量")
private Long fcnt;
}

View File

@ -0,0 +1,23 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
@Schema(description = "年度全过程放流统计")
public class YearRpStatisticsVo {
@Schema(description = "放流总数")
private Integer fpCount;
@Schema(description = "基地编码")
private String baseId;
@Schema(description = "基地名称")
private String baseName;
@Schema(description = "鱼类分组统计")
private List<FbFtpStatisticsVo> fpFtpStatitcsVos;
}

View File

@ -0,0 +1,37 @@
package com.yfd.platform.qgc_env.fb.service;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.qgc_env.fb.entity.vo.FbBsmfRQgcVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbBsmfRFishTableVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFlDataVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbRelatedYrVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbStInfoResultVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbStationStaticsDataVo;
import com.yfd.platform.qgc_env.fb.entity.vo.YearRpStatisticsVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbStationOverviewSecondVo;
import java.util.List;
public interface FbStationService {
List<YearRpStatisticsVo> getYearRpStatistics(String year);
DataSourceResult<FbStationOverviewSecondVo> getOverviewKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<FbFlDataVo> getFbFlDataKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<FbBsmfRQgcVo> getQgcBsmfRKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<FbBsmfRFishTableVo> getBsmfRFishKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<FbRelatedYrVo> getFbRelatedYrByStcd(String stcd);
FbStInfoResultVo getStInfoByStcd(String stcd);
DataSourceResult<FbStationStaticsDataVo> getQgcFbStaticsData(DataSourceRequest dataSourceRequest);
DataSourceResult<FbStationOverviewSecondVo> getOverviewSecond(DataSourceRequest dataSourceRequest);
DataSourceResult<FbStationOverviewSecondVo> getQgcOverviewSecond(DataSourceRequest dataSourceRequest);
}

View File

@ -278,8 +278,9 @@ public class FhHabitatServiceImpl implements FhHabitatService {
}
sql.append(buildSdrvwtsOrderBySql(dataSourceRequest == null ? null : dataSourceRequest.getSort()));
PageInfo pageInfo = loadOptions == null ? null : QgcQueryWrapperUtil.getPageInfo(loadOptions);
Page<?> page = pageInfo != null && pageInfo.getHasPageInfo() ? pageInfo.getPage() : null;
// PageInfo pageInfo = loadOptions == null ? null : QgcQueryWrapperUtil.getPageInfo(loadOptions);
// Page<?> page = pageInfo != null && pageInfo.getHasPageInfo() ? pageInfo.getPage() : null;
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
List<FhSdrvwtsVo> list = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), paramMap, FhSdrvwtsVo.class);
DataSourceResult<FhSdrvwtsVo> result = new DataSourceResult<>();
@ -330,8 +331,7 @@ public class FhHabitatServiceImpl implements FhHabitatService {
}
sql.append(buildSdriverdaysOrderBySql(dataSourceRequest == null ? null : dataSourceRequest.getSort()));
PageInfo pageInfo = loadOptions == null ? null : QgcQueryWrapperUtil.getPageInfo(loadOptions);
Page<?> page = pageInfo != null && pageInfo.getHasPageInfo() ? pageInfo.getPage() : null;
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
List<FhSdriverdayVo> list = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), paramMap, FhSdriverdayVo.class);
DataSourceResult<FhSdriverdayVo> result = new DataSourceResult<>();
@ -1744,8 +1744,7 @@ public class FhHabitatServiceImpl implements FhHabitatService {
sql.append(buildStTbYsOrderBySql(dataSourceRequest == null ? null : dataSourceRequest.getSort()));
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
PageInfo pageInfo = loadOptions == null ? null : QgcQueryWrapperUtil.getPageInfo(loadOptions);
Page<?> page = pageInfo != null && pageInfo.getHasPageInfo() ? pageInfo.getPage() : null;
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
List<StTbYsVo> list = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), paramMap, StTbYsVo.class);
DataSourceResult<StTbYsVo> result = new DataSourceResult<>();

View File

@ -70,6 +70,18 @@ public class FishPassageController {
return ResponseResult.successData(fpBuildService.processKendoList(dataSourceRequest));
}
@PostMapping("/fishDic/GetKendoListCust")
@Operation(summary = "鱼类字典列表")
public ResponseResult getFishDicList(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fpBuildService.getFishDicList(dataSourceRequest));
}
@PostMapping("/fishDic/stcd/GetKendoList")
@Operation(summary = "根据过鱼设施站点查询鱼类列表")
public ResponseResult getFishDicListByStcd(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fpBuildService.getFishDicListByStcd(dataSourceRequest));
}
@PostMapping("/vmsstbprpt/GetKendoList")
@Operation(summary = "根据条件查询过鱼设施基础列表")
public ResponseResult getVmsstbprptList(@RequestBody DataSourceRequest dataSourceRequest) {

View File

@ -0,0 +1,73 @@
package com.yfd.platform.qgc_env.fp.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
@Data
@Schema(description = "过鱼设施模块鱼类字典信息")
public class FpFishDicVo {
private String id;
private String code;
private String name;
private String nameEn;
private String alias;
private String logo;
private String introduce;
private String inffile;
private String orders;
private String family;
private String genus;
private String species;
private Integer type;
private String typeName;
private String fsz;
private Integer rare;
private String rareName;
private Integer specOrigin;
private String specOriginName;
private Integer ptype;
private String ptypeName;
private String rvcd;
private String rvcdName;
private String habitMigrat;
private String feedingHabit;
private String spawnCharact;
private String food;
private String timeFeed;
private String orignDate;
private String pretemp;
private String flowRate;
private String depth;
private String botmMater;
private String wqtq;
private String wqtqName;
private Integer habitat;
private String habitatName;
private Integer situation;
private String situationName;
private Integer resourceType;
private String resourceTypeName;
private String shapedesc;
private String protectlvl;
private String habitation;
private String fid;
private String description;
private Integer enable;
private String enableName;
private Integer internal;
private String internalName;
private Integer orderIndex;
private String recordUser;
private Date recordTime;
private String modifyUser;
private Date modifyTime;
private Integer isDeleted;
private String deleteUser;
private Date deleteTime;
private String spawnMonth;
private String vlsr;
private Date vlsrTm;
}

View File

@ -3,6 +3,7 @@ package com.yfd.platform.qgc_env.fp.service;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.qgc_env.fp.entity.vo.FpConstructionSituationVo;
import com.yfd.platform.qgc_env.fp.entity.vo.FpFishDicVo;
import com.yfd.platform.qgc_env.fp.entity.vo.FpVmsstbprptVo;
public interface FpBuildService {
@ -11,6 +12,10 @@ public interface FpBuildService {
DataSourceResult<FpVmsstbprptVo> getVmsstbprptList(DataSourceRequest dataSourceRequest);
DataSourceResult<FpFishDicVo> getFishDicList(DataSourceRequest dataSourceRequest);
DataSourceResult<FpFishDicVo> getFishDicListByStcd(DataSourceRequest dataSourceRequest);
DataSourceResult<FpVmsstbprptVo> getFpqMsstbprptList(DataSourceRequest dataSourceRequest);
FpVmsstbprptVo getStInfoByStcd(String stcd);

View File

@ -1,21 +1,29 @@
package com.yfd.platform.qgc_env.fp.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.common.DataSourceLoadOptionsBase;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.common.GroupHelper;
import com.yfd.platform.common.GroupingInfo;
import com.yfd.platform.common.MicroservicDynamicSQLMapper;
import com.yfd.platform.common.PageInfo;
import com.yfd.platform.common.exception.BizException;
import com.yfd.platform.qgc_env.fp.entity.vo.FpConstructionSituationVo;
import com.yfd.platform.qgc_env.fp.entity.vo.FpFishDicVo;
import com.yfd.platform.qgc_env.fp.entity.vo.FpVmsstbprptVo;
import com.yfd.platform.qgc_env.fp.service.FpBuildService;
import com.yfd.platform.utils.QgcQueryWrapperUtil;
import jakarta.annotation.Resource;
import org.springframework.util.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -28,8 +36,7 @@ public class FpBuildServiceImpl implements FpBuildService {
@Override
public DataSourceResult<FpConstructionSituationVo> processKendoList(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest();
PageInfo pageInfo = QgcQueryWrapperUtil.getPageInfo(loadOptions);
Page<?> page = pageInfo.getHasPageInfo() ? pageInfo.getPage() : null;
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
String sql = "SELECT t.STTP AS sttpCode, " +
" SUM(CASE WHEN t.DTIN = 1 THEN 1 ELSE 0 END) AS bonusing, " +
@ -61,6 +68,98 @@ public class FpBuildServiceImpl implements FpBuildService {
return queryVmsstbprptList(dataSourceRequest, null);
}
@Override
public DataSourceResult<FpFishDicVo> getFishDicList(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
Map<String, Object> paramMap = new HashMap<>();
String filterSql = buildFishDicFilterCondition(
dataSourceRequest == null ? null : dataSourceRequest.getFilter(),
paramMap,
new int[]{0}
);
if (CollUtil.isNotEmpty(dataSourceRequest == null ? null : dataSourceRequest.getGroup())) {
StringBuilder groupedBaseSql = new StringBuilder("SELECT * FROM (")
.append(buildFishDicBaseSql())
.append(") t WHERE 1 = 1 ");
if (StrUtil.isNotBlank(filterSql)) {
groupedBaseSql.append(" AND ").append(filterSql).append(" ");
}
GroupingInfo[] groupInfos = loadOptions == null ? null : loadOptions.getGroup();
String groupedSql = buildFishDicGroupSql(groupedBaseSql.toString(), groupInfos);
List<Map<String, Object>> rows = microservicDynamicSQLMapper.pageAllList(null, groupedSql, paramMap);
DataSourceResult result = new DataSourceResult();
if (Boolean.TRUE.equals(dataSourceRequest.getGroupResultFlat())) {
result.setData(new GroupHelper().faltGroup(rows, Arrays.asList(groupInfos)));
} else {
result.setData(new GroupHelper().group(rows, Arrays.asList(groupInfos)));
}
result.setTotal((long) rows.size());
result.setAggregates(new HashMap<>());
return result;
}
StringBuilder sql = new StringBuilder("SELECT ")
.append(buildFishDicDetailSelectSql(dataSourceRequest == null ? null : dataSourceRequest.getSelect()))
.append(" FROM (")
.append(buildFishDicBaseSql())
.append(") t WHERE 1 = 1 ");
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql).append(" ");
}
sql.append(buildFishDicOrderBySql(dataSourceRequest == null ? null : dataSourceRequest.getSort()));
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
List<FpFishDicVo> list = microservicDynamicSQLMapper.pageAllListWithResultType(
page, sql.toString(), paramMap, FpFishDicVo.class
);
DataSourceResult<FpFishDicVo> result = new DataSourceResult<>();
result.setData(list);
result.setTotal(page != null ? page.getTotal() : list.size());
result.setAggregates(new HashMap<>());
return result;
}
@Override
public DataSourceResult<FpFishDicVo> getFishDicListByStcd(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
String stcd = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "stcd");
if (StrUtil.isBlank(stcd)) {
throw new BizException("过鱼设施站点编码(stcd)不能为空.");
}
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("stcd", StrUtil.trim(stcd));
String sql = "SELECT DISTINCT " +
" fish.ID AS id, " +
" fish.NAME AS name " +
"FROM SD_FPSS_B_H fp " +
"INNER JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD " +
" AND NVL(eng.IS_DELETED, 0) = 0 " +
"INNER JOIN SD_FISHDICTORY_RLTN_B rel ON rel.RVCD = eng.HBRVCD " +
" AND NVL(rel.IS_DELETED, 0) = 0 " +
"INNER JOIN SD_FISHDICTORY_B fish ON fish.ID = NVL(rel.ZY_FISH_ID, rel.FISH_ID) " +
" AND NVL(fish.IS_DELETED, 0) = 0 " +
" AND NVL(fish.ENABLE, 1) = 1 " +
"WHERE fp.STCD = #{map.stcd} " +
"ORDER BY fish.NAME";
List<FpFishDicVo> list = microservicDynamicSQLMapper.getAllListWithResultType(
sql,
paramMap,
FpFishDicVo.class
);
DataSourceResult<FpFishDicVo> result = new DataSourceResult<>();
result.setData(list);
result.setTotal(list == null ? 0L : list.size());
result.setAggregates(new HashMap<>());
return result;
}
@Override
public DataSourceResult<FpVmsstbprptVo> getFpqMsstbprptList(DataSourceRequest dataSourceRequest) {
return queryVmsstbprptList(dataSourceRequest, "FPQ");
@ -113,6 +212,77 @@ public class FpBuildServiceImpl implements FpBuildService {
return list.getFirst();
}
private String buildFishDicBaseSql() {
return "SELECT " +
"src.ID AS id, " +
"src.CODE AS code, " +
"src.NAME AS name, " +
"src.NAME_EN AS nameEn, " +
"src.ALIAS AS alias, " +
"src.LOGO AS logo, " +
"src.INTRODUCE AS introduce, " +
"src.INFFILE AS inffile, " +
"src.ORDERS AS orders, " +
"src.FAMILY AS family, " +
"src.GENUS AS genus, " +
"src.SPECIES AS species, " +
"src.TYPE AS type, " +
"CASE WHEN src.TYPE = 1 THEN '淡水' WHEN src.TYPE = 2 THEN '海水' ELSE NULL END AS typeName, " +
"src.FSZ AS fsz, " +
"src.RARE AS rare, " +
"CASE WHEN src.RARE = 1 THEN '是' WHEN src.RARE = 0 THEN '否' ELSE NULL END AS rareName, " +
"src.SPEC_ORIGIN AS specOrigin, " +
"CASE WHEN src.SPEC_ORIGIN = 1 THEN '本土物种' WHEN src.SPEC_ORIGIN = 2 THEN '外来物种' ELSE NULL END AS specOriginName, " +
"src.PTYPE AS ptype, " +
"CASE src.PTYPE " +
"WHEN 1 THEN '濒危' WHEN 2 THEN '极危' WHEN 3 THEN '近危' WHEN 4 THEN '易危' " +
"WHEN 5 THEN '重点保护' WHEN 6 THEN '无危' WHEN 7 THEN '国家二级' WHEN 8 THEN '市二级保护' ELSE NULL END AS ptypeName, " +
"src.RVCD AS rvcd, " +
"rv.RVNM AS rvcdName, " +
"src.HABIT_MIGRAT AS habitMigrat, " +
"src.FEEDING_HABIT AS feedingHabit, " +
"src.SPAWN_CHARACT AS spawnCharact, " +
"src.FOOD AS food, " +
"src.TIME_FEED AS timeFeed, " +
"src.ORIGN_DATE AS orignDate, " +
"src.PRETEMP AS pretemp, " +
"src.FLOW_RATE AS flowRate, " +
"src.DEPTH AS depth, " +
"src.BOTM_MATER AS botmMater, " +
"src.WQTQ AS wqtq, " +
"CASE src.WQTQ " +
"WHEN '1' THEN 'Ⅰ类' WHEN '2' THEN 'Ⅱ类' WHEN '3' THEN 'Ⅲ类' WHEN '4' THEN 'Ⅳ类' WHEN '5' THEN 'Ⅴ类' WHEN '6' THEN '劣V类' ELSE NULL END AS wqtqName, " +
"src.HABITAT AS habitat, " +
"CASE src.HABITAT WHEN 1 THEN '流水生境' WHEN 2 THEN '静缓流生境' WHEN 3 THEN '洞穴生境' ELSE NULL END AS habitatName, " +
"src.SITUATION AS situation, " +
"CASE src.SITUATION WHEN 1 THEN '优势种' WHEN 2 THEN '常见种' WHEN 3 THEN '少见种' WHEN 4 THEN '记录种' ELSE NULL END AS situationName, " +
"src.RESOURCE_TYPE AS resourceType, " +
"CASE src.RESOURCE_TYPE WHEN 1 THEN '保护鱼类' WHEN 2 THEN '特有鱼类' WHEN 3 THEN '重要经济鱼类' WHEN 4 THEN '濒危状况' ELSE NULL END AS resourceTypeName, " +
"src.SHAPEDESC AS shapedesc, " +
"src.PROTECTLVL AS protectlvl, " +
"src.HABITATION AS habitation, " +
"src.FID AS fid, " +
"src.DESCRIPTION AS description, " +
"src.ENABLE AS enable, " +
"CASE WHEN src.ENABLE = 1 THEN '启用' WHEN src.ENABLE = 0 THEN '禁用' ELSE NULL END AS enableName, " +
"src.INTERNAL AS internal, " +
"CASE WHEN src.INTERNAL = 1 THEN '是' WHEN src.INTERNAL = 0 THEN '否' ELSE NULL END AS internalName, " +
"src.ORDER_INDEX AS orderIndex, " +
"src.RECORD_USER AS recordUser, " +
"src.RECORD_TIME AS recordTime, " +
"src.MODIFY_USER AS modifyUser, " +
"src.MODIFY_TIME AS modifyTime, " +
"src.IS_DELETED AS isDeleted, " +
"src.DELETE_USER AS deleteUser, " +
"src.DELETE_TIME AS deleteTime, " +
"src.SPAWN_MONTH AS spawnMonth, " +
"src.VLSR AS vlsr, " +
"src.VLSR_TM AS vlsrTm " +
"FROM SD_FISHDICTORY_B src " +
"LEFT JOIN SD_RVCD_DIC rv ON rv.RVCD = src.RVCD " +
"WHERE NVL(src.IS_DELETED, 0) = 0 ";
}
private String buildVmsstbprptBaseSql() {
StringBuilder sql = new StringBuilder();
sql.append("SELECT ")
@ -319,6 +489,87 @@ public class FpBuildServiceImpl implements FpBuildService {
return selectMap;
}
private String buildFishDicDetailSelectSql(List<String> selectFields) {
LinkedHashMap<String, String> columnMap = buildFishDicSelectColumnMap();
if (CollUtil.isEmpty(selectFields)) {
return String.join(", ", columnMap.values());
}
List<String> selectColumns = new ArrayList<>();
for (String field : selectFields) {
String column = columnMap.get(field);
if (StrUtil.isNotBlank(column)) {
selectColumns.add(column);
}
}
return selectColumns.isEmpty() ? String.join(", ", columnMap.values()) : String.join(", ", selectColumns);
}
private LinkedHashMap<String, String> buildFishDicSelectColumnMap() {
LinkedHashMap<String, String> columnMap = new LinkedHashMap<>();
columnMap.put("id", "t.id AS id");
columnMap.put("code", "t.code AS code");
columnMap.put("name", "t.name AS name");
columnMap.put("nameEn", "t.nameEn AS nameEn");
columnMap.put("alias", "t.alias AS alias");
columnMap.put("logo", "t.logo AS logo");
columnMap.put("introduce", "t.introduce AS introduce");
columnMap.put("inffile", "t.inffile AS inffile");
columnMap.put("orders", "t.orders AS orders");
columnMap.put("family", "t.family AS family");
columnMap.put("genus", "t.genus AS genus");
columnMap.put("species", "t.species AS species");
columnMap.put("type", "t.type AS type");
columnMap.put("typeName", "t.typeName AS typeName");
columnMap.put("fsz", "t.fsz AS fsz");
columnMap.put("rare", "t.rare AS rare");
columnMap.put("rareName", "t.rareName AS rareName");
columnMap.put("specOrigin", "t.specOrigin AS specOrigin");
columnMap.put("specOriginName", "t.specOriginName AS specOriginName");
columnMap.put("ptype", "t.ptype AS ptype");
columnMap.put("ptypeName", "t.ptypeName AS ptypeName");
columnMap.put("rvcd", "t.rvcd AS rvcd");
columnMap.put("rvcdName", "t.rvcdName AS rvcdName");
columnMap.put("habitMigrat", "t.habitMigrat AS habitMigrat");
columnMap.put("feedingHabit", "t.feedingHabit AS feedingHabit");
columnMap.put("spawnCharact", "t.spawnCharact AS spawnCharact");
columnMap.put("food", "t.food AS food");
columnMap.put("timeFeed", "t.timeFeed AS timeFeed");
columnMap.put("orignDate", "t.orignDate AS orignDate");
columnMap.put("pretemp", "t.pretemp AS pretemp");
columnMap.put("flowRate", "t.flowRate AS flowRate");
columnMap.put("depth", "t.depth AS depth");
columnMap.put("botmMater", "t.botmMater AS botmMater");
columnMap.put("wqtq", "t.wqtq AS wqtq");
columnMap.put("wqtqName", "t.wqtqName AS wqtqName");
columnMap.put("habitat", "t.habitat AS habitat");
columnMap.put("habitatName", "t.habitatName AS habitatName");
columnMap.put("situation", "t.situation AS situation");
columnMap.put("situationName", "t.situationName AS situationName");
columnMap.put("resourceType", "t.resourceType AS resourceType");
columnMap.put("resourceTypeName", "t.resourceTypeName AS resourceTypeName");
columnMap.put("shapedesc", "t.shapedesc AS shapedesc");
columnMap.put("protectlvl", "t.protectlvl AS protectlvl");
columnMap.put("habitation", "t.habitation AS habitation");
columnMap.put("fid", "t.fid AS fid");
columnMap.put("description", "t.description AS description");
columnMap.put("enable", "t.enable AS enable");
columnMap.put("enableName", "t.enableName AS enableName");
columnMap.put("internal", "t.internal AS internal");
columnMap.put("internalName", "t.internalName AS internalName");
columnMap.put("orderIndex", "t.orderIndex AS orderIndex");
columnMap.put("recordUser", "t.recordUser AS recordUser");
columnMap.put("recordTime", "t.recordTime AS recordTime");
columnMap.put("modifyUser", "t.modifyUser AS modifyUser");
columnMap.put("modifyTime", "t.modifyTime AS modifyTime");
columnMap.put("isDeleted", "t.isDeleted AS isDeleted");
columnMap.put("deleteUser", "t.deleteUser AS deleteUser");
columnMap.put("deleteTime", "t.deleteTime AS deleteTime");
columnMap.put("spawnMonth", "t.spawnMonth AS spawnMonth");
columnMap.put("vlsr", "t.vlsr AS vlsr");
columnMap.put("vlsrTm", "t.vlsrTm AS vlsrTm");
return columnMap;
}
private String buildVmsstbprptFilterCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
@ -345,6 +596,32 @@ public class FpBuildServiceImpl implements FpBuildService {
return String.join(logic, conditions);
}
private String buildFishDicFilterCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
if (filter == null) {
return "";
}
if (filter.getField() != null && !filter.getField().isBlank()) {
return buildFishDicLeafCondition(filter, paramMap, indexHolder);
}
if (CollectionUtils.isEmpty(filter.getFilters())) {
return "";
}
List<String> conditions = new ArrayList<>();
for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) {
String childSql = buildFishDicFilterCondition(child, paramMap, indexHolder);
if (!childSql.isBlank()) {
conditions.add("(" + childSql + ")");
}
}
if (conditions.isEmpty()) {
return "";
}
String logic = "or".equalsIgnoreCase(filter.getLogic()) ? " OR " : " AND ";
return String.join(logic, conditions);
}
private String buildVmsstbprptLeafCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
@ -410,6 +687,96 @@ public class FpBuildServiceImpl implements FpBuildService {
}
}
private String buildFishDicLeafCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
String column = mapFishDicColumn(filter.getField());
if (column == null || column.isBlank()) {
return "";
}
String operator = filter.getOperator() == null ? "eq" : filter.getOperator().toLowerCase();
Object value = filter.getValue();
if (isFishDicDateField(filter.getField())) {
return buildDateCondition(column, operator, value, paramMap, indexHolder, "fpFishDicP");
}
if ("isnull".equals(operator)) {
return column + " IS NULL";
}
if ("isnotnull".equals(operator)) {
return column + " IS NOT NULL";
}
if ("in".equals(operator)) {
List<Object> values = normalizeValues(value);
if (values.isEmpty()) {
return "";
}
List<String> placeholders = new ArrayList<>();
for (Object item : values) {
String paramKey = "fpFishDicP" + indexHolder[0]++;
paramMap.put(paramKey, item);
placeholders.add("#{map." + paramKey + "}");
}
return column + " IN (" + String.join(", ", placeholders) + ")";
}
if (value == null) {
return "";
}
String paramKey = "fpFishDicP" + indexHolder[0]++;
switch (operator) {
case "eq":
paramMap.put(paramKey, value);
return column + " = #{map." + paramKey + "}";
case "neq":
paramMap.put(paramKey, value);
return column + " <> #{map." + paramKey + "}";
case "contains":
paramMap.put(paramKey, "%" + value + "%");
return column + " LIKE #{map." + paramKey + "}";
case "startswith":
paramMap.put(paramKey, value + "%");
return column + " LIKE #{map." + paramKey + "}";
case "endswith":
paramMap.put(paramKey, "%" + value);
return column + " LIKE #{map." + paramKey + "}";
case "gt":
paramMap.put(paramKey, value);
return column + " > #{map." + paramKey + "}";
case "gte":
paramMap.put(paramKey, value);
return column + " >= #{map." + paramKey + "}";
case "lt":
paramMap.put(paramKey, value);
return column + " < #{map." + paramKey + "}";
case "lte":
paramMap.put(paramKey, value);
return column + " <= #{map." + paramKey + "}";
default:
return "";
}
}
private String buildDateCondition(String column,
String operator,
Object value,
Map<String, Object> paramMap,
int[] indexHolder,
String prefix) {
if (value == null) {
return "";
}
String paramKey = prefix + indexHolder[0]++;
paramMap.put(paramKey, value);
return switch (operator) {
case "eq" -> "TRUNC(" + column + ") = TRUNC(#{map." + paramKey + "})";
case "neq" -> "TRUNC(" + column + ") <> TRUNC(#{map." + paramKey + "})";
case "gt" -> column + " > #{map." + paramKey + "}";
case "gte" -> column + " >= #{map." + paramKey + "}";
case "lt" -> column + " < #{map." + paramKey + "}";
case "lte" -> column + " <= #{map." + paramKey + "}";
default -> "";
};
}
private List<Object> normalizeValues(Object value) {
List<Object> values = new ArrayList<>();
if (value instanceof List<?> list) {
@ -531,6 +898,76 @@ public class FpBuildServiceImpl implements FpBuildService {
return columnMap.get(field);
}
private String mapFishDicColumn(String field) {
if (StrUtil.isBlank(field)) {
return null;
}
return switch (field) {
case "id" -> "t.id";
case "code" -> "t.code";
case "name" -> "t.name";
case "nameEn" -> "t.nameEn";
case "alias" -> "t.alias";
case "logo" -> "t.logo";
case "introduce" -> "t.introduce";
case "inffile" -> "t.inffile";
case "orders" -> "t.orders";
case "family" -> "t.family";
case "genus" -> "t.genus";
case "species" -> "t.species";
case "type" -> "t.type";
case "typeName" -> "t.typeName";
case "fsz" -> "t.fsz";
case "rare" -> "t.rare";
case "rareName" -> "t.rareName";
case "specOrigin" -> "t.specOrigin";
case "specOriginName" -> "t.specOriginName";
case "ptype" -> "t.ptype";
case "ptypeName" -> "t.ptypeName";
case "rvcd" -> "t.rvcd";
case "rvcdName" -> "t.rvcdName";
case "habitMigrat" -> "t.habitMigrat";
case "feedingHabit" -> "t.feedingHabit";
case "spawnCharact" -> "t.spawnCharact";
case "food" -> "t.food";
case "timeFeed" -> "t.timeFeed";
case "orignDate" -> "t.orignDate";
case "pretemp" -> "t.pretemp";
case "flowRate" -> "t.flowRate";
case "depth" -> "t.depth";
case "botmMater" -> "t.botmMater";
case "wqtq" -> "t.wqtq";
case "wqtqName" -> "t.wqtqName";
case "habitat" -> "t.habitat";
case "habitatName" -> "t.habitatName";
case "situation" -> "t.situation";
case "situationName" -> "t.situationName";
case "resourceType" -> "t.resourceType";
case "resourceTypeName" -> "t.resourceTypeName";
case "shapedesc" -> "t.shapedesc";
case "protectlvl" -> "t.protectlvl";
case "habitation" -> "t.habitation";
case "fid" -> "t.fid";
case "description" -> "t.description";
case "enable" -> "t.enable";
case "enableName" -> "t.enableName";
case "internal" -> "t.internal";
case "internalName" -> "t.internalName";
case "orderIndex" -> "t.orderIndex";
case "recordUser" -> "t.recordUser";
case "recordTime" -> "t.recordTime";
case "modifyUser" -> "t.modifyUser";
case "modifyTime" -> "t.modifyTime";
case "isDeleted" -> "t.isDeleted";
case "deleteUser" -> "t.deleteUser";
case "deleteTime" -> "t.deleteTime";
case "spawnMonth" -> "t.spawnMonth";
case "vlsr" -> "t.vlsr";
case "vlsrTm" -> "t.vlsrTm";
default -> null;
};
}
private String buildVmsstbprptOrderBySql(List<DataSourceRequest.SortDescriptor> sorts) {
if (sorts == null || sorts.isEmpty()) {
return " ORDER BY t.baseStepSort ASC NULLS LAST, t.rvcdStepSort ASC NULLS LAST, " +
@ -555,6 +992,64 @@ public class FpBuildServiceImpl implements FpBuildService {
return " ORDER BY " + String.join(", ", orderItems);
}
private String buildFishDicOrderBySql(List<DataSourceRequest.SortDescriptor> sorts) {
List<String> orderItems = new ArrayList<>();
if (CollUtil.isNotEmpty(sorts)) {
for (DataSourceRequest.SortDescriptor sort : sorts) {
if (sort == null || sort.getField() == null || sort.getField().isBlank()) {
continue;
}
String column = mapFishDicColumn(sort.getField());
if (StrUtil.isBlank(column)) {
continue;
}
String direction = "desc".equalsIgnoreCase(sort.getDir()) || "des".equalsIgnoreCase(sort.getDir())
? "DESC" : "ASC";
orderItems.add(column + " " + direction + " NULLS LAST");
}
}
if (orderItems.isEmpty()) {
return " ORDER BY t.orderIndex ASC NULLS LAST, t.name ASC";
}
return " ORDER BY " + String.join(", ", orderItems);
}
private String buildFishDicGroupSql(String detailSql, GroupingInfo[] groupInfos) {
if (groupInfos == null || groupInfos.length == 0) {
return detailSql;
}
List<String> groupFields = new ArrayList<>();
List<String> selectItems = new ArrayList<>();
List<String> orderItems = new ArrayList<>();
for (GroupingInfo item : groupInfos) {
if (item == null || StrUtil.isBlank(item.getSelector())) {
continue;
}
String selector = item.getSelector();
String column = mapFishDicColumn(selector);
if (StrUtil.isBlank(column)) {
continue;
}
groupFields.add(column);
selectItems.add(column + " AS " + selector);
selectItems.add("COUNT(*) AS count_" + selector);
orderItems.add(column + (item.getDesc() ? " DESC" : " ASC"));
}
if (groupFields.isEmpty()) {
return "SELECT * FROM (" + detailSql + ") t WHERE 1 = 0";
}
return "SELECT " + String.join(", ", selectItems) +
" FROM (" + detailSql + ") t GROUP BY " + String.join(", ", groupFields) +
" ORDER BY " + String.join(", ", orderItems);
}
private boolean isFishDicDateField(String field) {
return "recordTime".equals(field)
|| "modifyTime".equals(field)
|| "deleteTime".equals(field)
|| "vlsrTm".equals(field);
}
private String mapVmsstbprptOuterColumn(String field) {
if (field == null || field.isBlank()) {
return null;

View File

@ -43,4 +43,6 @@ public class FprZyFishDicVo {
private String logo;
private String inffile;
private String spawnMonth;
private String orders;
private String vlsr;
}

View File

@ -201,7 +201,20 @@ public class FprMonitorServiceImpl implements FprMonitorService {
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql).append(" ");
}
// 增加排序
if(dataSourceRequest.getSort() !=null && !dataSourceRequest.getSort().isEmpty()){
List<DataSourceRequest.SortDescriptor> sortDescriptors = dataSourceRequest.getSort();
StringBuilder orderSql = new StringBuilder();
orderSql.append(" order by ");
for (DataSourceRequest.SortDescriptor sort:sortDescriptors){
orderSql.append(sort.getField()).append(" ").append(sort.getDir()).append(",");
}
sql.append(orderSql, 0, orderSql.length()-1);
// String[] beans = SpringContextHolder.getApplicationContext().getBeanDefinitionNames();
sql.append(" nulls last ");
}else{
sql.append(" order by rvcd nulls last ");
}
List<FprZyFishDicVo> list = microservicDynamicSQLMapper.getAllListWithResultType(
sql.toString(),
paramMap,
@ -535,6 +548,8 @@ public class FprMonitorServiceImpl implements FprMonitorService {
"src.DESCRIPTION AS description, " +
"src.LOGO AS logo, " +
"src.INFFILE AS inffile, " +
"src.ORDERS, \n" +
"src.VLSR, \n"+
"src.SPAWN_MONTH AS spawnMonth " +
"FROM SD_FISHDICTORY_B src " +
"LEFT JOIN SD_FISHDICTORY_RLTN_B rel ON src.ID = rel.ZY_FISH_ID " +
@ -1185,8 +1200,14 @@ public class FprMonitorServiceImpl implements FprMonitorService {
if (CollUtil.isEmpty(resultList) || loadOptions == null || loadOptions.getTake() == null || loadOptions.getTake() <= 0) {
return resultList;
}
int start = Math.max(loadOptions.getSkip() == null ? 0 : loadOptions.getSkip(), 0);
int end = Math.min(start + loadOptions.getTake(), resultList.size());
int page = loadOptions.getSkip() == null ? 1 : loadOptions.getSkip(); // 页码从1开始缺省为1
// 如果页码 0强制设为1避免负值
if (page < 1) {
page = 1;
}
int size = loadOptions.getTake();
int start = (page - 1) * size;
int end = Math.min(start + size, resultList.size());
if (start >= resultList.size()) {
return new ArrayList<>();
}

View File

@ -39,8 +39,7 @@ public class VpConstructionServiceImpl implements VpConstructionService {
@Override
public DataSourceResult processKendoList(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
PageInfo pageInfo = loadOptions == null ? new PageInfo() : QgcQueryWrapperUtil.getPageInfo(loadOptions);
Page<?> page = pageInfo.getHasPageInfo() ? pageInfo.getPage() : null;
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
String isBotanicalGarden = loadOptions == null ? null
: QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "isBotanicalGarden");
@ -90,8 +89,7 @@ public class VpConstructionServiceImpl implements VpConstructionService {
@Override
public DataSourceResult processVmsstbprptList(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
PageInfo pageInfo = loadOptions == null ? new PageInfo() : QgcQueryWrapperUtil.getPageInfo(loadOptions);
Page<?> page = pageInfo.getHasPageInfo() ? pageInfo.getPage() : null;
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
Map<String, Object> paramMap = new HashMap<>();
StringBuilder sql = new StringBuilder(buildVmsstbprptBaseSql());
@ -177,9 +175,7 @@ public class VpConstructionServiceImpl implements VpConstructionService {
@Override
public DataSourceResult<VpWvaRunVo> processWvaKendoList(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
PageInfo pageInfo = loadOptions == null ? new PageInfo() : QgcQueryWrapperUtil.getPageInfo(loadOptions);
Page<?> page = pageInfo.getHasPageInfo() ? pageInfo.getPage() : null;
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
Map<String, Object> paramMap = new HashMap<>();
StringBuilder sql = new StringBuilder(buildWvaBaseSql());
String filterSql = buildWvaFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(),
@ -218,8 +214,7 @@ public class VpConstructionServiceImpl implements VpConstructionService {
@Override
public DataSourceResult<VpVacVo> processVacKendoList(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
PageInfo pageInfo = loadOptions == null ? new PageInfo() : QgcQueryWrapperUtil.getPageInfo(loadOptions);
Page<?> page = pageInfo.getHasPageInfo() ? pageInfo.getPage() : null;
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
String isZoo = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "isZoo");
Map<String, Object> paramMap = new HashMap<>();
@ -260,9 +255,7 @@ public class VpConstructionServiceImpl implements VpConstructionService {
@Override
public DataSourceResult<VpVarVo> processVarKendoList(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
PageInfo pageInfo = loadOptions == null ? new PageInfo() : QgcQueryWrapperUtil.getPageInfo(loadOptions);
Page<?> page = pageInfo.getHasPageInfo() ? pageInfo.getPage() : null;
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
Map<String, Object> paramMap = new HashMap<>();
StringBuilder sql = new StringBuilder(buildVarBaseSql());
String filterSql = buildVarFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(),

View File

@ -3501,8 +3501,7 @@ public class EnvWqDataServiceImpl implements EnvWqDataService {
sql.append(buildStTbYsOrderBySql(dataSourceRequest == null ? null : dataSourceRequest.getSort()));
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
PageInfo pageInfo = loadOptions == null ? null : QgcQueryWrapperUtil.getPageInfo(loadOptions);
Page<?> page = pageInfo != null && pageInfo.getHasPageInfo() ? pageInfo.getPage() : null;
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
List<StTbYsVo> list = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), paramMap, StTbYsVo.class);
DataSourceResult<StTbYsVo> result = new DataSourceResult<>();

View File

@ -85,4 +85,10 @@ public class SdWtBaseInfoVO implements Serializable {
@Schema(description = "基地流域编码")
private String hbrvcd;
@Schema(description = "经度")
private Double lgtd;
@Schema(description = "纬度")
private Double lttd;
}

View File

@ -667,6 +667,8 @@ public class SdWtMonitorServiceImpl implements SdWtMonitorService {
.append("eng.STCD AS rstcd, ")
.append("NULL AS stCode, ")
.append("NULL AS stName, ")
.append("eng.LGTD AS lgtd, ")
.append("eng.LTTD AS lttd, ")
.append("eng.DVTP AS dvtp, ")
.append("hb.ORDER_INDEX AS baseStepSort, ")
.append("eng.HBRVCD AS hbrvcd, ")
@ -700,8 +702,10 @@ public class SdWtMonitorServiceImpl implements SdWtMonitorService {
.append("eng.DVTP AS dvtp, ")
.append("CASE WHEN NVL(dw.DTIN, 0) = 1 THEN '已接入' ELSE '未接入' END AS dtinName, ")
.append("CASE ")
.append("WHEN dw.BLDSTT_CODE IN ('1', '10', '11') THEN '已建' ")
.append("WHEN dw.BLDSTT_CODE IN ('2', '7', '8') THEN '在建' ")
.append("WHEN dw.BLDSTT_CODE = 2 THEN '已建' ")
.append("WHEN dw.BLDSTT_CODE = 1 THEN '在建' ")
// .append("WHEN dw.BLDSTT_CODE IN ('1', '10', '11') THEN '已建' ")
// .append("WHEN dw.BLDSTT_CODE IN ('2', '7', '8') THEN '在建' ")
.append("ELSE '未建/规划' END AS bldsttCcodeName, ")
.append("dw.BLDSTT_CODE AS bldsttCcode, ")
.append("eng.HBRVCD AS hbrvcd ")
@ -733,8 +737,10 @@ public class SdWtMonitorServiceImpl implements SdWtMonitorService {
.append("wt.STCD AS stcd, ")
.append("wt.RSTCD AS rstcd, ")
.append("CASE ")
.append("WHEN wt.BLDSTT_CODE IN ('1', '10', '11') THEN '已建' ")
.append("WHEN wt.BLDSTT_CODE IN ('2', '7', '8') THEN '在建' ")
.append("WHEN wt.BLDSTT_CODE = 2 THEN '已建' ")
.append("WHEN wt.BLDSTT_CODE = 1 THEN '在建' ")
// .append("WHEN wt.BLDSTT_CODE IN ('1', '10', '11') THEN '已建' ")
// .append("WHEN wt.BLDSTT_CODE IN ('2', '7', '8') THEN '在建' ")
.append("ELSE '未建/规划' END AS bldsttCcodeName, ")
.append("wt.BLDSTT_CODE AS bldsttCcode, ")
.append("NULL AS stCode, ")
@ -1929,7 +1935,7 @@ public class SdWtMonitorServiceImpl implements SdWtMonitorService {
if ("baseStepSort".equals(field)) {
orderColumns.add("NVL(baseStepSort, 999999) " + dir + " NULLS LAST");
} else if ("rvcdStepSort".equals(field)) {
orderColumns.add("NVL(rvcdStepSort, 999999) " + dir + " NULLS LAST");
// orderColumns.add("NVL(rvcdStepSort, 999999) " + dir + " NULLS LAST");
} else if ("rstcdStepSort".equals(field)) {
orderColumns.add("NVL(rstcdStepSort, 999999) " + dir + " NULLS LAST");
} else if ("siteStepSort".equals(field)) {

View File

@ -3,6 +3,7 @@ package com.yfd.platform.system.controller;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.SysConfig;
import com.yfd.platform.system.service.ISysConfigService;
@ -38,16 +39,22 @@ public class SysConfigController {
@PostMapping("/getOneById")
@Operation(summary = "根据id查询全局配置详情记录")
@ResponseBody
public SysConfig getOneById(String id){
return configService.getById(id);
public SysConfig getOneById(String id,
@RequestHeader(value = "Tenant_id", required = false) String tenantId){
LambdaQueryWrapper<SysConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysConfig::getId, id)
.eq(StrUtil.isNotBlank(tenantId), SysConfig::getTenantId, StrUtil.trim(tenantId));
return configService.getOne(queryWrapper);
}
@PostMapping("/addConfig")
@Operation(summary = "根据id查询全局配置详情记录")
@ResponseBody
public ResponseResult addConfig(@RequestBody SysConfig config ) throws IOException, UnsupportedAudioFileException {
public ResponseResult addConfig(@RequestBody SysConfig config,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) throws IOException, UnsupportedAudioFileException {
if (StrUtil.isEmpty(config.getId())){
config.setId(IdUtil.fastSimpleUUID()); }
config.setTenantId(StrUtil.trimToNull(tenantId));
config.setLastmodifier(userService.getUsername());
config.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
boolean ok=configService.save(config);
@ -57,7 +64,15 @@ public class SysConfigController {
@PostMapping("/updateById")
@Operation(summary = "根据id修改全局配置记录")
@ResponseBody
public ResponseResult updateById(@RequestBody SysConfig config) throws IOException, UnsupportedAudioFileException {
public ResponseResult updateById(@RequestBody SysConfig config,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) throws IOException, UnsupportedAudioFileException {
LambdaQueryWrapper<SysConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysConfig::getId, config.getId())
.eq(StrUtil.isNotBlank(tenantId), SysConfig::getTenantId, StrUtil.trim(tenantId));
if (configService.getOne(queryWrapper) == null) {
return ResponseResult.error("未找到对应租户的配置记录");
}
config.setTenantId(StrUtil.trimToNull(tenantId));
config.setLastmodifier(userService.getUsername());
config.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
boolean ok=configService.updateById(config);

View File

@ -1,5 +1,6 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
@ -42,10 +43,11 @@ public class SysLogController {
@Operation(summary = "分页查询日志信息")
public ResponseResult getLogList(String username, String optType,
String startDate,
String endDate, Page<SysLog> page) {
String endDate, Page<SysLog> page,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
tenantId=null;
Page<SysLog> sysLogPage = sysLogService.getLogList(username, optType,
startDate, endDate, page);
startDate, endDate, page, StrUtil.trimToNull(tenantId));
Map<String, Object> map = new HashMap<>();
map.put("list", sysLogPage.getRecords());
map.put("total", sysLogPage.getTotal());
@ -65,10 +67,11 @@ public class SysLogController {
public void exportExcel(String username, String optType,
String startDate,
String endDate, Page<SysLog> page,
HttpServletResponse response) throws IOException {
HttpServletResponse response,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) throws IOException {
tenantId=null;
Page<SysLog> sysLogPage = sysLogService.getLogList(username, optType,
startDate, endDate, page);
startDate, endDate, page, StrUtil.trimToNull(tenantId));
sysLogService.exportExcel(sysLogPage.getRecords(), response);
}
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.system.controller;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
@ -58,8 +59,9 @@ public class SysMenuController {
@ResponseBody
public List<Map<String, Object>> getMenuButtonTree(String systemcode,
String name,
String isdisplay) {
return sysMenuService.getMenuButtonTree(systemcode, name, isdisplay);
String isdisplay,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
return sysMenuService.getMenuButtonTree(systemcode, name, isdisplay, StrUtil.trimToNull(tenantId));
}
/***********************************
@ -75,8 +77,9 @@ public class SysMenuController {
@ResponseBody
public List<Map<String, Object>> getMenuTree(String systemcode,
String name,
String isdisplay) {
return sysMenuService.getMenuTree(systemcode, name, isdisplay);
String isdisplay,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
return sysMenuService.getMenuTree(systemcode, name, isdisplay, StrUtil.trimToNull(tenantId));
}
/***********************************
@ -90,11 +93,12 @@ public class SysMenuController {
@PostMapping("/permissionAssignment")
@Operation(summary = "获取分配权限(不含按钮)")
@ResponseBody
public List<Map<String, Object>> permissionAssignment(String code, String roleId) {
public List<Map<String, Object>> permissionAssignment(String code, String roleId,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
if (StrUtil.isBlank(code)) {
code = "1";
}
return sysMenuService.permissionAssignment(code,roleId);
return sysMenuService.permissionAssignment(code, roleId, StrUtil.trimToNull(tenantId));
}
/**********************************
@ -105,13 +109,13 @@ public class SysMenuController {
@GetMapping("/treeRoutes")
@Operation(summary = "获取当前用户菜单结构树")
@ResponseBody
public List<Map<String, Object>> getMenuTreeByUser() {
public List<Map<String, Object>> getMenuTreeByUser(@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
SysUser userInfo = userService.getUserInfo();
String id = "";
if (0 != userInfo.getUsertype()) {
id = userInfo.getId();
}
return sysMenuService.getMenuTree(id);
return sysMenuService.getMenuTree(id, StrUtil.isNotBlank(tenantId) ? StrUtil.trimToNull(tenantId) : userInfo.getTenantId());
}
/***********************************
@ -123,8 +127,12 @@ public class SysMenuController {
@PostMapping("/getOneById")
@Operation(summary = "根据id查询菜单或按钮详情")
@ResponseBody
public ResponseResult getOneById(String id) {
SysMenu sysMenu = sysMenuService.getById(id);
public ResponseResult getOneById(String id,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysMenu::getId, id)
.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId));
SysMenu sysMenu = sysMenuService.getOne(queryWrapper);
return ResponseResult.successData(sysMenu);
}
@ -138,7 +146,9 @@ public class SysMenuController {
@PostMapping("/addMenu")
@Operation(summary = "新增菜单及按钮")
@ResponseBody
public ResponseResult addMenu(@RequestBody SysMenu sysMenu) {
public ResponseResult addMenu(@RequestBody SysMenu sysMenu,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
sysMenu.setTenantId(StrUtil.trimToNull(tenantId));
boolean isOk = sysMenuService.addMenu(sysMenu);
if (isOk) {
return ResponseResult.success();
@ -157,7 +167,15 @@ public class SysMenuController {
@PostMapping("/updateById")
@Operation(summary = "修改菜单及按钮")
@ResponseBody
public ResponseResult updateById(@RequestBody SysMenu sysMenu) {
public ResponseResult updateById(@RequestBody SysMenu sysMenu,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysMenu::getId, sysMenu.getId())
.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId));
if (sysMenuService.getOne(queryWrapper) == null) {
return ResponseResult.error("未找到对应租户的菜单");
}
sysMenu.setTenantId(StrUtil.trimToNull(tenantId));
sysMenu.setLastmodifier(userService.getUsername());
sysMenu.setLastmodifydate(new Timestamp(System.currentTimeMillis()));
boolean isOk = sysMenuService.updateById(sysMenu);
@ -179,7 +197,14 @@ public class SysMenuController {
@PostMapping("/deleteIcon")
@Operation(summary = "根据id删除单个图标")
@ResponseBody
public ResponseResult deleteIcon(@RequestParam String id) {
public ResponseResult deleteIcon(@RequestParam String id,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysMenu::getId, id)
.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId));
if (sysMenuService.getOne(queryWrapper) == null) {
return ResponseResult.error("未找到对应租户的菜单");
}
boolean ok = sysMenuService.deleteIcon(id);
if (ok) {
return ResponseResult.success();
@ -199,10 +224,11 @@ public class SysMenuController {
@PostMapping("/setIsDisplay")
@Operation(summary = "更新菜单及按钮是否有效")
@ResponseBody
public ResponseResult setIsDisplay(String id, String isdisplay) {
public ResponseResult setIsDisplay(String id, String isdisplay,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
UpdateWrapper<SysMenu> updateWrapper = new UpdateWrapper<>();
//根据id 修改是否显示 最近修改人最近修改时间
updateWrapper.eq("id", id).set("isdisplay", isdisplay).set(
updateWrapper.eq("id", id).eq(StrUtil.isNotBlank(tenantId), "tenant_id", StrUtil.trim(tenantId)).set("isdisplay", isdisplay).set(
"lastmodifier", userService.getUsername()).set(
"lastmodifydate",
new Timestamp(System.currentTimeMillis()));
@ -227,8 +253,15 @@ public class SysMenuController {
@ResponseBody
public ResponseResult moveOrderno(@RequestParam String parentid,
@RequestParam String id,
@RequestParam int orderno) {
boolean ok = sysMenuService.moveOrderno(parentid, id, orderno);
@RequestParam int orderno,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysMenu::getId, id)
.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId));
if (sysMenuService.getOne(queryWrapper) == null) {
return ResponseResult.error("未找到对应租户的菜单");
}
boolean ok = sysMenuService.moveOrderno(parentid, id, orderno, StrUtil.trimToNull(tenantId));
if (ok) {
return ResponseResult.success();
} else {
@ -246,7 +279,14 @@ public class SysMenuController {
@PostMapping("/deleteById")
@Operation(summary = "根据id删除菜单或按钮")
@ResponseBody
public ResponseResult deleteById(@RequestParam String id) {
public ResponseResult deleteById(@RequestParam String id,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysMenu::getId, id)
.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId));
if (sysMenuService.getOne(queryWrapper) == null) {
return ResponseResult.error("未找到对应租户的菜单");
}
boolean ok = sysMenuService.deleteById(id);
if (ok) {
return ResponseResult.success();
@ -266,13 +306,23 @@ public class SysMenuController {
@Operation(summary = "菜单或按钮切换")
@ResponseBody
public ResponseResult changeMenuOrder(@RequestParam String fromId,
@RequestParam String toId) {
@RequestParam String toId,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
if (StrUtil.isBlank(fromId) || StrUtil.isBlank(toId)) {
return ResponseResult.error("参数为空!");
}
if (fromId.equals(toId)) {
return ResponseResult.error("切换失败!");
}
LambdaQueryWrapper<SysMenu> fromWrapper = new LambdaQueryWrapper<>();
fromWrapper.eq(SysMenu::getId, fromId)
.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId));
LambdaQueryWrapper<SysMenu> toWrapper = new LambdaQueryWrapper<>();
toWrapper.eq(SysMenu::getId, toId)
.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId));
if (sysMenuService.getOne(fromWrapper) == null || sysMenuService.getOne(toWrapper) == null) {
return ResponseResult.error("存在不属于当前租户的菜单");
}
boolean ok = sysMenuService.changeOderNoById(fromId, toId);
if (ok) {
return ResponseResult.success();
@ -290,9 +340,16 @@ public class SysMenuController {
@PostMapping("/uploadIcon")
@Operation(summary = "上传单个图标")
@ResponseBody
public ResponseResult uploadIcon(MultipartFile icon, String menuId) throws FileNotFoundException {
public ResponseResult uploadIcon(MultipartFile icon, String menuId,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) throws FileNotFoundException {
if (StrUtil.isNotBlank(menuId)) {
SysMenu sysMenu = sysMenuService.getById(menuId);
LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysMenu::getId, menuId)
.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId));
SysMenu sysMenu = sysMenuService.getOne(queryWrapper);
if (sysMenu == null) {
return ResponseResult.error("未找到对应租户的菜单");
}
//图片路径
String iconname =
System.getProperty("user.dir") + "\\src\\main" +

View File

@ -51,8 +51,9 @@ public class SysOrganizationController {
@PostMapping("/getOrgScopeTree")
@Operation(summary = "获取组织范围树结构")
@ResponseBody
public List<Map<String, Object>> getOrgScopeTree(String roleId) {
return organizationService.getOrgScopeTree(roleId);
public List<Map<String, Object>> getOrgScopeTree(String roleId,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
return organizationService.getOrgScopeTree(roleId, StrUtil.trimToNull(tenantId));
}
/***********************************
@ -64,8 +65,9 @@ public class SysOrganizationController {
@Operation(summary = "获取组织结构树")
@ResponseBody
public List<Map<String, Object>> getOrgTree(String parentid,
String params) {
return organizationService.getOrgTree(parentid, params);
String params,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
return organizationService.getOrgTree(parentid, params, StrUtil.trimToNull(tenantId));
}
/***********************************
@ -77,12 +79,13 @@ public class SysOrganizationController {
@PostMapping("/getOrganizationById")
@Operation(summary = "根据企业ID查询组织信息")
@ResponseBody
public ResponseResult getOrganizationById(String id, String orgName) {
public ResponseResult getOrganizationById(String id, String orgName,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
if (StrUtil.isBlank(id)) {
return ResponseResult.error("查询失败!");
}
List<SysOrganization> sysOrganizations =
organizationService.getOrganizationById(id, orgName);
organizationService.getOrganizationById(id, orgName, StrUtil.trimToNull(tenantId));
return ResponseResult.successData(sysOrganizations);
}
@ -95,8 +98,13 @@ public class SysOrganizationController {
@PostMapping("/getOneById")
@Operation(summary = "根据ID查询组织详情")
@ResponseBody
public ResponseResult getOneById(String id) {
SysOrganization sysOrganization = organizationService.getById(id);
public ResponseResult getOneById(String id,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
LambdaQueryWrapper<SysOrganization> queryWrapper =
new LambdaQueryWrapper<>();
queryWrapper.eq(SysOrganization::getId, id)
.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId));
SysOrganization sysOrganization = organizationService.getOne(queryWrapper);
return ResponseResult.successData(sysOrganization);
}
@ -110,7 +118,8 @@ public class SysOrganizationController {
@PostMapping("/addOrg")
@Operation(summary = "新增系统组织框架")
@ResponseBody
public ResponseResult addOrg(@RequestBody SysOrganization sysOrganization) {
public ResponseResult addOrg(@RequestBody SysOrganization sysOrganization,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
//判断是否是否填写 有效 否则默认为 1
if (StrUtil.isEmpty(sysOrganization.getIsvaild())) {
sysOrganization.setIsvaild("1");
@ -118,6 +127,7 @@ public class SysOrganizationController {
if("".equals(sysOrganization.getId())){
sysOrganization.setId(null);
}
sysOrganization.setTenantId(StrUtil.trimToNull(tenantId));
//填写 当前用户名称
sysOrganization.setLastmodifier(userService.getUsername());
//填写 当前日期
@ -141,7 +151,16 @@ public class SysOrganizationController {
@PostMapping("/updateById")
@Operation(summary = "修改系统组织框架")
@ResponseBody
public ResponseResult updateById(@RequestBody SysOrganization sysOrganization) {
public ResponseResult updateById(@RequestBody SysOrganization sysOrganization,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
LambdaQueryWrapper<SysOrganization> queryWrapper =
new LambdaQueryWrapper<>();
queryWrapper.eq(SysOrganization::getId, sysOrganization.getId())
.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId));
if (organizationService.getOne(queryWrapper) == null) {
return ResponseResult.error("未找到对应租户的组织");
}
sysOrganization.setTenantId(StrUtil.trimToNull(tenantId));
//填写 当前用户名称
sysOrganization.setLastmodifier(userService.getUsername());
//填写 当前日期
@ -166,10 +185,11 @@ public class SysOrganizationController {
@Operation(summary = "设置组织是否有效")
@ResponseBody
public ResponseResult setIsValid(@RequestParam String id,
@RequestParam String isvaild) {
@RequestParam String isvaild,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
UpdateWrapper<SysOrganization> updateWrapper = new UpdateWrapper<>();
//根据id 修改是否有效最近修改人最近修改时间
updateWrapper.eq("id", id).set("isvaild", isvaild).set("lastmodifier"
updateWrapper.eq("id", id).eq(StrUtil.isNotBlank(tenantId), "tenant_id", StrUtil.trim(tenantId)).set("isvaild", isvaild).set("lastmodifier"
, userService.getUsername()).set("lastmodifydate",
new Timestamp(System.currentTimeMillis()));
boolean isOk = organizationService.update(updateWrapper);
@ -190,21 +210,34 @@ public class SysOrganizationController {
@PostMapping("/deleteById")
@Operation(summary = "根据id删除系统组织框架")
@ResponseBody
public ResponseResult deleteById(@RequestParam String id) {
public ResponseResult deleteById(@RequestParam String id,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
String[] orgIds = id.split(",");
for (String orgId : orgIds) {
LambdaQueryWrapper<SysOrganization> currentWrapper =
new LambdaQueryWrapper<>();
currentWrapper.eq(SysOrganization::getId, orgId)
.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId));
if (organizationService.getOne(currentWrapper) == null) {
return ResponseResult.error("存在不属于当前租户的组织");
}
LambdaQueryWrapper<SysOrganization> queryWrapper =
new LambdaQueryWrapper<>();
List<SysOrganization> list =
organizationService.list(queryWrapper.eq(SysOrganization::getParentid, orgId));
organizationService.list(queryWrapper.eq(SysOrganization::getParentid, orgId)
.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId)));
List<String> ids =
list.stream().map(SysOrganization::getId).collect(Collectors.toList());
boolean isOk = organizationService.removeById(orgId);
boolean isOk = organizationService.remove(new LambdaQueryWrapper<SysOrganization>()
.eq(SysOrganization::getId, orgId)
.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId)));
if (!isOk) {
continue;
}
for (String oid : ids) {
organizationService.removeById(oid);
organizationService.remove(new LambdaQueryWrapper<SysOrganization>()
.eq(SysOrganization::getId, oid)
.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, StrUtil.trim(tenantId)));
}
}
return ResponseResult.success();

View File

@ -6,7 +6,9 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.SysMenu;
import com.yfd.platform.system.domain.SysRole;
import com.yfd.platform.system.service.ISysMenuService;
import com.yfd.platform.system.service.ISysRoleService;
import com.yfd.platform.system.service.IUserService;
import io.swagger.v3.oas.annotations.Operation;
@ -16,6 +18,7 @@ import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@ -38,6 +41,9 @@ public class SysRoleController {
@Resource
private IUserService userService;
@Resource
private ISysMenuService sysMenuService;
/***********************************
* 用途说明查询所有角色
* 参数说明
@ -47,8 +53,9 @@ public class SysRoleController {
@PostMapping("/list")
@Operation(summary = "查询所有角色")
@ResponseBody
public List<SysRole> list(@RequestParam(required = false) String rolename) {
return roleService.selectRoleList(rolename);
public List<SysRole> list(@RequestParam(required = false) String rolename,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
return roleService.selectRoleList(rolename, StrUtil.trimToNull(tenantId));
}
/***********************************
@ -60,8 +67,12 @@ public class SysRoleController {
@PostMapping("/getOneById")
@Operation(summary = "根据Id获取当个角色")
@ResponseBody
public ResponseResult getOneById(String id) {
SysRole sysRole = roleService.getById(id);
public ResponseResult getOneById(String id,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysRole::getId, id)
.eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, StrUtil.trim(tenantId));
SysRole sysRole = roleService.getOne(queryWrapper);
return ResponseResult.successData(sysRole);
}
@ -75,7 +86,9 @@ public class SysRoleController {
@PostMapping("/addRole")
@Operation(summary = "新增角色")
@ResponseBody
public ResponseResult addRole(@RequestBody SysRole sysRole) {
public ResponseResult addRole(@RequestBody SysRole sysRole,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
sysRole.setTenantId(StrUtil.trimToNull(tenantId));
boolean isOk = roleService.addRole(sysRole);
if (isOk) {
return ResponseResult.success();
@ -96,10 +109,11 @@ public class SysRoleController {
@Operation(summary = "分配操作权限")
@ResponseBody
public ResponseResult setOptScope(@RequestParam String id,
@RequestParam String optscope) {
@RequestParam String optscope,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
UpdateWrapper<SysRole> updateWrapper = new UpdateWrapper<>();
//根据id 更新权限最近修改人最近修改时间
updateWrapper.eq("id", id).set("optscope", optscope).set(
updateWrapper.eq("id", id).eq(StrUtil.isNotBlank(tenantId), "tenant_id", StrUtil.trim(tenantId)).set("optscope", optscope).set(
"lastmodifier", userService.getUsername()).set(
"lastmodifydate", LocalDateTime.now());
boolean ok = roleService.update(updateWrapper);
@ -121,13 +135,34 @@ public class SysRoleController {
@PostMapping("/setMenuById")
@Operation(summary = "角色菜单权限")
@ResponseBody
public ResponseResult setMenuById(String id, String menuIds) {
public ResponseResult setMenuById(String id, String menuIds,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
if (StrUtil.isBlank(id)) {
return ResponseResult.error("参数为空");
}
LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysRole::getId, id)
.eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, StrUtil.trim(tenantId));
if (roleService.getOne(queryWrapper) == null) {
return ResponseResult.error("未找到对应租户的角色");
}
if (StrUtil.isBlank(menuIds)) {
return ResponseResult.success();
}
List<String> menuIdList = Arrays.stream(menuIds.split(","))
.map(StrUtil::trim)
.filter(StrUtil::isNotBlank)
.distinct()
.toList();
if (menuIdList.isEmpty()) {
return ResponseResult.success();
}
long menuCount = sysMenuService.count(new LambdaQueryWrapper<SysMenu>()
.in(SysMenu::getId, menuIdList)
.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, StrUtil.trim(tenantId)));
if (menuCount != menuIdList.size()) {
return ResponseResult.error("存在不属于当前租户的菜单");
}
boolean ok = roleService.setMenuById(id, menuIds);
if (ok) {
return ResponseResult.success();
@ -149,10 +184,11 @@ public class SysRoleController {
@Operation(summary = "设置组织范围")
@ResponseBody
public ResponseResult setOrgscope(@RequestParam String id,
@RequestParam String orgscope) {
@RequestParam String orgscope,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
UpdateWrapper<SysRole> updateWrapper = new UpdateWrapper<>();
//根据id 更新组织范围最近修改人最近修改时间
updateWrapper.eq("id", id).set("orgscope", orgscope).set(
updateWrapper.eq("id", id).eq(StrUtil.isNotBlank(tenantId), "tenant_id", StrUtil.trim(tenantId)).set("orgscope", orgscope).set(
"lastmodifier", userService.getUsername()).set(
"lastmodifydate", LocalDateTime.now());
boolean ok = roleService.update(updateWrapper);
@ -175,10 +211,11 @@ public class SysRoleController {
@Operation(summary = "设置业务范围")
@ResponseBody
public ResponseResult setBusscope(@RequestParam String id,
@RequestParam String busscope) {
@RequestParam String busscope,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
UpdateWrapper<SysRole> updateWrapper = new UpdateWrapper<>();
//根据id 更新业务范围最近修改人最近修改时间
updateWrapper.eq("id", id).set("busscope", busscope).set(
updateWrapper.eq("id", id).eq(StrUtil.isNotBlank(tenantId), "tenant_id", StrUtil.trim(tenantId)).set("busscope", busscope).set(
"lastmodifier", userService.getUsername()).set(
"lastmodifydate", LocalDateTime.now());
boolean ok = roleService.update(updateWrapper);
@ -200,7 +237,14 @@ public class SysRoleController {
@PostMapping("/setRoleUsers")
@Operation(summary = "角色添加用户")
@ResponseBody
public ResponseResult setRoleUsers(String roleid, String userids) {
public ResponseResult setRoleUsers(String roleid, String userids,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
LambdaQueryWrapper<SysRole> roleWrapper = new LambdaQueryWrapper<>();
roleWrapper.eq(SysRole::getId, roleid)
.eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, StrUtil.trim(tenantId));
if (roleService.getOne(roleWrapper) == null) {
return ResponseResult.error("未找到对应租户的角色");
}
boolean isOk = true;
String[] temp = userids.split(",");
for (String userid : temp) {
@ -223,7 +267,14 @@ public class SysRoleController {
@Operation(summary = "删除角色用户")
@ResponseBody
public ResponseResult deleteRoleUsers(@RequestParam String roleid,
@RequestParam String userids) {
@RequestParam String userids,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
LambdaQueryWrapper<SysRole> roleWrapper = new LambdaQueryWrapper<>();
roleWrapper.eq(SysRole::getId, roleid)
.eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, StrUtil.trim(tenantId));
if (roleService.getOne(roleWrapper) == null) {
return ResponseResult.error("未找到对应租户的角色");
}
//根据角色id用户id删除
boolean ok = roleService.deleteRoleUsers(roleid, userids);
if (ok) {
@ -243,10 +294,11 @@ public class SysRoleController {
@PostMapping("/setIsvaild")
@Operation(summary = "设置角色是否有效")
@ResponseBody
public ResponseResult setIsvaild(String id, String isvaild) {
public ResponseResult setIsvaild(String id, String isvaild,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
UpdateWrapper<SysRole> updateWrapper = new UpdateWrapper<>();
//根据id 更新业务范围最近修改人最近修改时间
updateWrapper.eq("id", id).set("isvaild", isvaild).set("lastmodifier"
updateWrapper.eq("id", id).eq(StrUtil.isNotBlank(tenantId), "tenant_id", StrUtil.trim(tenantId)).set("isvaild", isvaild).set("lastmodifier"
, userService.getUsername()).set("lastmodifydate",
LocalDateTime.now());
boolean ok = roleService.update(updateWrapper);
@ -266,7 +318,15 @@ public class SysRoleController {
@PostMapping("/updateById")
@Operation(summary = "更新角色信息")
@ResponseBody
public ResponseResult updateById(@RequestBody SysRole sysRole) {
public ResponseResult updateById(@RequestBody SysRole sysRole,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysRole::getId, sysRole.getId())
.eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, StrUtil.trim(tenantId));
if (roleService.getOne(queryWrapper) == null) {
return ResponseResult.error("未找到对应租户的角色");
}
sysRole.setTenantId(StrUtil.trimToNull(tenantId));
//更新最近修改人
sysRole.setLastmodifier(userService.getUsername());
//更新最近修改时间
@ -289,7 +349,17 @@ public class SysRoleController {
@PostMapping("/deleteById")
@Operation(summary = "根据id删除角色")
@ResponseBody
public ResponseResult deleteById(@RequestParam String id) {
public ResponseResult deleteById(@RequestParam String id,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
String[] roleIds = id.split(",");
for (String roleId : roleIds) {
LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysRole::getId, roleId)
.eq(StrUtil.isNotBlank(tenantId), SysRole::getTenantId, StrUtil.trim(tenantId));
if (roleService.getOne(queryWrapper) == null) {
return ResponseResult.error("存在不属于当前租户的角色");
}
}
roleService.deleteById(id);
return ResponseResult.success();
}
@ -310,9 +380,10 @@ public class SysRoleController {
@ResponseBody
public List<Map> listRoleUsers(String orgid, String username,
String status, String level,
String rolename, String isvaild) {
String rolename, String isvaild,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
return roleService.listRoleUsers(orgid, username, status, level,
rolename, isvaild);
rolename, isvaild, StrUtil.trimToNull(tenantId));
}
}

View File

@ -1,6 +1,7 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
@ -41,7 +42,10 @@ public class UserController {
@PostMapping("/addUser")
@Operation(summary = "新增系统用户")
@ResponseBody
public ResponseResult addUser(@RequestBody SysUser user, String roleids) {
public ResponseResult addUser(@RequestBody SysUser user,
String roleids,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
user.setTenantId(StrUtil.trimToNull(tenantId));
Map reslut = userService.addUser(user, roleids);
return ResponseResult.successData(reslut);
}
@ -51,10 +55,12 @@ public class UserController {
@Operation(summary = "修改用户信息")
@ResponseBody
public ResponseResult updateUser(@RequestBody SysUser user,
String roleids) {
String roleids,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
if (StrUtil.isEmpty(user.getId())) {
return ResponseResult.error("没有用户ID");
}
user.setTenantId(StrUtil.trimToNull(tenantId));
//填写 当前用户名称
user.setLastmodifier(userService.getUsername());
//填写 当前日期
@ -68,10 +74,12 @@ public class UserController {
@Operation(summary = "查询用户信息")
@ResponseBody
public ResponseResult queryUsers(String orgid,
String username, Page<SysUser> page) {
String username,
Page<SysUser> page,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
Page<SysUser> mapPage = userService.queryUsers(orgid,
username, page);
username, StrUtil.trimToNull(tenantId), page);
return ResponseResult.successData(mapPage);
}
@ -104,8 +112,12 @@ public class UserController {
@GetMapping("/queryUserById")
@Operation(summary = "根据id查询用户信息")
@ResponseBody
public ResponseResult queryUserById(String id) {
SysUser user = userService.getById(id);
public ResponseResult queryUserById(String id,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysUser::getId, id)
.eq(StrUtil.isNotBlank(tenantId), SysUser::getTenantId, StrUtil.trim(tenantId));
SysUser user = userService.getOne(queryWrapper);
return ResponseResult.successData(user);
}
@ -232,8 +244,11 @@ public class UserController {
@GetMapping("/queryPendingAuditUsers")
@Operation(summary = "查询待审核用户列表")
@ResponseBody
public ResponseResult queryPendingAuditUsers(Page<SysUser> page,String name,String regStatus) {
Page<SysUser> result = userService.queryPendingAuditUsers(page,name,regStatus);
public ResponseResult queryPendingAuditUsers(Page<SysUser> page,
String name,
String regStatus,
@RequestHeader(value = "Tenant_id", required = false) String tenantId) {
Page<SysUser> result = userService.queryPendingAuditUsers(page, name, regStatus, StrUtil.trimToNull(tenantId));
return ResponseResult.successData(result);
}
}

View File

@ -48,6 +48,12 @@ public class SysConfig implements Serializable {
*/
private String remark;
/**
* 租户ID
*/
@TableField("TENANT_ID")
private String tenantId;
/**
* 最近修改者
*/

View File

@ -83,6 +83,12 @@ public class SysLog implements Serializable {
@TableField("REQUESTIP")
private String requestip;
/**
* 租户ID
*/
@TableField("TENANT_ID")
private String tenantId;
/**
* 浏览器类型
*/

View File

@ -85,6 +85,12 @@ public class SysMenu implements Serializable {
*/
private String isdisplay;
/**
* 租户ID
*/
@TableField("TENANT_ID")
private String tenantId;
/**
* 最近修改者
*/

View File

@ -63,6 +63,12 @@ public class SysOrganization implements Serializable {
*/
private String description;
/**
* 租户ID
*/
@TableField("TENANT_ID")
private String tenantId;
/**
* 最近修改者
*/

View File

@ -69,6 +69,12 @@ public class SysRole implements Serializable {
*/
private String isvaild;
/**
* 租户ID
*/
@TableField("TENANT_ID")
private String tenantId;
/**
* 最近修改者
*/

View File

@ -79,6 +79,12 @@ public class SysUser implements Serializable {
*/
private String orgid;
/**
* 租户ID
*/
@TableField("TENANT_ID")
private String tenantId;
/**
* 密码重置时间
*/

View File

@ -25,7 +25,10 @@ public interface SysMenuMapper extends BaseMapper<SysMenu> {
*upOrderno 大于等于序号更改的序号加一
* 返回值说明: 是否更新成功
***********************************/
boolean upMoveOrderno(@Param("parentid") String parentid, @Param("Orderno") int Orderno, @Param("upOrderno") int upOrderno);
boolean upMoveOrderno(@Param("parentid") String parentid,
@Param("Orderno") int Orderno,
@Param("upOrderno") int upOrderno,
@Param("tenantId") String tenantId);
/***********************************
* 用途说明菜单及按钮序号向下移动
@ -35,13 +38,16 @@ public interface SysMenuMapper extends BaseMapper<SysMenu> {
*downOrderno 小于等于序号更改的序号减一
* 返回值说明: 是否更新成功
***********************************/
boolean downMoveOrderno(@Param("parentid") String parentid, @Param("Orderno") int Orderno, @Param("downOrderno") int downOrderno);
boolean downMoveOrderno(@Param("parentid") String parentid,
@Param("Orderno") int Orderno,
@Param("downOrderno") int downOrderno,
@Param("tenantId") String tenantId);
List<String> selectPermsByUserId(String userId);
//List<SysMenu> selectMenuByUserId(String userId);
List<SysMenu> selectMenuByUserId(String userId);
List<SysMenu> selectMenuByUserId(@Param("userId") String userId, @Param("tenantId") String tenantId);
/***********************************
* 用途说明根据权限id查找系统类型
@ -55,5 +61,5 @@ public interface SysMenuMapper extends BaseMapper<SysMenu> {
* 参数说明 id 权限id
* 返回值说明: 返回权限集合
***********************************/
List<String> selectMenuByRoleId(String id);
List<String> selectMenuByRoleId(@Param("id") String id, @Param("tenantId") String tenantId);
}

View File

@ -44,8 +44,13 @@ public interface SysRoleMapper extends BaseMapper<SysRole> {
* isvaild 角色是否有效
* 返回值说明: 系统用户角色数据集合
***********************************/
List<Map> listRoleUsers(String orgid, String username, String status,
String level, String rolename, String isvaild);
List<Map> listRoleUsers(@Param("orgid") String orgid,
@Param("username") String username,
@Param("status") String status,
@Param("level") String level,
@Param("rolename") String rolename,
@Param("isvaild") String isvaild,
@Param("tenantId") String tenantId);
/***********************************
* 用途说明根据 角色id和用户id 删除 admin除外
@ -113,6 +118,6 @@ public interface SysRoleMapper extends BaseMapper<SysRole> {
* 参数说明rolename - 角色名称
* 返回值说明角色列表
***********************************/
List<SysRole> selectRoleList(@Param("rolename") String rolename);
List<SysRole> selectRoleList(@Param("rolename") String rolename, @Param("tenantId") String tenantId);
}

View File

@ -81,9 +81,10 @@ public interface SysUserMapper extends BaseMapper<SysUser> {
************************************/
boolean delInRoleUsersByUserid(@Param("userid") String userid,@Param("roleids")String[] roleids);
Page<SysUser> queryUsers(String orgid,
String username,
Page<SysUser> page);
Page<SysUser> queryUsers(@Param("orgid") String orgid,
@Param("username") String username,
@Param("tenantId") String tenantId,
Page<SysUser> page);
Map<String, String> getOrganizationByid(String id);

View File

@ -28,7 +28,7 @@ public interface ISysLogService extends IService<SysLog> {
***********************************/
Page<SysLog> getLogList(String username, String optType,
String startDate,
String endDate, Page<SysLog> page);
String endDate, Page<SysLog> page, String tenantId);
/**********************************

View File

@ -27,7 +27,7 @@ public interface ISysMenuService extends IService<SysMenu> {
* isdisplay 是否显示
* 返回值说明: 菜单结构树集合
***********************************/
List<Map<String,Object>> getMenuButtonTree(String systemcode, String name, String isdisplay);
List<Map<String,Object>> getMenuButtonTree(String systemcode, String name, String isdisplay, String tenantId);
/***********************************
* 用途说明获取菜单结构树不含按钮
@ -37,7 +37,7 @@ public interface ISysMenuService extends IService<SysMenu> {
* isdisplay 是否显示
* 返回值说明: 菜单结构树集合
***********************************/
List<Map<String,Object>> getMenuTree(String systemcode, String name, String isdisplay);
List<Map<String,Object>> getMenuTree(String systemcode, String name, String isdisplay, String tenantId);
/***********************************
@ -73,7 +73,7 @@ public interface ISysMenuService extends IService<SysMenu> {
* orderMap map<菜单及按钮表id,排列序号>
* 返回值说明: 是否更新成功
***********************************/
boolean moveOrderno(String parentid, String id, int orderno);
boolean moveOrderno(String parentid, String id, int orderno, String tenantId);
/***********************************
* 用途说明根据id删除菜单或按钮
@ -85,7 +85,7 @@ public interface ISysMenuService extends IService<SysMenu> {
boolean changeOderNoById(String fromId, String toId);
List<Map<String, Object>> getMenuTree(String id);
List<Map<String, Object>> getMenuTree(String id, String tenantId);
/***********************************
* 用途说明权限分配
@ -95,7 +95,7 @@ public interface ISysMenuService extends IService<SysMenu> {
* isdisplay 是否显示
* 返回值说明: 菜单结构树集合
***********************************/
List<Map<String, Object>> permissionAssignment(String code,String roleId);
List<Map<String, Object>> permissionAssignment(String code, String roleId, String tenantId);
String uploadIcon(MultipartFile icon) throws FileNotFoundException;
}

View File

@ -24,7 +24,7 @@ public interface ISysOrganizationService extends IService<SysOrganization> {
* params 名称根据名称查询二级
* 返回值说明: 组织树集合
***********************************/
List<Map<String, Object>> getOrgTree(String parentid, String params);
List<Map<String, Object>> getOrgTree(String parentid, String params, String tenantId);
/***********************************
* 用途说明新增系统组织框架
@ -40,7 +40,7 @@ public interface ISysOrganizationService extends IService<SysOrganization> {
* id 企业id
* 返回值说明: 系统组织框架对象
***********************************/
List<SysOrganization> getOrganizationById(String id,String orgName);
List<SysOrganization> getOrganizationById(String id, String orgName, String tenantId);
/***********************************
* 用途说明获取组织范围树结构
@ -48,7 +48,7 @@ public interface ISysOrganizationService extends IService<SysOrganization> {
*roleId 角色id
* 返回值说明: 组织树集合
***********************************/
List<Map<String, Object>> getOrgScopeTree(String roleId);
List<Map<String, Object>> getOrgScopeTree(String roleId, String tenantId);
/**********************************
* 用途说明: 修改角色组织范围

View File

@ -52,7 +52,7 @@ public interface ISysRoleService extends IService<SysRole> {
* isvaild 角色是否有效
* 返回值说明: 系统用户角色数据集合
***********************************/
List<Map> listRoleUsers(String orgid, String username, String status, String level, String rolename, String isvaild);
List<Map> listRoleUsers(String orgid, String username, String status, String level, String rolename, String isvaild, String tenantId);
/***********************************
@ -64,5 +64,5 @@ public interface ISysRoleService extends IService<SysRole> {
***********************************/
boolean setMenuById(String id, String menuIds);
List<SysRole> selectRoleList(String rolename);
List<SysRole> selectRoleList(String rolename, String tenantId);
}

View File

@ -132,7 +132,7 @@ public interface IUserService extends IService<SysUser> {
boolean addUserRoles(String roleid, String userid);
//Page<SysUser> queryUsers(String orgid, String username, Page<SysUser> page);
Page<SysUser> queryUsers(String orgid, String username, Page<SysUser> page);
Page<SysUser> queryUsers(String orgid, String username, String tenantId, Page<SysUser> page);
/***********************************
* 用途说明根据ID批量删除用户
@ -174,6 +174,6 @@ public interface IUserService extends IService<SysUser> {
*page 分页参数
* 返回值说明: 待审核用户分页列表
************************************/
Page<SysUser> queryPendingAuditUsers(Page<SysUser> page,String name, String regStatus);
Page<SysUser> queryPendingAuditUsers(Page<SysUser> page, String name, String regStatus, String tenantId);
}

View File

@ -17,10 +17,13 @@ import com.yfd.platform.utils.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.AnnotatedType;
@ -55,7 +58,7 @@ public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> impleme
@Override
public Page<SysLog> getLogList(String username, String optType,
String startDate,
String endDate, Page<SysLog> page) {
String endDate, Page<SysLog> page, String tenantId) {
LambdaQueryWrapper<SysLog> queryWrapper = new LambdaQueryWrapper<>();
// 没有传username就不按此条件查询
@ -72,6 +75,9 @@ public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> impleme
if (parseStartDate != null && parseEndDate != null) {
queryWrapper.ge(SysLog::getLogtime, parseStartDate).lt(SysLog::getLogtime, dateTime);
}
if (StrUtil.isNotBlank(tenantId)) {
queryWrapper.eq(SysLog::getTenantId, tenantId);
}
queryWrapper.orderByDesc(SysLog::getLogtime);
return sysLogMapper.selectPage(page, queryWrapper);
@ -152,6 +158,11 @@ public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> impleme
log.setUsername(nickname);
log.setParams(getParameter(method, joinPoint.getArgs()));
log.setBrowser(browser);
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
log.setTenantId(StrUtil.trimToNull(request.getHeader("tenant_id")));
}
String operationtype = getOperationtype(signature.getName());
log.setOpttype(operationtype);
log.setLogtime(new Timestamp(System.currentTimeMillis()));

View File

@ -64,23 +64,28 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
@Override
public List<Map<String, Object>> getMenuButtonTree(String systemcode,
String name,
String isdisplay) {
String isdisplay,
String tenantId) {
List<Map<String, Object>> mapList=null;
List<Map<String, Object>> listMap =new ArrayList<>();
if(StrUtil.isEmpty(name)){//不带名称查询返回树结构
QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("parentid", "0").eq("systemcode", systemcode).orderByAsc("orderno");
queryWrapper.eq("parentid", "0").eq("systemcode", systemcode)
.eq(StrUtil.isNotBlank(tenantId), "tenant_id", tenantId)
.orderByAsc("orderno");
mapList = this.listMaps(queryWrapper);
listMap.addAll(ObjectConverterUtil.convertMapFieldsToEntityFormat(SysMenu.class, mapList));
for (int i = 0; i < listMap.size(); i++) {
//查询下一子集
List<Map<String, Object>> childList = child(listMap.get(i).get(
"id").toString(), systemcode, name, null, null);
"id").toString(), systemcode, name, null, null, tenantId);
listMap.get(i).put("children", childList); //添加新列 子集
}
}else{ //根据菜单名称查询直接返回类别
QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name", name).eq("systemcode", systemcode).orderByAsc("name");
queryWrapper.like("name", name).eq("systemcode", systemcode)
.eq(StrUtil.isNotBlank(tenantId), "tenant_id", tenantId)
.orderByAsc("name");
mapList = this.listMaps(queryWrapper);
listMap.addAll(ObjectConverterUtil.convertMapFieldsToEntityFormat(SysMenu.class, mapList));
}
@ -97,7 +102,8 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
@Override
public List<Map<String, Object>> getMenuTree(String systemcode,
String name,
String isdisplay) {
String isdisplay,
String tenantId) {
QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
if (StrUtil.isNotEmpty(isdisplay)) {
queryWrapper.eq("isdisplay", isdisplay);
@ -107,11 +113,11 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
//根据系统 ,类型不为2 显示序号 正序排序
queryWrapper.eq("parentid", "0").eq("systemcode", systemcode).ne(
"type", "2").orderByAsc("orderno");
"type", "2").eq(StrUtil.isNotBlank(tenantId), "tenant_id", tenantId).orderByAsc("orderno");
List<Map<String, Object>> listMap = this.listMaps(queryWrapper);
for (int i = 0; i < listMap.size(); i++) {
List<Map<String, Object>> childList = child(listMap.get(i).get(
"id").toString(), systemcode, name, isdisplay, "2");//查询下一子集
"id").toString(), systemcode, name, isdisplay, "2", tenantId);//查询下一子集
listMap.get(i).put("children", childList); //添加新列 子集
}
return listMap;
@ -128,10 +134,11 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
***********************************/
private List<Map<String, Object>> child(String parentid,
String systemcode, String name,
String isdisplay, String type) {
String isdisplay, String type, String tenantId) {
List<Map<String, Object>> mapList;
QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("parentid", parentid).eq("systemcode", systemcode);
queryWrapper.eq(StrUtil.isNotBlank(tenantId), "tenant_id", tenantId);
//根据上级id 系统 查询
if (StrUtil.isNotEmpty(type)) {
queryWrapper.ne("type", type);
@ -146,7 +153,7 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
for (int i = 0; i < listMap.size(); i++) { //遍历表数据
List<Map<String, Object>> childList =
child(listMap.get(i).get("id").toString(), systemcode
, name, isdisplay, type); //循环获取下一子集
, name, isdisplay, type, tenantId); //循环获取下一子集
listMap.get(i).put("children", childList); //添加新列 子集
}
}
@ -165,20 +172,24 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
String parentId = sysMenu.getParentid();
QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
//根据上级id 查询到总数 并累加
long orderno = this.count(queryWrapper.eq("parentid",
parentId)) + 1L;
queryWrapper.eq("parentid", parentId)
.eq(StrUtil.isNotBlank(sysMenu.getTenantId()), "tenant_id", sysMenu.getTenantId());
long orderno = this.count(queryWrapper) + 1L;
// 生成排序号
sysMenu.setOrderno((int) orderno);
// 生成编号
QueryWrapper<SysMenu> queryMaxCode = new QueryWrapper<>();
queryMaxCode.eq("parentid", parentId);
queryMaxCode.eq("parentid", parentId)
.eq(StrUtil.isNotBlank(sysMenu.getTenantId()), "tenant_id", sysMenu.getTenantId());
// 使用 Oracle 兼容的 NVL 函数处理空值
List<Object> maxList = this.listObjs(
queryMaxCode.select("NVL(MAX(code), '0') as code")
.eq("systemcode", sysMenu.getSystemcode())
);
SysMenu parentMenu = sysMenuMapper.selectById(parentId);
SysMenu parentMenu = "0".equals(parentId) ? null : this.getOne(new LambdaQueryWrapper<SysMenu>()
.eq(SysMenu::getId, parentId)
.eq(StrUtil.isNotBlank(sysMenu.getTenantId()), SysMenu::getTenantId, sysMenu.getTenantId()));
// 最大编号转换成int类型
String maxCode = !maxList.isEmpty() ? maxList.getFirst().toString() : "0";
int max = ObjectUtil.isEmpty(maxList) ? 0 :
@ -302,18 +313,25 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
* 返回值说明: 是否更新成功
***********************************/
@Override
public boolean moveOrderno(String parentid, String id, int orderno) {
public boolean moveOrderno(String parentid, String id, int orderno, String tenantId) {
boolean ok = true;
SysMenu sysMenu = this.getById(id); //根据id查询原顺序号
SysMenu sysMenu = this.getOne(new LambdaQueryWrapper<SysMenu>()
.eq(SysMenu::getId, id)
.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, tenantId)); //根据id查询原顺序号
if (sysMenu == null) {
return false;
}
if (sysMenu.getOrderno() > orderno) {
ok = sysMenuMapper.upMoveOrderno(parentid, sysMenu.getOrderno(),
orderno); //根据 父级id 小于原序号 大于等于更改序号
orderno, tenantId); //根据 父级id 小于原序号 大于等于更改序号
} else {
ok = sysMenuMapper.downMoveOrderno(parentid, sysMenu.getOrderno()
, orderno); //根据 父级id 大于原序号 小于等于更改序号
, orderno, tenantId); //根据 父级id 大于原序号 小于等于更改序号
}
UpdateWrapper<SysMenu> updateWrapper = new UpdateWrapper<>();
ok = ok && this.update(updateWrapper.eq("id", id).set("orderno",
ok = ok && this.update(updateWrapper.eq("id", id)
.eq(StrUtil.isNotBlank(tenantId), "tenant_id", tenantId)
.set("orderno",
orderno)); //根据 id修改序号
return ok;
}
@ -345,8 +363,9 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
}
QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
//根据上级id 查询 根据 orderno 正序排序
queryWrapper.eq("parentid", sysMenu.getParentid()).orderByAsc(
"orderno");
queryWrapper.eq("parentid", sysMenu.getParentid())
.eq(StrUtil.isNotBlank(sysMenu.getTenantId()), "tenant_id", sysMenu.getTenantId())
.orderByAsc("orderno");
List<SysMenu> list = this.list(queryWrapper);
for (int i = 0; i < list.size(); i++) {
SysMenu menu = list.get(i);
@ -409,16 +428,20 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
* 返回值说明: 返回菜单树
***********************************/
@Override
public List<Map<String, Object>> getMenuTree(String id) {
public List<Map<String, Object>> getMenuTree(String id, String tenantId) {
// 根据id获取菜单
//List<SysMenu> sysMenus = sysMenuMapper.selectMenuByUserId(id);
List<SysMenu> sysMenuList;
if (StrUtil.isBlank(id)) {
LambdaQueryWrapper<SysMenu> queryWrapper =
new LambdaQueryWrapper<>();
sysMenuList = this.list(queryWrapper.eq(SysMenu::getIsdisplay, "1").ne(SysMenu::getType, "2").eq(SysMenu::getSystemcode, "1").orderByAsc(SysMenu::getOrderno));
sysMenuList = this.list(queryWrapper.eq(SysMenu::getIsdisplay, "1")
.ne(SysMenu::getType, "2")
// .eq(SysMenu::getSystemcode, "1")
.eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, tenantId)
.orderByAsc(SysMenu::getOrderno));
} else {
sysMenuList = sysMenuMapper.selectMenuByUserId(id);
sysMenuList = sysMenuMapper.selectMenuByUserId(id, tenantId);
}
// SysMenu 转换为 Map 并构建树
List<Map<String, Object>> list = sysMenuList.stream()
@ -451,7 +474,7 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
* 返回值说明: 菜单结构树集合
***********************************/
@Override
public List<Map<String, Object>> permissionAssignment(String code,String roleId) {
public List<Map<String, Object>> permissionAssignment(String code, String roleId, String tenantId) {
// String code = sysMenuMapper.getSystemCodeById(roleId);
// if (code == null) {
@ -459,13 +482,13 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
// }
LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysMenu::getSystemcode, code).select(SysMenu::getId,
SysMenu::getParentid, SysMenu::getName).orderByAsc
SysMenu::getParentid, SysMenu::getName).eq(StrUtil.isNotBlank(tenantId), SysMenu::getTenantId, tenantId).orderByAsc
(SysMenu::getOrderno);
List<Map<String, Object>> mapList =
sysMenuMapper.selectMaps(queryWrapper);
List<Map<String, Object>> listAll = ObjectConverterUtil.convertMapFieldsToEntityFormat(SysMenu.class, mapList);
List<String> listRole =
sysMenuMapper.selectMenuByRoleId(roleId);
sysMenuMapper.selectMenuByRoleId(roleId, tenantId);
for (Map<String, Object> map : listAll) {
String id = (String) map.get("id");
if (listRole.contains(id)) {

View File

@ -56,7 +56,8 @@ public class SysOrganizationServiceImpl extends ServiceImpl<SysOrganizationMappe
***********************************/
@Override
public List<Map<String, Object>> getOrgTree(String parentid,
String params) {
String params,
String tenantId) {
SysUser userInfo = userService.getUserInfo();
// 构建权限过滤条件
@ -75,7 +76,9 @@ public class SysOrganizationServiceImpl extends ServiceImpl<SysOrganizationMappe
allowedOrgIds.addAll(stringList);
// 查询这些组织的父级ID
List<SysOrganization> list = sysOrganizationMapper.selectList(
new LambdaQueryWrapper<SysOrganization>().in(SysOrganization::getId, stringList));
new LambdaQueryWrapper<SysOrganization>()
.in(SysOrganization::getId, stringList)
.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, tenantId));
for (SysOrganization org : list) {
if (org.getParentid() != null) {
allowedOrgIds.add(org.getParentid());
@ -90,6 +93,9 @@ public class SysOrganizationServiceImpl extends ServiceImpl<SysOrganizationMappe
if (!allowedOrgIds.isEmpty()) {
queryWrapper.in("id", allowedOrgIds);
}
if (StrUtil.isNotBlank(tenantId)) {
queryWrapper.eq("tenant_id", tenantId);
}
if (StrUtil.isNotEmpty(params)) {
queryWrapper.like("orgname", params);
}
@ -189,13 +195,18 @@ public class SysOrganizationServiceImpl extends ServiceImpl<SysOrganizationMappe
queryWrapper.select("max(orgcode)");
if (StrUtil.isNotEmpty(sysOrganization.getParentid())) {
//根据父级id查询父级信息
parent = this.getById(sysOrganization.getParentid());
parent = this.getOne(new LambdaQueryWrapper<SysOrganization>()
.eq(SysOrganization::getId, sysOrganization.getParentid())
.eq(StrUtil.isNotBlank(sysOrganization.getTenantId()), SysOrganization::getTenantId, sysOrganization.getTenantId()));
queryWrapper.eq("parentid", sysOrganization.getParentid());
} else {
//默认 填写父级id为0
sysOrganization.setParentid("0");
queryWrapper.eq("parentid", "0");
}
if (StrUtil.isNotBlank(sysOrganization.getTenantId())) {
queryWrapper.eq("tenant_id", sysOrganization.getTenantId());
}
List<Object> max = this.listObjs(queryWrapper);
//判断查询是否存在 存在转换成 int 类型并给 codeMax 替换值
if (!max.isEmpty() && max.getFirst() != null) {
@ -233,7 +244,8 @@ public class SysOrganizationServiceImpl extends ServiceImpl<SysOrganizationMappe
***********************************/
@Override
public List<SysOrganization> getOrganizationById(String id,
String orgName) {
String orgName,
String tenantId) {
SysUser userInfo = userService.getUserInfo();
// 收集所有允许的组织ID
@ -258,6 +270,7 @@ public class SysOrganizationServiceImpl extends ServiceImpl<SysOrganizationMappe
// 构建查询条件
LambdaQueryWrapper<SysOrganization> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysOrganization::getParentid, id);
queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, tenantId);
if (StrUtil.isNotBlank(orgName)) {
queryWrapper.like(SysOrganization::getOrgname, orgName);
@ -281,7 +294,7 @@ public class SysOrganizationServiceImpl extends ServiceImpl<SysOrganizationMappe
* 返回值说明: 组织树集合
***********************************/
@Override
public List<Map<String, Object>> getOrgScopeTree(String roleId) {
public List<Map<String, Object>> getOrgScopeTree(String roleId, String tenantId) {
LambdaQueryWrapper<SysOrganization> queryWrapper = new LambdaQueryWrapper<>();
if(!"admin".equals(SecurityUtils.getCurrentUsername())){
@ -300,11 +313,17 @@ public class SysOrganizationServiceImpl extends ServiceImpl<SysOrganizationMappe
queryWrapper.in(SysOrganization::getId, ids);
}
queryWrapper.eq(SysOrganization::getIsvaild, '1');
queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysOrganization::getTenantId, tenantId);
queryWrapper.orderByAsc(SysOrganization::getOrgcode);
List<Map<String, Object>> mapList = this.listMaps(queryWrapper);
List<Map<String, Object>> listMaps = ObjectConverterUtil.convertMapFieldsToEntityFormat(SysOrganization.class, mapList);
// 获取当前角色
SysRole sysRole = sysRoleMapper.selectById(roleId);
SysRole sysRole = sysRoleMapper.selectOne(new QueryWrapper<SysRole>()
.eq("id", roleId)
.eq(StrUtil.isNotBlank(tenantId), "tenant_id", tenantId));
if (sysRole == null) {
return new ArrayList<>();
}
String orgscope = sysRole.getOrgscope();
List<String> ids = new ArrayList<>();
if (StrUtil.isNotBlank(orgscope)) {

View File

@ -47,6 +47,7 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
int codeMax = 0;
DecimalFormat df = new DecimalFormat("000");//四位数字编号
QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(StringUtils.isNotBlank(sysRole.getTenantId()), "tenant_id", sysRole.getTenantId());
List<Object> max = this.listObjs(queryWrapper.select("MAX(rolecode) " +
"rolecode"));// 查询最大的编号
// 存在转换成 int 类型并给 codeMax 替换值
@ -140,9 +141,9 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
@Override
public List<Map> listRoleUsers(String orgid, String username,
String status, String level,
String rolename, String isvaild) {
String rolename, String isvaild, String tenantId) {
return roleMapper.listRoleUsers(orgid, username, status, level,
rolename, isvaild);
rolename, isvaild, tenantId);
}
/***********************************
@ -167,8 +168,8 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
}
@Override
public List<SysRole> selectRoleList(String rolename) {
return roleMapper.selectRoleList(rolename);
public List<SysRole> selectRoleList(String rolename, String tenantId) {
return roleMapper.selectRoleList(rolename, tenantId);
}
}

View File

@ -567,9 +567,10 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
@Override
public Page<SysUser> queryUsers(String orgid,
String username,
String tenantId,
Page<SysUser> page) {
Page<SysUser> mapPage = sysUserMapper.queryUsers(orgid,
username, page);
username, tenantId, page);
mapPage.getRecords().forEach(record -> {
String id = record.getId();
List<SysRole> sysRoles = sysRoleMapper.getRoleByUserId(id);
@ -651,10 +652,11 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
}
@Override
public Page<SysUser> queryPendingAuditUsers(Page<SysUser> page, String name, String regStatus) {
public Page<SysUser> queryPendingAuditUsers(Page<SysUser> page, String name, String regStatus, String tenantId) {
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(SysUser::getRegStatus, "PENDING", "APPROVED", "REJECTED");
queryWrapper.eq(ObjectUtil.isNotEmpty(regStatus), SysUser::getRegStatus, regStatus);
queryWrapper.eq(StrUtil.isNotBlank(tenantId), SysUser::getTenantId, tenantId);
queryWrapper.and(StrUtil.isNotBlank(name), wrapper ->
wrapper.like(SysUser::getNickname, name)
.or()

View File

@ -4,12 +4,26 @@
<mapper namespace="com.yfd.platform.system.mapper.SysMenuMapper">
<!-- 向上调整序号 根据父级id 序号小于原序号 并且 大于等于替换序号-->
<update id="upMoveOrderno">
update sys_menu set orderno=orderno+1 where parentid=#{parentid} and orderno &lt; #{Orderno} and orderno &gt;= #{upOrderno}
update sys_menu
set orderno=orderno+1
where parentid=#{parentid}
and orderno &lt; #{Orderno}
and orderno &gt;= #{upOrderno}
<if test="tenantId != null and tenantId != ''">
and tenant_id = #{tenantId}
</if>
</update>
<!-- 向下调整序号 根据父级id 序号大于原序号 并且 小于等于替换序号-->
<update id="downMoveOrderno">
update sys_menu SET orderno=orderno-1 where parentid=#{parentid} and orderno &gt; #{Orderno} and orderno &lt;= #{downOrderno}
update sys_menu
SET orderno=orderno-1
where parentid=#{parentid}
and orderno &gt; #{Orderno}
and orderno &lt;= #{downOrderno}
<if test="tenantId != null and tenantId != ''">
and tenant_id = #{tenantId}
</if>
</update>
<select id="selectPermsByUserId" resultType="java.lang.String">
@ -47,6 +61,10 @@
WHERE
r.isvaild = 1
AND ru.userid = #{userId}
<if test="tenantId != null and tenantId != ''">
AND m.tenant_id = #{tenantId}
AND r.tenant_id = #{tenantId}
</if>
AND m.isdisplay=1
AND m.type != 2
ORDER BY
@ -63,6 +81,9 @@
WHERE
m.isdisplay = 1
AND rm.roleid= #{id}
<if test="tenantId != null and tenantId != ''">
AND m.tenant_id = #{tenantId}
</if>
ORDER BY
m.orderno ASC
</select>

View File

@ -86,6 +86,10 @@
<if test="isvaild != null">
and c.isvaild=#{isvaild}
</if>
<if test="tenantId != null and tenantId != ''">
and b.tenant_id = #{tenantId}
and c.tenant_id = #{tenantId}
</if>
ORDER BY c.level,b.orgid,b.code
</select>
<!--根据用户id获取角色信息-->
@ -129,6 +133,9 @@
<if test="rolename != null and rolename != ''">
AND r.rolename LIKE '%' || #{rolename} || '%'
</if>
<if test="tenantId != null and tenantId != ''">
AND r.tenant_id = #{tenantId}
</if>
AND r."LEVEL" != '1'
</where>
ORDER BY r."LEVEL" ASC, lastmodifydate ASC

View File

@ -67,6 +67,7 @@
u.phone,
u.avatar,
u.orgid,
u.tenant_id AS tenantId,
u.status,
u.lastmodifier,
u.lastmodifydate
@ -82,6 +83,9 @@
<if test="username != null">
and u.username LIKE '%' || #{username} || '%'
</if>
<if test="tenantId != null and tenantId != ''">
and u.tenant_id = #{tenantId}
</if>
ORDER BY u.lastmodifydate DESC
</select>
<select id="getOrganizationByid" resultType="java.util.Map">

View File

@ -0,0 +1,114 @@
<!-- setup 无法设置组件名称组件名称keepAlive必须 -->
<script lang="ts">
export default {
name: 'Page401'
};
</script>
<script setup lang="ts">
import { reactive, toRefs } from 'vue';
import { useRouter } from 'vue-router';
const state = reactive({
errGif: new URL(`../../assets/401_images/401.gif`, import.meta.url).href,
ewizardClap:
'https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646',
dialogVisible: false
});
const { errGif, ewizardClap, dialogVisible } = toRefs(state);
const router = useRouter();
function back() {
router.back();
}
</script>
<template>
<div class="errPage-container">
<el-button icon="el-icon-arrow-left" class="pan-back-btn" @click="back">
返回
</el-button>
<el-row>
<el-col :span="12">
<h1 class="text-jumbo text-ginormous">Oops!</h1>
gif来源<a href="https://zh.airbnb.com/" target="_blank">airbnb</a> 页面
<h2>你没有权限去该页面</h2>
<h6>如有不满请联系你领导</h6>
<ul class="list-unstyled">
<li>或者你可以去:</li>
<li class="link-type">
<router-link to="/"> 回首页 </router-link>
</li>
<li class="link-type">
<a href="https://www.taobao.com/">随便看看</a>
</li>
<li>
<a href="#" @click.prevent="dialogVisible = true">点我看图</a>
</li>
</ul>
</el-col>
<el-col :span="12">
<img
:src="errGif"
width="313"
height="428"
alt="Girl has dropped her ice cream."
/>
</el-col>
</el-row>
<el-dialog v-model="dialogVisible" title="随便看">
<img :src="ewizardClap" class="pan-img" />
</el-dialog>
</div>
</template>
<style lang="scss" scoped>
.errPage-container {
width: 800px;
max-width: 100%;
margin: 100px auto;
.pan-back-btn {
background: #008489;
color: #fff;
border: none !important;
}
.pan-gif {
margin: 0 auto;
display: block;
}
.pan-img {
display: block;
margin: 0 auto;
width: 100%;
}
.text-jumbo {
font-size: 60px;
font-weight: 700;
color: #484848;
}
.list-unstyled {
font-size: 14px;
li {
padding-bottom: 5px;
}
a {
color: #008489;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
}
</style>

View File

@ -0,0 +1,280 @@
<!-- setup 无法设置组件名称组件名称keepAlive必须 -->
<script lang="ts">
export default {
name: 'Page404'
};
</script>
<script setup lang="ts">
function message() {
return 'The webmaster said that you can not enter this page...';
}
</script>
<template>
<div class="wscn-http404-container">
<div class="wscn-http404">
<div class="pic-404">
<img
class="pic-404__parent"
src="@/assets/404_images/404.png"
alt="404"
/>
<img
class="pic-404__child left"
src="@/assets/404_images/404_cloud.png"
alt="404"
/>
<img
class="pic-404__child mid"
src="@/assets/404_images/404_cloud.png"
alt="404"
/>
<img
class="pic-404__child right"
src="@/assets/404_images/404_cloud.png"
alt="404"
/>
</div>
<div class="bullshit">
<div class="bullshit__oops">OOPS!</div>
<div class="bullshit__info">
All rights reserved
<a
style="color: #20a0ff"
href="https://wallstreetcn.com"
target="_blank"
>wallstreetcn</a
>
</div>
<div class="bullshit__headline">{{ message }}</div>
<div class="bullshit__info">
Please check that the URL you entered is correct, or click the button
below to return to the homepage.
</div>
<a href="" class="bullshit__return-home">Back to home</a>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.wscn-http404-container {
transform: translate(-50%, -50%);
position: absolute;
top: 40%;
left: 50%;
}
.wscn-http404 {
position: relative;
width: 1200px;
padding: 0 50px;
overflow: hidden;
.pic-404 {
position: relative;
float: left;
width: 600px;
overflow: hidden;
&__parent {
width: 100%;
}
&__child {
position: absolute;
&.left {
width: 80px;
top: 17px;
left: 220px;
opacity: 0;
animation-name: cloudLeft;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
&.mid {
width: 46px;
top: 10px;
left: 420px;
opacity: 0;
animation-name: cloudMid;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1.2s;
}
&.right {
width: 62px;
top: 100px;
left: 500px;
opacity: 0;
animation-name: cloudRight;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
@keyframes cloudLeft {
0% {
top: 17px;
left: 220px;
opacity: 0;
}
20% {
top: 33px;
left: 188px;
opacity: 1;
}
80% {
top: 81px;
left: 92px;
opacity: 1;
}
100% {
top: 97px;
left: 60px;
opacity: 0;
}
}
@keyframes cloudMid {
0% {
top: 10px;
left: 420px;
opacity: 0;
}
20% {
top: 40px;
left: 360px;
opacity: 1;
}
70% {
top: 130px;
left: 180px;
opacity: 1;
}
100% {
top: 160px;
left: 120px;
opacity: 0;
}
}
@keyframes cloudRight {
0% {
top: 100px;
left: 500px;
opacity: 0;
}
20% {
top: 120px;
left: 460px;
opacity: 1;
}
80% {
top: 180px;
left: 340px;
opacity: 1;
}
100% {
top: 200px;
left: 300px;
opacity: 0;
}
}
}
}
.bullshit {
position: relative;
float: left;
width: 300px;
padding: 30px 0;
overflow: hidden;
&__oops {
font-size: 32px;
font-weight: bold;
line-height: 40px;
color: #1482f0;
opacity: 0;
margin-bottom: 20px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
&__headline {
font-size: 20px;
line-height: 24px;
color: #222;
font-weight: bold;
opacity: 0;
margin-bottom: 10px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.1s;
animation-fill-mode: forwards;
}
&__info {
font-size: 13px;
line-height: 21px;
color: grey;
opacity: 0;
margin-bottom: 30px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.2s;
animation-fill-mode: forwards;
}
&__return-home {
display: block;
float: left;
width: 110px;
height: 36px;
background: #1482f0;
border-radius: 100px;
text-align: center;
color: #ffffff;
opacity: 0;
font-size: 14px;
line-height: 36px;
cursor: pointer;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.3s;
animation-fill-mode: forwards;
}
@keyframes slideUp {
0% {
transform: translateY(60px);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
}
}
</style>

View File

@ -0,0 +1,997 @@
<template>
<div class="register-container">
<div class="register-wrapper">
<!-- 左侧背景图区域 -->
<div class="left-section">
<div class="slogan">
<p>{{ $t('login.title') }}</p>
</div>
</div>
<!-- 右侧注册表单区域 -->
<div class="right-section">
<a-tabs v-model:activeKey="activeTab" class="register-tabs">
<a-tab-pane key="register" tab="用户注册">
<a-form
:model="registerData"
:rules="registerRules"
layout="horizontal"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 18 }"
class="form-container"
@finish="handleFormFinish"
>
<!-- 账号信息 -->
<div class="form-section">
<div class="section-title">账号信息</div>
<!-- 账号 -->
<a-form-item name="username" label="账&nbsp;&nbsp;号">
<a-input
v-model:value="registerData.username"
placeholder="请输入登录账号4-20个字符"
/>
</a-form-item>
<!-- 密码 -->
<a-form-item
name="password"
label="密&nbsp;&nbsp;码"
:dependencies="['username']"
>
<a-input-password
v-model:value="registerData.password"
placeholder="请设置密码6-20个字符"
/>
</a-form-item>
<!-- 确认密码 -->
<a-form-item name="confirmPassword" label="确认密码">
<a-input-password
v-model:value="registerData.confirmPassword"
placeholder="请再次输入密码"
/>
</a-form-item>
</div>
<!-- 个人信息 -->
<div class="form-section">
<div class="section-title">个人信息</div>
<!-- 真实姓名 -->
<a-form-item name="realName" label="真实姓名">
<a-input
v-model:value="registerData.realName"
placeholder="请输入真实姓名"
/>
</a-form-item>
<!-- 所属单位 -->
<a-form-item name="belongingUnit" label="所属单位">
<a-input
v-model:value="registerData.belongingUnit"
placeholder="请输入所属单位(选填)"
/>
</a-form-item>
<!-- 手机号 -->
<a-form-item name="phone" label="手 机 号">
<a-row class="w-full" :gutter="8">
<a-col :span="16">
<a-input
v-model:value="registerData.phone"
placeholder="请输入11位手机号"
/>
</a-col>
<a-col :span="8">
<a-button
type="primary"
:disabled="smsCountdown > 0"
@click="handleSendSms"
>
{{
smsCountdown > 0 ? `${smsCountdown}s` : '获取验证码'
}}
</a-button>
</a-col>
</a-row>
</a-form-item>
<!-- 短信验证码 -->
<a-form-item name="smsCode" label="验证码">
<a-input
v-model:value="registerData.smsCode"
placeholder="请输入短信验证码"
/>
</a-form-item>
</div>
<!-- 注册按钮 -->
<a-form-item
style="
display: flex;
align-items: center;
justify-content: center;
width: 100%;
"
>
<a-button
type="primary"
size="large"
block
htmlType="submit"
:loading="loading"
style="margin-left: 20px"
>
<span>立即注册</span>
</a-button>
</a-form-item>
<!-- 返回登录 -->
<a-form-item
style="
display: flex;
align-items: center;
justify-content: center;
width: 100%;
"
>
<a-button type="link" size="small" block @click="backToLogin">
已有账号返回登录
</a-button>
<a-button type="link" size="small" block> | </a-button>
<div></div>
<a
href="/file/注册操作手册.docx"
download="注册用户操作手册.docx"
>
<a-button type="link" size="small" block>
注册用户操作手册
</a-button>
</a>
</a-form-item>
</a-form>
</a-tab-pane>
</a-tabs>
<!-- 注册确认弹框 -->
<a-modal
v-model:open="modalVisible"
title="选择所属组织"
width="600px"
:confirm-loading="loading"
@ok="onRegister"
@cancel="handleModalCancel"
:maskClosable="false"
>
<a-form
:model="organizationData"
:rules="organizationRules"
layout="horizontal"
ref="organizationFormRef"
:label-col="{ span: 4 }"
:wrapper-col="{ span: 20 }"
>
<!-- 集团单选字符串 -->
<a-form-item name="groupCode" label="集 团">
<a-select
v-model:value="organizationData.groupCode"
placeholder="请选择集团"
style="width: 100%"
show-search
:filter-option="filterOption"
@change="onGroupChange"
>
<a-select-option
v-for="item in groupList"
:key="item.hycd"
:value="item.hycd"
:label="item.hynm"
>
{{ item.hynm }}
</a-select-option>
</a-select>
</a-form-item>
<!-- 公司单选字符串 -->
<a-form-item name="companyCode" label="公 司">
<a-select
v-model:value="organizationData.companyCode"
placeholder="请选择公司"
style="width: 100%"
show-search
:filter-option="filterOption"
allow-clear
>
<a-select-option
v-for="item in companyList"
:key="item.hycd"
:value="item.hycd"
:label="item.hynm"
>
{{ item.hynm }}
</a-select-option>
</a-select>
</a-form-item>
<!-- 流域多选数组必填 -->
<a-form-item name="rvcdCode" label="流 域" required>
<a-select
v-model:value="organizationData.rvcdCode"
mode="multiple"
placeholder="请选择流域"
style="width: 100%"
show-search
:filter-option="filterOption"
@change="onRvcdChange"
>
<a-select-option
v-for="item in basinList"
:key="item.rvcd"
:value="item.rvcd"
:label="item.rvnm"
>
{{ item.rvnm }}
</a-select-option>
</a-select>
</a-form-item>
<!-- 电站多选数组必填依赖流域 -->
<a-form-item name="stationCode" label="电 站" required>
<a-select
v-model:value="organizationData.stationCode"
mode="multiple"
placeholder="请先选择流域"
:disabled="organizationData.rvcdCode.length === 0"
style="width: 100%"
show-search
:filter-option="filterOption"
>
<a-select-option
v-for="item in stationList"
:key="item.stcd"
:value="item.stcd"
:label="item.ennm"
>
{{ item.ennm }}
</a-select-option>
</a-select>
</a-form-item>
</a-form>
</a-modal>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, onMounted, onUnmounted } from 'vue';
import {
getBasinList,
getGroupList,
getCompanyList,
getStationList,
sendSmsCode,
verifySmsCode,
registerUser,
getAccessToken
} from '@/api/auth';
import { message } from 'ant-design-vue';
import router from '@/router';
import { encrypt } from '@/utils/rsaEncrypt';
//
const registerData = reactive({
//
username: '',
password: '',
confirmPassword: '',
realName: '',
belongingUnit: '',
phone: '',
smsCode: ''
});
const accessToken = ref(''); // access_token
//
const basinList = ref<any[]>([]);
const groupList = ref<any[]>([]);
const companyList = ref<any[]>([]);
const stationList = ref<any[]>([]);
//
const smsCountdown = ref(0);
let smsTimer: any = null;
// ==================== ====================
const organizationData = reactive({
groupCode: '', //
companyCode: '', //
rvcdCode: [], //
stationCode: [] //
});
//
const organizationFormRef = ref();
// ==================== ====================
const organizationRules = {
rvcdCode: [
{
validator: (rule: any, value: any[]) => {
if (!value || value.length === 0) {
return Promise.reject('请至少选择一个流域');
}
return Promise.resolve();
},
trigger: 'change'
}
],
stationCode: [
{
validator: (rule: any, value: any[]) => {
if (!value || value.length === 0) {
return Promise.reject('请至少选择一个电站');
}
return Promise.resolve();
},
trigger: 'change'
}
]
};
//
const registerRules = {
//
username: [
{ required: true, message: '请输入登录账号', trigger: 'blur' },
{ min: 4, max: 20, message: '账号长度4-20个字符', trigger: 'blur' },
{
pattern: /^[a-zA-Z0-9_]+$/,
message: '只能包含字母、数字和下划线',
trigger: 'blur'
}
],
//
password: [
{
required: true,
validator: (rule: any, value: string) => {
if (!value) {
return Promise.reject('请输入密码');
}
// 1. 10
if (value.length < 10) {
return Promise.reject('密码长度不能少于10位');
}
// 2.
const hasUpperCase = /[A-Z]/.test(value);
const hasLowerCase = /[a-z]/.test(value);
const hasNumber = /[0-9]/.test(value);
const hasSpecial = /[^a-zA-Z0-9]/.test(value);
const typeCount = [
hasUpperCase,
hasLowerCase,
hasNumber,
hasSpecial
].filter(Boolean).length;
if (typeCount < 3) {
return Promise.reject(
'密码必须包含大写字母、小写字母、数字、特殊字符中的至少三类'
);
}
// 3.
// 3.1 2
for (let i = 0; i <= value.length - 2; i++) {
if (value[i] === value[i + 1]) {
return Promise.reject(
'密码不能包含2位及以上相同字符的连续重复如11、aa'
);
}
}
// 3.2 2/
for (let i = 0; i <= value.length - 2; i++) {
const char1 = value.charCodeAt(i);
const char2 = value.charCodeAt(i + 1);
//
if (/\d/.test(value[i]) && /\d/.test(value[i + 1])) {
//
if (Math.abs(char2 - char1) === 1) {
return Promise.reject(
'密码不能包含2位及以上连续递增或递减的数字如12、21'
);
}
}
}
// 3.3 2/
for (let i = 0; i <= value.length - 2; i++) {
const char1 = value.charCodeAt(i);
const char2 = value.charCodeAt(i + 1);
//
if (/[a-zA-Z]/.test(value[i]) && /[a-zA-Z]/.test(value[i + 1])) {
//
if (Math.abs(char2 - char1) === 1) {
return Promise.reject(
'密码不能包含2位及以上连续递增或递减的字母如ab、ba'
);
}
}
}
// 4.
// 4.0
const username = registerData.username;
if (!username || username.trim() === '') {
//
return Promise.resolve();
}
const usernameLower = username.toLowerCase();
const passwordLower = value.toLowerCase();
// 4.1
if (passwordLower.includes(usernameLower)) {
return Promise.reject('密码不能包含用户名');
}
// 4.2
const passwordLetters = passwordLower.replace(/[^a-z]/g, '');
// 4.3 >= 3
if (
passwordLetters.length >= 3 &&
usernameLower.includes(passwordLetters)
) {
return Promise.reject('密码的字母部分不能是用户名的子串');
}
// 4.4 3
for (let i = 0; i <= passwordLetters.length - 3; i++) {
const substring = passwordLetters.substring(i, i + 3);
if (usernameLower.includes(substring)) {
return Promise.reject('密码不能与用户名存在明显关联');
}
}
return Promise.resolve();
},
trigger: 'blur'
}
],
//
confirmPassword: [
{ required: true, message: '请再次输入密码', trigger: 'blur' },
{
validator: (rule: any, value: string) => {
if (value && value !== registerData.password) {
return Promise.reject('两次输入的密码不一致');
}
return Promise.resolve();
},
trigger: 'blur'
}
],
//
realName: [
{ required: true, message: '请输入真实姓名', trigger: 'blur' },
{ min: 2, max: 20, message: '姓名长度2-20个字符', trigger: 'blur' }
],
//
//
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{
pattern: /^1[3-9]\d{9}$/,
message: '请输入正确的11位手机号',
trigger: 'blur'
}
],
//
smsCode: [
{ required: true, message: '请输入短信验证码', trigger: 'blur' },
{ len: 6, message: '验证码为6位数字', trigger: 'blur' }
]
};
const loading = ref(false);
const activeTab = ref('register');
const modalVisible = ref(false);
//
const loadGroupList = async () => {
try {
const res = await getGroupList();
groupList.value = res.data || [];
} catch (error) {
// console.error("", error);
}
};
//
const onGroupChange = async () => {
//
// if (value) {
try {
// const res = await getCompanyList(organizationData.groupCode ? organizationData.groupCode : '');
const res = await getCompanyList();
companyList.value = res.data || [];
} catch (error) {
// message.error("");
}
// }
};
//
const onCompanyChange = async () => {
//
// if (value) {
try {
const res = await getBasinList();
basinList.value = res.data || [];
} catch (error) {
// message.error("");
}
// }
};
//
const onBasinChange = async (ids: any) => {
//
// if (value) {
try {
const res = await getStationList(ids);
stationList.value = res.data || [];
} catch (error) {
// message.error("");
}
// }
};
// ==================== ====================
const onRvcdChange = () => {
//
organizationData.stationCode = [];
// ID
if (organizationData.rvcdCode && organizationData.rvcdCode.length > 0) {
onBasinChange({ rvcds: organizationData.rvcdCode });
} else {
//
stationList.value = [];
}
};
//
const handleSendSms = async () => {
//
if (!/^1[3-9]\d{9}$/.test(registerData.phone)) {
message.error('请输入正确的手机号');
return;
}
try {
const res: any = await sendSmsCode(registerData.phone, 1); // type=1
if (res.code == 1) {
return;
}
message.success('验证码已发送');
// 60
smsCountdown.value = 60;
smsTimer = setInterval(() => {
smsCountdown.value--;
if (smsCountdown.value <= 0) {
clearInterval(smsTimer);
smsTimer = null;
}
}, 1000);
} catch (error: any) {
// message.error(error.message || "");
}
};
//
const handleFormFinish = async () => {
//
// const res: any = await verifySmsCode(registerData.phone, registerData.smsCode, 1);
// if (res.code == 1) {
// message.error('')
// return
// }
//
modalVisible.value = true;
};
//
const handleModalCancel = () => {
//
modalVisible.value = false;
//
organizationData.groupCode = '';
organizationData.companyCode = '';
organizationData.rvcdCode = [];
organizationData.stationCode = [];
//
organizationFormRef.value?.clearValidate();
};
//
const onRegister = async () => {
//
try {
await organizationFormRef.value.validate();
} catch (error) {
// message.error("");
return; //
}
loading.value = true;
try {
//
const encryptedPassword = encrypt(registerData.password);
//
const registerParams: any = {
type: 1, //
phone: registerData.phone, //
code: registerData.smsCode, //
username: registerData.username, //
password: encryptedPassword, //
realName: registerData.realName //
};
//
if (registerData.belongingUnit) {
registerParams.belongingUnit = registerData.belongingUnit;
}
//
if (organizationData.groupCode) {
registerParams.groupCode = organizationData.groupCode;
}
//
if (organizationData.companyCode) {
registerParams.companyCode = organizationData.companyCode;
}
//
if (organizationData.rvcdCode && organizationData.rvcdCode.length > 0) {
registerParams.rvcdCode = organizationData.rvcdCode.join(',');
}
//
if (
organizationData.stationCode &&
organizationData.stationCode.length > 0
) {
registerParams.stationCode = organizationData.stationCode.join(',');
}
//
const res1: any = await registerUser(registerParams);
if (res1.code == 1) {
message.error('注册失败,请重试');
return;
}
message.success('注册成功,等待管理员审核');
//
modalVisible.value = false;
//
setTimeout(() => {
router.push({ path: '/login' });
}, 1500);
} catch (error: any) {
//
// if (error.message && error.message.includes('')) {
// message.error("");
// } else {
// message.error(error.message || "");
// }
} finally {
loading.value = false;
}
};
//
const backToLogin = () => {
router.push({ path: '/login' });
};
const init = async () => {
try {
const res: any = await getAccessToken();
if (res.code == 1) {
message.error('获取令牌失败,请重试');
return;
}
localStorage.setItem('register-token', res.data.registerToken);
accessToken.value = res.data.accessToken;
loadGroupList();
onGroupChange();
onCompanyChange();
} catch (error) {
// message.error("");
}
};
//
onMounted(() => {
init();
// modalVisible.value = true
});
//
onUnmounted(() => {
if (smsTimer) {
clearInterval(smsTimer);
smsTimer = null;
}
});
const filterOption = (inputValue: string, option: any) => {
if (!option.label) return false;
return option.label.indexOf(inputValue) !== -1;
};
</script>
<style scoped lang="scss">
.register-container {
margin: 0 auto;
position: relative;
width: 100%;
height: 100%;
min-width: 1200px; //
background-color: #fff;
.register-wrapper {
position: relative;
width: 100%;
height: 100%;
min-height: 600px;
background: url('@/assets/images/bg_sjtb.png');
background-repeat: no-repeat;
background-size: cover; // cover
background-position: center; //
}
//
.left-section {
.slogan {
position: absolute;
top: 20%;
left: 5%; //
width: 40vw; // 使
max-width: 700px; //
min-width: 300px; //
color: #040504;
font-size: clamp(24px, 3vw, 40px); //
line-height: 1.5;
p {
margin: 0;
word-wrap: break-word; //
}
}
}
//
.right-section {
position: absolute;
right: 5%; // right
top: 50%; //
transform: translateY(-50%); //
width: clamp(380px, 30vw, 500px); //
min-height: 600px; //
max-height: 90vh; // 90%
border-radius: 8px; //
padding: clamp(15px, 2vw, 24px) clamp(15px, 2vw, 24px); //
padding-top: 0 !important;
background-color: rgba(255, 255, 255, 0.98); //
overflow-y: auto;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); //
//
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.2);
border-radius: 3px;
}
&::-webkit-scrollbar-track {
background-color: transparent;
}
:deep(.ant-tabs-nav) {
height: auto; //
margin-bottom: 16px;
}
//
.form-section {
margin-bottom: clamp(12px, 1.5vh, 20px); //
.section-title {
font-size: clamp(13px, 1.2vw, 15px); //
font-weight: 600;
color: #333;
padding-left: 10px;
margin-bottom: clamp(8px, 1vh, 12px);
padding-bottom: clamp(6px, 0.8vh, 10px);
border-bottom: 1px solid #e8e8e8;
}
}
:deep(.ant-form-item) {
margin-bottom: clamp(10px, 1.2vh, 16px); //
}
:deep(.ant-form-item-label) {
text-align: right !important;
line-height: 32px;
> label {
font-size: clamp(12px, 1vw, 14px); //
color: #333;
white-space: nowrap;
display: inline-block;
&::after {
content: ':';
}
}
}
:deep(.ant-input),
:deep(.ant-input-password) {
font-size: clamp(12px, 1vw, 14px); //
}
:deep(.ant-btn) {
font-size: clamp(12px, 1vw, 14px); //
}
:deep(.ant-radio-group) {
display: flex;
gap: clamp(12px, 1.5vw, 20px); //
}
:deep(.ant-form-item-control-input-content) {
display: flex;
align-items: center;
}
}
}
// -
@media (max-width: 1400px) {
.register-container {
.left-section {
.slogan {
left: 3%;
width: 45vw;
font-size: clamp(20px, 2.5vw, 32px);
}
}
.right-section {
right: 3%;
width: clamp(350px, 35vw, 450px);
}
}
}
//
@media (min-width: 1401px) and (max-width: 1920px) {
.register-container {
.left-section {
.slogan {
left: 5%;
width: 40vw;
}
}
.right-section {
right: 5%;
width: clamp(380px, 30vw, 480px);
}
}
}
//
@media (min-width: 1921px) {
.register-container {
.left-section {
.slogan {
left: 8%;
width: 35vw;
font-size: clamp(32px, 3.5vw, 48px);
}
}
.right-section {
right: 8%;
width: clamp(420px, 28vw, 550px);
padding: 24px 32px;
}
}
}
//
@media (max-width: 1200px) {
.register-container {
.left-section {
.slogan {
display: none; //
}
}
.right-section {
left: 50%;
right: auto;
transform: translate(-50%, -50%); //
width: clamp(320px, 90vw, 420px);
}
}
}
// 125%150%
@media (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {
.register-container {
.right-section {
padding: clamp(12px, 1.5vw, 20px);
.form-section {
margin-bottom: clamp(10px, 1.2vh, 16px);
}
:deep(.ant-form-item) {
margin-bottom: 8px;
}
}
}
}
//
@media (orientation: landscape) and (max-height: 700px) {
.register-container {
.right-section {
max-height: 95vh;
padding: 10px 15px;
.form-section {
margin-bottom: 8px;
.section-title {
margin-bottom: 6px;
padding-bottom: 6px;
font-size: 13px;
}
}
:deep(.ant-form-item) {
margin-bottom: 8px;
}
}
}
}
</style>

View File

@ -643,7 +643,8 @@ onMounted(() => {
<template #default="scope">
<span v-if="scope.row.systemcode == '1'">Web端</span>
<span v-else-if="scope.row.systemcode == '2'">手机App</span>
<span v-else>Pad端</span>
<span v-else-if="scope.row.systemcode == '3'">Pad端</span>
<span v-else-if="scope.row.systemcode == '4'">数据填报</span>
</template>
</el-table-column>
<!-- <el-table-column label="图标" width="100" prop="icon" align="center">

View File

@ -7,7 +7,7 @@ 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://10.84.121.127:8093'
# 测试环境
# VITE_APP_BASE_URL = 'http://172.16.21.142:8093'
# VITE_APP_BASE_URL = 'http://172.16.21.142:8096'

View File

@ -0,0 +1,17 @@
import request from '@/utils/request';
export function getFishResourceList(data) {
return request({
url: '/fpr/fishDic/GetKendoList',
method: 'post',
data
});
}
export function getFishResourceZYList(data) {
return request({
url: '/fpr/fishDic/zy/GetKendoList',
method: 'post',
data
});
}

View File

@ -2,7 +2,7 @@ import request from '@/utils/request';
//生态流量达标情况
export function qgcetQgcStaticData(data: any) {
return request({
url: '/api/wmp-eng-server/eng/eq/interval/qgc/getQgcStaticData',
url: '/eq/interval/qgc/getQgcStaticData',
method: 'post',
data
});
@ -10,7 +10,7 @@ export function qgcetQgcStaticData(data: any) {
//tabs 日
export function dayGetKendoListCust(data: any) {
return request({
url: '/api/wmp-eng-server/eng/eq/interval/qgc/day/GetKendoListCust',
url: '/eq/interval/qgc/day/GetKendoListCust',
method: 'post',
data
});
@ -18,7 +18,7 @@ export function dayGetKendoListCust(data: any) {
//tabs 小时
export function hourGetKendoListCust(queryParams: any) {
return request({
url: '/api/wmp-eng-server/eng/eq/interval/qgc/hour/GetKendoListCust',
url: '/eq/interval/qgc/hour/GetKendoListCust',
method: 'post',
data: queryParams
});
@ -26,7 +26,7 @@ export function hourGetKendoListCust(queryParams: any) {
//接入过生态流量数据的电站
export function evnmAutoMonitorGetKendoListCust(queryParams: any) {
return request({
url: '/api/dec-lygk-base-server/base/evnmAutoMonitor/GetKendoListCust',
url: '/eq/evnmAutoMonitor/GetKendoListCust',
method: 'post',
data: queryParams
});
@ -34,15 +34,63 @@ export function evnmAutoMonitorGetKendoListCust(queryParams: any) {
//获取电站
export function vmsstbprptGetKendoList(queryParams: any) {
return request({
url: '/api/dec-lygk-base-server/base/vmsstbprpt/GetKendoList',
url: '/eq/vmsstbprpt/GetKendoList',
method: 'post',
data: queryParams
});
}
//生态流量达标情况 /api/wmp-eng-server/eng/eq/qecRateCount
//生态流量达标情况
export function eqqecRateCount(queryParams: any) {
return request({
url: '/api/wmp-eng-server/eng/eq/qecRateCount',
url: '/eq/qecRateCount',
method: 'post',
data: queryParams
});
}
// 获取生态流量达标率按基地
export function intervalGetKendoListCust(queryParams: any) {
return request({
url: '/eq/interval/GetKendoListCust',
method: 'post',
data: queryParams
});
}
// 获取生态流量达标率按性能
export function eqGetKendoListCust(queryParams: any) {
return request({
url: '/api/wmp-eng-server/eng/to/eq/GetKendoListCust',
method: 'post',
data: queryParams
});
}
//生态流量沿程变化
export function qgcHourVGetKendoListCust(queryParams: any) {
return request({
url: '/eq/engalong/statistics/qgcHourV/GetKendoListCust',
method: 'post',
data: queryParams
});
}
//根据流域获取电站
export function wbsbGetKendoList(queryParams: any) {
return request({
url: '/eq/wbsb/GetKendoList',
method: 'post',
data: queryParams
});
}
//生态流量泄放方式
export function msstbprptGetKendoList(queryParams: any) {
return request({
url: '/eq/msstbprpt/GetKendoList',
method: 'post',
data: queryParams
});
}
//根据流域获取电站
export function qgcgetEngLimit(queryParams: any) {
return request({
url: '/api/wmp-eng-server/eng/engalong/statistics/qgc/getEngLimit',
method: 'post',
data: queryParams
});

View File

@ -43,7 +43,7 @@
:allow-clear="item.fieldProps?.allowClear"
:presets="item.presets"
style="width: 100%"
@change="(val) => triggerManualValuesChange(item.name, val)"
@change="val => triggerManualValuesChange(item.name, val)"
/>
<!-- 日期范围选择器 -->
@ -58,7 +58,7 @@
:allow-clear="item.fieldProps?.allowClear"
:presets="item.presets"
style="width: 100%"
@change="(val) => triggerManualValuesChange(item.name, val)"
@change="val => triggerManualValuesChange(item.name, val)"
/>
<!-- 普通输入框 -->
@ -68,11 +68,16 @@
:placeholder="item.placeholder || '请输入'"
:allow-clear="item.fieldProps?.allowClear"
:style="{ width: item.width ? item.width + 'px' : '200px' }"
@change="(e) => triggerManualValuesChange(item.name, e.target.value)"
@change="
e => triggerManualValuesChange(item.name, e.target.value)
"
/>
<!-- 电站下拉框 -->
<div class="flex gap-[10px]" v-else-if="item.type === 'waterStation'">
<div
class="flex gap-[10px]"
v-else-if="item.type === 'waterStation'"
>
<a-form-item-rest>
<!-- 基地下拉框 -->
<!-- <a-select
@ -103,7 +108,11 @@
:loading="shuJuTianBaoStore.lyLoading"
:filter-option="filterOption"
style="width: 135px"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto', minWidth: '360px' }"
:dropdown-style="{
maxHeight: '400px',
overflow: 'auto',
minWidth: '360px'
}"
>
<a-select-option
v-for="opt in shuJuTianBaoStore.lyOption"
@ -168,8 +177,9 @@
v-model:value="formData[item.name]"
:placeholder="item.placeholder || '请选择'"
:allow-clear="item.fieldProps?.allowClear"
:loading="item.loading || false"
:style="{ width: item.width ? item.width + 'px' : '200px' }"
@change="(val) => triggerManualValuesChange(item.name, val)"
@change="val => triggerManualValuesChange(item.name, val)"
show-search
:filter-option="filterOption"
>
@ -195,13 +205,13 @@
item.fieldNames || {
label: 'label',
value: 'value',
children: 'children',
children: 'children'
}
"
:show-search="item.showSearch !== false"
:tree-checkable="item.treeCheckable"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
@change="(val) => triggerManualValuesChange(item.name, val)"
@change="val => triggerManualValuesChange(item.name, val)"
/>
<!-- 单选框 -->
@ -209,9 +219,15 @@
v-else-if="item.type === 'Radio'"
v-model:value="formData[item.name]"
:style="{ width: item.width ? item.width + 'px' : '200px' }"
@change="(e) => triggerManualValuesChange(item.name, e.target.value)"
@change="
e => triggerManualValuesChange(item.name, e.target.value)
"
>
<a-radio v-for="opt in item.options" :key="opt.value" :value="opt.value">
<a-radio
v-for="opt in item.options"
:key="opt.value"
:value="opt.value"
>
{{ opt.label }}
</a-radio>
</a-radio-group>
@ -245,16 +261,16 @@
</template>
<script lang="ts" setup>
import { ref, computed, reactive, watch, onMounted, nextTick } from "vue";
import { useShuJuTianBaoStore } from "@/store/modules/shuJuTianBao";
import { ref, computed, reactive, watch, onMounted, nextTick } from 'vue';
import { useShuJuTianBaoStore } from '@/store/modules/shuJuTianBao';
const shuJuTianBaoStore = useShuJuTianBaoStore();
// --- ---
export interface SearchItem {
type?: "Input" | "Select" | "TreeSelect" | "DataPicker" | string;
type?: 'Input' | 'Select' | 'TreeSelect' | 'DataPicker' | string;
name: string;
label: string;
picker?: "year" | "month" | "date" | "week";
picker?: 'year' | 'month' | 'date' | 'week';
fieldProps?: any;
placeholder?: string;
span?: number;
@ -292,13 +308,13 @@ interface Props {
const props = withDefaults(defineProps<Props>(), {
initialValues: () => ({}),
showSearch: true,
showReset: true,
showReset: true
});
const emit = defineEmits<{
(e: "finish", values: any): void;
(e: "valuesChange", changedValues: any, allValues: any): void;
(e: "reset"): void;
(e: 'finish', values: any): void;
(e: 'valuesChange', changedValues: any, allValues: any): void;
(e: 'reset'): void;
}>();
const formRef = ref<any>();
@ -311,7 +327,7 @@ const filterOption = (inputValue: string, option: any) => {
};
// 2. false/null/undefined
const validSearchList = computed(() => {
return props.searchList.filter((item) => item);
return props.searchList.filter(item => item);
});
// --- ---
@ -319,14 +335,14 @@ const initForm = () => {
const initial = JSON.parse(JSON.stringify(props.initialValues || {}));
// 1. formData
Object.keys(formData).forEach((key) => delete formData[key]);
Object.keys(formData).forEach(key => delete formData[key]);
// 2.
Object.assign(formData, initial);
// 3. searchList false/null/undefined
validSearchList.value.forEach((item) => {
if (item.type == "waterStation") {
validSearchList.value.forEach(item => {
if (item.type == 'waterStation') {
//
// shuJuTianBaoStore.getBaseOption();
shuJuTianBaoStore.getSelectForOption();
@ -334,7 +350,7 @@ const initForm = () => {
}
if (item.fieldProps?.required) {
rules[item.name] = [
{ required: true, message: `${item.label}不能为空`, trigger: "blur" },
{ required: true, message: `${item.label}不能为空`, trigger: 'blur' }
];
}
});
@ -350,7 +366,7 @@ const triggerManualValuesChange = (changedKey: string, newValue: any) => {
const changedValues = { [changedKey]: newValue };
//
// 使 {...formData}
emit("valuesChange", changedValues, { ...formData });
emit('valuesChange', changedValues, { ...formData });
};
// const dataDimensionDataChange = (value: any) => {
@ -364,24 +380,24 @@ const triggerManualValuesChange = (changedKey: string, newValue: any) => {
const lyChange = (value: any) => {
formData.rvcd = value;
formData.rstcd = "";
formData.rstcd = '';
shuJuTianBaoStore.getEngOption(formData.rvcd);
// valuesChange a-form-item-rest
triggerManualValuesChange("rvcd", formData.rvcd);
triggerManualValuesChange('rvcd', formData.rvcd);
};
const stcdIdChange = (value: any) => {
if (props.zhujianfujian == "fu") {
if (props.zhujianfujian == 'fu') {
formData.rstcd = value;
shuJuTianBaoStore.getFpssOption(formData.rvcd, value);
// valuesChange
triggerManualValuesChange("rstcd", formData.rstcd);
triggerManualValuesChange('rstcd', formData.rstcd);
} else {
formData.stcd = value;
shuJuTianBaoStore.getFpssOption(formData.rvcd, value);
// valuesChange
triggerManualValuesChange("stcd", formData.stcd);
triggerManualValuesChange('stcd', formData.stcd);
}
};
@ -391,7 +407,7 @@ onMounted(() => {
watch(
() => props.initialValues,
(newVal) => {
newVal => {
if (newVal && formRef.value) {
formRef.value.setFieldsValue(newVal);
Object.assign(formData, newVal);
@ -403,11 +419,11 @@ watch(
// --- ---
const handleFinish = (values: any) => {
const finalValues = { ...formData, ...values };
emit("finish", finalValues);
emit('finish', finalValues);
};
const handleValuesChange = (changedValues: any, allValues: any) => {
emit("valuesChange", changedValues, allValues);
emit('valuesChange', changedValues, allValues);
};
const handleReset = () => {
@ -416,7 +432,7 @@ const handleReset = () => {
nextTick(() => {
initForm();
});
emit("reset");
emit('reset');
}
};
@ -424,7 +440,7 @@ defineExpose({
form: formRef,
formData,
reset: handleReset,
submit: () => formRef.value?.submit(),
submit: () => formRef.value?.submit()
});
</script>

View File

@ -9,6 +9,7 @@
:pagination="paginationConfig"
:scroll="scrollConfig"
:row-key="rowKey"
:customRow="customRow"
@change="handleTableChange"
>
<!-- 合计行插槽 -->
@ -85,6 +86,7 @@ const emit = defineEmits<{
e: 'sort-change',
sortInfo: { field: string; order: 'ascend' | 'descend' | null }
): void;
(e: 'row-click', record: any): void;
}>();
// --- State ---
@ -228,6 +230,17 @@ const handleTableChange = (pag: any, filters: any, sorter: any) => {
getList();
}
};
const handleRowClick = (record: any) => {
emit('row-click', record);
};
const customRow = (record: any) => {
return {
onClick: () => {
handleRowClick(record);
}
};
};
const reset = () => {
page.value = 1;
@ -432,4 +445,9 @@ watch(
::v-deep(.ant-table-tbody > tr > td) {
border-bottom: 1px solid #f0f0f0;
}
:deep(.ant-pagination) {
.ant-select {
width: 100px;
}
}
</style>

View File

@ -994,22 +994,22 @@ const wtPointColumns: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '建成日期',
filed: 'jcdt',
@ -1070,22 +1070,22 @@ const FhWpPointColumns: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '建成日期',
filed: 'jcdt',
@ -1259,22 +1259,22 @@ const FhZQPointColumns: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '建成日期',
filed: 'jcdt',
@ -1328,22 +1328,22 @@ const FPPointColumns: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '开工日期',
@ -1507,22 +1507,22 @@ const FPPointColumns1: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '开工日期',
@ -1766,22 +1766,22 @@ const FPPointColumns2: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '开工日期',
@ -1971,22 +1971,22 @@ const FPPointColumns4: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '开工日期',
@ -2190,22 +2190,22 @@ const FPPointColumns5: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '开工日期',
@ -2254,22 +2254,22 @@ const FBPointColumns: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '开工日期',
@ -2420,22 +2420,22 @@ const VaPointColumns: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '开工日期',
@ -2551,22 +2551,22 @@ const VPPointColumns: Array<any> = [
format: 'YYYY-MM-DD',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '建成日期',
filed: 'jcdt',
@ -2644,22 +2644,22 @@ const wePointColumns: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '',
filed: '',
@ -2684,22 +2684,22 @@ const waPointColumns: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '监测方式',
filed: 'mwayName',
@ -2759,22 +2759,22 @@ const StinfoAiVidoPointColumns: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '监控点地址',
filed: 'stlc',
@ -2822,22 +2822,22 @@ const DwPointColumns: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '所属电站',
filed: 'ennm',
@ -3006,22 +3006,22 @@ const DwFivePointColumns: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '所属电站',
filed: 'ennm',
@ -3176,22 +3176,22 @@ const DwSixPointColumns: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '所属电站',
filed: 'ennm',
@ -3325,22 +3325,22 @@ const DwOnePointColumns: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '所属电站',
filed: 'ennm',
@ -3486,22 +3486,22 @@ const EQPointColumns2: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '所属电站',
filed: 'ennm',
@ -3619,22 +3619,22 @@ const EQPointColumns5: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '所属电站',
filed: 'ennm',
@ -3723,22 +3723,22 @@ const EQPointColumns3: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '所属电站',
filed: 'ennm',
@ -3857,22 +3857,22 @@ const EQPointColumns4: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '所属电站',
filed: 'ennm',
@ -3990,22 +3990,22 @@ const EQPointColumns1: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '所属电站',
filed: 'ennm',
@ -4123,22 +4123,22 @@ const EQPointColumns7: Array<any> = [
type: 'select',
url: ''
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: ''
},
// {
// name: '经度(°)',
// filed: 'lgtd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
// {
// name: '纬度(°)',
// filed: 'lttd',
// visible: true,
// type: 'number',
// toFixed: 6,
// url: ''
// },
{
name: '所属电站',
filed: 'ennm',

View File

@ -683,9 +683,11 @@ const handleFocus = () => {
// Handle focus
};
const filterOption = (input: string, option?: { value: string }) => {
const filterOption = (input: string, option?: { label: string; value: string }) => {
if (!option) return false;
return option.value.toLowerCase().includes(input.toLowerCase());
const label = option.label?.toLowerCase() || '';
const value = option.value?.toLowerCase() || '';
return label.includes(input.toLowerCase()) || value.includes(input.toLowerCase());
};
//
@ -725,6 +727,16 @@ const emitAllValues = () => {
selectedNodeExtra: selectedNodeExtra.value
};
//
if (datetimeValue.value) {
// 使 format picker
const format =
props.datetimePicker.format ||
getDefaultFormat(props.datetimePicker.picker);
payload.datetime = datetimeValue.value.format(format);
} else {
payload.datetime = null;
}
//
if (datetimeValue.value) {
// 使 format picker

View File

@ -88,7 +88,7 @@
</div>
<!-- 详情弹窗 -->
<a-modal v-model:open="detailModalVisible" :title="`${detailData.stnm || ''} 详细信息`" width="80%" :footer="null"
<a-modal v-model:open="detailModalVisible" :title="`${detailData.stnm || ''} 详细信息`" width="1536px" :footer="null"
@cancel="handleDetailModalClose">
<HJMZDTwoLays :tc="{
stcd: detailData.stcd || '',

View File

@ -63,7 +63,7 @@ const customTransform = (res: any) => {
//
const handleViewDetail = (record: any) => {
modelStore.modalVisible = true;
modelStore.params.sttp = "VD_FBFM";
modelStore.params.sttp = record.sttpCode;
modelStore.title = record.stnm ;
modelStore.params.stcd = record.stcd;
}

View File

@ -1,11 +1,21 @@
<!-- SidePanelItem.vue -->
<template>
<div>
<SidePanelItem title="生态流量限值沿程变化" :select="select" :datetimePicker="datetimePicker" >
<!-- 图表容器 -->
<div ref="chartRef" style="width: 100%; height: 400px;"></div>
</SidePanelItem>
</div>
<div>
<SidePanelItem
title="生态流量限值沿程变化"
:select="select"
:datetimePicker="datetimePicker"
@update-values="handlePanelChange1"
>
<!-- 图表容器 -->
<div class="chart-container">
<a-spin :spinning="loading" tip="加载中...">
<div ref="chartRef" class="chart-wrapper" :class="{ 'has-data': chartData.length > 0 }"></div>
<a-empty v-if="!loading && chartData.length === 0" description="暂无数据" />
</a-spin>
</div>
</SidePanelItem>
</div>
</template>
<script lang="ts" setup>
@ -13,191 +23,327 @@ import { ref, onMounted, computed, watch, onBeforeUnmount } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
import dayjs from 'dayjs';
import { wbsbGetKendoList, qgcgetEngLimit } from '@/api/stll';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { useModelStore } from '@/store/modules/model';
const modelStore = useModelStore();
//
defineOptions({
name: 'xieFangFenBu'
name: 'xieFangFenBu'
});
const select = ref({
show: true,
value: undefined,
options: [
const JidiSelectEventStore = useJidiSelectEventStore();
let wbsCode = ref('');
]
const select = ref({
show: true,
value: undefined,
options: [],
picker: undefined,
format: undefined
});
const datetimePicker = ref({
show: true,
value: undefined,
format: 'YYYY-MM', //YYYY-MM-DD HH
picker: 'month' //date | week | month | quarter | year
show: true,
value: dayjs().format('YYYY-MM'), //
format: 'YYYY-MM', //YYYY-MM-DD HH
picker: 'month', //date | week | month | quarter | year
options: [] // options
});
//
const chartData = ref([
{ stnm: '站点A001', qecLimit: 120.5 },
{ stnm: '站点B002', qecLimit: 135.8 },
{ stnm: '站点C003', qecLimit: 98.3 },
{ stnm: '站点D004', qecLimit: 142.6 },
{ stnm: '站点E005', qecLimit: 115.2 },
{ stnm: '站点F006', qecLimit: 128.9 },
{ stnm: '站点G007', qecLimit: 105.4 },
{ stnm: '站点H008', qecLimit: 138.7 },
{ stnm: '站点I009', qecLimit: 122.1 },
{ stnm: '站点J010', qecLimit: 145.3 },
{ stnm: '站点K011', qecLimit: 110.6 },
{ stnm: '站点L012', qecLimit: 132.4 },
{ stnm: '站点M013', qecLimit: 118.9 },
{ stnm: '站点N014', qecLimit: 140.2 },
{ stnm: '站点O015', qecLimit: 125.7 }
]);
//
const chartData = ref([]);
//
const loading = ref(false);
//
const flowUnit = ref('m³/s');
//
const generateModerateColor = () => {
const hue = Math.floor(Math.random() * 360);
const saturation = 50 + Math.floor(Math.random() * 30); // 50-80%
const lightness = 45 + Math.floor(Math.random() * 20); // 45-65%
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
};
//
const chartOption = computed<EChartsOption>(() => {
const dataLength = chartData.value.length;
const dataLength = chartData.value.length;
return {
legend: {
data: ['生态流量限值'],
center: true,
icon: 'rect',
itemHeight: 3
},
grid: {
top: 40,
left: 40,
right: 20,
bottom: 60
},
tooltip: {
trigger: 'axis',
confine: true,
formatter: function (params: any) {
if (!params || params.length === 0) return '';
const value = params[0].value ?? '-';
return `<h3 style="color:#FFF">${params[0].name}</h3>
return {
legend: {
data: ['生态流量限值'],
center: true,
icon: 'rect',
itemHeight: 3
},
grid: {
top: 40,
left: 40,
right: 20,
bottom: 60
},
tooltip: {
trigger: 'axis',
confine: true,
formatter: function (params: any) {
if (!params || params.length === 0) return '';
const value = params[0].value ?? '-';
return `<h3 style="color:#FFF">${params[0].name}</h3>
<div>${params[0].marker}生态流量限值: &nbsp;&nbsp;&nbsp;&nbsp;<span style="float:right">${value} ${flowUnit.value}</span></div>`;
},
axisPointer: {
type: 'line'
}
},
xAxis: {
type: 'category',
data: chartData.value.map((item: any) => item.stnm),
axisLabel: {
interval: dataLength > 12 ? 2 : 0,
rotate: 0,
formatter: (value: string, index: number) => {
const displayText = value.substring(0, 6) + (value.length > 6 ? '...' : '');
},
axisPointer: {
type: 'line'
}
},
xAxis: {
type: 'category',
data: chartData.value.map((item: any) => item.stnm),
axisLabel: {
interval: dataLength > 12 ? 2 : 0,
rotate: 0,
formatter: (value: string, index: number) => {
const displayText =
value.substring(0, 6) + (value.length > 6 ? '...' : '');
if (dataLength === 2) {
return `{a|${displayText}}`;
} else if (index % 2 !== 0) {
//
return `{a|${displayText}}`;
} else {
//
return '\n{b|}' + `{b|${displayText}}`;
}
},
rich: {
a: {
height: 20,
align: 'center'
},
b: {
height: 30,
align: 'center'
}
}
},
axisTick: {
show: false
}
if (dataLength === 2) {
return `{a|${displayText}}`;
} else if (index % 2 !== 0) {
//
return `{a|${displayText}}`;
} else {
//
return '\n{b|}' + `{b|${displayText}}`;
}
},
yAxis: [{
type: 'value',
name: `流量(${flowUnit.value})`
}],
dataZoom: [
{
type: 'inside',
show: false
},
{
type: 'slider',
show: false
}
],
series: [
{
name: '生态流量限值',
type: 'line',
data: chartData.value.map((item: any) => item.qecLimit),
smooth: false,
showSymbol: true,
symbolSize: 6
}
],
color: [generateModerateColor()]
};
rich: {
a: {
height: 20,
align: 'center'
},
b: {
height: 30,
align: 'center'
}
}
},
axisTick: {
show: false
}
},
yAxis: [
{
type: 'value',
name: `流量(${flowUnit.value})`
}
],
dataZoom: [
{
type: 'inside',
show: false
},
{
type: 'slider',
show: false
}
],
series: [
{
name: '生态流量限值',
type: 'line',
data: chartData.value.map((item: any) => ({
value: item.qecLimit,
stcd: item.stcd,
stnm: item.stnm
})),
smooth: false,
showSymbol: true,
symbolSize: 6,
itemStyle: {
color: '#f7a737'
},
lineStyle: {
color: '#f7a737'
}
}
],
color: ['#f7a737']
};
});
//
let chartInstance: echarts.ECharts | null = null;
const chartRef = ref<HTMLDivElement>();
//
const handleChartClick = (params: any) => {
// debugger
console.log('点击数据点:', params);
const { name, value, data } = params;
modelStore.modalVisible = true;
modelStore.params.sttp ='ENG';
modelStore.title = name ;
modelStore.params.stcd = data?.stcd
modelStore.params.eqtp = 'QEC';
// data
console.log(`站点: ${name}, 流量: ${value} ${flowUnit.value}, stcd: ${data?.stcd}`);
};
//
const initChart = () => {
if (!chartRef.value) {
console.warn('图表容器未找到');
return;
}
if (!chartRef.value) {
console.warn('图表容器未找到');
return;
}
console.log('开始初始化图表...');
chartInstance = echarts.init(chartRef.value);
chartInstance.setOption(chartOption.value);
console.log('图表初始化完成');
console.log('开始初始化图表...');
chartInstance = echarts.init(chartRef.value);
chartInstance.setOption(chartOption.value);
//
window.addEventListener('resize', handleResize);
//
chartInstance.on('click', handleChartClick);
console.log('图表初始化完成');
//
window.addEventListener('resize', handleResize);
};
//
const handleResize = () => {
chartInstance?.resize();
chartInstance?.resize();
};
//
watch(chartOption, (newOption) => {
if (chartInstance) {
chartInstance.setOption(newOption, true);
}
watch(chartOption, newOption => {
if (chartInstance) {
chartInstance.setOption(newOption, true);
}
});
onMounted(() => {
initChart();
//
watch(chartData, (newData) => {
if (chartInstance && newData.length === 0) {
chartInstance.clear();
}
});
onMounted(async () => {
await selectdata();
await getEchartsData();
initChart();
});
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
chartInstance = null;
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
chartInstance = null;
});
const selectdata = async () => {
try {
let params = {
filter: {
logic: 'and',
filters: [
{
field: 'wbsType',
operator: 'eq',
dataType: 'string',
value: 'PSB_RVCD'
},
{
field: 'objId',
operator: 'eq',
dataType: 'string',
value: wbsCode.value
}
]
},
group: [
{
dir: 'asc',
field: 'orderIndex'
},
{
dir: 'asc',
field: 'wbsCode'
},
{
dir: 'asc',
field: 'wbsName'
}
],
groupResultFlat: 'true'
};
const res = await wbsbGetKendoList(params);
if (res.data?.data && res.data.data.length > 0) {
select.value.options = res.data.data.map((item: any) => {
return {
value: item.wbsCode,
label: item.wbsName
};
});
select.value.value = res.data.data[0].wbsCode;
}
} catch (error) {
console.error('获取站点数据失败:', error);
}
};
const getEchartsData = async () => {
loading.value = true;
try {
if (!select.value.value) {
console.warn('未选择站点,无法获取图表数据');
chartData.value = [];
return;
}
let params = {
date: dayjs(datetimePicker.value.value).format('YYYY-MM-DD HH:mm:ss'),
rvcd: select.value.value
};
let res = await qgcgetEngLimit(params);
if (res.data && Array.isArray(res.data)) {
chartData.value = res.data;
} else {
console.warn('获取到的图表数据为空或格式不正确');
chartData.value = [];
}
} catch (error) {
console.error('获取图表数据失败:', error);
chartData.value = [];
} finally {
loading.value = false;
}
};
watch(
() => JidiSelectEventStore.selectedItem,
async (newVal) => {
console.log('流域切换:', newVal);
if (newVal?.wbsCode) {
wbsCode.value = newVal.wbsCode;
await selectdata();
}
},
{ deep: true, immediate: true }
);
const handlePanelChange1 = async (data: any) => {
console.log('当前所有控件状态:', data);
if (data.select && data.datetime) {
await getEchartsData();
}
};
</script>
<style lang="scss" scoped>
.chart-container {
width: 100%;
height: 400px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.chart-wrapper {
width: 100%;
height: 100%;
&.has-data {
min-height: 0;
}
}
</style>

View File

@ -0,0 +1,879 @@
<template>
<div class="stlldbqk-container">
<!-- 搜索表单 -->
<a-form layout="inline" class="search-form">
<a-form-item label="基地选择">
<a-select
v-model:value="params.qid"
placeholder="请选择基地"
style="width: 200px; margin-right: 10px"
show-search
:filter-option="filterOption"
:options="jidiOptions"
@change="handleJidiChange"
/>
<a-select
v-model:value="params.rstcd"
placeholder="请选择电站"
style="width: 200px"
show-search
:filter-option="filterOption"
:options="rstcdOptions"
/>
</a-form-item>
<a-form-item>
<a-space>
<a-button type="primary" @click="handleSearch">查询</a-button>
</a-space>
</a-form-item>
</a-form>
<!-- Tabs 标签页 -->
<a-tabs
v-if="tabList.length > 0"
v-model:activeKey="ecoFlowType"
class="tab-style"
@change="fetchTableData"
>
<a-tab-pane v-for="item in tabList" :key="item.key" :tab="item.label" />
</a-tabs>
<div class="body_zhengti">
<div class="echarts">
<a-spin :spinning="dataLoading">
<div v-if="pieData.length > 0" ref="chartRef" class="pie-chart"></div>
<a-empty
v-if="!dataLoading && pieData.length === 0"
description="暂无数据"
/>
</a-spin>
</div>
<div class="table_1">
<BasicTable
ref="tableRef"
:columns="columns"
:scrollY="380"
:scrollX="100"
:list-url="vmsstbprptGetKendoList"
:search-params="searchParams"
:transform-data="customTransform"
:enable-sort="true"
@sort-change="handleSortChange"
>
<template #stnm="{ record }">
<a-button
type="link"
size="small"
@click="handleView(record, 'EQ')"
>{{ record.stnm }}</a-button
>
</template>
<template #ennm="{ record }">
<a-button
type="link"
size="small"
@click="handleView(record, 'ENG')"
>{{ record.ennm }}</a-button
>
</template>
</BasicTable>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
import dayjs from 'dayjs';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import {
dayGetKendoListCust,
vmsstbprptGetKendoList,
msstbprptGetKendoList
} from '@/api/stll';
import BasicTable from '@/components/BasicTable/index.vue';
import { useModelStore } from '@/store/modules/model';
import { NullableDateType } from 'ant-design-vue/es/vc-picker/interface';
const modelStore = useModelStore();
const props = defineProps<{
basicId?: string;
sttpCodekey: string;
}>();
const JidiSelectEventStore = useJidiSelectEventStore();
// ==================== ====================
// Tab
const columnsConfig = {
EQ_6: [
{
key: 'stnm',
title: '设施名称',
dataIndex: 'stnm',
slots: { customRender: 'stnm' },
fixed: 'left' ,
width: '120px',
sorter: true
},
{
key: 'ennm',
title: '所属电站',
dataIndex: 'ennm',
slots: { customRender: 'ennm' },
fixed: 'left',
width: '120px',
sorter: true
},
{
key: 'ttpwr',
title: '装机容量',
dataIndex: 'ttpwr',
width: '160px',
sorter: true
},
{
key: 'stjzysq',
title: '生态机组额定流量(m³/s)',
dataIndex: 'stjzysq',
width: '200px',
sorter: true
}
],
EQ_5: [
{
key: 'stnm',
title: '设施名称',
dataIndex: 'stnm',
slots: { customRender: 'stnm' },
fixed: 'left',
width: '120px',
sorter: true
},
{
key: 'ennm',
title: '所属电站',
dataIndex: 'ennm',
slots: { customRender: 'ennm' },
fixed: 'left',
width: '120px',
sorter: true
},
{
key: 'jhfdgk',
title: '基荷发电工况',
dataIndex: 'jhfdgk',
width: '100px',
sorter: true
},
{
key: 'fdll',
title: '发电量(MKW)',
dataIndex: 'fdll',
width: '120px',
sorter: true
},
{
key: 'blprdName',
title: '所属建设阶段',
dataIndex: 'blprdName',
width: '160px',
sorter: true
}
],
default: [
{
key: 'stnm',
title: '设施名称',
dataIndex: 'stnm',
slots: { customRender: 'stnm' },
fixed: 'left',
width: '120px',
sorter: true
},
{
key: 'ennm',
title: '所属电站',
dataIndex: 'ennm',
slots: { customRender: 'ennm' },
fixed: 'left',
width: '120px',
sorter: true
},
{
key: 'ddzgq',
title: '死水位时保证流量(m³/s)',
dataIndex: 'ddzgq',
width: '190px',
sorter: true
},
{
key: 'flkq',
title: '最大泄放流量(m³/s)',
dataIndex: 'flkq',
sorter: true,
width: '160px'
},
{
key: 'jskgc',
title: '进水口底版高程(m)',
dataIndex: 'jskgc',
sorter: true,
width: '160px'
},
{
key: 'outflrelev',
title: '出水口底版高程(m)',
dataIndex: 'outflrelev',
sorter: true,
width: '160px'
},
{
key: 'flksz',
title: '孔口尺寸(m)',
dataIndex: 'flksz',
sorter: true,
width: '120px'
},
{
key: 'frntwlltyp',
title: '结构形式',
dataIndex: 'frntwlltyp',
sorter: true,
width: '160px'
},
{
key: 'blprdName',
title: '所属建设阶段',
dataIndex: 'blprdName',
sorter: true,
width: '160px'
}
]
};
// Tab
const columns = computed(() => {
const type = ecoFlowType.value;
if (type === 'EQ_6') return columnsConfig.EQ_6;
if (type === 'EQ_5') return columnsConfig.EQ_5;
return columnsConfig.default;
});
const tableRef = ref();
//
const sortInfo = ref<{ field: string; order: string | null }>({
field: '',
order: null
});
const sort2 = ref([
{
field: 'baseStepSort',
dir: 'asc'
},
{
field: 'rvcdStepSort',
dir: 'asc'
},
{
field: 'rstcdStepSort',
dir: 'asc'
},
{
field: 'siteStepSort',
dir: 'asc'
}
]);
//
const searchParams = computed(() => {
let baseSort;
//
if (sortInfo.value.field && sortInfo.value.order) {
baseSort = [
{
field: sortInfo.value.field,
dir: sortInfo.value.order === 'ascend' ? 'asc' : 'desc'
}
];
} else {
// 使
baseSort = sort2.value;
}
return {
sort: baseSort,
group: [],
select: [],
groupResultFlat: false
};
});
//
const handleSortChange = (info: {
field: string;
order: 'ascend' | 'descend' | null;
}) => {
sortInfo.value.field = info.field || '';
sortInfo.value.order = info.order || null;
// DOM
nextTick(() => {
fetchTableData();
});
};
const params = ref({
qid: props.basicId || 'all',
rstcd: ''
});
// 使 handleView
const activeSTime = ref('');
const activeETime = ref('');
// Tab
const tabList = ref<any[]>([]);
const ecoFlowType = ref<string>(props.sttpCodekey || '');
const loading = ref<boolean>(false);
const jidiOptions = computed(() => {
return [
...JidiSelectEventStore.jidiData.map((item: any) => ({
value: item.wbsCode,
label: item.wbsName
}))
];
});
const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
// ==================== ====================
const chartRef = ref<HTMLDivElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
const pieData = ref<any[]>([]); //
const dataLoading = ref<boolean>(false);
const pieCode = ref<string[]>([]); //
//
const themeecLists = [];
const jdColor = [
'#4b79ab',
'#78c300',
'#9556a4',
'#df91ab',
'#7399c6',
'#dbb629',
'#56c2e3',
'#f56a06',
'#cdba75',
'#76523b',
'#df75b6',
'#00a050',
'#f5a644',
'#4b79ab',
'#78c300',
'#9556a4',
'#df91ab',
'#7399c6',
'#dbb629',
'#56c2e3',
'#f56a06',
'#cdba75',
'#76523b',
'#df75b6',
'#00a050',
'#f5a644'
];
//
const fetchPieData = async () => {
dataLoading.value = true;
try {
const { qid, rstcd } = params.value;
let obj = {
filter: {
logic: 'and',
filters: [
qid != 'all'
? {
field: 'baseId',
operator: 'contains',
dataType: 'string',
value: qid
}
: null,
{
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: ecoFlowType.value
},
{
field: 'baseName',
operator: 'isnotnull',
dataType: 'string'
},
rstcd
? {
field: 'rstcd',
operator: 'eq',
dataType: 'string',
value: rstcd
}
: null
].filter(Boolean)
},
group: [
{
dir: 'asc',
field: 'baseStepSort'
},
{
dir: 'asc',
field: 'baseId'
},
{
dir: 'desc',
field: 'baseName'
},
{
dir: 'desc',
field: 'sttpCode'
}
],
groupResultFlat: 'true'
};
let res = await vmsstbprptGetKendoList(obj);
if (res?.data?.data) {
const dataSource = res.data.data.map((el: any) => ({
id: el.baseId,
name: el.baseName,
value: el.count_baseId,
key: el.baseId
}));
pieData.value = dataSource;
pieCode.value = []; //
// DOM
await nextTick();
initOrUpdateChart();
} else {
pieData.value = [];
}
} catch (error) {
console.error('获取饼图数据失败:', error);
pieData.value = [];
} finally {
dataLoading.value = false;
}
};
//
const initOrUpdateChart = () => {
if (!chartRef.value) return;
//
if (!chartInstance) {
chartInstance = echarts.init(chartRef.value);
//
chartInstance.on('legendselectchanged', handleLegendSelectChanged);
}
updateChart();
};
//
const updateChart = () => {
if (!chartInstance) return;
const total =
pieData.value.reduce((pre: number, cur: any) => pre + cur.value, 0) || 0;
//
const colors = pieData.value.map((item: any, index: number) => {
const matched = themeecLists.find((i: any) => i.name === item.name);
return matched?.color || jdColor[index % jdColor.length];
});
const option: EChartsOption = {
color: colors,
tooltip: {
trigger: 'item',
formatter: '{b}: {c} (座) ({d}%)'
},
legend: {
orient: 'vertical',
right: 20,
top: 80,
type: 'scroll',
textStyle: {
width: 100, //
overflow: 'truncate', //
ellipsis: '...' //
}
},
title: [
{
text: total.toString(),
left: '34%',
top: '44%',
textAlign: 'center',
textStyle: {
fontSize: 24,
fontWeight: 'bold',
color: '#333'
}
},
{
text: '电站总数量',
left: '34%',
top: '51%',
textAlign: 'center',
textStyle: {
fontSize: 14,
color: '#666'
}
},
{
text: '(座)',
left: '34%',
top: '55%',
textAlign: 'center',
textStyle: {
fontSize: 12,
color: '#999'
}
}
],
series: [
{
name: '电站总数量',
type: 'pie',
radius: ['31%', '40%'],
center: ['35%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
formatter: function (params) {
const maxLen = 8; //
let name = params.name;
if (name.length > maxLen) {
return name.substring(0, maxLen) + '...';
}
return name;
}
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold'
}
},
data: pieData.value
}
]
};
chartInstance.setOption(option, true);
};
//
const handleLegendSelectChanged = (params: any) => {
const selected = params.selected;
const trueRivers = Object.keys(selected).filter(key => selected[key]);
const allFalse = Object.values(selected).every(value => value === false);
const selectedKeys = pieData.value
.filter((item: any) => trueRivers.includes(item.name))
.map((item: any) => item.key);
pieCode.value = allFalse ? ['0'] : selectedKeys;
//
fetchTableData();
};
//
const customTransform = (res: any) => {
return {
records: res?.data?.data || [],
total: res?.data?.total || 0
};
};
// Tab
const fetchTabList = async () => {
loading.value = true;
try {
const { qid, rstcd } = params.value;
let obj = {
filter: {
logic: 'and',
filters: [
qid != 'all'
? {
field: 'baseId',
operator: 'contains',
dataType: 'string',
value: qid
}
: null,
{
field: 'sttpFullPath',
operator: 'contains',
dataType: 'string',
value: 'ENV,ENVP,EQ,'
},
{
field: 'sttpFullPath',
operator: 'neq',
dataType: 'string',
value: 'ENV,ENVP,EQ,'
},
{
field: 'baseName',
operator: 'isnotnull',
dataType: 'string'
},
rstcd
? {
field: 'rstcd',
operator: 'eq',
dataType: 'string',
value: rstcd
}
: null
].filter(Boolean)
},
group: [
{
dir: 'desc',
field: 'sttpCode'
}
]
};
let res = await msstbprptGetKendoList(obj);
if (res?.data?.data?.length > 0) {
const resData = res.data.data;
tabList.value = resData.map(item => ({
key: item.key,
value: item.key,
label: `${item.keyName}(${item.count}个)`
}));
// ""
// ecoFlowType.value = tabList.value[0].key;
//
fetchPieData();
//
fetchTableData();
} else {
tabList.value = [];
}
} catch (error) {
console.error('获取 Tab 列表失败:', error);
tabList.value = [];
} finally {
loading.value = false;
}
};
const handleView = (record: any, type: 'ENG' | 'EQ') => {
modelStore.modalVisible = true;
modelStore.params.sttp = type == 'EQ' ? record.sttpCode :'ENG';
modelStore.title = type === 'ENG' ? record.ennm : record.stnm;
modelStore.params.stcd = type === 'ENG' ? record.rstcd : record.stcd;
modelStore.params.eqtp = record.eqtp;
modelStore.filter.rangeTm = [activeSTime.value, activeETime.value];
};
//table
const fetchTableData = async () => {
//
const { qid, rstcd } = params.value;
const filters: any[] = [
{
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: ecoFlowType.value
},
{
field: 'baseName',
operator: 'isnotnull',
dataType: 'string'
},
qid != 'all'
? {
field: 'baseId',
operator: 'contains',
dataType: 'string',
value: qid
}
: null,
rstcd
? {
field: 'rstcd',
operator: 'eq',
dataType: 'string',
value: rstcd
}
: null
].filter(Boolean);
//
if (pieCode.value.length > 0) {
if (qid === 'all') {
filters.push({
field: 'baseId',
operator: 'in',
dataType: 'string',
value: pieCode.value
});
} else {
filters.push({
field: 'hbrvcd',
operator: 'in',
dataType: 'string',
value: pieCode.value
});
}
}
const filter = {
logic: 'and',
filters
};
tableRef.value?.getList(filter);
};
// ecoFlowType
watch(ecoFlowType, () => {
fetchPieData();
});
const handleSearch = () => {
// Tab
fetchTabList();
};
//
let rstcdOptions: any = ref([]);
const rstcdOption = async () => {
let obj = {
filter: {
logic: 'and',
filters: [
params.value.qid != 'all'
? {
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: 'ENG'
}
: null
].filter(Boolean)
},
sort: [
{
field: 'ttpwr',
dir: 'desc'
}
],
select: ['stcd', 'stnm']
};
let res = await vmsstbprptGetKendoList(obj);
rstcdOptions.value = res.data.data.map((item: any) => {
return {
value: item.stcd,
label: item.stnm
};
});
};
const handleJidiChange = (value: string) => {
rstcdOption();
};
onMounted(() => {
fetchTabList();
rstcdOption();
//
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
//
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
window.removeEventListener('resize', handleResize);
});
//
const handleResize = () => {
chartInstance?.resize();
};
</script>
<style scoped lang="scss">
.stlldbqk-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: #ffffff;
box-sizing: border-box;
// padding: 16px;
}
.body_zhengti {
width: 100%;
display: flex;
justify-content: space-between;
flex: 1;
.echarts {
width: 35%;
height: 482px;
// position: relative;
min-width: 521px;
.pie-chart {
width: 100%;
height: 100%;
}
:deep(.ant-spin-nested-loading) {
width: 100%;
height: 100%;
}
:deep(.ant-spin-container) {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
}
.table_1 {
width: 65%;
height: 482px;
// overflow: auto;
// max-width: 500px;
}
}
</style>

View File

@ -1,194 +1,365 @@
<!-- SidePanelItem.vue -->
<template>
<div class="xie-fang-fang-shi-container">
<SidePanelItem title="生态流量泄放方式">
<div ref="chartRef" class="pie-chart"></div>
</SidePanelItem>
</div>
<div class="xie-fang-fang-shi-container">
<SidePanelItem title="生态流量泄放方式">
<!-- Loading 状态 -->
<a-spin v-if="loading" :spinning="true" style="width: 100%; height: 350px; display: flex; justify-content: center; align-items: center;" />
<!-- 空状态提示 -->
<a-empty v-else-if="!loading && pieData.length === 0" description="暂无数据" style="height: 350px; display: flex; justify-content: center; align-items: center;flex-direction: column;text-indent:0em" />
<!-- 图表容器 -->
<div v-else ref="chartRef" class="pie-chart"></div>
</SidePanelItem>
<!-- 详情弹框 -->
<a-modal
v-model:open="modalVisible"
:title="'生态流量泄放方式'"
width="1536px"
@cancel="handleModalCancel"
>
<STLLXFFS
v-if="modalVisible"
:basicId="wbsCode"
:sttpCodekey ="selectedData.sttpCode"
/>
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import * as echarts from 'echarts';
import type { ECharts } from 'echarts';
import { msstbprptGetKendoList } from '@/api/stll';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import STLLXFFS from './TwoLayer/STLLXFFS.vue'
// 便
defineOptions({
name: 'xieFangFangShi'
name: 'xieFangFangShi'
});
const JidiSelectEventStore = useJidiSelectEventStore();
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: ECharts | null = null;
let wbsCode = ref('');
//
const pieData = [
{ value: 44.83, name: '基荷发电' },
{ value: 19.31, name: '泄洪设施' },
{ value: 8.28, name: '生态机组' },
{ value: 8.96, name: '生态放流管' },
{ value: 9.65, name: '生态放流闸' },
{ value: 5.52, name: '生态放流孔' },
{ value: 3.45, name: '生态放流洞' }
];
// Loading
const loading = ref(false);
//
const pieData = ref<any[]>([]);
const totalCount = ref(0);
const apiRawData = ref<any[]>([]); // API
//
const modalVisible = ref(false);
const modalTitle = ref('');
const selectedData = ref<any>(null);
//
const colors = [
'#9556a4', // -
'#30b7b9', // - 绿
'#4b79ab', // -
'#dbb629', // -
'#df91ab', // -
'#78c300', // - 绿
'#7399c6' // -
'#9556a4', // -
'#30b7b9', // - 绿
'#4b79ab', // -
'#dbb629', // -
'#df91ab', // -
'#78c300', // - 绿
'#7399c6' // -
];
//
const initChart = () => {
if (!chartRef.value) return;
if (!chartRef.value) return;
//
if (chartRef.value.clientHeight === 0) {
// 0
setTimeout(() => {
initChart();
}, 100);
return;
}
//
if (chartRef.value.clientHeight === 0) {
// 0
setTimeout(() => {
initChart();
}, 100);
return;
}
chartInstance = echarts.init(chartRef.value);
chartInstance = echarts.init(chartRef.value);
const option = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c}%'
const option = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c}%'
},
series: [
{
name: '泄放设施',
type: 'pie',
radius: ['42%', '62%'], // 42% 62%
center: ['50%', '50%'],
avoidLabelOverlap: true,
itemStyle: {
borderRadius: 0,
borderColor: '#fff',
borderWidth: 2
},
series: [
{
name: '泄放设施',
type: 'pie',
radius: ['42%', '62%'], // 42% 62%
center: ['50%', '50%'],
avoidLabelOverlap: true,
itemStyle: {
borderRadius: 0,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
position: 'outside',
alignTo: 'edge', //
margin: 8, //
formatter: (params: any) => {
return `{name|${params.name}}\n{value|${params.value}%}`;
},
rich: {
name: {
fontSize: 12,
color: '#666666', //
lineHeight: 18,
fontFamily: 'Microsoft YaHei, sans-serif',
align: 'left' //
},
value: {
fontSize: 12,
color: '#2f6b98', //
lineHeight: 18,
fontFamily: 'Microsoft YaHei, sans-serif',
align: 'center', //
fontWeight: 'bold' //
}
},
overflow: 'none', //
padding: [0, 0]
},
labelLine: {
show: true,
length: 12,
length2: 12,
lineStyle: {
width: 1
}
},
emphasis: {
scale: false, //
itemStyle: {
brightness: 1.2, // 20%
shadowBlur: 0 //
},
labelLine: {
show: true // 线
}
},
data: pieData.map((item, index) => ({
...item,
itemStyle: { color: colors[index % colors.length] },
labelLine: {
lineStyle: {
color: colors[index % colors.length]
}
}
}))
}
],
//
title: {
text: '145',
subtext: '泄放设施总数量\n(个)',
left: 'center',
top: 'center',
textStyle: {
color: '#2e86de',
fontSize: 30,
fontWeight: 'bold',
fontFamily: 'Arial'
label: {
show: true,
position: 'outside',
alignTo: 'edge', //
margin: 8, //
formatter: (params: any) => {
return `{name|${params.name}}\n{value|${params.value}%}`;
},
rich: {
name: {
fontSize: 12,
color: '#666666', //
lineHeight: 18,
fontFamily: 'Microsoft YaHei, sans-serif',
align: 'left' //
},
subtextStyle: {
color: '#666',
fontSize: 12,
lineHeight: 16,
fontFamily: 'Microsoft YaHei, sans-serif'
value: {
fontSize: 12,
color: '#2f6b98', //
lineHeight: 18,
fontFamily: 'Microsoft YaHei, sans-serif',
align: 'center', //
fontWeight: 'bold' //
}
}
},
overflow: 'none', //
padding: [0, 0]
},
labelLine: {
show: true,
length: 12,
length2: 12,
lineStyle: {
width: 1
}
},
emphasis: {
scale: false, //
itemStyle: {
brightness: 1.2, // 20%
shadowBlur: 0 //
},
labelLine: {
show: true // 线
}
},
data: pieData.value.map((item, index) => ({
...item,
itemStyle: { color: colors[index % colors.length] },
labelLine: {
lineStyle: {
color: colors[index % colors.length]
}
}
}))
}
],
//
title: {
text: totalCount.value.toString(),
subtext: '泄放设施总数量\n(个)',
left: 'center',
top: 'center',
textStyle: {
color: '#2e86de',
fontSize: 30,
fontWeight: 'bold',
fontFamily: 'Arial'
},
subtextStyle: {
color: '#666',
fontSize: 12,
lineHeight: 16,
fontFamily: 'Microsoft YaHei, sans-serif'
}
}
};
chartInstance.setOption(option);
//
chartInstance.on('click', handleChartClick);
};
/**
* 图表点击事件
*/
const handleChartClick = (params: any) => {
//
const clickedData = params.data;
if (clickedData) {
selectedData.value = {
name: clickedData.name,
value: clickedData.value,
sttpCode: clickedData.sttpCode,
count:
apiRawData.value.find(
(item: any) => item.sttpCode === clickedData.sttpCode
)?.count_sttpName || 0,
...apiRawData.value.find(
(item: any) => item.sttpCode === clickedData.sttpCode
) //
};
chartInstance.setOption(option);
modalTitle.value = `${clickedData.name} - 详细信息`;
modalVisible.value = true;
}
};
/**
* 弹框取消事件
*/
const handleModalCancel = () => {
modalVisible.value = false;
selectedData.value = null;
};
//
const handleResize = () => {
chartInstance?.resize();
chartInstance?.resize();
};
//
onMounted(() => {
// 使 nextTick DOM
// 使 nextTick DOM
setTimeout(() => {
initChart();
// resize
setTimeout(() => {
initChart();
// resize
setTimeout(() => {
chartInstance?.resize();
}, 200);
}, 50);
window.addEventListener('resize', handleResize);
chartInstance?.resize();
}, 200);
}, 50);
window.addEventListener('resize', handleResize);
//
if (wbsCode.value) {
getecharts();
}
});
//
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
});
const getecharts = async () => {
loading.value = true;
let params = {
filter: {
logic: 'and',
filters: [
wbsCode.value != 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: wbsCode.value
}
: null,
{
field: 'sttpFullPath',
operator: 'contains',
dataType: 'string',
value: 'ENV,ENVP,EQ,'
},
{
field: 'sttpFullPath',
operator: 'neq',
dataType: 'string',
value: 'ENV,ENVP,EQ,'
},
{
field: 'baseName',
operator: 'isnotnull',
dataType: 'string'
}
].filter(Boolean)
},
group: [
{
dir: 'desc',
field: 'sttpCode'
},
{
dir: 'desc',
field: 'sttpName'
}
],
groupResultFlat: 'true'
};
try {
let res = await msstbprptGetKendoList(params);
//
if (!res || !res.data || !res.data.data || !Array.isArray(res.data.data)) {
console.warn('未获取到有效的泄放设施数据:', res);
pieData.value = [];
totalCount.value = 0;
return;
}
const apiData = res.data.data;
//
apiRawData.value = apiData;
//
const total = apiData.reduce((sum: number, item: any) => {
return sum + (item.count_sttpName || 0);
}, 0);
totalCount.value = total;
//
pieData.value = apiData.map((item: any) => ({
name: item.sttpName,
value:
total > 0
? Number(((item.count_sttpName / total) * 100).toFixed(2))
: 0,
sttpCode: item.sttpCode // sttpCode
}));
//
setTimeout(() => {
initChart();
}, 100);
} catch (error) {
console.error('获取泄放设施数据失败:', error);
pieData.value = [];
totalCount.value = 0;
} finally {
loading.value = false;
}
};
watch(
() => JidiSelectEventStore.selectedItem,
newVal => {
console.log('流域切换:', newVal);
if (newVal?.wbsCode) {
wbsCode.value = newVal.wbsCode;
getecharts();
}
},
{ deep: true, immediate: true }
);
</script>
<style lang="scss" scoped>
.xie-fang-fang-shi-container {
width: 100%;
height: 100%;
width: 100%;
height: 100%;
}
.pie-chart {
width: 100%;
height: 350px;
width: 100%;
height: 350px;
}
</style>

View File

@ -0,0 +1,737 @@
<template>
<div class="xffs-fb-container">
<!-- 搜索表单 -->
<a-form layout="inline" class="search-form">
<a-form-item label="基地选择">
<a-select
v-model:value="params.JiDi"
placeholder="请选择基地"
style="width: 200px; margin-right: 10px"
show-search
:filter-option="filterOption"
:options="jidiOptions"
/>
</a-form-item>
<a-form-item label="生态流量泄放方式">
<a-select
v-model:value="params.XFFS"
placeholder="请选择泄放方式"
style="width: 200px; margin-right: 10px"
show-search
:filter-option="filterOption"
:options="xffsOptions"
/>
</a-form-item>
<a-form-item>
<a-input
v-model:value="params.stnm"
placeholder="请输入电站或设施名称"
style="width: 200px; margin-right: 10px"
allow-clear
/>
</a-form-item>
<a-form-item>
<a-space>
<a-button type="primary" @click="handleSearch">查询</a-button>
</a-space>
</a-form-item>
</a-form>
<!-- 图表和表格布局 -->
<div class="body-content">
<!-- 左侧饼图 -->
<div class="chart-section">
<a-spin :spinning="chartLoading">
<div v-if="pieData.length > 0" ref="chartRef" class="pie-chart"></div>
<a-empty
v-if="!chartLoading && pieData.length === 0"
description="暂无数据"
/>
</a-spin>
</div>
<!-- 右侧表格 -->
<div class="table-section">
<BasicTable
ref="tableRef"
:columns="columns"
:scrollY="385"
:scrollX="100"
:list-url="vmsstbprptGetKendoList"
:search-params="searchParams"
:transform-data="customTransform"
:enable-sort="true"
@sort-change="handleSortChange"
>
<template #stnm="{ record }">
<a-button
type="link"
size="small"
@click="handleView(record, 'EQ')"
>
{{ record.stnm }}
</a-button>
</template>
<template #ennm="{ record }">
<a-button
type="link"
size="small"
@click="handleView(record, 'ENG')"
>
{{ record.ennm }}
</a-button>
</template>
</BasicTable>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
import { msstbprptGetKendoList, vmsstbprptGetKendoList } from '@/api/stll';
import BasicTable from '@/components/BasicTable/index.vue';
import { useModelStore } from '@/store/modules/model';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
const modelStore = useModelStore();
const JidiSelectEventStore = useJidiSelectEventStore();
// ==================== Props ====================
const props = defineProps<{
dataDimensionVal?: string | number | boolean;
defaultJidiInfo?: Record<string, string | number | boolean> | null;
jidiName?: string;
selectData?: string;
jiDiList?: (Record<string, string | number | boolean> | null)[];
}>();
// ==================== ====================
const columnsConfig = {
EQ_6: [
{
key: 'stnm',
title: '设施名称',
dataIndex: 'stnm',
slots: { customRender: 'stnm' },
fixed: 'left',
width: '120px',
sorter: true
},
{
key: 'ennm',
title: '所属电站',
dataIndex: 'ennm',
slots: { customRender: 'ennm' },
fixed: 'left',
width: '120px',
sorter: true
},
{
key: 'ttpwr',
title: '装机容量',
dataIndex: 'ttpwr',
width: '160px',
sorter: true
},
{
key: 'stjzysq',
title: '生态机组额定流量(m³/s)',
dataIndex: 'stjzysq',
width: '200px',
sorter: true
}
],
EQ_5: [
{
key: 'stnm',
title: '设施名称',
dataIndex: 'stnm',
slots: { customRender: 'stnm' },
fixed: 'left',
width: '120px',
sorter: true
},
{
key: 'ennm',
title: '所属电站',
dataIndex: 'ennm',
slots: { customRender: 'ennm' },
fixed: 'left',
width: '120px',
sorter: true
},
{
key: 'jhfdgk',
title: '基荷发电工况',
dataIndex: 'jhfdgk',
width: '100px',
sorter: true
},
{
key: 'fdll',
title: '发电量(MKW)',
dataIndex: 'fdll',
width: '120px',
sorter: true
},
{
key: 'blprdName',
title: '所属建设阶段',
dataIndex: 'blprdName',
width: '160px',
sorter: true
}
],
default: [
{
key: 'stnm',
title: '设施名称',
dataIndex: 'stnm',
slots: { customRender: 'stnm' },
fixed: 'left',
width: '120px',
sorter: true
},
{
key: 'ennm',
title: '所属电站',
dataIndex: 'ennm',
slots: { customRender: 'ennm' },
fixed: 'left',
width: '120px',
sorter: true
},
{
key: 'ddzgq',
title: '死水位时保证流量(m³/s)',
dataIndex: 'ddzgq',
width: '190px',
sorter: true
},
{
key: 'flkq',
title: '最大泄放流量(m³/s)',
dataIndex: 'flkq',
sorter: true,
width: '160px'
},
{
key: 'jskgc',
title: '进水口底版高程(m)',
dataIndex: 'jskgc',
sorter: true,
width: '160px'
},
{
key: 'outflrelev',
title: '出水口底版高程(m)',
dataIndex: 'outflrelev',
sorter: true,
width: '160px'
},
{
key: 'flksz',
title: '孔口尺寸(m)',
dataIndex: 'flksz',
sorter: true,
width: '120px'
},
{
key: 'frntwlltyp',
title: '结构形式',
dataIndex: 'frntwlltyp',
sorter: true,
width: '160px'
},
{
key: 'blprdName',
title: '所属建设阶段',
dataIndex: 'blprdName',
sorter: true,
width: '160px'
}
]
};
//
const columns = computed(() => {
const xffsName = params.value.XFFS;
if (xffsName === '生态机组') return columnsConfig.EQ_6;
if (xffsName === '基荷发电') return columnsConfig.EQ_5;
return columnsConfig.default;
});
const tableRef = ref();
//
const sortInfo = ref<{ field: string; order: string | null }>({
field: '',
order: null
});
const sort2 = ref([
{
field: 'rvcdStepSort',
dir: 'asc'
},
{
field: 'rstcdStepSort',
dir: 'asc'
}
]);
//
const searchParams = computed(() => {
let baseSort;
if (sortInfo.value.field && sortInfo.value.order) {
baseSort = [
{
field: sortInfo.value.field,
dir: sortInfo.value.order === 'ascend' ? 'asc' : 'desc'
}
];
} else {
baseSort = sort2.value;
}
return {
sort: baseSort,
group: [],
select: [],
groupResultFlat: false
};
});
//
const handleSortChange = (info: {
field: string;
order: 'ascend' | 'descend' | null;
}) => {
sortInfo.value.field = info.field || '';
sortInfo.value.order = info.order || null;
nextTick(() => {
fetchTableData();
});
};
// ==================== ====================
const params = ref({
JiDi: props.jidiName || '',
XFFS: props.selectData || '',
stnm: ''
});
//
const jidiOptions = computed(() => {
return (props.jiDiList || []).map((item: any) => ({
value: item?.wbsCode,
label: item?.wbsName
}));
});
//
const xffsOptions = computed(() => {
return echartData.value.map((item: any) => ({
value: item.dataIndex,
label: item.name
}));
});
const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
// ==================== ====================
const chartRef = ref<HTMLDivElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
const pieData = ref<any[]>([]);
const chartLoading = ref<boolean>(false);
const pieCode = ref<string[]>([]); //
//
const jdColor = [
'#4b79ab',
'#78c300',
'#9556a4',
'#df91ab',
'#7399c6',
'#dbb629',
'#56c2e3',
'#f56a06',
'#cdba75',
'#76523b',
'#df75b6',
'#00a050',
'#f5a644'
];
//
const echartData = computed(() => {
const v = (eqtp: string) => {
const index = pieData.value.findIndex((item: any) => item.name === eqtp);
if (index !== -1) {
return pieData.value[index]?.value || 0;
}
return 0;
};
return [
{ dataIndex: 'EQ_1', value: v('EQ_1'), name: '生态放流孔' },
{ dataIndex: 'EQ_2', value: v('EQ_2'), name: '生态放流闸' },
{ dataIndex: 'EQ_3', value: v('EQ_3'), name: '生态放流洞' },
{ dataIndex: 'EQ_4', value: v('EQ_4'), name: '生态放流管' },
{ dataIndex: 'EQ_5', value: v('EQ_5'), name: '基荷发电' },
{ dataIndex: 'EQ_6', value: v('EQ_6'), name: '生态机组' },
{ dataIndex: 'EQ_7', value: v('EQ_7'), name: '泄洪设施' }
];
});
//
const fetchPieData = async () => {
chartLoading.value = true;
try {
let obj = {
filter: {
logic: 'and',
filters: [
params.value.JiDi !== 'all'
? {
field: 'baseId',
operator: 'contains',
dataType: 'string',
value: params.value.JiDi
}
: null,
params.value.XFFS
? {
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: params.value.XFFS
}
: null
].filter(Boolean)
},
group: [
{
dir: 'desc',
field: 'sttpCode'
},
{
dir: 'desc',
field: 'sttpName'
}
],
groupResultFlat: 'true'
};
const res = await msstbprptGetKendoList(obj);
if (res?.data?.data) {
const dataSource = res.data.data.map((el: any) => ({
name: el.sttpName,
value: el.count_sttpCode
}));
pieData.value = dataSource;
pieCode.value = []; //
// DOM
await nextTick();
initOrUpdateChart();
} else {
pieData.value = [];
}
} catch (error) {
console.error('获取饼图数据失败:', error);
pieData.value = [];
} finally {
chartLoading.value = false;
}
};
//
const initOrUpdateChart = () => {
if (!chartRef.value) return;
if (!chartInstance) {
chartInstance = echarts.init(chartRef.value);
chartInstance.on('legendselectchanged', handleLegendSelectChanged);
}
updateChart();
};
//
const updateChart = () => {
if (!chartInstance) return;
const total =
pieData.value.reduce((pre: number, cur: any) => pre + cur.value, 0) || 0;
const colors = pieData.value.map((item: any, index: number) => {
return jdColor[index % jdColor.length];
});
const option: EChartsOption = {
color: colors,
tooltip: {
trigger: 'item',
formatter: '{b}: {c} 个 ({d}%)'
},
legend: {
orient: 'vertical',
right: 20,
top: 80,
type: 'scroll',
textStyle: {
width: 100,
overflow: 'truncate',
ellipsis: '...'
}
},
title: [
{
text: total.toString(),
left: '34%',
top: '44%',
textAlign: 'center',
textStyle: {
fontSize: 24,
fontWeight: 'bold',
color: '#333'
}
},
{
text: '电站总数',
left: '34%',
top: '51%',
textAlign: 'center',
textStyle: {
fontSize: 14,
color: '#666'
}
},
{
text: '(个)',
left: '34%',
top: '55%',
textAlign: 'center',
textStyle: {
fontSize: 12,
color: '#999'
}
}
],
series: [
{
name: '电站总数量',
type: 'pie',
radius: ['31%', '40%'],
center: ['35%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
formatter: function (params) {
const maxLen = 8;
let name = params.name;
if (name.length > maxLen) {
return name.substring(0, maxLen) + '...';
}
return name;
}
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold'
}
},
data: pieData.value
}
]
};
chartInstance.setOption(option, true);
};
//
const handleLegendSelectChanged = (params: any) => {
const selected = params.selected;
const trueRivers = Object.keys(selected).filter(key => selected[key]);
const allFalse = Object.values(selected).every(value => value === false);
const selectedKeys = pieData.value
.filter((item: any) => trueRivers.includes(item.name))
.map((item: any) => item.name);
pieCode.value = allFalse ? [] : selectedKeys;
//
fetchTableData();
};
//
const customTransform = (res: any) => {
return {
records: res?.data?.data || [],
total: res?.data?.total || 0
};
};
//
const fetchTableData = async () => {
const filters: any[] = [
params.value.XFFS
? {
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: params.value.XFFS
}
: null,
params.value.JiDi
? {
field: 'baseId',
operator: 'contains',
dataType: 'string',
value: params.value.JiDi
}
: null,
params.value.stnm
? {
logic: 'or',
filters: [
{
field: 'stnm',
operator: 'contains',
value: '12'
},
{
field: 'ennm',
operator: 'contains',
value: '12'
}
]
}
: null
].filter(Boolean);
//
if (pieCode.value.length > 0) {
filters.push({
field: 'sttpName',
operator: 'in',
dataType: 'string',
value: pieCode.value
});
}
const filter = {
logic: 'and',
filters
};
tableRef.value?.getList(filter);
};
//
const handleView = (record: any, type: 'ENG' | 'EQ') => {
modelStore.modalVisible = true;
modelStore.params.sttp = type === 'EQ' ? record.sttpCode : 'ENG';
modelStore.title = type === 'ENG' ? record.ennm : record.stnm;
modelStore.params.stcd = type === 'ENG' ? record.rstcd : record.stcd;
modelStore.params.eqtp = record.eqtp;
};
//
const handleSearch = () => {
fetchPieData();
fetchTableData();
};
//
const handleResize = () => {
chartInstance?.resize();
};
onMounted(() => {
fetchPieData();
fetchTableData()
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
window.removeEventListener('resize', handleResize);
});
</script>
<style scoped lang="scss">
.xffs-fb-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: #ffffff;
box-sizing: border-box;
}
.search-form {
padding: 16px;
border-bottom: 1px solid #f0f0f0;
}
.body-content {
width: 100%;
display: flex;
justify-content: space-between;
flex: 1;
padding: 16px;
.chart-section {
width: 35%;
height: 482px;
min-width: 521px;
.pie-chart {
width: 100%;
height: 100%;
}
:deep(.ant-spin-nested-loading) {
width: 100%;
height: 100%;
}
:deep(.ant-spin-container) {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
}
.table-section {
width: 65%;
height: 482px;
}
}
</style>

View File

@ -1,386 +1,479 @@
<!-- SidePanelItem.vue -->
<template>
<div>
<SidePanelItem title="泄放方式分布情况">
<div class="chart-container">
<!-- 自定义图例区域 -->
<div class="legend-container">
<div class="legend-items">
<div
v-for="(item) in currentLegendItems"
:key="item.name"
class="legend-item"
:class="{ 'inactive': legendInactiveSet.has(item.name) }"
@click="toggleLegend(item.name)"
>
<span class="legend-color" :style="{ backgroundColor: item.color }"></span>
<span class="legend-text">{{ item.name }}</span>
</div>
</div>
<!-- 分页控制 -->
<div class="legend-pagination" v-if="totalPages > 1">
<span
class="pagination-btn"
:class="{ disabled: currentPage === 1 }"
@click="prevPage"
>
</span>
<span class="pagination-text">{{ currentPage }}/{{ totalPages }}</span>
<span
class="pagination-btn"
:class="{ disabled: currentPage === totalPages }"
@click="nextPage"
>
</span>
</div>
</div>
<!-- ECharts 图表容器 -->
<div ref="chartRef" class="chart"></div>
</div>
</SidePanelItem>
</div>
<SidePanelItem title="泄放方式分布情况">
<div ref="chartRef" class="bar-chart-container"></div>
<!-- 空状态提示 -->
<a-empty v-if="showEmpty" description="暂无数据" />
</SidePanelItem>
<!-- 详情弹框 -->
<a-modal
v-model:open="modalVisible"
title="泄放方式分布情况"
width="1536px"
:footer="null"
@cancel="handleModalCancel"
>
<FBQKTwolayer
v-if="modalVisible"
:selectData="selectData"
:jidiName="jidiName"
:jiDiList="JidiSelectEventStore.jidiData"
></FBQKTwolayer>
</a-modal>
</template>
<script lang="ts" setup>
import { ref, onMounted, computed, watch, onBeforeUnmount } from 'vue';
import {
ref,
onMounted,
onBeforeUnmount,
watch,
computed,
nextTick
} from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
import type { ECharts } from 'echarts';
import { vmsstbprptGetKendoList } from '@/api/stll';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import FBQKTwolayer from './TwoLayer/FenBuQingKuangTwoLayer.vue';
//
defineOptions({
name: 'xieFangFenBu'
name: 'XieFangFenBu'
});
//
const JidiSelectEventStore = useJidiSelectEventStore();
// DOM
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
let chartInstance: ECharts | null = null;
//
const ITEMS_PER_PAGE = 4; // 4
const currentPage = ref(1); //
//
const loading = ref(false);
const data = ref<any[]>([]);
const echartsXData = ref<string[]>([]);
const wbsCode = ref('');
// 8
const allLegendItems = ref([
{ name: '生态放流孔', color: '#7cb342' },
{ name: '生态放流闸', color: '#ce93d8' },
{ name: '生态放流洞', color: '#64b5f6' },
{ name: '生态放流管', color: '#ffd54f' },
{ name: '生态放流口', color: '#ff8a65' },
{ name: '生态放流道', color: '#4db6ac' },
{ name: '生态放流渠', color: '#ba68c8' },
{ name: '生态放流站', color: '#a1887f' }
]);
//
const modalVisible = ref(false);
const selectData = ref(''); //
const jidiName = ref(''); //
//
const totalPages = computed(() => {
return Math.ceil(allLegendItems.value.length / ITEMS_PER_PAGE);
//
const typeName = [
{ label: '生态放流孔', eqtp: 'EQ_1' },
{ label: '生态放流闸', eqtp: 'EQ_2' },
{ label: '生态放流洞', eqtp: 'EQ_3' },
{ label: '生态放流管', eqtp: 'EQ_4' },
{ label: '基荷发电', eqtp: 'EQ_5' },
{ label: '生态机组', eqtp: 'EQ_6' },
{ label: '泄洪设施', eqtp: 'EQ_7' }
];
// getUnitConfigByCode 使
const defaultColors = [
'#9556a4', // EQ_1 -
'#30b7b9', // EQ_2 - 绿
'#4b79ab', // EQ_3 -
'#dbb629', // EQ_4 -
'#df91ab', // EQ_5 -
'#78c300', // EQ_6 - 绿
'#7399c6' // EQ_7 -
];
//
const showEmpty = computed(() => {
return !loading.value && (!data.value || data.value.length === 0);
});
//
const currentLegendItems = computed(() => {
const start = (currentPage.value - 1) * ITEMS_PER_PAGE;
const end = start + ITEMS_PER_PAGE;
return allLegendItems.value.slice(start, end);
});
/**
* 手写 omit 函数替代 lodash.omit
*/
const omit = (obj: any, keys: string[]) => {
const result = { ...obj };
keys.forEach(key => {
delete result[key];
});
return result;
};
// inactive
const legendInactiveSet = ref<Set<string>>(new Set());
/**
* 获取颜色配置模拟 getUnitConfigByCode
* TODO: 如果项目中有等效实现请替换此处逻辑
*/
const getColorByType = (type: string): string => {
// getUnitConfigByCode
// const config = getUnitConfigByCode('Other', type);
// return config?.lineColor || config?.pieColor;
// /
const toggleLegend = (name: string) => {
if (legendInactiveSet.value.has(name)) {
legendInactiveSet.value.delete(name);
// 使
const index = typeName.findIndex(item => item.eqtp === type);
return defaultColors[index] || '#999999';
};
/**
* 初始化图表
*/
const initChart = () => {
if (!chartRef.value) return;
//
if (chartRef.value.clientHeight === 0) {
setTimeout(() => {
initChart();
}, 100);
return;
}
if (!chartInstance) {
chartInstance = echarts.init(chartRef.value);
}
const option = buildChartOption();
chartInstance.setOption(option, true);
//
chartInstance.off('click');
chartInstance.on('click', handleChartClick);
};
/**
* 构建图表配置
*/
const buildChartOption = () => {
//
const countSums: Record<string, number> = {};
data.value.forEach(item => {
const baseid = item.baseid;
const count = Number(item.count) || 0;
if (countSums[baseid]) {
countSums[baseid] += count;
} else {
legendInactiveSet.value.add(name);
countSums[baseid] = count;
}
updateChart();
};
});
//
const prevPage = () => {
if (currentPage.value > 1) {
currentPage.value--;
}
};
const values = Object.values(countSums);
const maxValue = values.length > 0 ? Math.max(...values) : 0;
//
const nextPage = () => {
if (currentPage.value < totalPages.value) {
currentPage.value++;
}
};
//
const totalData: number[] = [];
const uniqueBaseNames = [...new Set(echartsXData.value)];
uniqueBaseNames.forEach((basename, index) => {
let total = 0;
data.value.forEach(item => {
if (item.basename === basename) {
total += Number(item.count) || 0;
}
});
totalData[index] = total;
});
// - API
const xData = ref([
'金沙江干流',
'雅砻江干流',
'大渡河干流',
'乌江干流',
'湘西',
'黄河上游干流',
'东北',
'闽浙赣',
'其他'
]);
// series
const seriesData = typeName.map(type => {
return uniqueBaseNames.map(basename => {
const found = data.value.find(
item => item.eqtp === type.eqtp && item.basename === basename
);
return found ? Number(found.count) || 0 : 0;
});
});
// 8
const seriesData = ref([
{ name: '生态放流孔', data: [2, 1, 3, 1, 2, 1, 0, 1, 5] },
{ name: '生态放流闸', data: [3, 2, 4, 2, 3, 1, 1, 2, 8] },
{ name: '生态放流洞', data: [5, 2, 6, 3, 4, 2, 1, 2, 9] },
{ name: '生态放流管', data: [15, 0, 12, 18, 4, 0, 0, 0, 21] },
{ name: '生态放流口', data: [0, 0, 0, 0, 0, 0, 0, 0, 0] },
{ name: '生态放流道', data: [0, 0, 0, 0, 0, 0, 0, 0, 0] },
{ name: '生态放流渠', data: [0, 0, 0, 0, 0, 0, 0, 0, 0] },
{ name: '生态放流站', data: [0, 0, 0, 0, 0, 0, 0, 0, 0] }
]);
//
const colors = typeName.map(type => getColorByType(type.eqtp));
//
const calculateTotal = (index: number) => {
return seriesData.value
.filter(series => !legendInactiveSet.value.has(series.name)) //
.reduce((sum, series) => {
return sum + (series.data[index] || 0);
}, 0);
};
//
const updateChart = () => {
if (!chartInstance) return;
const option: EChartsOption = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: (params: any) => {
let result = `${params[0].name}<br/>`;
params.forEach((param: any) => {
// active
if (!legendInactiveSet.value.has(param.seriesName)) {
result += `${param.marker} ${param.seriesName}: ${param.value}<br/>`;
}
});
return result;
const option: any = {
tooltip: {
trigger: 'axis',
confine: true,
formatter: (params: any) => {
const content = params
.map((item: any) => {
let value = item.value || 0;
if (item.seriesName === '总计') {
value = totalData[item.dataIndex];
}
return `<div>${item.marker}${item.seriesName}: &nbsp;&nbsp;&nbsp;&nbsp;<span style="float:right">${value} 个</span></div>`;
})
.join('');
return `<h3>${params[0].name}</h3>${content}`;
},
axisPointer: {
type: 'line'
}
},
grid: {
left: '8%',
right: '4%',
bottom: '20%',
top: '20%'
},
legend: {
type: 'scroll',
icon: 'rect',
orient: 'horizontal',
itemWidth: 12,
itemHeight: 12,
textStyle: {
fontSize: 12,
color: '#6A93B9',
height: 8
},
data: typeName.map(item => item.label)
},
xAxis: {
show: true,
type: 'category',
axisLine: { show: true },
axisLabel: {
fontSize: 12,
color: '#686868',
rotate: 37
},
axisTick: {
alignWithLabel: true
},
data: uniqueBaseNames
},
yAxis: {
max: maxValue,
type: 'value',
barWidth: 10,
name: '数量(个)',
nameTextStyle: {
fontSize: 12,
color: '#848484',
align: 'center'
},
axisTick: { show: false },
axisLabel: {
fontSize: 12,
color: '#343434',
fontFamily: 'Bebas'
}
},
series: [
...typeName.map((type, index) => ({
name: type.label,
type: 'bar' as const,
stack: 'total',
barCategoryGap: '50%',
data: seriesData[index]
})),
{
name: '总计',
type: 'bar' as const,
stack: 'total',
label: {
show: true,
position: 'top',
formatter: (params: any) => {
return String(totalData[params.dataIndex]);
}
},
grid: {
left: '3%',
right: '4%',
bottom: '15%',
top: '10%',
containLabel: true
itemStyle: {
color: 'transparent'
},
xAxis: {
type: 'category',
data: xData.value,
axisLabel: {
rotate: 45, // X 45
interval: 0 //
},
axisTick: {
alignWithLabel: true
}
},
yAxis: {
type: 'value',
min: 0,
// Y
axisLabel: {
formatter: '{value}'
}
},
series: seriesData.value.map((series, index) => {
//
const legendItem = allLegendItems.value.find(item => item.name === series.name);
const color = legendItem?.color;
data: Array(totalData.length).fill(0)
}
],
color: colors
};
//
const isHidden = legendInactiveSet.value.has(series.name);
return option;
};
return {
name: series.name,
type: 'bar',
stack: 'total',
barWidth: '60%',
// null使
data: isHidden ? series.data.map(() => null) : series.data,
//
itemStyle: {
color: color
},
// -
label: {
show: index === seriesData.value.length - 1, //
position: 'top',
fontSize: 12,
color: '#333',
formatter: (params: any) => {
//
const total = calculateTotal(params.dataIndex);
return total > 0 ? total.toString() : '';
}
},
//
emphasis: {
itemStyle: {
shadowBlur: 0,
shadowColor: 'rgba(0, 0, 0, 0)'
}
}
};
})
/**
* 图表点击事件
*/
const handleChartClick = (params: any) => {
// sttpCode (eqtp)
const typeConfig = typeName.find(item => item.label === params.seriesName);
selectData.value = typeConfig ? typeConfig.eqtp : '';
// wbsCode
const jidiInfo = JidiSelectEventStore.jidiData.find(
(item: any) => item.wbsName === params.name
);
jidiName.value = jidiInfo ? jidiInfo.wbsCode : params.name;
modalVisible.value = true;
};
/**
* 弹框取消事件
*/
const handleModalCancel = () => {
modalVisible.value = false;
selectData.value = '';
jidiName.value = '';
};
/**
* 获取数据
*/
const fetchData = async () => {
if (!wbsCode.value) return;
loading.value = true;
try {
//
let params: any = {
filter: {
logic: 'and',
filters: [
wbsCode.value !== 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: wbsCode.value
}
: null,
{
field: 'sttpFullPath',
operator: 'contains',
dataType: 'string',
value: 'ENV,ENVP,EQ,'
}
].filter(Boolean)
},
group: [
{
dir: 'asc',
field: 'baseStepSort'
},
{
dir: 'asc',
field: 'baseId'
},
{
dir: 'desc',
field: 'sttpCode'
}
],
groupResultFlat: 'true'
};
chartInstance.setOption(option, true);
// baseId
if (wbsCode.value === 'all') {
params = omit(params, ['filter']);
params.filter = {
logic: 'and',
filters: [
{
field: 'sttpFullPath',
operator: 'contains',
dataType: 'string',
value: 'ENV,ENVP,EQ,'
}
]
};
}
const res = await vmsstbprptGetKendoList(params);
if (res.data && res.data.data) {
const apiData = res.data.data;
//
const list: any[] = [];
apiData.forEach((it: any) => {
list.push({
key: it.baseId,
count: it.count_sttpCode,
eqtp: it.sttpCode
});
});
// 使 JidiSelectEventStore.jidiData
const processedData = list.map((item: any) => {
// jidiData
const jidiInfo = JidiSelectEventStore.jidiData.find(
(jidi: any) => jidi.wbsCode === item.key
);
return {
baseid: item.key,
basename: jidiInfo ? jidiInfo.wbsName : item.key, // 使 wbsName使 baseId
count: item.count,
eqtp: item.eqtp
};
});
data.value = processedData;
// debugger
// X
echartsXData.value = [
...new Set(processedData.map(item => item.basename))
];
//
await nextTick();
initChart();
} else {
data.value = [];
echartsXData.value = [];
}
} catch (error) {
console.error('获取泄放方式分布数据失败:', error);
data.value = [];
echartsXData.value = [];
} finally {
loading.value = false;
}
};
//
const initChart = () => {
if (!chartRef.value) return;
//
setTimeout(() => {
chartInstance = echarts.init(chartRef.value);
updateChart();
//
setTimeout(() => {
chartInstance?.resize();
}, 100);
}, 50);
};
//
/**
* 处理窗口大小变化
*/
const handleResize = () => {
chartInstance?.resize();
chartInstance?.resize();
};
//
watch([currentPage, legendInactiveSet], () => {
updateChart();
}, { deep: true });
//
//
onMounted(() => {
// DOM
setTimeout(() => {
initChart();
window.addEventListener('resize', handleResize);
setTimeout(() => {
chartInstance?.resize();
}, 200);
}, 50);
window.addEventListener('resize', handleResize);
//
if (wbsCode.value) {
fetchData();
}
});
//
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
chartInstance = null;
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
chartInstance = null;
});
//
const refreshData = (newXData: string[], newSeriesData: any[]) => {
xData.value = newXData;
seriesData.value = newSeriesData;
updateChart();
};
//
const setLegendData = (legendData: Array<{ name: string; color: string }>) => {
allLegendItems.value = legendData;
currentPage.value = 1; //
legendInactiveSet.value.clear();
};
// 使
defineExpose({
refreshData,
setLegendData
});
//
watch(
() => JidiSelectEventStore.selectedItem,
newVal => {
console.log('流域切换:', newVal);
if (newVal?.wbsCode) {
wbsCode.value = newVal.wbsCode;
fetchData();
}
},
{ deep: true, immediate: true }
);
</script>
<style lang="scss" scoped>
.chart-container {
width: 100%;
.legend-container {
display: flex;
justify-content: space-between;
align-items: center;
.legend-items {
display: flex;
gap: 10px; //
flex-wrap: nowrap; //
flex: 1; //
min-width: 0; //
.legend-item {
display: flex;
align-items: center;
cursor: pointer;
transition: opacity 0.3s;
flex-shrink: 0; //
&:hover {
opacity: 0.8;
}
&.inactive {
opacity: 0.5;
}
.legend-color {
width: 12px;
height: 12px;
border-radius: 2px;
margin-right: 4px;
flex-shrink: 0;
}
.legend-text {
font-size: 12px; //
color: #333;
white-space: nowrap;
}
}
}
.legend-pagination {
display: flex;
align-items: center;
flex-shrink: 0;
margin-left: 5px; //
.pagination-btn {
cursor: pointer;
font-size: 14px;
color: #666;
user-select: none;
transition: color 0.3s;
&:hover:not(.disabled) {
color: #409eff;
}
&.disabled {
cursor: not-allowed;
color: #ccc;
}
}
.pagination-text {
font-size: 13px;
color: #666;
min-width: 30px;
text-align: center;
}
}
}
.chart {
width: 100%;
height: 350px;
}
.bar-chart-container {
width: 100%;
height: 350px;
}
</style>

View File

@ -295,7 +295,7 @@ const handleChange = async () => {
select: ['stcd', 'stnm']
};
let res = await vmsstbprptGetKendoList(params);
if (res?.data?.success && res?.data?.data) {
if ( res?.data?.data) {
let data = res.data.data;
stcdOptions.value = data.map((item: any) => ({
value: item.stcd,

View File

@ -36,7 +36,7 @@
v-model:value="dateRange"
:allow-clear="false"
format="YYYY-MM-DD"
style="width: 360px"
style="width: 260px"
/>
</a-form-item>
@ -70,11 +70,11 @@
/>
</a-spin>
</div>
<div class="table">
<div class="table1">
<BasicTable
ref="tableRef"
:columns="columns"
:scrollY="380"
:scrollY="400"
:list-url="
activeTimeType == 'day' ? dayGetKendoListCust : hourGetKendoListCust
"
@ -952,7 +952,7 @@ const handleResize = () => {
align-items: center;
}
}
.table {
.table1 {
width: 65%;
height: 482px;
}

View File

@ -0,0 +1,812 @@
<template>
<div class="stlldbqk-container">
<!-- 搜索表单 -->
<a-form layout="inline" class="search-form">
<a-form-item label="基地选择">
<a-select
v-model:value="params.qid"
placeholder="请选择基地"
style="width: 200px"
show-search
:filter-option="filterOption"
:options="jidiOptions"
/>
</a-form-item>
<!-- <a-form-item label=" "> -->
<a-input
v-model:value="params.ennm"
placeholder=" "
style="width: 200px; margin-right: 15px"
/>
<!-- </a-form-item> -->
<a-form-item label="日期范围">
<a-range-picker
v-model:value="dateRange"
:allow-clear="false"
format="YYYY-MM-DD"
style="width: 360px"
/>
</a-form-item>
<a-form-item>
<a-space>
<a-button type="primary" @click="handleSearch">查询</a-button>
</a-space>
</a-form-item>
</a-form>
<!-- Tabs 选择器仅在 type === 'left' 时显示 -->
<a-spin :spinning="tabsLoading" tip="加载中...">
<a-tabs
v-if="props.type === 'left' && tabOptions.length > 0"
v-model:activeKey="activeTab"
@change="handleTabChange"
class="stll-tabs"
>
<a-tab-pane
v-for="item in tabOptions"
:key="item.qecPerformance"
:tab="`${item.qecPerformanceName} (${
item.qecRate !== null &&
item.qecRate !== undefined &&
item.qecRate !== ''
? Number(item.qecRate).toFixed(2) + '%'
: '-%'
})`"
/>
</a-tabs>
<div class="body_zhengti">
<div class="echarts">
<a-spin :spinning="dataLoading">
<div
v-show="pieData.length > 0"
ref="chartRef"
class="pie-chart"
></div>
<a-empty
v-show="!dataLoading && pieData.length === 0"
description="暂无数据"
/>
</a-spin>
</div>
<div class="table">
<BasicTable
ref="tableRef"
:columns="columns"
:scrollY="'450px'"
:list-url="
props.type == 'top'
? intervalGetKendoListCust
: eqGetKendoListCust
"
:search-params="searchParams"
:transform-data="customTransform"
:enable-sort="true"
@sort-change="handleSortChange"
>
<template #ennm="{ column, record }">
<a-button type="link" size="small" @click="handleView(record)">{{
record.ennm
}}</a-button>
</template>
</BasicTable>
</div>
</div>
</a-spin>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
import dayjs from 'dayjs';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import BasicTable from '@/components/BasicTable/index.vue';
import { useModelStore } from '@/store/modules/model';
import {
vmsstbprptGetKendoList,
intervalGetKendoListCust,
eqqecRateCount,
eqGetKendoListCust
} from '@/api/stll';
const modelStore = useModelStore();
const props = defineProps<{
type?: string;
basicId?: string;
qecPerformance?: any;
}>();
const JidiSelectEventStore = useJidiSelectEventStore();
const columns = [
props.type == 'left'
? {
key: 'baseName',
title: '所属基地',
dataIndex: 'baseName',
sorter: true //
}
: null,
{
key: 'ennm',
title: '电站名称',
dataIndex: 'ennm',
slots: { customRender: 'action' },
sorter: true //
},
{
key: 'addvcdName',
title: '行政区',
dataIndex: 'addvcdName',
sorter: true //
},
{
key: 'hbrvcdName',
title: '所在河段',
dataIndex: 'hbrvcdName',
width: '300px'
},
{
key: 'qecRate',
title: `生态流量达标率(%)`,
dataIndex: 'qecRate',
sorter: true, //
width: '160px',
customRender: ({ text }: any) => {
if (text === null || text === undefined || text === '' || text === '-')
return '-';
return Number(text).toFixed(2);
}
},
{
key: 'beforeQecRate',
title: '去年同期达标率(%)',
dataIndex: 'beforeQecRate',
width: '160px',
sorter: true, //
customRender: ({ text }: any) => {
if (text === null || text === undefined || text === '' || text === '-')
return '-';
return Number(text).toFixed(2);
}
}
].filter(Boolean);
const tableRef = ref();
//
const sortInfo = ref<{ field: string; order: string | null }>({
field: '',
order: null
});
const defaultSort = ref([
{
field: 'baseId',
dir: 'asc'
},
{
field: 'rvcdStepSort',
dir: 'asc'
},
{
field: 'siteStepSort',
dir: 'asc'
},
{
field: 'qecRate',
dir: 'asc'
}
]);
//
const searchParams = computed(() => {
let baseSort;
//
if (sortInfo.value.field && sortInfo.value.order) {
baseSort = [
{
field: sortInfo.value.field,
dir: sortInfo.value.order === 'ascend' ? 'asc' : 'desc'
}
];
} else {
// 使
baseSort = defaultSort.value;
}
return {
sort: baseSort
};
});
//
const handleSortChange = (info: {
field: string;
order: 'ascend' | 'descend' | null;
}) => {
sortInfo.value.field = info.field || '';
sortInfo.value.order = info.order || null;
// DOM
nextTick(() => {
fetchTableData();
});
};
//
const initDateRange = () => {
const today = dayjs();
const lastMonthSameDay = today.subtract(1, 'month');
return [lastMonthSameDay, today];
};
const dateRange = ref(initDateRange());
const params = ref({
qid: props.basicId || 'all',
ennm: '',
sTime: '',
eTime: ''
});
const jidiOptions = computed(() => {
return [
...JidiSelectEventStore.jidiData.map((item: any) => ({
value: item.wbsCode,
label: item.wbsName
}))
];
});
const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
// ==================== Tabs ====================
const activeTab = ref<string>(props.qecPerformance || ''); // tab key
const tabOptions = ref<any[]>([]); // tabs
const tabsLoading = ref<boolean>(false); // tabs
// Tabs
const fetchTabOptions = async () => {
if (props.type !== 'left') return;
tabsLoading.value = true;
try {
const res = await eqqecRateCount({
filter: {
logic: 'and',
filters: [
params.value.qid !== 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: params.value.qid
}
: null,
{
field: 'type',
operator: 'eq',
dataType: 'string',
value: 'DAY'
},
{
field: 'RGCP_CODE',
operator: 'in',
dataType: 'string',
value: ['1']
},
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value:
params.value.sTime ||
dayjs().subtract(1, 'month').format('YYYY-MM-DD 00:00:00')
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: params.value.eTime || dayjs().format('YYYY-MM-DD 23:59:59')
}
].filter(Boolean)
},
group: [{ dir: 'asc', field: 'qecPerformance' }]
});
if (res?.data?.data && res.data.data.length > 0) {
tabOptions.value = res.data.data;
//
activeTab.value =props.qecPerformance || res.data.data[0].qecPerformance;
} else {
tabOptions.value = [];
activeTab.value = '';
}
} catch (error) {
console.error('获取tabs选项失败:', error);
tabOptions.value = [];
activeTab.value = '';
} finally {
tabsLoading.value = false;
}
};
// Tab
const handleTabChange = (key: string) => {
activeTab.value = key;
//
fetchPieData();
fetchTableData();
};
// ==================== ====================
const chartRef = ref<HTMLDivElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
const pieData = ref<any[]>([]); //
const dataLoading = ref<boolean>(false);
const pieCode = ref<string[]>([]); //
//
const themeecLists = [];
const jdColor = [
'#4b79ab',
'#78c300',
'#9556a4',
'#df91ab',
'#7399c6',
'#dbb629',
'#56c2e3',
'#f56a06',
'#cdba75',
'#76523b',
'#df75b6',
'#00a050',
'#f5a644',
'#4b79ab',
'#78c300',
'#9556a4',
'#df91ab',
'#7399c6',
'#dbb629',
'#56c2e3',
'#f56a06',
'#cdba75',
'#76523b',
'#df75b6',
'#00a050',
'#f5a644'
];
//
const fetchPieData = async () => {
if (!params.value.sTime || !params.value.eTime) return;
dataLoading.value = true;
try {
const { sTime, eTime, qid, ennm } = params.value;
let obj = {
filter: {
logic: 'and',
filters: [
{
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: 'ENG'
},
{
field: 'prsc',
operator: 'in',
dataType: 'string',
value: [1, 2, 3]
},
qid != 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: qid
}
: null,
{
field: 'bldstt',
operator: 'in',
dataType: 'string',
value: [1, 10, 11]
},
props.type != 'left'
? {
field: 'dtinEnv',
operator: 'in',
dataType: 'string',
value: [1, 2]
}
: {
field: 'RGCP_CODE',
operator: 'in',
dataType: 'string',
value: [activeTab.value]
}
].filter(Boolean)
},
group: [
{
dir: 'asc',
field: 'rvcdStepSort'
},
{
dir: 'asc',
field: 'hbrvcd'
},
{
dir: 'asc',
field: 'hbrvcdName'
}
],
groupResultFlat: true
};
// TODO: API -
const res = await vmsstbprptGetKendoList(obj);
if (res?.data?.data) {
const dataSource = res.data.data.map((el: any) => ({
id: el.hbrvcd,
name: el.hbrvcdName,
value: el.count_hbrvcd,
key: el.hbrvcd
}));
pieData.value = dataSource;
pieCode.value = []; //
// DOM
await nextTick();
initOrUpdateChart();
} else {
pieData.value = [];
}
} catch (error) {
console.error('获取饼图数据失败:', error);
pieData.value = [];
} finally {
dataLoading.value = false;
}
};
//
const initOrUpdateChart = () => {
if (!chartRef.value) return;
//
if (!chartInstance) {
chartInstance = echarts.init(chartRef.value);
//
chartInstance.on('legendselectchanged', handleLegendSelectChanged);
}
updateChart();
};
//
const updateChart = () => {
if (!chartInstance) return;
const total =
pieData.value.reduce((pre: number, cur: any) => pre + cur.value, 0) || 0;
//
const colors = pieData.value.map((item: any, index: number) => {
const matched = themeecLists.find((i: any) => i.name === item.name);
return matched?.color || jdColor[index % jdColor.length];
});
const option: EChartsOption = {
color: colors,
tooltip: {
trigger: 'item',
formatter: '{b}: {c} (座) ({d}%)'
},
legend: {
orient: 'vertical',
right: 20,
top: 80,
type: 'scroll',
textStyle: {
width: 100, //
overflow: 'truncate', //
ellipsis: '...' //
}
},
title: [
{
text: total.toString(),
left: '34%',
top: '44%',
textAlign: 'center',
textStyle: {
fontSize: 24,
fontWeight: 'bold',
color: '#333'
}
},
{
text: '电站总数量',
left: '34%',
top: '51%',
textAlign: 'center',
textStyle: {
fontSize: 14,
color: '#666'
}
},
{
text: '(座)',
left: '34%',
top: '55%',
textAlign: 'center',
textStyle: {
fontSize: 12,
color: '#999'
}
}
],
series: [
{
name: '电站总数量',
type: 'pie',
radius: ['31%', '40%'],
center: ['35%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
formatter: function (params) {
const maxLen = 8; //
let name = params.name;
if (name.length > maxLen) {
return name.substring(0, maxLen) + '...';
}
return name;
}
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold'
}
},
data: pieData.value
}
]
};
chartInstance.setOption(option, true);
};
//
const handleLegendSelectChanged = (params: any) => {
const selected = params.selected;
const trueRivers = Object.keys(selected).filter(key => selected[key]);
const allFalse = Object.values(selected).every(value => value === false);
const selectedKeys = pieData.value
.filter((item: any) => trueRivers.includes(item.name))
.map((item: any) => item.key);
pieCode.value = allFalse ? ['0'] : selectedKeys;
//
fetchTableData();
};
//
const customTransform = (res: any) => {
return {
records: res?.data?.data || [],
total: res?.data?.total || 0
};
};
const handleView = (record: any) => {
modelStore.modalVisible = true;
modelStore.params.sttp = 'ENG';
modelStore.title = record.ennm;
modelStore.params.stcd = record.stcd;
modelStore.params.eqtp = record.eqtp;
};
//
const fetchTableData = async () => {
const { sTime, eTime, qid, ennm } = params.value;
// TODO: -
const filters = [
qid != 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: qid
}
: null,
{
field: 'dtinEnv',
operator: 'in',
dataType: 'string',
value: [1, 2]
},
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: sTime
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: eTime
},
ennm
? {
field: 'ennm',
operator: 'contains',
dataType: 'string',
value: ennm
}
: null,
props.type == 'left'
? {
field: 'rgcpCode',
operator: 'eq',
dataType: 'string',
value: activeTab.value
}
: null,
props.type == 'left'
? {
field: 'type',
operator: 'eq',
dataType: 'string',
value: 'DAY'
}
: null
].filter(Boolean);
const filter = {
logic: 'and',
filters
};
tableRef.value?.getList(filter);
};
const handleSearch = () => {
// params
if (dateRange.value && dateRange.value.length === 2) {
params.value.sTime = dateRange.value[0].format('YYYY-MM-DD 00:00:00');
params.value.eTime = dateRange.value[1].format('YYYY-MM-DD 23:59:59');
}
// type === 'left' tabs
if (props.type === 'left') {
fetchTabOptions().then(() => {
// tabs
fetchPieData();
fetchTableData();
});
} else {
//
fetchPieData();
fetchTableData();
}
};
onMounted(() => {
//
if (dateRange.value && dateRange.value.length === 2) {
params.value.sTime = dateRange.value[0].format('YYYY-MM-DD 00:00:00');
params.value.eTime = dateRange.value[1].format('YYYY-MM-DD 23:59:59');
// type === 'left' tabs
if (props.type === 'left') {
fetchTabOptions().then(() => {
// tabs
console.log(JidiSelectEventStore.jidiData);
fetchPieData();
fetchTableData();
});
} else {
//
console.log(JidiSelectEventStore.jidiData);
fetchPieData();
fetchTableData();
}
}
//
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
//
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
window.removeEventListener('resize', handleResize);
});
//
const handleResize = () => {
chartInstance?.resize();
};
</script>
<style scoped lang="scss">
.stlldbqk-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: #ffffff;
box-sizing: border-box;
// padding: 16px;
}
.stll-tabs {
margin-top: 16px;
margin-bottom: 16px;
:deep(.ant-tabs-nav) {
margin-bottom: 0;
}
}
.body_zhengti {
width: 100%;
display: flex;
justify-content: space-between;
flex: 1;
margin-top: 25px;
.echarts {
width: 35%;
height: 482px;
position: relative;
.pie-chart {
width: 100%;
height: 100%;
}
:deep(.ant-spin-nested-loading) {
width: 100%;
height: 100%;
}
:deep(.ant-spin-container) {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
}
.table {
width: 65%;
height: 482px;
}
}
</style>

View File

@ -7,7 +7,9 @@
-->
<template #click-action-content>
<div v-if="titleData.cnt" style="max-width: 300px; line-height: 1.6">
<p>1时间{{ getdate().startDate1 }} {{ getdate().endDate1 }}</p>
<p>
1时间{{ getdate().startDate1 }} {{ getdate().endDate1 }}
</p>
<p>
2范围接入过生态流量数据的电站<span
style="color: #5989ad; cursor: pointer"
@ -39,6 +41,21 @@
>
<ModalYkzhbzdjcgz v-if="huanbaoModalVisible" :titleData="titleData" />
</a-modal>
<!-- 生态流量达标率详情弹框 -->
<a-modal
v-model:open="detailModalVisible"
:title="detailModalTitle"
width="1536px"
:footer="null"
>
<STLLXFFS
v-if="detailModalVisible"
:type="mode"
:basicId="detailData[0]?.baseId"
:qecPerformance=detailData[0].qecPerformance
/>
</a-modal>
</template>
<script lang="ts" setup>
@ -47,15 +64,11 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import * as echarts from 'echarts';
import { eqqecRateCount, evnmAutoMonitorGetKendoListCust } from '@/api/stll';
import ModalYkzhbzdjcgz from '../shengtaidabiaoMod/TwoLayer/ModalYkzhbzdjcgz.vue';
import STLLXFFS from './TwoLayer/STLLXFFS.vue'
// 便
defineOptions({
name: 'shengtaidabiaoMod'
});
const obj = {
show: true,
value:
'1、统计电站范围接入过生态流量数据的电站2、当来水不足时生态流量不小于入库流量判定为达标3、"≥95% 座数"表示统计电站范围内时段达标率大于等于 95% 的电站数量'
};
const mode = ref('top');
const spinning = ref(false);
const chartRef = ref<HTMLElement | null>(null);
@ -66,45 +79,20 @@ const chartData = ref<{
categories: string[];
currentData: number[];
lastYearData: number[];
baseIds: (string | number)[];
qecPerformances: (string | number)[];
}>({
categories: [],
currentData: [],
lastYearData: []
lastYearData: [],
baseIds: [],
qecPerformances: []
});
const huanbaoModalVisible = ref(false);
//
const handleStationClick = () => {
huanbaoModalVisible.value = true;
};
//
const baseData = {
categories: [
'金沙江干流',
'雅砻江干流',
'大渡河干流',
'乌江干流',
'长江上游干流',
'湘西',
'黄河上游干流',
'黄河中游干流',
'南盘江 - 红水河',
'东北',
'澜沧江干流',
'闽浙赣',
'其他'
],
currentData: [98, 100, 99.5, 99.8, 100, 98.5, 100, 100, 100, 97, 100, 93, 98],
lastYearData: [92, 100, 99, 100, 100, 98, 100, 100, 100, 100, 100, 88, 93]
};
//
const performanceData = {
categories: ['多年调节', '年调节', '季调节', '周调节', '其他'],
currentData: [95, 92, 88, 85, 90],
lastYearData: [93, 90, 85, 82, 88]
};
//
const loadData = async () => {
spinning.value = true;
@ -303,11 +291,48 @@ const initChart = () => {
chartInstance.setOption(option);
//
chartInstance.off('click');
chartInstance.on('click', (params: any) => {
handleChartClick(params);
});
//
setTimeout(() => {
chartInstance?.resize();
}, 0);
};
//
const handleChartClick = (params: any) => {
const categoryName = params.name;
const currentIndex = params.dataIndex;
// debugger
//
detailModalTitle.value =
mode.value === 'top'
? `生态流量达标率(按基地统计) `
: `生态流量达标率(按调节性能统计)`;
//
const baseId = mode.value === 'top' ? chartData.value.baseIds[currentIndex] : undefined;
const qecPerformance = mode.value === 'left' ? chartData.value.qecPerformances[currentIndex] : undefined;
// debugger
const currentItem = {
baseId: baseId,
baseName: mode.value === 'top' ? categoryName :'',
qecPerformance: qecPerformance,
qecPerformanceName: mode.value === 'left' ? categoryName : '',
qecRate: chartData.value.currentData[currentIndex],
beforeQecRate: chartData.value.lastYearData[currentIndex]
};
detailData.value = [currentItem];
detailModalVisible.value = true;
};
const getdate = () => {
const now = new Date();
const oneMonthAgo = new Date(now);
@ -409,7 +434,9 @@ const getEcharts = async () => {
),
lastYearData: uniqueData.map((item: any) =>
item.beforeQecRate != null ? Number(item.beforeQecRate) : 0
)
),
baseIds: uniqueData.map((item: any) => item.baseId),
qecPerformances: []
};
} else {
//
@ -420,7 +447,9 @@ const getEcharts = async () => {
),
lastYearData: apiData.map((item: any) =>
item.beforeQecRate != null ? Number(item.beforeQecRate) : 0
)
),
baseIds: [],
qecPerformances: apiData.map((item: any) => item.qecPerformance || '')
};
}
} else {
@ -429,7 +458,9 @@ const getEcharts = async () => {
chartData.value = {
categories: [],
currentData: [],
lastYearData: []
lastYearData: [],
baseIds: [],
qecPerformances: []
};
}
} catch (error) {
@ -438,7 +469,9 @@ const getEcharts = async () => {
chartData.value = {
categories: [],
currentData: [],
lastYearData: []
lastYearData: [],
baseIds: [],
qecPerformances: []
};
}
};
@ -484,6 +517,34 @@ onMounted(() => {
});
});
//
const detailModalVisible = ref(false);
const detailModalTitle = ref('');
const detailData = ref<any[]>([]);
const detailColumns = ref([
{
title: mode.value === 'top' ? '基地名称' : '调节性能',
dataIndex: mode.value === 'top' ? 'baseName' : 'qecPerformanceName',
key: mode.value === 'top' ? 'baseName' : 'qecPerformanceName',
width: 150,
fixed: 'left'
},
{
title: '当前达标率',
dataIndex: 'qecRate',
key: 'qecRate',
width: 120,
align: 'right'
},
{
title: '去年同期达标率',
dataIndex: 'beforeQecRate',
key: 'beforeQecRate',
width: 150,
align: 'right'
}
]);
// mode
watch(mode, () => {
loadData();
@ -523,4 +584,8 @@ watch(mode, () => {
height: 449px;
// padding: 10px;
}
.detail-content {
padding: 16px 0;
}
</style>

View File

@ -0,0 +1,614 @@
<template>
<div>
<SidePanelItem
title="生态流量沿程变化"
:iconmap="iconmap"
:select="select"
:datetimePicker="datetimePicker"
@update-values="handlePanelChange"
>
<!-- 加载状态 -->
<div v-if="dataLoading" class="chart-loading">
<a-spin tip="加载中..." />
</div>
<!-- 无数据提示 -->
<a-empty
v-if="!chartData.length && !dataLoading"
description="暂无数据"
class="chart-empty"
/>
<!-- 图表容器使用 display 控制避免 v-if 销毁 DOM-->
<div
ref="chartRef"
class="chart-container"
:style="{
display: chartData.length && !dataLoading ? 'block' : 'none'
}"
></div>
</SidePanelItem>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, nextTick, onBeforeUnmount } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
// import { wbsbGetKendoList } from '@/api/sz';
import * as echarts from 'echarts';
import dayjs from 'dayjs';
// TODO: API
import { qgcHourVGetKendoListCust, wbsbGetKendoList } from '@/api/stll';
import { useModelStore } from '@/store/modules/model';
//
defineOptions({
name: 'StllyanchengChangeMod'
});
// ==================== ====================
//
const iconmap = ref({
show: true,
value:
'入库流量是基于库容曲线和水量平衡的推算值,非实测数据。出库流量是基于机组出力特征曲线和闸门开度的推算值,非实测数据。',
icon: 'iconfont icon-time'
});
//
const datetimePicker = ref({
show: true,
value: dayjs().format('YYYY-MM-DD HH:mm'), //
format: 'YYYY-MM-DD HH:mm',
picker: 'date',
timeFormat: 'HH:mm',
options: []
});
//
const select = ref({
show: true,
value: '',
options: [],
picker: undefined,
format: undefined
});
const modelStore = useModelStore();
//
const wbsCode = ref(''); //
const selectData = ref(''); //
const chartData = ref<any[]>([]); //
const dataLoading = ref(false); //
const latestTime = ref(''); //
const hasTimeData = ref(false); //
//
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
//
const modalVisible = ref(false);
const modalData = ref<any>({
stcd: '',
stnm: '',
titleName: ''
});
// Store
const JidiSelectEventStore = useJidiSelectEventStore();
// ==================== ====================
/**
* 获取河段列表
*/
const getSelect = async () => {
if (!wbsCode.value) {
console.warn('wbsCode 为空,无法获取河段数据');
return;
}
let params = {
filter: {
logic: 'and',
filters: [
{
field: 'objId',
operator: 'eq',
value: wbsCode.value
},
{
field: 'wbsType',
operator: 'eq',
value: 'PSB_RVCD'
}
]
},
group: [
{
dir: 'asc',
field: 'orderIndex'
},
{
dir: 'asc',
field: 'wbsCode'
},
{
dir: 'asc',
field: 'wbsName'
},
{
dir: 'asc',
field: 'objid'
}
],
groupResultFlat: 'true'
};
try {
let res = await wbsbGetKendoList(params);
//
let data;
if (res && res.data && res.data.data) {
if (Array.isArray(res.data.data)) {
data = res.data.data;
} else if (res.data.data.data && Array.isArray(res.data.data.data)) {
data = res.data.data.data;
} else {
console.warn('无法解析河段数据:', res);
return;
}
} else {
console.warn('未获取到河段数据');
return;
}
if (data && data.length > 0) {
// debugger;
select.value.value = data[0].wbsCode;
selectData.value = data[0].wbsCode; //
select.value.options = data.map(item => ({
value: item.wbsCode,
label: item.wbsName
}));
//
await loadChartData();
} else {
console.warn('河段数据为空');
select.value.value = '';
select.value.options = [];
}
} catch (error) {
console.error('获取河段数据失败:', error);
}
};
/**
* 获取生态流量数据预留 API 位置
*/
const getList = async (rvcd: string, sDate: string) => {
// TODO: API
// React
// - baseId: JidiSelectEventStore.selectedItem
// - rvcd:
// - tm: 1
const currentTime = dayjs(sDate);
const startTime = currentTime.subtract(1, 'month');
let params = {
filter: {
logic: 'and',
filters: [
{
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: wbsCode.value
},
{
field: 'rvcd',
operator: 'eq',
dataType: 'string',
value: rvcd
},
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: startTime.format('YYYY-MM-DD HH:mm:ss')
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: currentTime.format('YYYY-MM-DD HH:mm:ss')
}
]
},
sort: [
{
field: 'sort',
dir: 'asc'
}
]
};
// TODO: API FAA
const res = await qgcHourVGetKendoListCust(params);
//
if (!res || !res.data || !res.data.data || !Array.isArray(res.data.data)) {
console.warn('未获取到有效的生态流量数据:', res);
return [];
}
//
return res.data.data.map((item: any) => ({
TM: dayjs(item.tm).format('YYYY-MM-DD H时'),
stnm: item.stnm,
stcd: item.stcd,
qec: item.qec, //
qecLimit: item.qecLimit, //
qi: item.qi //
}));
};
/**
* 加载图表数据
*/
const loadChartData = async () => {
if (!selectData.value || !datetimePicker.value.value) {
return;
}
dataLoading.value = true;
try {
const data = await getList(selectData.value, datetimePicker.value.value);
if (data && data.length > 0) {
chartData.value = data;
hasTimeData.value = true;
//
if (data[0]?.TM) {
latestTime.value = data[0].TM;
}
//
await nextTick();
initChart();
} else {
chartData.value = [];
hasTimeData.value = false;
latestTime.value = '';
//
if (chartInstance) {
chartInstance.clear();
}
}
} catch (error) {
console.error('加载图表数据失败:', error);
chartData.value = [];
} finally {
dataLoading.value = false;
}
};
/**
* 初始化 ECharts 图表
*/
const initChart = () => {
if (!chartRef.value) {
console.warn('图表容器未准备好');
return;
}
//
if (chartInstance) {
chartInstance.dispose();
}
//
chartInstance = echarts.init(chartRef.value);
//
const xData: string[] = [];
const inData: (number | string)[] = []; //
const outData: (number | string)[] = []; //
const limitData: (number | string)[] = []; //
let hasValidData = false; //
chartData.value.forEach(item => {
xData.push(item.stnm);
const qecValue = item.qec ?? '-';
const qiValue = item.qi ?? '-';
const qecLimitValue = item.qecLimit ?? '-';
outData.push(qecValue);
inData.push(qiValue);
limitData.push(qecLimitValue);
//
if (qecValue !== '-' || qiValue !== '-' || qecLimitValue !== '-') {
hasValidData = true;
}
});
//
if (!hasValidData && chartData.value.length > 0) {
chartData.value = [];
if (chartInstance) {
chartInstance.clear();
}
return;
}
//
const option: echarts.EChartsOption = {
tooltip: {
trigger: 'axis',
confine: true,
formatter: function (params: any) {
const datum = chartData.value.find(
(el: any) => el.stnm === params[0].name
);
const unit = 'm³/s'; // TODO:
const content = params
.map((item: any) => {
const value = item.value ?? '-';
return `<div>${item.marker}${item.seriesName}: &nbsp;&nbsp;&nbsp;&nbsp;<span style="float:right">${value} ${unit}</span></div>`;
})
.join('');
return `<h3 style="color:white">${params[0].name}<br/>${
datum?.TM || ''
}</h3>${content}`;
},
axisPointer: {
type: 'line'
}
},
legend: {
data: ['入库流量', '生态流量', '环评要求限值'],
icon: 'roundRect',
top: 10
},
grid: {
left: 10,
right: 10,
bottom: 10,
top: 70,
containLabel: true
},
xAxis: {
type: 'category',
data: xData,
axisLine: {
lineStyle: {
color: '#505050'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#8f8f8f',
type: 'solid'
}
},
axisLabel: {
interval: xData.length > 12 ? 2 : 0,
rotate: 0,
formatter: (value: string, index: number) => {
const shortValue =
value.substring(0, 6) + (value.length > 6 ? '...' : '');
if (index % 2 !== 0) {
return `{a|${shortValue}}`;
} else {
return `\n{b|}${shortValue}`;
}
},
rich: {
a: {
height: 20,
align: 'center'
},
b: {
height: 30,
align: 'center'
}
}
}
},
yAxis: {
type: 'value',
name: '流量(m³/s)', // TODO:
minInterval: 1,
axisLine: {
lineStyle: {
color: '#505050'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#8f8f8f',
type: 'solid'
}
}
},
dataZoom: [
{
type: 'inside',
xAxisIndex: 0,
start: 0,
end: 100,
zoomOnMouseWheel: true,
moveOnMouseMove: true
}
],
series: [
{
name: '入库流量',
data: inData,
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 6,
connectNulls: true,
color: '#5470c6' // TODO:
},
{
name: '生态流量',
data: outData,
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 6,
connectNulls: true,
color: '#91cc75' // TODO:
},
{
name: '环评要求限值',
data: limitData,
type: 'bar',
barMaxWidth: 10,
color: '#fac858' // TODO:
}
]
};
chartInstance.setOption(option);
//
chartInstance.on('click', handleChartClick);
//
window.addEventListener('resize', handleResize);
};
/**
* 图表点击事件
*/
const handleChartClick = (params: any) => {
const datum = chartData.value.find((item: any) => item.stnm === params.name);
if (datum) {
const currentTime = dayjs(datetimePicker.value.value);
const startTime = currentTime.subtract(1, 'month');
modalVisible.value = true;
modelStore.modalVisible = true;
modelStore.params.sttp = 'ENG';
modelStore.title = datum.stnm;
modelStore.params.stcd = datum.stcd;
modelStore.params.eqtp = 'QEC';
modelStore.filter.rangeTm = [startTime, currentTime];
modelStore.filter.stllgzlx = 'qecInterval';
modelStore.filter.stllTmType = 'day';
}
};
/**
* 窗口大小改变时重新调整图表
*/
const handleResize = () => {
if (chartInstance) {
chartInstance.resize();
}
};
/**
* 弹窗取消事件
*/
const handleModalCancel = () => {
modalVisible.value = false;
modalData.value = {
stcd: '',
stnm: '',
titleName: ''
};
};
/**
* 面板数据变化处理
*/
const handlePanelChange = async (data: any) => {
console.log('当前所有控件状态:', data);
//
if (data.select) {
select.value.value = data.select;
selectData.value = data.select;
}
if (data.datetime) {
datetimePicker.value.value = data.datetime;
}
//
if (data.select || data.datetime) {
await loadChartData();
}
};
// ==================== ====================
//
watch(
() => JidiSelectEventStore.selectedItem,
newVal => {
console.log('流域切换:', newVal);
if (newVal?.wbsCode) {
wbsCode.value = newVal.wbsCode;
getSelect();
}
},
{ deep: true, immediate: true }
);
//
onBeforeUnmount(() => {
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
window.removeEventListener('resize', handleResize);
});
</script>
<style lang="scss" scoped>
.chart-loading {
display: flex;
justify-content: center;
align-items: center;
height: 424px;
}
.chart-empty {
display: flex;
align-items: center;
height: 424px;
flex-direction: column;
/* align-content: center; */
justify-content: center;
text-align: center !important;
:deep(.ant-empty-description) {
text-align: center !important;
text-indent: 0;
width: 100%;
}
}
.chart-container {
width: 406px;
height: 424px;
}
.time-tip {
text-align: right;
font-size: 12px;
color: #8e8e8e;
padding: 8px 0;
margin-top: 4px;
}
</style>

View File

@ -19,6 +19,7 @@ service.interceptors.request.use(
`Expected 'config' and 'config.headers' not to be undefined`
);
}
config.headers.tenant_id = '1';
if (
config.url.includes('/dec-lygk-base-server') ||
config.url.includes('/wmp-env-server') ||
@ -33,7 +34,7 @@ service.interceptors.request.use(
config.headers._sysid = '10EC2E0B-AEA9-4757-83A2-201BA1BC54E9';
config.headers.authorization =
'bearer aa5be16b-d1a3-4b93-9886-b2490025c7d6';
'bearer 0952e56d-8a77-4c43-abe4-a44367a22d73';
config.baseURL = '/';
} else {
const user = useUserStoreHook();

View File

@ -0,0 +1,10 @@
<template>
<div class="">
批复文件
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,10 @@
<template>
<div class="h-full bg-red-500">
基础
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,10 @@
<template>
<div class="">
综合导出
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,10 @@
<template>
<div class="">
过鱼监测数据
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,10 @@
<template>
<div class="">
鱼类放鱼数据
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,127 @@
<template>
<div class="approval-detail-search">
<BasicSearch
ref="basicSearchRef"
:searchList="searchList"
:initial-values="initSearchData"
:zhujianfujian="'fu'"
@reset="handleReset"
@finish="onSearchFinish"
@values-change="onValuesChange"
>
<template #actions>
<a-button @click="exportBtn">导出</a-button>
</template>
</BasicSearch>
</div>
</template>
<script lang="ts" setup>
import moment from 'moment';
import { ref, computed, onMounted } from 'vue';
import BasicSearch from '@/components/BasicSearch/index.vue';
interface Props {
exportBtn: () => void;
fish_ptype: any[];
familyList: any[];
ptypeLoading?: boolean;
familyLoading?: boolean;
}
const props = defineProps<Props>();
const emit = defineEmits<{
(e: 'reset', values: any): void;
(e: 'search-finish', values: any): void;
}>();
const localTypeDate = ref<string>(null);
const basicSearchRef = ref<any>();
const btnLoading = ref<boolean>(false);
const initSearchData = {
rvcd: 'all',
stcd: null,
ptype: 'all',
family: '全部'
};
const searchData = ref<any>({ ...initSearchData });
const searchList: any = computed(() => [
{
type: 'waterStation',
name: 'rvcd',
label: '流域',
fieldProps: {
allowClear: true
},
options: []
},
{
type: 'Select',
name: 'ptype',
label: '保护类别',
fieldProps: {
allowClear: false
},
loading: props.ptypeLoading,
options: props.fish_ptype.map((item: any) => ({
label: item.dictName,
value: item.itemCode
}))
},
{
type: 'Select',
name: 'family',
label: '科',
fieldProps: {
allowClear: false
},
loading: props.familyLoading,
options: props.familyList.map((item: any) => ({
label: item.key,
value: item.key
}))
},
{
type: 'Input',
name: 'name',
label: '',
placeholder: '请输入鱼类名称',
fieldProps: {},
options: []
}
]);
const onSearchFinish = (values: any) => {
emit('search-finish', values);
};
const onValuesChange = (changedValues: any, allValues: any) => {
searchData.value = { ...searchData.value, ...allValues };
if (
Object.keys(changedValues)[0] == 'rstcd' ||
Object.keys(changedValues)[0] == 'rvcd'
) {
const formInstance = basicSearchRef.value?.formData;
formInstance.stcd = null;
}
};
const handleReset = () => {
localTypeDate.value = null;
emit('reset', initSearchData);
};
defineExpose({
btnLoading,
searchData
});
onMounted(() => {
emit('search-finish', initSearchData);
});
</script>
<style lang="scss"></style>

View File

@ -0,0 +1,573 @@
<template>
<div class="w-full h-full">
<!-- 搜索组件 -->
<FishResourceSearch
:fish_ptype="fish_ptype_list"
:familyList="familyList"
:ptypeLoading="ptypeLoading"
:familyLoading="familyLoading"
:exportBtn="exportBtn"
@search-finish="onSearchFinish"
ref="searchRef"
/>
<a-row
type="flex"
class="mt-[20px] w-full"
style="height: calc(100% - 80px)"
>
<a-col flex="75%" class="pr-4 flex overflow-auto">
<!-- 表格组件 -->
<BasicTable
ref="tableRef"
:scrollX="tableScrollX"
:scrollY="tableScrollY"
:columns="columns"
:list-url="getFishResourceZYList"
:transformData="transformData"
@row-click="handleRowClick"
>
</BasicTable>
</a-col>
<a-col flex="25%" class="overflow-hidden">
<div
ref="rightPanelRef"
class="bg-[#fafafa] h-full pt-[10px] pr-[15px] pl-[15px]"
>
<a-spin :spinning="rightPanelLoading">
<div style="display: flex; align-items: center">
<div
style="
width: 4px;
height: 18px;
background-color: rgb(47, 107, 152);
margin-right: 10px;
"
></div>
<div style="font-size: 18px; color: rgba(0, 0, 0, 0.85)">
{{ fishResource.name }}
</div>
</div>
<div
:style="{ width: carouselWidth + 'px' }"
class="mt-[10px] px-[10px]"
>
<a-carousel
arrows
v-if="fishResource.logoList.length > 0"
class="w-full h-[306px] slick-arrow"
>
<template #prevArrow>
<div
class="custom-slick-arrow"
style="left: 10px; z-index: 1"
>
<left-circle-outlined />
</div>
</template>
<template #nextArrow>
<div class="custom-slick-arrow" style="right: 10px">
<right-circle-outlined />
</div>
</template>
<div v-for="(img, index) in fishResource.logoList" :key="index">
<img
:src="img"
alt=""
class="w-full h-[306px] object-cover"
/>
</div>
</a-carousel>
<a-empty v-else description="暂无图片" class="h-[306px]" />
</div>
<div
class="w-full mt-[10px] px-[10px]"
style="
margin-top: 24px;
font-size: 18px;
color: rgba(0, 0, 0, 0.85);
max-height: 440px;
overflow-y: scroll;
"
>
{{ fishResource.shapedesc }}
</div>
</a-spin>
</div>
</a-col>
</a-row>
</div>
</template>
<script setup lang="ts">
import {
ref,
computed,
watch,
onMounted,
onBeforeUnmount,
nextTick,
h
} from 'vue';
import FishResourceSearch from './FishResourceSearch.vue';
import BasicTable from '@/components/BasicTable/index.vue';
import { LeftCircleOutlined, RightCircleOutlined } from '@ant-design/icons-vue';
import { getDictItemsByCode } from '@/api/dict';
import {
getFishResourceList,
getFishResourceZYList
} from '@/api/DataQueryMenuModule';
import { calcTableScrollY } from '@/utils/index';
const fishResource = ref<any>({
name: '',
logoList: [],
shapedesc: ''
});
const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL;
const rightPanelRef = ref<HTMLElement | null>(null);
const carouselWidth = ref(0);
const tableScrollY = ref<string | number>(0);
const updateCarouselWidth = () => {
if (rightPanelRef.value) {
const rect = rightPanelRef.value.getBoundingClientRect();
carouselWidth.value = rect.width - 20; // px-[10px] padding
}
};
const updateTableScrollY = () => {
nextTick(() => {
tableScrollY.value = calcTableScrollY(rightPanelRef.value);
});
};
const resizeObserver = new ResizeObserver(() => {
updateCarouselWidth();
updateTableScrollY();
});
const tableScrollX = computed(() =>
Math.max(
columns.reduce((sum: number, col: any) => sum + (col.width || 180), 0),
600
)
);
const columns: any = [
{
key: 'index',
title: '序号',
dataIndex: 'index',
visible: true,
width: 80,
fixed: 'left'
},
{
key: 'name',
title: '中文名称',
dataIndex: 'name',
visible: true,
width: 150,
ellipsis: true,
fixed: 'left',
customRender: ({ text }: any) => {
return text
? h('span', { style: { color: '#2f6b98', cursor: 'pointer' } }, text)
: '-';
}
},
{
key: 'nameEn',
title: '拉丁学名',
dataIndex: 'nameEn',
visible: true,
width: 200,
ellipsis: true,
fixed: 'left'
},
{
key: 'rvcdName',
title: '所属流域',
dataIndex: 'rvcdName',
visible: true,
width: 100,
ellipsis: true,
fixed: 'left'
},
{
key: 'typeName',
title: '分类',
dataIndex: 'typeName',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'species',
title: '种',
dataIndex: 'species',
visible: true,
width: 150,
ellipsis: true
},
{
key: 'genus',
title: '属',
dataIndex: 'genus',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'family',
title: '科',
dataIndex: 'family',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'orders',
title: '目',
dataIndex: 'orders',
visible: true,
width: 150,
ellipsis: true
},
// {
// "key": "nameEn",
// "title": "",
// "dataIndex": "nameEn",
// "visible": true,
// width: 200,
// ellipsis: true,
// },
{
key: 'alias',
title: '俗名',
dataIndex: 'alias',
visible: true,
width: 200,
ellipsis: true
},
{
key: 'fsz',
title: '成鱼大小(cm)',
dataIndex: 'fsz',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'shapedesc',
title: '形态描述',
dataIndex: 'shapedesc',
visible: true,
width: 300,
ellipsis: true
},
{
key: 'habitation',
title: '栖息习性',
dataIndex: 'habitation',
visible: true,
width: 200,
ellipsis: true
},
{
key: 'habitMigrat',
title: '洄游习性',
dataIndex: 'habitMigrat',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'feedingHabit',
title: '摄食习性',
dataIndex: 'feedingHabit',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'food',
title: '主要食物',
dataIndex: 'food',
visible: true,
width: 200,
ellipsis: true
},
{
key: 'timeFeed',
title: '觅食时段',
dataIndex: 'timeFeed',
visible: true,
width: 200,
ellipsis: true
},
{
key: 'spawnMonth',
title: '产卵期(月)',
dataIndex: 'spawnMonth',
visible: true,
width: 200,
ellipsis: true
},
{
key: 'orignDate',
title: '产地及产期',
dataIndex: 'orignDate',
visible: true,
width: 300,
ellipsis: true
},
{
key: 'description',
title: '内容',
dataIndex: 'description',
visible: true,
width: 200,
ellipsis: true
},
{
key: 'pretemp',
title: '适宜温度',
dataIndex: 'pretemp',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'flowRate',
title: '适宜流速',
dataIndex: 'flowRate',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'depth',
title: '适宜水深(m)',
dataIndex: 'depth',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'wqtq',
title: '水质要求',
dataIndex: 'wqtq',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'spawnCharact',
title: '型',
dataIndex: 'spawnCharact',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'botmMater',
title: '地质',
dataIndex: 'botmMater',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'ptypeName',
title: '保护类型',
dataIndex: 'ptypeName',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'specOriginName',
title: '物种来源',
dataIndex: 'specOriginName',
visible: true,
width: 100,
ellipsis: true
},
{
key: 'vlsr',
title: '数据来源',
dataIndex: 'vlsr',
visible: true,
width: 150,
ellipsis: true
}
// {
// "key": "inffile",
// "title": "",
// "dataIndex": "inffile",
// "visible": true,
// width: 100,
// ellipsis: true,
// "fixed": "right",
// },
];
const rightNumber = ref(0);
const tableRef = ref();
const fish_ptype_list = ref<any>([]);
const familyList = ref<any>([]);
const ptypeLoading = ref(false);
const familyLoading = ref(false);
const rightPanelLoading = ref(false);
const exportBtn = () => {
console.log(fishResource.value);
};
const handleRowClick = (record: any) => {
rightPanelLoading.value = true;
// inffile
let logoList: string[] = [];
if (record.inffile && record.inffile !== '-') {
// URL
logoList = record.inffile
.split(',')
.map((item: string) => item.trim())
.filter((item: string) => item && item !== '-' && item.length > 0)
.map((item: string) => `${baseUrl}/?${item}&view=jpg`);
}
fishResource.value = {
name: record.name,
logoList,
shapedesc: record.shapedesc
};
// loading
setTimeout(() => {
rightPanelLoading.value = false;
}, 200);
};
const onSearchFinish = (values: any) => {
fishResource.value = {
name: '',
logoList: [],
shapedesc: ''
};
ininTable(values);
};
const transformData = (res: any) => {
if (res?.data?.data) {
if (rightNumber.value === 0) {
handleRowClick(res?.data?.data[0]);
}
rightNumber.value++;
}
return res?.data || [];
};
const ininTable = (values: any) => {
const params = {
logic: 'and',
filters: [
values.ptype && values.ptype !== 'all'
? {
field: 'ptype',
operator: 'eq',
dataType: 'string',
value: values.ptype
}
: null,
values.family && values.family !== 'all' && values.family !== '全部'
? {
field: 'family',
operator: 'eq',
dataType: 'string',
value: values.family
}
: null,
values.name
? {
field: 'name',
operator: 'contains',
dataType: 'string',
value: values.name
}
: null
].filter(Boolean)
};
tableRef.value.getList(params);
};
const init = () => {
ptypeLoading.value = true;
familyLoading.value = true;
getDictItemsByCode({ dictCode: 'FISH_PTYPE' }).then(res => {
res.data.unshift({
itemCode: 'all',
dictName: '全部'
});
fish_ptype_list.value = res.data;
ptypeLoading.value = false;
});
const params = {
group: [
{
field: 'family',
dir: 'asc'
}
]
};
getFishResourceList(params).then(res => {
res?.data?.data.unshift({
count: '全部',
key: '全部'
});
familyList.value = res?.data?.data || [];
familyLoading.value = false;
});
};
onMounted(() => {
init();
nextTick(() => {
updateCarouselWidth();
updateTableScrollY();
if (rightPanelRef.value) {
resizeObserver.observe(rightPanelRef.value);
}
});
});
onBeforeUnmount(() => {
resizeObserver.disconnect();
});
</script>
<style scoped lang="scss">
:deep(.slick-slide) {
text-align: center;
background: #364d79;
overflow: hidden;
}
:deep(.slick-arrow.custom-slick-arrow) {
width: 25px;
height: 25px;
font-size: 25px;
color: #fff;
background-color: rgba(31, 45, 61, 0.11);
transition: ease all 0.3s;
opacity: 0.3;
z-index: 1;
}
:deep(.slick-arrow.custom-slick-arrow:before) {
display: none;
}
:deep(.slick-arrow.custom-slick-arrow:hover) {
color: #fff;
opacity: 0.5;
}
:deep(.slick-slide h3) {
color: #fff;
}
</style>

View File

@ -0,0 +1,10 @@
<template>
<div class="">
生态流量运行数据
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,10 @@
<template>
<div class="">
流量站数据
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,10 @@
<template>
<div class="">
表层水温数据
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,10 @@
<template>
<div class="">
垂向水温数据
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,10 @@
<template>
<div class="">
水质监测数据
</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

Some files were not shown because too many files have changed in this diff Show More