Commit 806bad32 authored by chenjianxing's avatar chenjianxing Committed by jianxing
Browse files

feat: 场景用例支持自定义排序

parent 0236bc3a
dev dev-workstation feat_api_custom_field feat_custom_field feat_custom_function feat_environment_group feat_environment_group_copy feat_remove_organization feat_timing_clean feat_vc feat_vc_testtrack fix_lyh_v1.17 master pr@dev@feat@四种协议test、case页面优化 pr@dev@feat_add_issueremark pr@dev@feat_sync pr@dev@feat_工作空间多项目环境组合 pr@dev@feat_性能测试版本对比页面修改_自动执行 pr@dev@feat_接口测试_文档结构断言 pr@dev@feat_测试计划用例自定义排序 pr@dev@feat_脑图保存临时节点 pr@dev@feat_脑图用例没保存提示 pr@dev@fix pr@dev@fix_scenario_load_test pr@dev@fix_sql版本冲突 pr@dev@fix_sql错误 pr@dev@fix_xmind格式导入优化标签 pr@dev@fix_从公共用例库移除_再编辑用例发现无法加到公共用例库了 pr@dev@fix_代码扫描图标不显示 pr@dev@fix_修复条件控制器变量值中有换行导致判断失败问题 pr@dev@fix_修复环境设置中编辑下模块和路径匹配时模块和路径允许为空的缺陷 pr@dev@fix_修改db版本号 pr@dev@fix_功能用例版本切换 pr@dev@fix_场景导入按钮失效 pr@dev@fix_应用管理没有自动保存 pr@dev@fix_接口case优化 pr@dev@fix_接口定义_用例批量 pr@dev@fix_接口定义导入order字段为空 pr@dev@fix_接口测试_复制接口 pr@dev@fix_接口测试_安全漏洞 pr@dev@fix_接口测试_引用问题 pr@dev@fix_接口用例在定义后面 pr@dev@fix_接口详情-变更历史无变更详情日志 pr@dev@fix_操作日志_增删改查除系统设置中的操作均无法跳转 pr@dev@fix_新增测试阶段字段在筛选列表中未更新 pr@dev@fix_测试计划实际结果无法编辑 pr@dev@fix_测试计划性能测试sql pr@dev@fix_测试跟踪_功能用例_公共用例库_选择修改用例责任人后,新的责任人仍不可编辑和删除该用例 pr@dev@fix_用例评审_测试计划_关注人支持多选 pr@dev@fix_被引用的数据删除显示重复 pr@dev@refactor_menu_pos pr@dev@refactor_swagger导入body参数的顺序不变 pr@dev@refactor_升级Jython版本 pr@dev@refactor_获取场景报告接口效率优化 pr@dev@refactor_请求头加描述 pr@dev@内置函数构造器优化增加mock数据说明示例及场景变量 pr@master@fix_代码扫描图标不显示 pr@v1.14@fix_接口测试_复制接口 pr@v1.14@fix_用例评审_测试计划_关注人支持多选 pr@v1.15@fix_sync pr@v1.16@fix_scenario_load pr@v1.16@fix_接口测试_安全漏洞 pr@v1.16@fix_接口测试_引用问题 pr@v1.16@fix_接口详情-变更历史无变更详情日志 pr@v1.16@fix_测试跟踪_功能用例_公共用例库_选择修改用例责任人后,新的责任人仍不可编辑和删除该用例 pr@v1.16@refactor_获取场景报告接口效率优化 pr@v1.17@feat_我的工作台加版本筛选 pr@v1.17@fix pr@v1.17@fix_功能用例版本切换 pr@v1.17@fix_新增测试阶段字段在筛选列表中未更新 pr@v1.18@fix_修复环境设置中编辑下模块和路径匹配时模块和路径允许为空的缺陷 refactor_environment_group refactor_project_setting refactor_ws_notice_template repr@dev_master_v1.16@ repr@dev_v1.10@9dc0f51ea06584447020dcd946d291115362a1b1@feat_脑图用例没保存提示 repr@dev_v1.14@@fix_【接口定义】-添加mock函数时值生成优化+页面翻译“return” repr@dev_v1.14@f7409212@fix_接口测试_CSV优化 repr@dev_v1.14_v1.16@fc598de402cffa8744ee656948f715c31e7d58a2@refactor_场景资源池执行添加日志打印 repr@dev_v1.16@1abe60fc@fix_接口测试_循环控制器 repr@dev_v1.16@22a21ac3@fix_接口测试_自动化步骤 repr@dev_v1.16@5d8ba4eb@fix_接口详情-变更历史无变更详情日志 repr@dev_v1.16@6de996ff@fix_接口定义_开启过多时环境与接口名称重叠 repr@dev_v1.16@a009bb38@fix_接口测试_场景执行 repr@dev_v1.16@e15672af3dc95618192ee81aedbefffdfd377b8a@fix_代码扫描图标不显示 repr@dev_v1.16@e43c11a7@fix_应用管理没有保存 repr@dev_v1.16@e43c11a7@fix_应用管理没有自动保存 repr@dev_v1.16_v1.17@430a1864ffe9800240f4fbd9b0c92991305c0baa@fix_脑图创建的用例导出状态和责任人为空 repr@dev_v1.16_v1.17@91c1b2a7@fix_接口测试_插件步骤 repr@dev_v1.17@0d05cd92d9a1b005aac8c07594625f3cda8319080d05cd92d9a1b005aac8c07594625f3cda831908@feat_测试跟踪用例版本相关 repr@dev_v1.17@0d05cd92d9a1b005aac8c07594625f3cda831908@fix_功能用例版本管理回收站 repr@dev_v1.18@abc86b09@fix_lyh_dev repr@devev_v1.16@31e9453dccbf5b363f72b9a2c4d6b1f40d9e92f5@fix_tapd不显示图片 repr@v1.16@fix_JSONPATH断言等有200个字符限制 repr@v1.16_dev@09a4129d@fix_接口测试_调试状态 repr@v1.16_dev@11eb4bc6@feat_error_report repr@v1.16_dev@6a89622f@fix_接口测试_JSON校验处理 repr@v1.16_dev@d5cf72dc@fix_接口测试_场景报告 repr@v1.16_dev@e2e90011@fix_testplan_用例执行 repr@v1.16_dev@ef78a7eb@fix_xpack_code repr@v1.16_v1.17_dev@bfb01376@fix_bugs_import_api repr@v1.16_v1.17_dev@dd1880fa@fix_bugs_0118 seleniumdocker获取报告图表 ui v1.13 v1.14 v1.15 v1.16 v1.17 v1.18 工作空间多项目环境组合 v1.18.2-rc2 v1.18.2-rc1 v1.18.2-rc0 v1.18.2-arm64 v1.18.1 v1.18.0 v1.17.3 v1.17.2 v1.17.1 v1.17.0 v1.16.6 v1.16.5 v1.16.4 v1.16.3 v1.16.2 v1.16.1 v1.16.0 v1.15.4 v1.15.3 v1.15.2 v1.15.1 v1.15.0 v1.14.7 v1.14.6 v1.14.5 v1.14.4 v1.14.3 v1.14.2 v1.14.1 v1.14.0 v1.14.0-rc3 v1.14.0-rc2 v1.14.0-rc1 v1.13.2 v1.13.1 v1.13.0
No related merge requests found
Showing with 175 additions and 16 deletions
+175 -16
......@@ -14,6 +14,7 @@ import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
......@@ -105,6 +106,12 @@ public class ApiAutomationController {
return apiAutomationService.update(request, bodyFiles, scenarioFiles);
}
@PostMapping("/edit/order")
public void orderCase(@RequestBody ResetOrderRequest request) {
apiAutomationService.updateOrder(request);
}
@GetMapping("/delete/{id}")
@MsAuditLog(module = "api_automation", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#id)", msClass = ApiAutomationService.class)
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ_DELETE)
......
......@@ -31,6 +31,7 @@ import io.metersphere.base.mapper.ext.*;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.dto.ApiReportCountDTO;
import io.metersphere.dto.BaseSystemConfigDTO;
......@@ -189,7 +190,7 @@ public class ApiAutomationService {
*/
private ApiScenarioRequest initRequest(ApiScenarioRequest request, boolean setDefultOrders, boolean checkThisWeekData) {
if (setDefultOrders) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
request.setOrders(ServiceUtils.getDefaultSortOrder(request.getOrders()));
}
if (StringUtils.isNotEmpty(request.getExecuteStatus())) {
Map<String, List<String>> statusFilter = new HashMap<>();
......@@ -235,6 +236,7 @@ public class ApiAutomationService {
scenario.setNum(nextNum);
List<ApiMethodUrlDTO> useUrl = this.parseUrl(scenario);
scenario.setUseUrl(JSONArray.toJSONString(useUrl));
scenario.setOrder(ServiceUtils.getNextOrder(scenario.getProjectId(), extApiScenarioMapper::getLastOrder));
//检查场景的请求步骤。如果含有ESB请求步骤的话,要做参数计算处理。
esbApiParamService.checkScenarioRequests(request);
......@@ -2502,4 +2504,22 @@ public class ApiAutomationService {
return result.longValue();
}
}
public void initOrderField() {
ServiceUtils.initOrderField(ApiScenarioWithBLOBs.class, ApiScenarioMapper.class,
extApiScenarioMapper::selectProjectIds,
extApiScenarioMapper::getIdsOrderByCreateTime);
}
/**
* 用例自定义排序
* @param request
*/
public void updateOrder(ResetOrderRequest request) {
ServiceUtils.updateOrderField(request, ApiScenarioWithBLOBs.class,
apiScenarioMapper::selectByPrimaryKey,
extApiScenarioMapper::getPreOrder,
extApiScenarioMapper::getLastOrder,
apiScenarioMapper::updateByPrimaryKeySelective);
}
}
......@@ -57,5 +57,7 @@ public class ApiScenario implements Serializable {
private Integer executeTimes;
private Long order;
private static final long serialVersionUID = 1L;
}
\ No newline at end of file
......@@ -1853,6 +1853,66 @@ public class ApiScenarioExample {
addCriterion("execute_times not between", value1, value2, "executeTimes");
return (Criteria) this;
}
public Criteria andOrderIsNull() {
addCriterion("`order` is null");
return (Criteria) this;
}
public Criteria andOrderIsNotNull() {
addCriterion("`order` is not null");
return (Criteria) this;
}
public Criteria andOrderEqualTo(Long value) {
addCriterion("`order` =", value, "order");
return (Criteria) this;
}
public Criteria andOrderNotEqualTo(Long value) {
addCriterion("`order` <>", value, "order");
return (Criteria) this;
}
public Criteria andOrderGreaterThan(Long value) {
addCriterion("`order` >", value, "order");
return (Criteria) this;
}
public Criteria andOrderGreaterThanOrEqualTo(Long value) {
addCriterion("`order` >=", value, "order");
return (Criteria) this;
}
public Criteria andOrderLessThan(Long value) {
addCriterion("`order` <", value, "order");
return (Criteria) this;
}
public Criteria andOrderLessThanOrEqualTo(Long value) {
addCriterion("`order` <=", value, "order");
return (Criteria) this;
}
public Criteria andOrderIn(List<Long> values) {
addCriterion("`order` in", values, "order");
return (Criteria) this;
}
public Criteria andOrderNotIn(List<Long> values) {
addCriterion("`order` not in", values, "order");
return (Criteria) this;
}
public Criteria andOrderBetween(Long value1, Long value2) {
addCriterion("`order` between", value1, value2, "order");
return (Criteria) this;
}
public Criteria andOrderNotBetween(Long value1, Long value2) {
addCriterion("`order` not between", value1, value2, "order");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
......
......@@ -28,6 +28,7 @@
<result column="delete_time" jdbcType="BIGINT" property="deleteTime" />
<result column="delete_user_id" jdbcType="VARCHAR" property="deleteUserId" />
<result column="execute_times" jdbcType="INTEGER" property="executeTimes" />
<result column="order" jdbcType="BIGINT" property="order" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiScenarioWithBLOBs">
<result column="scenario_definition" jdbcType="LONGVARCHAR" property="scenarioDefinition" />
......@@ -96,7 +97,7 @@
id, project_id, tags, user_id, api_scenario_module_id, module_path, `name`, `level`,
`status`, principal, step_total, follow_people, schedule, create_time, update_time,
pass_rate, last_result, report_id, num, original_state, custom_num, create_user,
version, delete_time, delete_user_id, execute_times
version, delete_time, delete_user_id, execute_times, `order`
</sql>
<sql id="Blob_Column_List">
scenario_definition, description, use_url
......@@ -158,8 +159,9 @@
pass_rate, last_result, report_id,
num, original_state, custom_num,
create_user, version, delete_time,
delete_user_id, execute_times, scenario_definition,
description, use_url)
delete_user_id, execute_times, `order`,
scenario_definition, description,
use_url)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{tags,jdbcType=VARCHAR},
#{userId,jdbcType=VARCHAR}, #{apiScenarioModuleId,jdbcType=VARCHAR}, #{modulePath,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR}, #{level,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
......@@ -168,8 +170,9 @@
#{passRate,jdbcType=VARCHAR}, #{lastResult,jdbcType=VARCHAR}, #{reportId,jdbcType=VARCHAR},
#{num,jdbcType=INTEGER}, #{originalState,jdbcType=VARCHAR}, #{customNum,jdbcType=VARCHAR},
#{createUser,jdbcType=VARCHAR}, #{version,jdbcType=INTEGER}, #{deleteTime,jdbcType=BIGINT},
#{deleteUserId,jdbcType=VARCHAR}, #{executeTimes,jdbcType=INTEGER}, #{scenarioDefinition,jdbcType=LONGVARCHAR},
#{description,jdbcType=LONGVARCHAR}, #{useUrl,jdbcType=LONGVARCHAR})
#{deleteUserId,jdbcType=VARCHAR}, #{executeTimes,jdbcType=INTEGER}, #{order,jdbcType=BIGINT},
#{scenarioDefinition,jdbcType=LONGVARCHAR}, #{description,jdbcType=LONGVARCHAR},
#{useUrl,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenarioWithBLOBs">
insert into api_scenario
......@@ -252,6 +255,9 @@
<if test="executeTimes != null">
execute_times,
</if>
<if test="order != null">
`order`,
</if>
<if test="scenarioDefinition != null">
scenario_definition,
</if>
......@@ -341,6 +347,9 @@
<if test="executeTimes != null">
#{executeTimes,jdbcType=INTEGER},
</if>
<if test="order != null">
#{order,jdbcType=BIGINT},
</if>
<if test="scenarioDefinition != null">
#{scenarioDefinition,jdbcType=LONGVARCHAR},
</if>
......@@ -439,6 +448,9 @@
<if test="record.executeTimes != null">
execute_times = #{record.executeTimes,jdbcType=INTEGER},
</if>
<if test="record.order != null">
`order` = #{record.order,jdbcType=BIGINT},
</if>
<if test="record.scenarioDefinition != null">
scenario_definition = #{record.scenarioDefinition,jdbcType=LONGVARCHAR},
</if>
......@@ -481,6 +493,7 @@
delete_time = #{record.deleteTime,jdbcType=BIGINT},
delete_user_id = #{record.deleteUserId,jdbcType=VARCHAR},
execute_times = #{record.executeTimes,jdbcType=INTEGER},
`order` = #{record.order,jdbcType=BIGINT},
scenario_definition = #{record.scenarioDefinition,jdbcType=LONGVARCHAR},
description = #{record.description,jdbcType=LONGVARCHAR},
use_url = #{record.useUrl,jdbcType=LONGVARCHAR}
......@@ -515,7 +528,8 @@
version = #{record.version,jdbcType=INTEGER},
delete_time = #{record.deleteTime,jdbcType=BIGINT},
delete_user_id = #{record.deleteUserId,jdbcType=VARCHAR},
execute_times = #{record.executeTimes,jdbcType=INTEGER}
execute_times = #{record.executeTimes,jdbcType=INTEGER},
`order` = #{record.order,jdbcType=BIGINT}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
......@@ -598,6 +612,9 @@
<if test="executeTimes != null">
execute_times = #{executeTimes,jdbcType=INTEGER},
</if>
<if test="order != null">
`order` = #{order,jdbcType=BIGINT},
</if>
<if test="scenarioDefinition != null">
scenario_definition = #{scenarioDefinition,jdbcType=LONGVARCHAR},
</if>
......@@ -637,6 +654,7 @@
delete_time = #{deleteTime,jdbcType=BIGINT},
delete_user_id = #{deleteUserId,jdbcType=VARCHAR},
execute_times = #{executeTimes,jdbcType=INTEGER},
`order` = #{order,jdbcType=BIGINT},
scenario_definition = #{scenarioDefinition,jdbcType=LONGVARCHAR},
description = #{description,jdbcType=LONGVARCHAR},
use_url = #{useUrl,jdbcType=LONGVARCHAR}
......@@ -668,7 +686,8 @@
version = #{version,jdbcType=INTEGER},
delete_time = #{deleteTime,jdbcType=BIGINT},
delete_user_id = #{deleteUserId,jdbcType=VARCHAR},
execute_times = #{executeTimes,jdbcType=INTEGER}
execute_times = #{executeTimes,jdbcType=INTEGER},
`order` = #{order,jdbcType=BIGINT}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>
\ No newline at end of file
......@@ -72,4 +72,12 @@ public interface ExtApiScenarioMapper {
List<String> selectIdsByExecuteTimeIsNull();
Long countExecuteTimesByProjectID(String projectId);
List<String> selectProjectIds();
List<String> getIdsOrderByCreateTime(@Param("projectId") String projectId);
Long getPreOrder(@Param("projectId")String projectId, @Param("baseOrder") Long baseOrder);
Long getLastOrder(@Param("projectId")String projectId, @Param("baseOrder") Long baseOrder);
}
......@@ -461,6 +461,28 @@
SELECT SUM(execute_times) FROM api_scenario
WHERE project_id = #{0}
</select>
<select id="selectProjectIds" resultType="java.lang.String">
select DISTINCT project_id from api_scenario;
</select>
<select id="getIdsOrderByCreateTime" resultType="java.lang.String">
select id from api_scenario where project_id = #{projectId} order by create_time DESC;
</select>
<select id="getLastOrder" resultType="java.lang.Long">
select `order` from api_scenario where project_id = #{projectId}
<if test="baseOrder != null">
and `order` &gt; #{baseOrder}
</if>
order by `order` desc limit 1;
</select>
<select id="getPreOrder" resultType="java.lang.Long">
select `order` from api_scenario where project_id = #{projectId}
<if test="baseOrder != null">
and `order` &lt; #{baseOrder}
</if>
order by `order` desc limit 1;
</select>
<sql id="queryWhereConditionReview">
<where>
......
......@@ -142,8 +142,7 @@ public class ServiceUtils {
Long order = 0L;
List<String> ids = getIdsOrderByCreateTimeFunc.apply(projectId);
for (String id : ids) {
T item = null;
item = (T) clazz.newInstance();
T item = clazz.newInstance();
setId.invoke(item, id);
setOrder.invoke(item, order);
order += 5000;
......
......@@ -111,6 +111,7 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
initOnceOperate(performanceTestService::initScenarioLoadTest, "init.scenario.load.test");
initOnceOperate(testCaseService::initOrderField, "init.sort.test.case");
initOnceOperate(apiTestCaseService::initOrderField, "init.sort.api.test.case");
initOnceOperate(apiAutomationService::initOrderField, "init.sort.api.scenario");
}
/**
......
......@@ -36,3 +36,5 @@ update api_scenario set module_path = replace (`module_path`,'/默认模块','/
ALTER TABLE test_case ADD `order` bigint(20) NOT NULL COMMENT '自定义排序,间隔5000';
ALTER TABLE api_test_case ADD `order` bigint(20) NOT NULL COMMENT '自定义排序,间隔5000';
ALTER TABLE api_scenario ADD `order` bigint(20) NOT NULL COMMENT '自定义排序,间隔5000';
import {getUUID} from "@/common/js/utils";
import {getUploadConfig, request} from "@/common/js/ajax";
import {basePost} from "@/network/base-network";
function buildBodyFile(item, bodyUploadFiles, obj, bodyParam) {
if (bodyParam) {
......@@ -99,3 +100,7 @@ export function saveScenario(url, scenario, scenarioDefinition, _this,success) {
}
});
}
export function editApiScenarioCaseOrder(request, callback) {
return basePost('/api/automation/edit/order', request, callback);
}
......@@ -16,6 +16,8 @@
:field-key=tableHeaderKey
:remember-order="true"
operator-width="200"
:enable-order-drag="enableOrderDrag"
row-key="id"
@refresh="search(projectId)"
@callBackSelectAll="callBackSelectAll"
@callBackSelect="callBackSelect"
......@@ -234,13 +236,14 @@ import {API_SCENARIO_CONFIGS} from "@/business/components/common/components/sear
import {API_SCENARIO_LIST} from "../../../../../common/js/constants";
import {
getCustomTableHeader, getCustomTableWidth, getLastTableSortField, saveLastTableSortField
getCustomTableHeader, getCustomTableWidth, getLastTableSortField, handleRowDrop, saveLastTableSortField
} from "@/common/js/tableUtils";
import {API_SCENARIO_FILTERS} from "@/common/js/table-constants";
import {scenario} from "@/business/components/track/plan/event-bus";
import MsTable from "@/business/components/common/components/table/MsTable";
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
import {editApiScenarioCaseOrder} from "@/business/components/api/automation/api-automation";
export default {
name: "MsApiScenarioList",
......@@ -345,6 +348,7 @@ export default {
operators: [],
selectRows: new Set(),
isStop: false,
enableOrderDrag: true,
trashOperators: [
{
tip: this.$t('commons.reduction'),
......@@ -563,6 +567,8 @@ export default {
this.condition.projectId = this.projectId;
}
this.enableOrderDrag = this.condition.orders.length > 0 ? false : true;
//检查是否只查询本周数据
this.condition.selectThisWeedData = false;
this.condition.executeStatus = null;
......@@ -592,12 +598,20 @@ export default {
item.tags = JSON.parse(item.tags);
}
});
this.$nextTick(() => {
handleRowDrop(this.tableData, (param) => {
param.projectId = this.condition.projectId;
editApiScenarioCaseOrder(param);
});
if (this.$refs.scenarioTable) {
this.$refs.scenarioTable.clear();
this.$nextTick(() => {
this.$refs.scenarioTable.doLayout();
});
}
});
this.$emit('getTrashCase');
});
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment