feat(工作台): 新增用户布局
Some checks failed
MeterSphere 覆盖率统计 / 覆盖率统计 (push) Waiting to run
MeterSphere 前端代码校验 / 前端代码校验 (push) Waiting to run
SonarCloud / Build and analyze (push) Waiting to run
Mirror GitHub Auto Queried Repos to Gitee / Sync-GitHub-to-Gitee (push) Waiting to run
Check untimely handle issues / check-untimely-handle-issues (push) Has been cancelled

This commit is contained in:
guoyuqi 2024-11-07 19:47:14 +08:00 committed by Craftsman
parent 787996f806
commit 5a1e9ae697
35 changed files with 1675 additions and 217 deletions

View File

@ -0,0 +1,106 @@
package io.metersphere.system.domain;
import io.metersphere.validation.groups.*;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import lombok.Data;
@Data
public class UserLayout implements Serializable {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{user_layout.id.not_blank}", groups = {Updated.class})
@Size(min = 1, max = 50, message = "{user_layout.id.length_range}", groups = {Created.class, Updated.class})
private String id;
@Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{user_layout.user_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{user_layout.user_id.length_range}", groups = {Created.class, Updated.class})
private String userId;
@Schema(description = "组织ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{user_layout.org_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{user_layout.org_id.length_range}", groups = {Created.class, Updated.class})
private String orgId;
@Schema(description = "用户布局配置字段")
private byte[] configuration;
private static final long serialVersionUID = 1L;
public enum Column {
id("id", "id", "VARCHAR", false),
userId("user_id", "userId", "VARCHAR", false),
orgId("org_id", "orgId", "VARCHAR", false),
configuration("configuration", "configuration", "LONGVARBINARY", false);
private static final String BEGINNING_DELIMITER = "`";
private static final String ENDING_DELIMITER = "`";
private final String column;
private final boolean isColumnNameDelimited;
private final String javaProperty;
private final String jdbcType;
public String value() {
return this.column;
}
public String getValue() {
return this.column;
}
public String getJavaProperty() {
return this.javaProperty;
}
public String getJdbcType() {
return this.jdbcType;
}
Column(String column, String javaProperty, String jdbcType, boolean isColumnNameDelimited) {
this.column = column;
this.javaProperty = javaProperty;
this.jdbcType = jdbcType;
this.isColumnNameDelimited = isColumnNameDelimited;
}
public String desc() {
return this.getEscapedColumnName() + " DESC";
}
public String asc() {
return this.getEscapedColumnName() + " ASC";
}
public static Column[] excludes(Column ... excludes) {
ArrayList<Column> columns = new ArrayList<>(Arrays.asList(Column.values()));
if (excludes != null && excludes.length > 0) {
columns.removeAll(new ArrayList<>(Arrays.asList(excludes)));
}
return columns.toArray(new Column[]{});
}
public static Column[] all() {
return Column.values();
}
public String getEscapedColumnName() {
if (this.isColumnNameDelimited) {
return new StringBuilder().append(BEGINNING_DELIMITER).append(this.column).append(ENDING_DELIMITER).toString();
} else {
return this.column;
}
}
public String getAliasedEscapedColumnName() {
return this.getEscapedColumnName();
}
}
}

View File

@ -0,0 +1,410 @@
package io.metersphere.system.domain;
import java.util.ArrayList;
import java.util.List;
public class UserLayoutExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public UserLayoutExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(String value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(String value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(String value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(String value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(String value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(String value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdLike(String value) {
addCriterion("id like", value, "id");
return (Criteria) this;
}
public Criteria andIdNotLike(String value) {
addCriterion("id not like", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<String> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<String> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(String value1, String value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(String value1, String value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andUserIdIsNull() {
addCriterion("user_id is null");
return (Criteria) this;
}
public Criteria andUserIdIsNotNull() {
addCriterion("user_id is not null");
return (Criteria) this;
}
public Criteria andUserIdEqualTo(String value) {
addCriterion("user_id =", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotEqualTo(String value) {
addCriterion("user_id <>", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdGreaterThan(String value) {
addCriterion("user_id >", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdGreaterThanOrEqualTo(String value) {
addCriterion("user_id >=", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLessThan(String value) {
addCriterion("user_id <", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLessThanOrEqualTo(String value) {
addCriterion("user_id <=", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLike(String value) {
addCriterion("user_id like", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotLike(String value) {
addCriterion("user_id not like", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdIn(List<String> values) {
addCriterion("user_id in", values, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotIn(List<String> values) {
addCriterion("user_id not in", values, "userId");
return (Criteria) this;
}
public Criteria andUserIdBetween(String value1, String value2) {
addCriterion("user_id between", value1, value2, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotBetween(String value1, String value2) {
addCriterion("user_id not between", value1, value2, "userId");
return (Criteria) this;
}
public Criteria andOrgIdIsNull() {
addCriterion("org_id is null");
return (Criteria) this;
}
public Criteria andOrgIdIsNotNull() {
addCriterion("org_id is not null");
return (Criteria) this;
}
public Criteria andOrgIdEqualTo(String value) {
addCriterion("org_id =", value, "orgId");
return (Criteria) this;
}
public Criteria andOrgIdNotEqualTo(String value) {
addCriterion("org_id <>", value, "orgId");
return (Criteria) this;
}
public Criteria andOrgIdGreaterThan(String value) {
addCriterion("org_id >", value, "orgId");
return (Criteria) this;
}
public Criteria andOrgIdGreaterThanOrEqualTo(String value) {
addCriterion("org_id >=", value, "orgId");
return (Criteria) this;
}
public Criteria andOrgIdLessThan(String value) {
addCriterion("org_id <", value, "orgId");
return (Criteria) this;
}
public Criteria andOrgIdLessThanOrEqualTo(String value) {
addCriterion("org_id <=", value, "orgId");
return (Criteria) this;
}
public Criteria andOrgIdLike(String value) {
addCriterion("org_id like", value, "orgId");
return (Criteria) this;
}
public Criteria andOrgIdNotLike(String value) {
addCriterion("org_id not like", value, "orgId");
return (Criteria) this;
}
public Criteria andOrgIdIn(List<String> values) {
addCriterion("org_id in", values, "orgId");
return (Criteria) this;
}
public Criteria andOrgIdNotIn(List<String> values) {
addCriterion("org_id not in", values, "orgId");
return (Criteria) this;
}
public Criteria andOrgIdBetween(String value1, String value2) {
addCriterion("org_id between", value1, value2, "orgId");
return (Criteria) this;
}
public Criteria andOrgIdNotBetween(String value1, String value2) {
addCriterion("org_id not between", value1, value2, "orgId");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}

View File

@ -0,0 +1,40 @@
package io.metersphere.system.mapper;
import io.metersphere.system.domain.UserLayout;
import io.metersphere.system.domain.UserLayoutExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface UserLayoutMapper {
long countByExample(UserLayoutExample example);
int deleteByExample(UserLayoutExample example);
int deleteByPrimaryKey(String id);
int insert(UserLayout record);
int insertSelective(UserLayout record);
List<UserLayout> selectByExampleWithBLOBs(UserLayoutExample example);
List<UserLayout> selectByExample(UserLayoutExample example);
UserLayout selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") UserLayout record, @Param("example") UserLayoutExample example);
int updateByExampleWithBLOBs(@Param("record") UserLayout record, @Param("example") UserLayoutExample example);
int updateByExample(@Param("record") UserLayout record, @Param("example") UserLayoutExample example);
int updateByPrimaryKeySelective(UserLayout record);
int updateByPrimaryKeyWithBLOBs(UserLayout record);
int updateByPrimaryKey(UserLayout record);
int batchInsert(@Param("list") List<UserLayout> list);
int batchInsertSelective(@Param("list") List<UserLayout> list, @Param("selective") UserLayout.Column ... selective);
}

View File

@ -0,0 +1,269 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.system.mapper.UserLayoutMapper">
<resultMap id="BaseResultMap" type="io.metersphere.system.domain.UserLayout">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="user_id" jdbcType="VARCHAR" property="userId" />
<result column="org_id" jdbcType="VARCHAR" property="orgId" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.system.domain.UserLayout">
<result column="configuration" jdbcType="LONGVARBINARY" property="configuration" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, user_id, org_id
</sql>
<sql id="Blob_Column_List">
configuration
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.system.domain.UserLayoutExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from user_layout
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByExample" parameterType="io.metersphere.system.domain.UserLayoutExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from user_layout
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from user_layout
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from user_layout
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.system.domain.UserLayoutExample">
delete from user_layout
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.system.domain.UserLayout">
insert into user_layout (id, user_id, org_id,
configuration)
values (#{id,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR}, #{orgId,jdbcType=VARCHAR},
#{configuration,jdbcType=LONGVARBINARY})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.system.domain.UserLayout">
insert into user_layout
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="userId != null">
user_id,
</if>
<if test="orgId != null">
org_id,
</if>
<if test="configuration != null">
configuration,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="userId != null">
#{userId,jdbcType=VARCHAR},
</if>
<if test="orgId != null">
#{orgId,jdbcType=VARCHAR},
</if>
<if test="configuration != null">
#{configuration,jdbcType=LONGVARBINARY},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.system.domain.UserLayoutExample" resultType="java.lang.Long">
select count(*) from user_layout
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update user_layout
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.userId != null">
user_id = #{record.userId,jdbcType=VARCHAR},
</if>
<if test="record.orgId != null">
org_id = #{record.orgId,jdbcType=VARCHAR},
</if>
<if test="record.configuration != null">
configuration = #{record.configuration,jdbcType=LONGVARBINARY},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update user_layout
set id = #{record.id,jdbcType=VARCHAR},
user_id = #{record.userId,jdbcType=VARCHAR},
org_id = #{record.orgId,jdbcType=VARCHAR},
configuration = #{record.configuration,jdbcType=LONGVARBINARY}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update user_layout
set id = #{record.id,jdbcType=VARCHAR},
user_id = #{record.userId,jdbcType=VARCHAR},
org_id = #{record.orgId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.system.domain.UserLayout">
update user_layout
<set>
<if test="userId != null">
user_id = #{userId,jdbcType=VARCHAR},
</if>
<if test="orgId != null">
org_id = #{orgId,jdbcType=VARCHAR},
</if>
<if test="configuration != null">
configuration = #{configuration,jdbcType=LONGVARBINARY},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.system.domain.UserLayout">
update user_layout
set user_id = #{userId,jdbcType=VARCHAR},
org_id = #{orgId,jdbcType=VARCHAR},
configuration = #{configuration,jdbcType=LONGVARBINARY}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.system.domain.UserLayout">
update user_layout
set user_id = #{userId,jdbcType=VARCHAR},
org_id = #{orgId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<insert id="batchInsert" parameterType="map">
insert into user_layout
(id, user_id, org_id, configuration)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.userId,jdbcType=VARCHAR}, #{item.orgId,jdbcType=VARCHAR},
#{item.configuration,jdbcType=LONGVARBINARY})
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
insert into user_layout (
<foreach collection="selective" item="column" separator=",">
${column.escapedColumnName}
</foreach>
)
values
<foreach collection="list" item="item" separator=",">
(
<foreach collection="selective" item="column" separator=",">
<if test="'id'.toString() == column.value">
#{item.id,jdbcType=VARCHAR}
</if>
<if test="'user_id'.toString() == column.value">
#{item.userId,jdbcType=VARCHAR}
</if>
<if test="'org_id'.toString() == column.value">
#{item.orgId,jdbcType=VARCHAR}
</if>
<if test="'configuration'.toString() == column.value">
#{item.configuration,jdbcType=LONGVARBINARY}
</if>
</foreach>
)
</foreach>
</insert>
</mapper>

View File

@ -4,5 +4,73 @@ SET SESSION innodb_lock_wait_timeout = 7200;
-- 缺陷自定义字段增加文本字段
ALTER TABLE bug_custom_field ADD COLUMN `content` VARCHAR(1000) COMMENT '字段文本';
CREATE TABLE IF NOT EXISTS user_layout(
`id` VARCHAR(50) NOT NULL COMMENT 'id' ,
`user_id` VARCHAR(50) NOT NULL COMMENT '用户ID' ,
`org_id` VARCHAR(50) NOT NULL COMMENT '组织ID' ,
`configuration` LONGBLOB COMMENT '用户布局配置字段' ,
PRIMARY KEY (id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '用户布局表';
CREATE INDEX idx_user_id_org_id ON user_layout(`user_id`,`org_id`);
CREATE INDEX idx_project_id_delete_create_time_create_user
ON functional_case (project_id, deleted, create_time, create_user);
CREATE INDEX idx_project_id_delete_create_time
ON functional_case (project_id, deleted, create_time);
DROP INDEX idx_create_user ON case_review;
CREATE INDEX idx_project_id_create_time
ON case_review (project_id, create_time);
CREATE INDEX idx_project_id_create_time_create_user
ON case_review (project_id, create_time, create_user);
DROP INDEX idx_create_user ON api_definition;
CREATE INDEX idx_project_id_delete_create_time_create_user
ON api_definition (project_id, deleted, create_time, create_user);
CREATE INDEX idx_project_id_delete_create_time
ON api_definition (project_id, deleted, create_time);
DROP INDEX idx_create_user ON api_test_case;
CREATE INDEX idx_project_id_delete_create_time
ON api_test_case (project_id, deleted, create_time);
CREATE INDEX idx_project_id_delete_create_time_create_user
ON api_test_case (project_id, deleted, create_time, create_user);
DROP INDEX idx_create_user ON api_scenario;
CREATE INDEX idx_project_id_delete_create_time
ON api_scenario (project_id, deleted, create_time);
CREATE INDEX idx_project_id_delete_create_time_create_user
ON api_scenario (project_id, deleted, create_time, create_user);
DROP INDEX idx_create_user ON test_plan;
CREATE INDEX idx_project_id_delete_create_time
ON test_plan (project_id, create_time);
CREATE INDEX idx_project_id_create_time_create_user
ON test_plan (project_id, create_time, create_user);
CREATE INDEX idx_project_id_delete_create_time
ON bug (project_id, deleted, create_time);
CREATE INDEX idx_project_id_delete_create_time_create_user
ON bug (project_id, deleted, create_time, create_user);
-- set innodb lock wait timeout to default
SET SESSION innodb_lock_wait_timeout = DEFAULT;

View File

@ -11,12 +11,14 @@ import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.scenario.ScenarioSystemRequest;
import io.metersphere.project.dto.DropNode;
import io.metersphere.project.dto.NodeSortQueryParam;
import io.metersphere.project.dto.ProjectCountDTO;
import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.dto.table.TableBatchProcessDTO;
import io.metersphere.system.interceptor.BaseConditionFilter;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
public interface ExtApiDefinitionMapper {
void deleteApiToGc(@Param("ids") List<String> ids, @Param("userId") String userId, @Param("time") long time);
@ -107,4 +109,6 @@ public interface ExtApiDefinitionMapper {
long countByProjectAndId(@Param("projectId") String projectId, @Param("id") String id);
Long selectNumById(String id);
List<ProjectCountDTO> projectApiCount(@Param("projectIds") Set<String> projectIds, @Param("startTime") long startTime, @Param("endTime") long endTime, @Param("userId") String userId);
}

View File

@ -771,4 +771,20 @@
from api_definition
where id = #{0}
</select>
<select id="projectApiCount"
resultType="io.metersphere.project.dto.ProjectCountDTO">
SELECT api_definition.project_id as projectId, count(api_definition.id) as count
FROM api_definition
WHERE api_definition.project_id IN
<foreach collection="projectIds" item="projectId" separator="," open="(" close=")">
#{projectId}
</foreach>
AND api_definition.deleted = false
AND api_definition.create_time BETWEEN #{startTime} AND #{endTime}
<if test="userId != null and userId != ''">
AND api_definition.create_user = #{userId}
</if>
group by api_definition.project_id;
</select>
</mapper>

View File

@ -8,6 +8,7 @@ import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.project.dto.DropNode;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.NodeSortQueryParam;
import io.metersphere.project.dto.ProjectCountDTO;
import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.system.dto.sdk.BaseTreeNode;
@ -15,6 +16,7 @@ import io.metersphere.system.interceptor.BaseConditionFilter;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
public interface ExtApiScenarioMapper {
@ -100,4 +102,7 @@ public interface ExtApiScenarioMapper {
List<ApiScenario> selectBaseInfoByModuleIdAndProjectId(@Param("moduleId") String moduleId, @Param("projectId") String projectId);
List<ApiScenario> getNameInfo(@Param("ids") List<String> ids);
List<ProjectCountDTO> projectApiScenarioCount(@Param("projectIds") Set<String> projectIds, @Param("startTime") long startTime, @Param("endTime") long endTime, @Param("userId") String userId);
}

View File

@ -765,4 +765,21 @@
AND project_id = #{projectId}
AND deleted = false
</select>
<select id="projectApiScenarioCount"
resultType="io.metersphere.project.dto.ProjectCountDTO">
SELECT api_scenario.project_id as projectId, count(api_scenario.id) as count
FROM api_scenario
WHERE api_scenario.deleted = false
AND api_scenario.project_id IN
<foreach collection="projectIds" item="projectId" separator="," open="(" close=")">
#{projectId}
</foreach>
AND api_scenario.create_time BETWEEN #{startTime} AND #{endTime}
<if test="userId != null and userId != ''">
AND api_scenario.create_user = #{userId}
</if>
group by api_scenario.project_id;
</select>
</mapper>

View File

@ -8,6 +8,7 @@ import io.metersphere.dto.TestCaseProviderDTO;
import io.metersphere.project.dto.DropNode;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.NodeSortQueryParam;
import io.metersphere.project.dto.ProjectCountDTO;
import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.system.dto.sdk.BaseTreeNode;
@ -17,6 +18,7 @@ import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
/**
* @author jianxing
@ -132,4 +134,7 @@ public interface ExtApiTestCaseMapper {
List<ApiTestCaseWithBlob> selectAllDetailByIds(@Param("ids") List<String> apiIds);
List<ApiTestCaseDTO> selectBaseInfoByProjectIdAndApiId(@Param("projectId") String projectId, @Param("apiId") String apiId);
List<ProjectCountDTO> projectApiCaseCount(@Param("projectIds") Set<String> projectIds, @Param("startTime") long startTime, @Param("endTime") long endTime, @Param("userId") String userId);
}

View File

@ -985,4 +985,21 @@
AND api_definition_id = #{apiId}
AND deleted = false
</select>
<select id="projectApiCaseCount"
resultType="io.metersphere.project.dto.ProjectCountDTO">
SELECT api_test_case.project_id as projectId, count(api_test_case.id) as count
FROM api_test_case
WHERE api_test_case.deleted = false
AND api_test_case.project_id IN
<foreach collection="projectIds" item="projectId" separator="," open="(" close=")">
#{projectId}
</foreach>
AND api_test_case.create_time BETWEEN #{startTime} AND #{endTime}
<if test="userId != null and userId != ''">
AND api_test_case.create_user = #{userId}
</if>
group by api_test_case.project_id;
</select>
</mapper>

View File

@ -5,12 +5,14 @@ import io.metersphere.bug.dto.request.BugPageRequest;
import io.metersphere.bug.dto.response.BugDTO;
import io.metersphere.bug.dto.response.BugTagEditDTO;
import io.metersphere.dto.BugProviderDTO;
import io.metersphere.project.dto.ProjectCountDTO;
import io.metersphere.request.AssociateBugRequest;
import io.metersphere.request.BugPageProviderRequest;
import io.metersphere.system.interceptor.BaseConditionFilter;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
public interface ExtBugMapper {
@ -109,4 +111,7 @@ public interface ExtBugMapper {
*/
@BaseConditionFilter
List<String> getIdsByProvider(@Param("request") AssociateBugRequest request, @Param("deleted") boolean deleted);
List<ProjectCountDTO> projectBugCount(@Param("projectIds") Set<String> projectIds, @Param("startTime") long startTime, @Param("endTime") long endTime, @Param("userId") String userId);
}

View File

@ -353,5 +353,21 @@
<property name="deleted" value="${request.useTrash}"/>
</include>
</sql>
<select id="projectBugCount"
resultType="io.metersphere.project.dto.ProjectCountDTO">
SELECT bug.project_id as projectId, count(bug.id) as count
FROM bug
WHERE bug.deleted = false AND project_id IN
<foreach collection="projectIds" item="projectId" separator="," open="(" close=")">
#{projectId}
</foreach>
AND bug.create_time BETWEEN #{startTime} AND #{endTime}
<if test="userId != null and userId != ''">
AND bug.create_user = #{userId}
</if>
group by bug.project_id;
</select>
</mapper>

View File

@ -5,10 +5,12 @@ import io.metersphere.functional.dto.CaseReviewDTO;
import io.metersphere.functional.request.CaseReviewBatchRequest;
import io.metersphere.functional.request.CaseReviewPageRequest;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.ProjectCountDTO;
import io.metersphere.system.interceptor.BaseConditionFilter;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
/**
* @author guoyuqi
@ -39,4 +41,7 @@ public interface ExtCaseReviewMapper {
String getReviewPassRule(@Param("id") String id);
List<ProjectCountDTO> projectReviewCount(@Param("projectIds") Set<String> projectIds, @Param("startTime") long startTime, @Param("endTime") long endTime, @Param("userId") String userId);
}

View File

@ -267,186 +267,6 @@
</trim>
</sql>
<!--<sql id="combine">
<if test="request.combine != null">
<if test='${condition}.name != null'>
case_review.name
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.name"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.status != null'>
case_review.status
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.status"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.description != null'>
case_review.description
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.status"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.reviewPassRule != null'>
case_review.review_pass_rule
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.reviewPassRule"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.createUser != null'>
case_review.create_user
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.createUser"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.id != null'>
case_review.num
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.id"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="${condition}.updateTime != null">
case_review.update_time
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.updateTime"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="${condition}.createTime != null">
case_review.create_time
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.createTime"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="${condition}.startTime != null">
case_review.start_time
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.startTime"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="${condition}.endTime != null">
case_review.end_time
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.endTime"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.tags != null and ${ObjectTags}.operator == "not like"'>
(api_definition.tags is null or api_definition.tags
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.tags"/>
</include>
)
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.tags != null and ${ObjectTags}.operator == "like"'>
api_definition.tags
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.tags"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="${condition}.caseCount != null">
case_review.case_count
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.caseCount"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="${condition}.passRate != null">
case_review.pass_rate
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.passRate"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.reviewers != null and ${condition}.reviewers.size() > 0 and ${ObjectReviewers}.operator == "in"'>
case_review.id
<include refid="condition">
<property name="object" value="${condition}.reviewers"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.reviewers != null and ${condition}.reviewers.size() > 0 and ${ObjectReviewers}.operator == "not in"'>
case_review.id
<include refid="condition">
<property name="object" value="${condition}.reviewers"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.moduleIds != null and ${condition}.moduleIds.size() > 0 and ${ObjectModuleIds}.operator == "in"'>
case_review.module_id
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.moduleIds"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test='${condition}.moduleIds != null and ${condition}.moduleIds.size() > 0 and ${ObjectModuleIds}.operator == "not in"'>
case_review.module_id
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.moduleIds"/>
</include>
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
</if>
</sql>-->
<sql id="condition">
<choose>
@ -516,4 +336,20 @@
<select id="getReviewPassRule" resultType="java.lang.String">
select review_pass_rule from case_review where id = #{id}
</select>
<select id="projectReviewCount"
resultType="io.metersphere.project.dto.ProjectCountDTO">
SELECT case_review.project_id as projectId, count(case_review.id) as count
FROM case_review
WHERE case_review.project_id IN
<foreach collection="projectIds" item="projectId" separator="," open="(" close=")">
#{projectId}
</foreach>
AND case_review.create_time BETWEEN #{startTime} AND #{endTime}
<if test="userId != null and userId != ''">
AND case_review.create_user = #{userId}
</if>
group by case_review.project_id;
</select>
</mapper>

View File

@ -9,6 +9,7 @@ import io.metersphere.functional.dto.FunctionalCasePageDTO;
import io.metersphere.functional.dto.FunctionalCaseVersionDTO;
import io.metersphere.functional.request.*;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.ProjectCountDTO;
import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.system.dto.sdk.BaseTreeNode;
@ -16,6 +17,7 @@ import io.metersphere.system.interceptor.BaseConditionFilter;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
/**
* @author wx
@ -116,4 +118,7 @@ public interface ExtFunctionalCaseMapper {
List<FunctionalCase> getListBySelectIds(@Param("projectId") String projectId, @Param("ids") List<String> ids, @Param("testPlanId") String testPlanId);
List<FunctionalCase> getProjectIdByIds(@Param("ids") List<String> ids);
List<ProjectCountDTO> projectCaseCount(@Param("projectIds") Set<String> projectIds, @Param("startTime") long startTime, @Param("endTime") long endTime, @Param("userId") String userId);
}

View File

@ -899,4 +899,22 @@
#{id}
</foreach>
</select>
<select id="projectCaseCount"
resultType="io.metersphere.project.dto.ProjectCountDTO">
SELECT functional_case.project_id as projectId, count(functional_case.id) as count
FROM functional_case
WHERE functional_case.deleted = false
AND functional_case.project_id IN
<foreach collection="projectIds" item="projectId" separator="," open="(" close=")">
#{projectId}
</foreach>
AND functional_case.create_time BETWEEN #{startTime} AND #{endTime}
<if test="userId != null and userId != ''">
AND functional_case.create_user = #{userId}
</if>
group by functional_case.project_id;
</select>
</mapper>

View File

@ -1,8 +0,0 @@
package io.metersphere.dashboard;
import org.springframework.stereotype.Controller;
@Controller
public class DashboardController {
}

View File

@ -0,0 +1,56 @@
package io.metersphere.dashboard.controller;
import io.metersphere.dashboard.dto.LayoutDTO;
import io.metersphere.dashboard.request.DashboardFrontPageRequest;
import io.metersphere.dashboard.response.OverViewCountDTO;
import io.metersphere.dashboard.service.DashboardService;
import io.metersphere.system.security.CheckOwner;
import io.metersphere.system.utils.SessionUtils;
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.*;
import java.util.List;
@Tag(name = "工作台-首页")
@RestController
@RequestMapping("/dashboard")
public class DashboardController {
@Resource
private DashboardService dashboardService;
@PostMapping("/layout/edit/{organizationId}")
@Operation(summary = "编辑用户布局")
@CheckOwner(resourceId = "#organizationId", resourceType = "organization")
public List<LayoutDTO> editLayout(@PathVariable String organizationId, @Validated @RequestBody List<LayoutDTO> layoutDTO) {
return dashboardService.editLayout(organizationId, SessionUtils.getUserId(), layoutDTO);
}
@GetMapping("/layout/get/{organizationId}")
@Operation(summary = "获取用户布局")
@CheckOwner(resourceId = "#organizationId", resourceType = "organization")
public List<LayoutDTO> getLayout(@PathVariable String organizationId) {
return dashboardService.getLayout(organizationId, SessionUtils.getUserId());
}
@PostMapping("/CREATE_BY_ME")
@Operation(summary = "我创建的")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
public OverViewCountDTO createByMeCount(@Validated @RequestBody DashboardFrontPageRequest request) {
return dashboardService.createByMeCount(request, SessionUtils.getUserId());
}
@PostMapping("/PROJECT_VIEW")
@Operation(summary = "概览")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
public OverViewCountDTO projectViewCount(@Validated @RequestBody DashboardFrontPageRequest request) {
return dashboardService.projectViewCount(request, SessionUtils.getUserId());
}
}

View File

@ -11,13 +11,19 @@ import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
public class LayoutDTO {
@Schema(description = "布局卡片key")
@Schema(description = "布局卡片id")
private String id;
@Schema(description = "布局卡片key")
private String key;
@Schema(description = "布局卡片label")
private String label;
@Schema(description = "排序")
private Integer pos;
@Schema(description = "全屏/半屏")
private Boolean fullScreen;
@Schema(description = "选中的项目ID")
private List<String> projectIds;
@Schema(description = "人员集合")
private List<String> handleUsers;
}

View File

@ -0,0 +1,24 @@
package io.metersphere.dashboard.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class NameArrayDTO {
@Schema(description = "id")
private String id;
@Schema(description = "名称")
private String name;
@Schema(description = "数量集合")
private List<Integer> count;
}

View File

@ -3,14 +3,49 @@ package io.metersphere.dashboard.request;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.util.List;
@Data
public class DashboardFrontPageRequest extends DashboardBaseRequest{
@Schema(description = "固定时间天数")
private Integer dayNumber;
@Schema(description = "自定义开始时间")
private Long startTime;
@Schema(description = "自定义结束时间")
private Long endTime;
@Schema(description = "项目ID集合")
private List<String> projectIds;
@Schema(description = "人员集合")
private List<String> handleUsers;
public Long getToStartTime() {
if (startTime == null && dayNumber>0) {
LocalDate now = LocalDate.now();
LocalDate localDate = now.minusDays(dayNumber);
LocalDateTime localDateTime = LocalDateTime.of(localDate, LocalTime.MIN);//当天零点
return localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
} else {
return startTime;
}
}
public Long getToEndTime() {
if (endTime == null && dayNumber>0) {
LocalDateTime now = LocalDateTime.now();
return now.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
} else {
return endTime;
}
}
}

View File

@ -0,0 +1,26 @@
package io.metersphere.dashboard.response;
import io.metersphere.dashboard.dto.NameArrayDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OverViewCountDTO {
@Schema(description = "用例模块数量")
private Map<String, Integer> caseCountMap;
@Schema(description = "横坐标数量")
private List<String> xAxis;
@Schema(description = "项目模块数量DTO")
private List<NameArrayDTO> projectCountList;
}

View File

@ -1,8 +1,6 @@
package io.metersphere.dashboard.service;
import io.metersphere.project.domain.Project;
import io.metersphere.project.domain.ProjectExample;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.project.service.PermissionCheckService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.dto.user.UserDTO;
@ -20,32 +18,26 @@ public class DashboardProjectService {
@Resource
private PermissionCheckService permissionCheckService;
@Resource
private ProjectMapper projectMapper;
public static final String API_TEST = "apiTest";
public static final String TEST_PLAN = "testPlan";
public static final String FUNCTIONAL_CASE = "caseManagement";
public static final String BUG = "bugManagement";
public Map<String, Set<String>> getPermissionModuleProjectIds(String organizationId, List<String> projectIds, String userId) {
/**
* 获取用户组织内有只读权限且开启相关模块的项目
*
* @param userId 当前用户
* @return 只读权限对应的开启模块的项目ids
*/
public Map<String, Set<String>> getPermissionModuleProjectIds(List<Project> projects, String userId) {
boolean isAdmin = isAdmin(userId);
Set<String> projectSet;
Map<String, String> moduleMap;
if (CollectionUtils.isNotEmpty(projectIds)) {
projectSet = new HashSet<>(projectIds);
ProjectExample projectExample = new ProjectExample();
projectExample.createCriteria().andIdIn(projectIds);
List<Project> projects = projectMapper.selectByExample(projectExample);
moduleMap = projects.stream().collect(Collectors.toMap(Project::getId, Project::getModuleSetting));
} else {
ProjectExample projectExample = new ProjectExample();
projectExample.createCriteria().andOrganizationIdEqualTo(organizationId);
List<Project> projects = projectMapper.selectByExample(projectExample);
projectSet = projects.stream().map(Project::getId).collect(Collectors.toSet());
moduleMap = projects.stream().collect(Collectors.toMap(Project::getId, Project::getModuleSetting));
}
projectSet = projects.stream().map(Project::getId).collect(Collectors.toSet());
moduleMap = projects.stream().collect(Collectors.toMap(Project::getId, Project::getModuleSetting));
Map<String, Set<String>> hasModuleProjectIds = new HashMap<>();
Map<String, String> finalModuleMap = moduleMap;
Set<String> searchCaseProjectIds = new HashSet<>();
@ -63,6 +55,7 @@ public class DashboardProjectService {
Set<String> functionalProjectIds = hasUserPermissionProjectIds.get(PermissionConstants.FUNCTIONAL_CASE_READ);
//检查是否开启功能用例模块
if (CollectionUtils.isNotEmpty(functionalProjectIds)) {
//有权限
searchCaseProjectIds = functionalProjectIds.stream().filter(t -> finalModuleMap.get(t).contains(FUNCTIONAL_CASE)).collect(Collectors.toSet());
}
Set<String> reviewProjectIds = hasUserPermissionProjectIds.get(PermissionConstants.CASE_REVIEW_READ);
@ -102,6 +95,7 @@ public class DashboardProjectService {
searchPlanProjectIds = projectSet.stream().filter(t -> finalModuleMap.get(t).contains(TEST_PLAN)).collect(Collectors.toSet());
searchBugProjectIds = projectSet.stream().filter(t -> finalModuleMap.get(t).contains(BUG)).collect(Collectors.toSet());
}
//如果value 为空则没有权限或者没开启模块
hasModuleProjectIds.put(PermissionConstants.FUNCTIONAL_CASE_READ, searchCaseProjectIds);
hasModuleProjectIds.put(PermissionConstants.CASE_REVIEW_READ, searchReviewProjectIds);
hasModuleProjectIds.put(PermissionConstants.PROJECT_API_DEFINITION_READ, searchApiProjectIds);
@ -113,6 +107,31 @@ public class DashboardProjectService {
return hasModuleProjectIds;
}
/**
* 当前用户在组织内有任意权限的且开启模块的项目
*
* @param userProject 在组织内有任意权限项目
* @return 模块开启对应的项目ids
*/
public Map<String, Set<String>> getModuleProjectIds(List<Project> userProject) {
Map<String, String> moduleMap = userProject.stream().collect(Collectors.toMap(Project::getId, Project::getModuleSetting));
Set<String> projectIds = userProject.stream().map(Project::getId).collect(Collectors.toSet());
Set<String> searchCaseProjectIds = projectIds.stream().filter(t -> moduleMap.get(t).contains(FUNCTIONAL_CASE)).collect(Collectors.toSet());
Set<String> searchApiProjectIds = projectIds.stream().filter(t -> moduleMap.get(t).contains(API_TEST)).collect(Collectors.toSet());
Set<String> searchPlanProjectIds = projectIds.stream().filter(t -> moduleMap.get(t).contains(TEST_PLAN)).collect(Collectors.toSet());
Set<String> searchBugProjectIds = projectIds.stream().filter(t -> moduleMap.get(t).contains(BUG)).collect(Collectors.toSet());
Map<String, Set<String>> hasModuleProjectIds = new HashMap<>();
hasModuleProjectIds.put(PermissionConstants.FUNCTIONAL_CASE_READ, searchCaseProjectIds);
hasModuleProjectIds.put(PermissionConstants.CASE_REVIEW_READ, searchCaseProjectIds);
hasModuleProjectIds.put(PermissionConstants.PROJECT_API_DEFINITION_READ, searchApiProjectIds);
hasModuleProjectIds.put(PermissionConstants.PROJECT_API_DEFINITION_CASE_READ, searchApiProjectIds);
hasModuleProjectIds.put(PermissionConstants.PROJECT_API_SCENARIO_READ, searchApiProjectIds);
hasModuleProjectIds.put(PermissionConstants.TEST_PLAN_READ, searchPlanProjectIds);
hasModuleProjectIds.put(PermissionConstants.PROJECT_BUG_READ, searchBugProjectIds);
return hasModuleProjectIds;
}
private static Set<String> getPermissionSet() {
Set<String> permissionSet = new HashSet<>();
permissionSet.add(PermissionConstants.FUNCTIONAL_CASE_READ);
@ -127,6 +146,9 @@ public class DashboardProjectService {
private boolean isAdmin(String userId) {
UserDTO userDTO = permissionCheckService.getUserDTO(userId);
if (userDTO == null) {
return false;
}
return permissionCheckService.checkAdmin(userDTO);
}
}

View File

@ -0,0 +1,258 @@
package io.metersphere.dashboard.service;
import io.metersphere.api.mapper.ExtApiDefinitionMapper;
import io.metersphere.api.mapper.ExtApiScenarioMapper;
import io.metersphere.api.mapper.ExtApiTestCaseMapper;
import io.metersphere.bug.mapper.ExtBugMapper;
import io.metersphere.dashboard.dto.LayoutDTO;
import io.metersphere.dashboard.dto.NameArrayDTO;
import io.metersphere.dashboard.request.DashboardFrontPageRequest;
import io.metersphere.dashboard.response.OverViewCountDTO;
import io.metersphere.functional.mapper.ExtCaseReviewMapper;
import io.metersphere.functional.mapper.ExtFunctionalCaseMapper;
import io.metersphere.plan.mapper.ExtTestPlanMapper;
import io.metersphere.project.domain.Project;
import io.metersphere.project.dto.ProjectCountDTO;
import io.metersphere.project.mapper.ExtProjectMapper;
import io.metersphere.project.service.ProjectService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.domain.UserLayout;
import io.metersphere.system.domain.UserLayoutExample;
import io.metersphere.system.mapper.UserLayoutMapper;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author guoyuqi
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class DashboardService {
@Resource
private DashboardProjectService dashboardProjectService;
@Resource
private ExtFunctionalCaseMapper extFunctionalCaseMapper;
@Resource
private ExtCaseReviewMapper extCaseReviewMapper;
@Resource
private ExtApiDefinitionMapper extApiDefinitionMapper;
@Resource
private ExtApiTestCaseMapper extApiTestCaseMapper;
@Resource
private ExtApiScenarioMapper extApiScenarioMapper;
@Resource
private ExtTestPlanMapper extTestPlanMapper;
@Resource
private ExtBugMapper extBugMapper;
@Resource
private ExtProjectMapper extProjectMapper;
@Resource
private ProjectService projectService;
@Resource
private UserLayoutMapper userLayoutMapper;
public static final String FUNCTIONAL = "FUNCTIONAL"; // 功能用例
public static final String CASE_REVIEW = "CASE_REVIEW"; // 用例评审
public static final String API = "API";
public static final String API_CASE = "API_CASE";
public static final String API_SCENARIO = "API_SCENARIO";
public static final String TEST_PLAN = "TEST_PLAN"; // 测试计划
public static final String BUG_COUNT = "BUG_COUNT"; // 缺陷数量
public OverViewCountDTO createByMeCount(DashboardFrontPageRequest request, String userId) {
List<Project> projects;
if (CollectionUtils.isNotEmpty(request.getProjectIds())) {
projects = extProjectMapper.getProjectNameModule(null, request.getProjectIds());
} else {
projects = extProjectMapper.getProjectNameModule(request.getOrganizationId(), null);
}
Map<String, Set<String>> permissionModuleProjectIdMap = dashboardProjectService.getPermissionModuleProjectIds(projects, userId);
Long toStartTime = request.getToStartTime();
Long toEndTime = request.getToEndTime();
return getModuleCountMap(permissionModuleProjectIdMap, projects, toStartTime, toEndTime, userId);
}
@NotNull
private OverViewCountDTO getModuleCountMap(Map<String, Set<String>> permissionModuleProjectIdMap, List<Project> projects, Long toStartTime, Long toEndTime, String userId) {
Map<String, Integer> map = new HashMap<>();
List<String> xaxis = new ArrayList<>();
//TODO 返回数量顺序
List<NameArrayDTO> nameArrayDTOList = new ArrayList<>();
//功能用例
Map<String, ProjectCountDTO> caseProjectCount = new HashMap<>();
Set<String> caseProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.FUNCTIONAL_CASE_READ);
if (CollectionUtils.isNotEmpty(caseProjectIds)) {
//有权限
List<ProjectCountDTO> projectCaseCount = extFunctionalCaseMapper.projectCaseCount(caseProjectIds, toStartTime, toEndTime, userId);
int caseCount = projectCaseCount.stream().mapToInt(ProjectCountDTO::getCount).sum();
map.put(FUNCTIONAL, caseCount);
xaxis.add(FUNCTIONAL);
caseProjectCount = projectCaseCount.stream().collect(Collectors.toMap(ProjectCountDTO::getProjectId, t -> t));
}
//用例评审
Map<String, ProjectCountDTO> reviewProjectCount = new HashMap<>();
Set<String> reviewProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.CASE_REVIEW_READ);
if (CollectionUtils.isNotEmpty(reviewProjectIds)) {
List<ProjectCountDTO> projectReviewCount = extCaseReviewMapper.projectReviewCount(reviewProjectIds, toStartTime, toEndTime, userId);
int reviewCount = projectReviewCount.stream().mapToInt(ProjectCountDTO::getCount).sum();
map.put(CASE_REVIEW, reviewCount);
xaxis.add(CASE_REVIEW);
reviewProjectCount = projectReviewCount.stream().collect(Collectors.toMap(ProjectCountDTO::getProjectId, t -> t));
}
//接口
Map<String, ProjectCountDTO> apiProjectCount = new HashMap<>();
Set<String> apiProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.PROJECT_API_DEFINITION_READ);
if (CollectionUtils.isNotEmpty(apiProjectIds)) {
List<ProjectCountDTO> projectApiCount = extApiDefinitionMapper.projectApiCount(apiProjectIds, toStartTime, toEndTime, userId);
int apiCount = projectApiCount.stream().mapToInt(ProjectCountDTO::getCount).sum();
map.put(API, apiCount);
xaxis.add(API);
apiProjectCount = projectApiCount.stream().collect(Collectors.toMap(ProjectCountDTO::getProjectId, t -> t));
}
//接口用例
Map<String, ProjectCountDTO> apiCaseProjectCount = new HashMap<>();
Set<String> apiCaseProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.PROJECT_API_DEFINITION_CASE_READ);
if (CollectionUtils.isNotEmpty(apiCaseProjectIds)) {
List<ProjectCountDTO> projectApiCaseCount = extApiTestCaseMapper.projectApiCaseCount(apiCaseProjectIds, toStartTime, toEndTime, userId);
int apiCaseCount = projectApiCaseCount.stream().mapToInt(ProjectCountDTO::getCount).sum();
map.put(API_CASE, apiCaseCount);
xaxis.add(API_CASE);
apiCaseProjectCount = projectApiCaseCount.stream().collect(Collectors.toMap(ProjectCountDTO::getProjectId, t -> t));
}
//接口场景
Map<String, ProjectCountDTO> apiScenarioProjectCount = new HashMap<>();
Set<String> scenarioProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.PROJECT_API_SCENARIO_READ);
if (CollectionUtils.isNotEmpty(scenarioProjectIds)) {
List<ProjectCountDTO> projectApiScenarioCount = extApiScenarioMapper.projectApiScenarioCount(scenarioProjectIds, toStartTime, toEndTime, userId);
int apiScenarioCount = projectApiScenarioCount.stream().mapToInt(ProjectCountDTO::getCount).sum();
map.put(API_SCENARIO, apiScenarioCount);
xaxis.add(API_SCENARIO);
apiScenarioProjectCount = projectApiScenarioCount.stream().collect(Collectors.toMap(ProjectCountDTO::getProjectId, t -> t));
}
//测试计划
Map<String, ProjectCountDTO> testPlanProjectCount = new HashMap<>();
Set<String> planProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.TEST_PLAN_READ);
if (CollectionUtils.isNotEmpty(planProjectIds)) {
List<ProjectCountDTO> projectPlanCount = extTestPlanMapper.projectPlanCount(planProjectIds, toStartTime, toEndTime, userId);
int testPlanCount = projectPlanCount.stream().mapToInt(ProjectCountDTO::getCount).sum();
map.put(TEST_PLAN, testPlanCount);
xaxis.add(TEST_PLAN);
testPlanProjectCount = projectPlanCount.stream().collect(Collectors.toMap(ProjectCountDTO::getProjectId, t -> t));
}
//缺陷管理
Map<String, ProjectCountDTO> bugProjectCount = new HashMap<>();
Set<String> bugProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.PROJECT_BUG_READ);
if (CollectionUtils.isNotEmpty(bugProjectIds)) {
List<ProjectCountDTO> projectBugCount = extBugMapper.projectBugCount(bugProjectIds, toStartTime, toEndTime, userId);
int bugCount = projectBugCount.stream().mapToInt(ProjectCountDTO::getCount).sum();
map.put(BUG_COUNT, bugCount);
xaxis.add(TEST_PLAN);
bugProjectCount = projectBugCount.stream().collect(Collectors.toMap(ProjectCountDTO::getProjectId, t -> t));
}
for (Project project : projects) {
String projectId = project.getId();
String projectName = project.getName();
NameArrayDTO nameArrayDTO = new NameArrayDTO();
nameArrayDTO.setId(projectId);
nameArrayDTO.setName(projectName);
List<Integer> count = new ArrayList<>();
ProjectCountDTO projectCountDTO = caseProjectCount.get(projectId);
if (projectCountDTO != null) {
count.add(projectCountDTO.getCount());
} else {
count.add(0);
}
ProjectCountDTO reviewDTO = reviewProjectCount.get(projectId);
if (reviewDTO != null) {
count.add(reviewDTO.getCount());
} else {
count.add(0);
}
ProjectCountDTO apiDTO = apiProjectCount.get(projectId);
if (apiDTO != null) {
count.add(apiDTO.getCount());
} else {
count.add(0);
}
ProjectCountDTO apiCaseDTO = apiCaseProjectCount.get(projectId);
if (apiCaseDTO != null) {
count.add(apiCaseDTO.getCount());
} else {
count.add(0);
}
ProjectCountDTO apiScenarioDTO = apiScenarioProjectCount.get(projectId);
if (apiScenarioDTO != null) {
count.add(apiScenarioDTO.getCount());
} else {
count.add(0);
}
ProjectCountDTO testPlanDTO = testPlanProjectCount.get(projectId);
if (testPlanDTO != null) {
count.add(testPlanDTO.getCount());
} else {
count.add(0);
}
ProjectCountDTO bugDTO = bugProjectCount.get(projectId);
if (bugDTO != null) {
count.add(bugDTO.getCount());
} else {
count.add(0);
}
nameArrayDTO.setCount(count);
nameArrayDTOList.add(nameArrayDTO);
}
OverViewCountDTO overViewCountDTO = new OverViewCountDTO();
overViewCountDTO.setCaseCountMap(map);
overViewCountDTO.setXAxis(xaxis);
overViewCountDTO.setProjectCountList(nameArrayDTOList);
return overViewCountDTO;
}
public OverViewCountDTO projectViewCount(DashboardFrontPageRequest request, String userId) {
List<Project> userProject = projectService.getUserProject(request.getOrganizationId(), userId);
List<Project> collect = userProject.stream().filter(t -> request.getProjectIds().contains(t.getId())).toList();
Map<String, Set<String>> permissionModuleProjectIdMap = dashboardProjectService.getModuleProjectIds(collect);
Long toStartTime = request.getToStartTime();
Long toEndTime = request.getToEndTime();
return getModuleCountMap(permissionModuleProjectIdMap, collect, toStartTime, toEndTime, null);
}
public List<LayoutDTO> editLayout(String organizationId, String userId, List<LayoutDTO> layoutDTO) {
UserLayout userLayout = new UserLayout();
userLayout.setId(IDGenerator.nextStr());
userLayout.setUserId(userId);
userLayout.setOrgId(organizationId);
String configuration = JSON.toJSONString(layoutDTO);
userLayout.setConfiguration(configuration.getBytes());
userLayoutMapper.insert(userLayout);
return layoutDTO;
}
public List<LayoutDTO> getLayout(String organizationId, String userId) {
UserLayoutExample userLayoutExample = new UserLayoutExample();
userLayoutExample.createCriteria().andUserIdEqualTo(userId).andOrgIdEqualTo(organizationId);
List<UserLayout> userLayouts = userLayoutMapper.selectByExampleWithBLOBs(userLayoutExample);
UserLayout userLayout = userLayouts.getFirst();
byte[] configuration = userLayout.getConfiguration();
String layoutDTOStr = new String(configuration);
return JSON.parseArray(layoutDTOStr, LayoutDTO.class);
}
}

View File

@ -0,0 +1,118 @@
package io.metersphere.dashboard.controller;
import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.dashboard.constants.DashboardUserLayoutKeys;
import io.metersphere.dashboard.dto.LayoutDTO;
import io.metersphere.dashboard.request.DashboardFrontPageRequest;
import io.metersphere.dashboard.response.OverViewCountDTO;
import io.metersphere.dashboard.service.DashboardService;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.mapper.UserLayoutMapper;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.web.servlet.MvcResult;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class DashboardFrontPageControllerTests extends BaseTest {
@Resource
private DashboardService dashboardService;
@Resource
private UserLayoutMapper userLayoutMapper;
private static final String EDIT_LAYOUT = "/dashboard/layout/edit/";
private static final String GET_LAYOUT = "/dashboard/layout/get/";
private static final String CREATE_BY_ME = "/dashboard/CREATE_BY_ME";
private static final String PROJECT_VIEW = "/dashboard/PROJECT_VIEW";
@Test
@Order(1)
@Sql(scripts = {"/dml/init_dashboard.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void testSql() throws Exception {
DashboardFrontPageRequest dashboardFrontPageRequest = new DashboardFrontPageRequest();
dashboardFrontPageRequest.setOrganizationId(DEFAULT_ORGANIZATION_ID);
dashboardFrontPageRequest.setDayNumber(3);
dashboardFrontPageRequest.setCurrent(1);
dashboardFrontPageRequest.setPageSize(5);
dashboardFrontPageRequest.setProjectIds(List.of(DEFAULT_PROJECT_ID));
MvcResult mvcResult = this.requestPostWithOkAndReturn(CREATE_BY_ME, dashboardFrontPageRequest);
String contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
OverViewCountDTO moduleCount = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), OverViewCountDTO.class);
Assertions.assertNotNull(moduleCount);
MvcResult mvcResultAll = this.requestPostWithOkAndReturn(PROJECT_VIEW, dashboardFrontPageRequest);
OverViewCountDTO moduleCountAll = ApiDataUtils.parseObject(JSON.toJSONString(parseResponse(mvcResultAll).get("data")), OverViewCountDTO.class);
Assertions.assertNotNull(moduleCountAll);
dashboardFrontPageRequest.setDayNumber(null);
dashboardFrontPageRequest.setStartTime(1716185577387L);
dashboardFrontPageRequest.setEndTime(1730181702699L);
dashboardFrontPageRequest.setProjectIds(new ArrayList<>());
mvcResult = this.requestPostWithOkAndReturn(CREATE_BY_ME, dashboardFrontPageRequest);
moduleCount = JSON.parseObject(JSON.toJSONString(
JSON.parseObject(mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()),
OverViewCountDTO.class);
Assertions.assertNotNull(moduleCount);
mvcResultAll = this.requestPostWithOkAndReturn(PROJECT_VIEW, dashboardFrontPageRequest);
moduleCountAll = JSON.parseObject(JSON.toJSONString(
JSON.parseObject(mvcResultAll.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()),
OverViewCountDTO.class);
Assertions.assertNotNull(moduleCountAll);
OverViewCountDTO gyq = dashboardService.createByMeCount(dashboardFrontPageRequest, "gyq");
Assertions.assertNotNull(gyq);
OverViewCountDTO gyq1 = dashboardService.projectViewCount(dashboardFrontPageRequest, "gyq");
Assertions.assertNotNull(gyq1);
OverViewCountDTO gyq2 = dashboardService.projectViewCount(dashboardFrontPageRequest, "default-dashboard-member-user-gyq");
Assertions.assertNotNull(gyq2);
OverViewCountDTO gyq3 = dashboardService.projectViewCount(dashboardFrontPageRequest, "default-dashboard-member-user-gyq");
Assertions.assertNotNull(gyq3);
}
@Test
@Order(2)
public void testLayout() throws Exception {
List<LayoutDTO> layoutDTO = new ArrayList<>();
LayoutDTO layoutDTO1 = new LayoutDTO();
layoutDTO1.setId(UUID.randomUUID().toString());
layoutDTO1.setPos(1);
layoutDTO1.setKey(DashboardUserLayoutKeys.CASE_COUNT.toString());
layoutDTO1.setLabel("用例数量");
layoutDTO1.setProjectIds(new ArrayList<>());
layoutDTO1.setHandleUsers(new ArrayList<>());
layoutDTO1.setFullScreen(false);
layoutDTO.add(layoutDTO1);
MvcResult mvcResult = this.requestPostWithOkAndReturn(EDIT_LAYOUT+DEFAULT_ORGANIZATION_ID, layoutDTO);
String contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
List<LayoutDTO> layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class);
Assertions.assertNotNull(layoutDTOS);
MvcResult mvcResultGrt = this.requestGetWithOkAndReturn(GET_LAYOUT+DEFAULT_ORGANIZATION_ID);
contentAsString = mvcResultGrt.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class);
Assertions.assertNotNull(layoutDTOS);
}
}

View File

@ -0,0 +1,26 @@
INSERT INTO user(id, name, email, password, enable, create_time, update_time, language, last_organization_id, phone,
source,
last_project_id, create_user, update_user, deleted)
VALUES ('default-dashboard-member-user-gyq', 'default-project-member-user1', 'project-member-gyqDashboard@metersphere.io',
MD5('metersphere'),
true, UNIX_TIMESTAMP() * 1000,
UNIX_TIMESTAMP() * 1000, NULL, NUll, '', 'LOCAL', NULL, 'admin', 'admin', false);
INSERT INTO user_role_relation (id, user_id, role_id, source_id, organization_id, create_time, create_user)
VALUES (UUID(), 'default-dashboard-member-user-gyq', 'org_member', 'organization-review-case-test',
'organization-review-case-test', UNIX_TIMESTAMP() * 1000, 'admin');
INSERT INTO user_role_relation (id, user_id, role_id, source_id, organization_id, create_time, create_user)
VALUES (UUID(), 'default-dashboard-member-user-gyq', 'project_admin', 'project-review-case-test',
'organization-review-case-test', UNIX_TIMESTAMP() * 1000,
'admin');
INSERT INTO user_role_permission(id, role_id, permission_id)
VALUES ('user_role_gyq_permission1', 'project_admin', 'FUNCTIONAL_CASE:READ+COMMENT');

View File

@ -1,11 +1,8 @@
package io.metersphere.project.constants;
public class ProjectMenuConstants {
public static final String MODULE_MENU_WORKSTATION = "workstation";
public static final String MODULE_MENU_TEST_PLAN = "testPlan";
public static final String MODULE_MENU_BUG = "bugManagement";
public static final String MODULE_MENU_FUNCTIONAL_CASE = "caseManagement";
public static final String MODULE_MENU_API_TEST = "apiTest";
public static final String MODULE_MENU_UI = "uiTest";
public static final String MODULE_MENU_LOAD_TEST = "loadTest";
}

View File

@ -0,0 +1,19 @@
package io.metersphere.project.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProjectCountDTO {
@Schema(description = "项目id")
private String projectId;
@Schema(description = "数量")
private int count;
}

View File

@ -32,4 +32,6 @@ public interface ExtProjectMapper {
List<Project> getUserProjectWidthModule(@Param("organizationId") String organizationId, @Param("userId") String userId, @Param("module") String module);
List<Project> getProjectNameModule(@Param("organizationId") String organizationId, @Param("ids") List<String>projectIds);
}

View File

@ -116,4 +116,21 @@
CONVERT( p.name USING GBK) ASC
</select>
<select id="getProjectNameModule" resultType="io.metersphere.project.domain.Project">
select id, name, module_setting
from project
where enable = 1
and deleted = 0
<if test="organizationId != null and organizationId != ''">
and
organization_id = #{organizationId}
</if>
<if test="ids != null and ids.size() > 0">
and id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
</select>
</mapper>

View File

@ -253,12 +253,6 @@ public class ProjectService {
if (StringUtils.equalsIgnoreCase(module, "BUG")) {
moduleName = ProjectMenuConstants.MODULE_MENU_BUG;
}
if (StringUtils.equalsIgnoreCase(module, "PERFORMANCE")) {
moduleName = ProjectMenuConstants.MODULE_MENU_LOAD_TEST;
}
if (StringUtils.equalsIgnoreCase(module, "UI")) {
moduleName = ProjectMenuConstants.MODULE_MENU_UI;
}
if (StringUtils.equalsIgnoreCase(module, "TEST_PLAN")) {
moduleName = ProjectMenuConstants.MODULE_MENU_TEST_PLAN;
}

View File

@ -22,6 +22,8 @@ public class SystemInterceptor {
configList.add(new MybatisInterceptorConfig(UserExtend.class, "platformInfo", CompressUtils.class, "zip", "unzip"));
configList.add(new MybatisInterceptorConfig(PluginScript.class, "script", CompressUtils.class, "zip", "unzip"));
configList.add(new MybatisInterceptorConfig(PlatformSource.class, "config", CompressUtils.class, "zip", "unzip"));
configList.add(new MybatisInterceptorConfig(UserLayout.class, "configuration", CompressUtils.class, "zip", "unzip"));
return configList;

View File

@ -11,10 +11,12 @@ import io.metersphere.plan.dto.response.TestPlanResponse;
import io.metersphere.project.dto.DropNode;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.NodeSortQueryParam;
import io.metersphere.project.dto.ProjectCountDTO;
import io.metersphere.system.interceptor.BaseConditionFilter;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
public interface ExtTestPlanMapper {
List<String> selectIdByGroupId(String parentId);
@ -73,4 +75,7 @@ public interface ExtTestPlanMapper {
List<TestPlanGroupCountDTO> countByGroupPlan(String projectId);
List<String> selectIdByProjectIdAndWithoutList(@Param("projectId") String projectId, @Param("withoutList") List<String> withoutList);
List<ProjectCountDTO> projectPlanCount(@Param("projectIds") Set<String> projectIds, @Param("startTime") long startTime, @Param("endTime") long endTime, @Param("userId") String userId);
}

View File

@ -624,4 +624,21 @@
</foreach>
</if>
</sql>
<select id="projectPlanCount"
resultType="io.metersphere.project.dto.ProjectCountDTO">
SELECT test_plan.project_id as projectId, count(test_plan.id) as count
FROM test_plan
WHERE
test_plan.project_id IN
<foreach collection="projectIds" item="projectId" separator="," open="(" close=")">
#{projectId}
</foreach>
AND test_plan.create_time BETWEEN #{startTime} AND #{endTime}
<if test="userId != null and userId != ''">
AND test_plan.create_user = #{userId}
</if>
group by test_plan.project_id;
</select>
</mapper>