需求功能前后端代码实现
This commit is contained in:
@@ -0,0 +1,59 @@
|
|||||||
|
package com.test.test.controller;
|
||||||
|
|
||||||
|
import com.test.common.annotation.Log;
|
||||||
|
import com.test.common.core.controller.BaseController;
|
||||||
|
import com.test.common.core.domain.AjaxResult;
|
||||||
|
import com.test.common.core.page.TableDataInfo;
|
||||||
|
import com.test.common.enums.BusinessType;
|
||||||
|
import com.test.test.domain.TestProject;
|
||||||
|
import com.test.test.domain.qo.IDQO;
|
||||||
|
import com.test.test.domain.qo.TestProjectListQO;
|
||||||
|
import com.test.test.service.ITestProjectService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
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.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/test/project")
|
||||||
|
public class TestProjectController extends BaseController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ITestProjectService testProjectService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询需求列表
|
||||||
|
* @param qo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GetMapping("/projectList")
|
||||||
|
public TableDataInfo projectList(@Validated TestProjectListQO qo) {
|
||||||
|
startPage();
|
||||||
|
List<TestProject> list = testProjectService.selectTestProjectList(qo);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增需求
|
||||||
|
*/
|
||||||
|
@Log(title = "需求", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("/addProject")
|
||||||
|
public AjaxResult addProject(@RequestBody TestProject testProject) {
|
||||||
|
return toAjax(testProjectService.insertTestProject(testProject));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除需求
|
||||||
|
*/
|
||||||
|
@Log(title = "需求", businessType = BusinessType.DELETE)
|
||||||
|
@PostMapping("/delProject")
|
||||||
|
public AjaxResult delProject(@RequestBody IDQO qo) {
|
||||||
|
return toAjax(testProjectService.deleteTestProjectById(qo.getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package com.test.test.domain;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.test.common.annotation.Excel;
|
||||||
|
import com.test.common.core.domain.BaseEntity;
|
||||||
|
import java.util.Date;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
public class TestProject extends BaseEntity {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -8420426086386159695L;
|
||||||
|
|
||||||
|
/** 主键 */
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/** 需求编码 */
|
||||||
|
@Excel(name = "需求编码")
|
||||||
|
private String serialNumber;
|
||||||
|
|
||||||
|
/** 需求名称 */
|
||||||
|
@Excel(name = "需求名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/** 需求概要 */
|
||||||
|
@Excel(name = "需求概要")
|
||||||
|
private String outline;
|
||||||
|
|
||||||
|
/** 需求描述 */
|
||||||
|
@Excel(name = "需求描述")
|
||||||
|
private String detail;
|
||||||
|
|
||||||
|
/** 优先级(p0,p1,p2,p3,p4) */
|
||||||
|
@Excel(name = "优先级(p0,p1,p2,p3,p4)")
|
||||||
|
private String priority;
|
||||||
|
|
||||||
|
/** 预计完成时间 */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@Excel(name = "预计完成时间", width = 30, dateFormat = "yyyy-MM-dd")
|
||||||
|
private Date estimatedTime;
|
||||||
|
|
||||||
|
/** 需求来源(0,产品经理,1,客户) */
|
||||||
|
@Excel(name = "需求来源(0,产品经理,1,客户)")
|
||||||
|
private String source;
|
||||||
|
|
||||||
|
/** 需求类型(0,优化,1,新功能) */
|
||||||
|
@Excel(name = "需求类型(0,优化,1,新功能)")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/** 状态(0,未开始,1,进行中,2,已完成,3,已终止) */
|
||||||
|
@Excel(name = "状态(0,未开始,1,进行中,2,已完成,3,已终止)")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/** 负责人 */
|
||||||
|
@Excel(name = "负责人")
|
||||||
|
private String manager;
|
||||||
|
|
||||||
|
/** 版本 */
|
||||||
|
@Excel(name = "版本")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
/** 0,正常,1,删除 */
|
||||||
|
private String delFlag;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.test.test.domain.qo;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询需求列表请求参数qo
|
||||||
|
*
|
||||||
|
* @author pfl
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TestProjectListQO implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 4632218018365273102L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需求编码
|
||||||
|
*/
|
||||||
|
private String serialNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需求概要
|
||||||
|
*/
|
||||||
|
private String outline;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始创建时间
|
||||||
|
*/
|
||||||
|
private Date startCreateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束创建时间
|
||||||
|
*/
|
||||||
|
private Date endCreateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 负责人
|
||||||
|
*/
|
||||||
|
private String manager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优先级(p0,p1,p2,p3,p4)
|
||||||
|
*/
|
||||||
|
private String priority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0,未开始,1,进行中,2,已完成,3,已终止)
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.test.test.mapper;
|
||||||
|
|
||||||
|
import com.test.test.domain.TestProject;
|
||||||
|
import com.test.test.domain.qo.TestProjectListQO;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface TestProjectMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询需求列表
|
||||||
|
* @param qo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<TestProject> selectTestProjectList(TestProjectListQO qo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增需求
|
||||||
|
* @param testProject
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
int insertTestProject(TestProject testProject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除需求
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
int deleteTestProjectById(Long id);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.test.test.service;
|
||||||
|
|
||||||
|
import com.test.test.domain.TestProject;
|
||||||
|
import com.test.test.domain.qo.TestProjectListQO;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需求Service接口
|
||||||
|
*
|
||||||
|
* @author pfl
|
||||||
|
*/
|
||||||
|
public interface ITestProjectService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询需求列表
|
||||||
|
* @param qo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<TestProject> selectTestProjectList(TestProjectListQO qo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增需求
|
||||||
|
* @param testProject
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int insertTestProject(TestProject testProject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除需求
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int deleteTestProjectById(Long id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.test.test.service.impl;
|
||||||
|
|
||||||
|
import com.test.common.utils.DateUtils;
|
||||||
|
import com.test.test.domain.TestProject;
|
||||||
|
import com.test.test.domain.qo.TestProjectListQO;
|
||||||
|
import com.test.test.mapper.TestProjectMapper;
|
||||||
|
import com.test.test.service.ITestProjectService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class TestProjectServiceImpl implements ITestProjectService {
|
||||||
|
// 0正常,1删除
|
||||||
|
private static final String DEL_FLAG = "0";
|
||||||
|
|
||||||
|
// 状态: 0未开始,1进行中,2已完成,3已终止
|
||||||
|
private static final String STATUS = "0";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TestProjectMapper testProjectMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询需求列表
|
||||||
|
* @param qo
|
||||||
|
* @return TestProject
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<TestProject> selectTestProjectList(TestProjectListQO qo) {
|
||||||
|
return testProjectMapper.selectTestProjectList(qo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增需求
|
||||||
|
* @param testProject
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int insertTestProject(TestProject testProject) {
|
||||||
|
testProject.setStatus(STATUS);
|
||||||
|
testProject.setCreateTime(DateUtils.getNowDate());
|
||||||
|
testProject.setDelFlag(DEL_FLAG);
|
||||||
|
return testProjectMapper.insertTestProject(testProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除需求
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int deleteTestProjectById(Long id) {
|
||||||
|
return testProjectMapper.deleteTestProjectById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
<?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="com.test.test.mapper.TestProjectMapper">
|
||||||
|
|
||||||
|
<insert id="insertTestProject" parameterType="testProject" useGeneratedKeys="true" keyProperty="id">
|
||||||
|
INSERT INTO test_project (
|
||||||
|
<trim prefix="" suffix="" suffixOverrides=",">
|
||||||
|
<if test="id != null">id,</if>
|
||||||
|
<if test="serialNumber != null and serialNumber != ''">serial_number,</if>
|
||||||
|
<if test="name != null and name != ''">name,</if>
|
||||||
|
<if test="outline != null and outline != ''">outline,</if>
|
||||||
|
<if test="detail != null and detail != ''">detail,</if>
|
||||||
|
<if test="priority != null and priority != ''">priority,</if>
|
||||||
|
<if test="estimatedTime != null">estimated_time,</if>
|
||||||
|
<if test="source != null and source != ''">source,</if>
|
||||||
|
<if test="type != null and type != ''">type,</if>
|
||||||
|
<if test="status != null and status != ''">status,</if>
|
||||||
|
<if test="manager != null and manager != ''">manager,</if>
|
||||||
|
<if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateTime != null">update_time,</if>
|
||||||
|
<if test="version != null">version,</if>
|
||||||
|
<if test="delFlag != null and delFlag != ''">del_flag,</if>
|
||||||
|
</trim>
|
||||||
|
) VALUES (
|
||||||
|
<trim prefix="" suffix="" suffixOverrides=",">
|
||||||
|
<if test="id != null">#{id},</if>
|
||||||
|
<if test="serialNumber != null and serialNumber != ''">#{serialNumber},</if>
|
||||||
|
<if test="name != null and name != ''">#{name},</if>
|
||||||
|
<if test="outline != null and outline != ''">#{outline},</if>
|
||||||
|
<if test="detail != null and detail != ''">#{detail},</if>
|
||||||
|
<if test="priority != null and priority != ''">#{priority},</if>
|
||||||
|
<if test="estimatedTime != null">#{estimatedTime},</if>
|
||||||
|
<if test="source != null and source != ''">#{source},</if>
|
||||||
|
<if test="type != null and type != ''">#{type},</if>
|
||||||
|
<if test="status != null and status != ''">#{status},</if>
|
||||||
|
<if test="manager != null and manager != ''">#{manager},</if>
|
||||||
|
<if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateTime != null">#{updateTime},</if>
|
||||||
|
<if test="version != null">#{version},</if>
|
||||||
|
<if test="delFlag != null and delFlag != ''">#{delFlag},</if>
|
||||||
|
</trim>
|
||||||
|
)
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<delete id="deleteTestProjectById">
|
||||||
|
DELETE
|
||||||
|
FROM test_project
|
||||||
|
WHERE id = #{id}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<select id="selectTestProjectList" parameterType="TestProjectListQO" resultType="TestProject">
|
||||||
|
SELECT
|
||||||
|
tp.id AS id,
|
||||||
|
tp.serial_number AS serialNumber,
|
||||||
|
tp.name ,
|
||||||
|
tp.outline,
|
||||||
|
tp.detail,
|
||||||
|
tp.priority,
|
||||||
|
tp.estimated_time AS estimatedTime,
|
||||||
|
tp.source,
|
||||||
|
tp.type,
|
||||||
|
tp.status,
|
||||||
|
su.user_name AS manager,
|
||||||
|
tp.create_time AS createTime,
|
||||||
|
tp.version,
|
||||||
|
tp.del_flag
|
||||||
|
FROM test_project tp
|
||||||
|
LEFT JOIN sys_user su ON su.user_id = tp.manager
|
||||||
|
where 1=1
|
||||||
|
<if test="serialNumber != null and serialNumber != ''">
|
||||||
|
AND serial_number LIKE concat('%', #{serialNumber}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="outline != null and outline != ''">
|
||||||
|
AND outline LIKE concat('%', #{outline}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="startCreateTime != null">
|
||||||
|
AND DATE_FORMAT(IFNULL(tp.create_time,''),'%Y%m%d') <![CDATA[ >= ]]> DATE_FORMAT(#{startCreateTime},'%Y%m%d')
|
||||||
|
</if>
|
||||||
|
<if test="endCreateTime != null">
|
||||||
|
AND DATE_FORMAT(IFNULL(tp.create_time,''),'%Y%m%d') <![CDATA[ <= ]]> DATE_FORMAT(#{endCreateTime},'%Y%m%d')
|
||||||
|
</if>
|
||||||
|
<if test="manager != null and manager != ''">
|
||||||
|
AND manager = #{manager}
|
||||||
|
</if>
|
||||||
|
<if test="priority != null and priority != ''">
|
||||||
|
AND priority = #{priority}
|
||||||
|
</if>
|
||||||
|
<if test="status !=null and status != ''">
|
||||||
|
AND tp.status = #{status}
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
</mapper>
|
||||||
41
test-ui/src/api/test/project.js
Normal file
41
test-ui/src/api/test/project.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
const api = {
|
||||||
|
managerList: 'system/user/list',
|
||||||
|
projectList: 'test/project/projectList',
|
||||||
|
addProject: 'test/project/addProject',
|
||||||
|
delProject: 'test/project/delProject'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function managerList(data) {
|
||||||
|
return request({
|
||||||
|
url: api.managerList,
|
||||||
|
method: 'get',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProjectList(data) {
|
||||||
|
return request({
|
||||||
|
url: api.projectList,
|
||||||
|
method: 'get',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addProject(data) {
|
||||||
|
return request({
|
||||||
|
url: api.addProject,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function delProject(id) {
|
||||||
|
return request({
|
||||||
|
url: api.delProject,
|
||||||
|
method: 'post',
|
||||||
|
data: {id}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
33
test-ui/src/components/FormItem/option/SimpleOptions.vue
Normal file
33
test-ui/src/components/FormItem/option/SimpleOptions.vue
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<div class="options">
|
||||||
|
<el-option
|
||||||
|
v-for="(option, i) in options"
|
||||||
|
:key="getKey(option, i)"
|
||||||
|
:label="getLabel(option, i)"
|
||||||
|
:value="getValue(option, i)"
|
||||||
|
:disabled="option.disabled"
|
||||||
|
></el-option>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'SimpleOptions',
|
||||||
|
props: {
|
||||||
|
options: Array,
|
||||||
|
label: String,
|
||||||
|
value: String,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getKey(option, i) {
|
||||||
|
return 'option_' + i
|
||||||
|
},
|
||||||
|
getLabel(option) {
|
||||||
|
return this.label ? option[this.label] : option.label
|
||||||
|
},
|
||||||
|
getValue(option) {
|
||||||
|
return this.value ? option[this.value] : option.value
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
419
test-ui/src/views/test/project/index.vue
Normal file
419
test-ui/src/views/test/project/index.vue
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<!-- 顶部导航 -->
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-header class="header">
|
||||||
|
<div class="head1">
|
||||||
|
<span style="font-size: 18px; font-weight: bold; margin-right: 20px;">需求列表</span>
|
||||||
|
</div>
|
||||||
|
<div class="head2">
|
||||||
|
<el-input :placeholder="placeholderText" v-model="query" class="input-with-select" clearable>
|
||||||
|
<el-select v-model="select" slot="prepend" placeholder="请选择" style="width: 80px;">
|
||||||
|
<el-option label="概要" value="1"></el-option>
|
||||||
|
<el-option label="ID" value="2"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-button slot="append" icon="el-icon-search" @click="handleQuery"></el-button>
|
||||||
|
</el-input>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="medium"
|
||||||
|
style="margin-right: 10px;"
|
||||||
|
@click="handleCollapse(!activeNames.includes('1'))"
|
||||||
|
>高级筛选
|
||||||
|
</el-button>
|
||||||
|
<el-dropdown trigger="click" placement="bottom-end">
|
||||||
|
<span class="el-dropdown-link">
|
||||||
|
列表视图<i class="el-icon-arrow-down el-icon--right"></i>
|
||||||
|
</span>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item>列表视图</el-dropdown-item>
|
||||||
|
<el-dropdown-item>看板视图</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
<el-button type="primary" size="medium" style="margin-left: 10px;" @click="addProjectVue">新建需求</el-button>
|
||||||
|
</div>
|
||||||
|
</el-header>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-collapse v-model="activeNames">
|
||||||
|
<el-collapse-item class="collapse-search" name="1">
|
||||||
|
<el-form ref="queryForm" :model="queryParams" label-width="110px">
|
||||||
|
<el-row :gutter="10" class="high-search">
|
||||||
|
<el-form-item label="创建时间">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryParams.createTime"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
value-format="yyyy-MM-dd"
|
||||||
|
></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="负责人">
|
||||||
|
<el-select v-model="queryParams.manager" placeholder="请选择" clearable filterable>
|
||||||
|
<simple-options :options="managerList"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="优先级">
|
||||||
|
<el-select v-model="queryParams.priority" placeholder="请选择" clearable filterable>
|
||||||
|
<simple-options :options="dict.type.priority_level"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" size="mini" icon="el-icon-search" @click="handleAdvancedSearch">搜索</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetAdvancedFilter">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
|
||||||
|
<!-- 标签页 -->
|
||||||
|
<el-tabs v-model="activeTab" @tab-click="handleTabClick" style="margin-top: 10px;">
|
||||||
|
<el-tab-pane :label="'全部(' + statusCounts.all + ')'" name="all"></el-tab-pane>
|
||||||
|
<el-tab-pane :label="'未开始(' + statusCounts.notStarted + ')'" name="0"></el-tab-pane>
|
||||||
|
<el-tab-pane :label="'进行中(' + statusCounts.inProgress + ')'" name="1"></el-tab-pane>
|
||||||
|
<el-tab-pane :label="'已完成(' + statusCounts.completed + ')'" name="2"></el-tab-pane>
|
||||||
|
<el-tab-pane :label="'已终止(' + statusCounts.terminated + ')'" name="3"></el-tab-pane>
|
||||||
|
|
||||||
|
<el-Table v-loading="loading" :data="list">
|
||||||
|
<el-table-column type="selection"/>
|
||||||
|
<el-table-column prop="serialNumber" label="ID" align="center"/>
|
||||||
|
<el-table-column prop="version" label="版本" align="center"/>
|
||||||
|
<el-table-column prop="outline" label="概要" align="center"/>
|
||||||
|
<el-table-column prop="priority" label="优先级" align="center"/>
|
||||||
|
<el-table-column prop="status" label="状态" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<dict-tag :options="dict.type.status" :value="row.status"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="manager" label="负责人" align="center"/>
|
||||||
|
<el-table-column prop="createTime" label="创建时间" align="center"/>
|
||||||
|
<el-table-column label="操作" align="left" fixed="right">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-delete" @click.native.stop="handleDelete(scope.row.id)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-Table>
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<div style="margin-top: 10px; display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" size="small">全部导出</el-button>
|
||||||
|
<el-button size="small">批量导出</el-button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<pagination
|
||||||
|
v-show="total > 0"
|
||||||
|
:total="total"
|
||||||
|
:page.sync="queryParams.pageNum"
|
||||||
|
:limit.sync="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog title="新建需求" :visible.sync="addOpen" width="90%">
|
||||||
|
<el-form ref="form" :rules="rules" :model="form" label-width="110px" label-position="right">
|
||||||
|
<el-container>
|
||||||
|
<el-main>
|
||||||
|
<el-form-item label="需求概要" prop="outline">
|
||||||
|
<el-input v-model="form.outline" placeholder="请输入"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- 描述 -->
|
||||||
|
<el-form-item label="描述" prop="detail">
|
||||||
|
<el-input type="textarea" v-model="form.detail" :rows="22"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-main>
|
||||||
|
<el-aside width="450px" class="basic-information">
|
||||||
|
<h3>基础信息</h3>
|
||||||
|
<el-form-item label="需求名称" prop="name">
|
||||||
|
<el-input v-model="form.name" placeholder="请输入"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="需求ID" prop="serialNumber">
|
||||||
|
<el-input v-model="form.serialNumber" placeholder="请输入"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="负责人" prop="manager">
|
||||||
|
<el-select v-model="form.manager" placeholder="请选择负责人" clearable>
|
||||||
|
<SimpleOptions :options="managerList"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="优先级" prop="priority">
|
||||||
|
<el-select v-model="form.priority" placeholder="未设置" clearable filterable>
|
||||||
|
<simple-options :options="dict.type.priority_level"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="预期完成时间" prop="estimatedTime">
|
||||||
|
<el-date-picker
|
||||||
|
style="width: 100%"
|
||||||
|
v-model="form.estimatedTime"
|
||||||
|
type="date"
|
||||||
|
placeholder="请选择预期完成时间"
|
||||||
|
></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="需求来源" prop="source">
|
||||||
|
<el-select v-model="form.source" placeholder="未设置" clearable>
|
||||||
|
<simple-options :options="dict.type.project_source"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="需求类型" prop="type">
|
||||||
|
<el-select v-model="form.type" placeholder="未设置" clearable>
|
||||||
|
<simple-options :options="dict.type.project_type"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="版本" prop="version">
|
||||||
|
<el-input v-model="form.version" placeholder="请输入版本"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-aside>
|
||||||
|
</el-container>
|
||||||
|
</el-form>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="addOpen = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {addProject, delProject, getProjectList, managerList} from "@/api/test/project";
|
||||||
|
import SimpleOptions from "@/components/FormItem/option/SimpleOptions.vue";
|
||||||
|
import {delCase} from "@/api/test/case";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'project',
|
||||||
|
components: {SimpleOptions},
|
||||||
|
dicts: ['priority_level', 'project_source', 'project_type', 'status'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
statusCounts: {
|
||||||
|
all: 0,
|
||||||
|
notStarted: 0,
|
||||||
|
inProgress: 0,
|
||||||
|
completed: 0,
|
||||||
|
terminated: 0
|
||||||
|
},
|
||||||
|
query: '',
|
||||||
|
rules: {
|
||||||
|
serialNumber: [{required: true, message: '请输入需求ID', trigger: 'blur'}],
|
||||||
|
detail: [{required: true, message: '请输入描述', trigger: 'blur'}],
|
||||||
|
name: [{required: true, message: '请输入需求名称', trigger: 'blur'}],
|
||||||
|
outline: [{required: true, message: '请输入需求概要', trigger: 'blur'}],
|
||||||
|
manager: [{required: true, message: '请选择负责人', trigger: 'blur'}],
|
||||||
|
priority: [{required: true, message: '请选择优先级', trigger: 'blur'}],
|
||||||
|
estimatedTime: [{required: true, message: '请选择预期完成时间', trigger: 'blur'}],
|
||||||
|
source: [{required: true, message: '请选择需求来源', trigger: 'blur'}],
|
||||||
|
type: [{required: true, message: '请选择需求类型', trigger: 'blur'}]
|
||||||
|
},
|
||||||
|
input3: '',
|
||||||
|
select: '1',
|
||||||
|
searchKeyword: '',
|
||||||
|
activeTab: 'all',
|
||||||
|
total: 0,
|
||||||
|
list: [],
|
||||||
|
// 遮罩层
|
||||||
|
loading: false,
|
||||||
|
submitLoading: false,
|
||||||
|
//新增弹窗
|
||||||
|
addOpen: false,
|
||||||
|
managerList: [],
|
||||||
|
queryParams: {
|
||||||
|
serialNumber: '',
|
||||||
|
outline: '',
|
||||||
|
manager: '',
|
||||||
|
priority: '',
|
||||||
|
createTime: [],
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
},
|
||||||
|
activeNames: [], // 控制 collapse 的展开状态
|
||||||
|
form: {
|
||||||
|
serialNumber: '',
|
||||||
|
name: '',
|
||||||
|
outline: '',
|
||||||
|
detail: '',
|
||||||
|
manager: '',
|
||||||
|
priority: '',
|
||||||
|
estimatedTime: '',
|
||||||
|
source: '',
|
||||||
|
type: '',
|
||||||
|
version: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getList();
|
||||||
|
this.getManagerList();
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
placeholderText() {
|
||||||
|
return this.select === '1' ? '请输入需求概要搜索' : '请输入需求ID搜索';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTabClick(tab) {
|
||||||
|
this.activeTab = tab.name;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
// 获取负责人列表
|
||||||
|
getManagerList() {
|
||||||
|
managerList()
|
||||||
|
.then((list) => {
|
||||||
|
this.managerList = (list.rows || []).map((e) => ({value: e.userId, label: e.userName}))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 搜索
|
||||||
|
handleQuery() {
|
||||||
|
if (this.select === '1') {
|
||||||
|
this.queryParams.outline = this.query;
|
||||||
|
this.queryParams.serialNumber = '';
|
||||||
|
} else if (this.select === '2') {
|
||||||
|
this.queryParams.serialNumber = this.query;
|
||||||
|
this.queryParams.outline = '';
|
||||||
|
}
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
addProjectVue() {
|
||||||
|
this.addOpen = true;
|
||||||
|
this.reset();
|
||||||
|
},
|
||||||
|
/** 查询列表 */
|
||||||
|
getList() {
|
||||||
|
this.loading = true
|
||||||
|
const [startCreateTime, endCreateTime] = this.queryParams.createTime || []
|
||||||
|
const queryParams = {
|
||||||
|
...this.queryParams,
|
||||||
|
startCreateTime,
|
||||||
|
endCreateTime,
|
||||||
|
status: this.activeTab !== 'all' ? this.activeTab : ''
|
||||||
|
}
|
||||||
|
getProjectList(queryParams).then(list => {
|
||||||
|
this.list = list.rows;
|
||||||
|
this.total = list.total;
|
||||||
|
this.loading = false
|
||||||
|
|
||||||
|
// 统计状态数量
|
||||||
|
this.statusCounts.all = this.total;
|
||||||
|
this.statusCounts.notStarted = this.list.filter(item => item.status === '0').length;
|
||||||
|
this.statusCounts.inProgress = this.list.filter(item => item.status === '1').length;
|
||||||
|
this.statusCounts.completed = this.list.filter(item => item.status === '2').length;
|
||||||
|
this.statusCounts.terminated = this.list.filter(item => item.status === '3').length
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 表单重置
|
||||||
|
reset() {
|
||||||
|
const form = {}
|
||||||
|
Object.keys(this.form).forEach((key) => {
|
||||||
|
form[key] = ''
|
||||||
|
})
|
||||||
|
this.form = form
|
||||||
|
this.resetForm('form')
|
||||||
|
},
|
||||||
|
// 展开/折叠
|
||||||
|
handleCollapse(val) {
|
||||||
|
this.activeNames = val ? ['1'] : [];
|
||||||
|
},
|
||||||
|
handleAdvancedSearch() {
|
||||||
|
// 高级筛选条件搜索
|
||||||
|
this.queryParams.pageNum = 1
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
|
resetAdvancedFilter() {
|
||||||
|
// 重置高级筛选条件
|
||||||
|
this.resetForm('queryFrom')
|
||||||
|
this.handleAdvancedSearch()
|
||||||
|
},
|
||||||
|
submitForm() {
|
||||||
|
const form = {
|
||||||
|
...this.form,
|
||||||
|
}
|
||||||
|
console.log('submit', form)
|
||||||
|
this.$refs?.form.validate((valid) => {
|
||||||
|
if (!valid) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.submitLoading = true
|
||||||
|
addProject(form)
|
||||||
|
.then(() => {
|
||||||
|
this.$message.success('添加成功')
|
||||||
|
this.addOpen = false
|
||||||
|
this.getList()
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.$message.error('添加失败')
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.submitLoading = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleDelete(id) {
|
||||||
|
this.$modal.confirm('是否确认删除需求?').then(function () {
|
||||||
|
return delProject(id);
|
||||||
|
}).then(() => {
|
||||||
|
this.getList();
|
||||||
|
this.$modal.msgSuccess("删除成功");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.input-with-select {
|
||||||
|
background-color: #ffffff;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-search {
|
||||||
|
::v-deep .el-collapse-item__header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.high-search {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-top: 40px;
|
||||||
|
background-color: rgb(248, 248, 249);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head1 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head2 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: flex-end;
|
||||||
|
column-gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog .el-form {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog .el-form-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog .el-textarea {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.basic-information {
|
||||||
|
background-color: rgb(248, 248, 249) !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user