预设项目进度控制

This commit is contained in:
2025-04-12 14:30:23 +08:00
parent f77cf3655c
commit a67cac2ebe
17 changed files with 291 additions and 174 deletions

View File

@@ -6,6 +6,7 @@ import java.util.Arrays;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.ruoyi.oa.domain.bo.SysOaWarehouseDetailBo;
import com.ruoyi.oa.domain.vo.SysOaFileVo;
import com.ruoyi.oa.domain.vo.SysOaOutWarehouseListVo;
import com.ruoyi.oa.mapper.SysOaTaskMapper;
import lombok.RequiredArgsConstructor;
@@ -130,9 +131,7 @@ public class SysOaProjectController extends BaseController {
@DSTransactional
@DeleteMapping("/{projectIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] projectIds) {
Arrays.asList(projectIds).forEach(v ->{
sysOaTaskMapper.deleteSysOaTaskByProjectId(v);
});
Arrays.asList(projectIds).forEach(sysOaTaskMapper::deleteSysOaTaskByProjectId);
return toAjax(iSysOaProjectService.deleteWithValidByIds(Arrays.asList(projectIds), true));
}
@@ -144,4 +143,10 @@ public class SysOaProjectController extends BaseController {
public TableDataInfo<SysOaOutWarehouseListVo> outWareList(SysOaWarehouseDetailBo bo, PageQuery pageQuery) {
return iSysOaProjectService.queryOutWarePageList(bo, pageQuery);
}
}
@GetMapping("/files")
public TableDataInfo<SysOaProjectVo> files(SysOaWarehouseDetailBo bo, PageQuery pageQuery) {
return iSysOaProjectService.queryFiles(bo, pageQuery);
}
}

View File

@@ -81,27 +81,6 @@ public class SysOaTaskController extends BaseController {
return R.ok(iSysOaTaskService.listDocumentProject(projectId));
}
/**
* 根据工作类型字典查询任务列表
* @param pid
* @return
*/
@GetMapping("/getTaskByDictType/{pid}")
public R taskByDictType(@PathVariable Long pid){
R taskByDictList = iSysOaTaskService.queryTaskByDictList(pid);
return R.ok("ok", taskByDictList);
}
/**
* 根据工作类型查询列表
* @param bo
* @return
*/
@GetMapping("/listByType")
public List<SysOaTaskVo> listByType(SysOaTaskBo bo){
return iSysOaTaskService.queryListByType(bo);
}
/**
* 导出任务管理列表
*/

View File

@@ -140,4 +140,9 @@ public class SysOaTask extends BaseEntity {
*/
private Date tempTime;
/**
* 文件
*/
private String files;
}

View File

@@ -80,4 +80,5 @@ public class SysOaTaskItem extends BaseEntity {
*/
private String remark;
}

View File

@@ -182,4 +182,6 @@ public class SysOaTaskBo extends BaseEntity {
private Long itemStatus;
private String files;
}

View File

@@ -9,9 +9,10 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.convert.ExcelDictConvert;
import com.ruoyi.oa.domain.SysOaTask;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
@@ -212,4 +213,10 @@ public class SysOaProjectVo {
* 项目剩余时间
*/
private Long remainTime;
private List<SysOaTaskVo> taskList;
/**
* 最近更新时间
*/
private Date updateTime;
}

View File

@@ -107,4 +107,7 @@ public class SysOaTaskItemVo {
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date completedTime;
private String nickName;
}

View File

@@ -49,7 +49,7 @@ public class SysOaTaskVo {
*/
@ExcelProperty(value = "工作类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_work_type")
private String taskType;
private Long taskType;
/**
* 优先级

View File

@@ -39,4 +39,7 @@ public interface SysOaProjectMapper extends BaseMapperPlus<SysOaProjectMapper, S
Map<String, Object> selectProjectDetails(@Param("projectId") Long projectId);
Page<SysOaProjectVo> selectVoPlus(@Param("page") Page<SysOaProjectVo> build,@Param(Constants.WRAPPER) LambdaQueryWrapper<SysOaProject> lqw);
Page<SysOaProjectVo> selectFileVoList(@Param("page") Page<Object> build, @Param(Constants.WRAPPER) QueryWrapper<SysOaProject> sysOaProjectQueryWrapper);
}

View File

@@ -64,4 +64,6 @@ public interface ISysOaProjectService {
* @return
*/
List<SysOaProjectVo> getProjectDataByMonthAndDate();
TableDataInfo<SysOaProjectVo> queryFiles(SysOaWarehouseDetailBo bo, PageQuery pageQuery);
}

View File

@@ -33,19 +33,6 @@ public interface ISysOaTaskService {
*/
List<SysOaTaskVo> queryList(SysOaTaskBo bo);
/****
* 据工作类型字典查询任务列表
* @param pid
* @return
*/
R queryTaskByDictList(Long pid);
/**
* 根据工作类型查询列表
* @param bo
* @return
*/
List<SysOaTaskVo> queryListByType(SysOaTaskBo bo);
/**
* 新增任务管理
*/

View File

@@ -79,9 +79,7 @@ public class SysOaHolidayServiceImpl implements ISysOaHolidayService {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<SysOaHoliday> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getType() != null, SysOaHoliday::getType, bo.getType());
System.out.println(bo);
if (bo.getHolidayTime() != null) {
System.out.println("今年考了哈士大夫");
lqw.between(SysOaHoliday::getHolidayTime, getFirstDay(bo.getHolidayTime()),getLastDay(bo.getHolidayTime()));
}
lqw.like(StringUtils.isNotBlank(bo.getName()), SysOaHoliday::getName, bo.getName());

View File

@@ -11,6 +11,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.oa.domain.bo.SysOaWarehouseDetailBo;
import com.ruoyi.oa.domain.vo.SysOaOutWarehouseListVo;
import com.ruoyi.oa.domain.vo.SysOaTaskVo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.ruoyi.oa.domain.bo.SysOaProjectBo;
@@ -20,6 +21,7 @@ import com.ruoyi.oa.mapper.SysOaProjectMapper;
import com.ruoyi.oa.service.ISysOaProjectService;
import java.util.*;
import java.util.stream.Collectors;
/**
* 项目管理Service业务层处理
@@ -153,6 +155,57 @@ public class SysOaProjectServiceImpl implements ISysOaProjectService {
return projectVos;
}
@Override
public TableDataInfo<SysOaProjectVo> queryFiles(SysOaWarehouseDetailBo bo, PageQuery pageQuery) {
QueryWrapper<SysOaProject> sysOaProjectQueryWrapper = buildOutWareQueryWrapper(bo);
sysOaProjectQueryWrapper.groupBy("sop.project_id","sop.project_name","t.task_id","t.task_type","t.status","nick_name","ti.item_id","ti.sign_time","sop.create_time");
// sysOaProjectQueryWrapper.having("file_urls IS NOT NULL");
Page<SysOaProjectVo> result = baseMapper.selectFileVoList(pageQuery.build(), sysOaProjectQueryWrapper);
List<SysOaProjectVo> projects = result.getRecords();
// 2) 遍历每个项目,对其 taskList 做补充
for (SysOaProjectVo project : projects) {
List<SysOaTaskVo> taskList = project.getTaskList();
if (taskList == null || taskList.isEmpty()) {
continue;
}
// 2.1 取出已经出现的 taskType
Set<Long> existingTypes = taskList.stream()
.map(SysOaTaskVo::getTaskType)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
// 2.2 找出最大 taskType
Long maxType = existingTypes.stream().max(Long::compareTo).orElse(0L);
if (maxType <= 1) {
// 如果最大只有1且你仍想补齐1..1,那其实啥都不补。
// 也可以补其它逻辑
continue;
}
// 2.3 在 1..maxType 范围内检查是否缺失
for (Long type = 1L; type <= maxType; type++) {
if (!existingTypes.contains(type)) {
// 缺失则插入一个空对象
SysOaTaskVo emptyTask = new SysOaTaskVo();
emptyTask.setTaskType(type);
// 例如给 status 默认 0, 或者不赋值
emptyTask.setStatus(null);
// 任务item列表为空
emptyTask.setTaskItemVoList(new ArrayList<>());
// 其他字段如 nickName, createTime, etc. 也可设为空或默认值
taskList.add(emptyTask);
}
}
// 此时taskList已经包含了 1..maxType 全部类型
// 如果你想让结果中的 taskType 从大到小排序或从小到大排序再手动sort一下
taskList.sort(Comparator.comparing(SysOaTaskVo::getTaskType));
}
return TableDataInfo.build(result);
}
private QueryWrapper<SysOaProject> buildOutWareQueryWrapper(SysOaWarehouseDetailBo bo) {
QueryWrapper<SysOaProject> lqw = Wrappers.query();
lqw.like(StringUtils.isNotBlank(bo.getProjectName()), "sop.projec_name", bo.getProjectName());

View File

@@ -107,60 +107,6 @@ public class SysOaTaskServiceImpl implements ISysOaTaskService {
return TableDataInfo.build(result);
}
/**
* 据工作类型字典查询任务列表
* @param pid
* @return
*/
@Override
public R queryTaskByDictList(Long pid){
List<Object> objects = new ArrayList<>();
List<SysDictData> sysWorkType = dictTypeService.selectDictDataByType("sys_work_type");
sysWorkType.forEach(item -> {
SysOaTaskBo sysOaTaskBo = new SysOaTaskBo();
sysOaTaskBo.setProjectId(pid);
sysOaTaskBo.setTaskType(item.getDictValue());
List<SysOaTaskVo> sysOaTaskVos = this.queryListByType(sysOaTaskBo);
Map<String, Object> ajax = new HashMap<>();
ajax.put("dictLabel", item.getDictLabel());
ajax.put("dictValue", item.getDictValue());
ajax.put("taskList", sysOaTaskVos);
ajax.put("size", "large");
ajax.put("type", "primary");
ajax.put("icon", "el-icon-more");
ajax.put("color", "#cccccc");
objects.add(ajax);
});
//根据项目id获取任务列表类型属性最大的值
SysOaTaskBo task = new SysOaTaskBo();
task.setProjectId(pid);
List<SysOaTaskVo> taskVos = this.queryListByType(task);
List<Integer> collect = taskVos.stream().map(v -> Integer.parseInt(v.getTaskType())).collect(Collectors.toList());
OptionalInt max = collect.stream().mapToInt(Integer::intValue).max();
Map<String, Object> map = new HashMap<>();
if(max.isPresent()){
map.put("active", max.getAsInt());
}else {
map.put("active", 0);
}
map.put("taskList", objects);
return R.ok(map);
}
/**
* 根据工作类型查询列表
* @param bo
* @return
*/
@Override
public List<SysOaTaskVo> queryListByType(SysOaTaskBo bo){
LambdaQueryWrapper<SysOaTask> lqw = new LambdaQueryWrapper<>();
lqw.eq(bo.getProjectId()!=null, SysOaTask::getProjectId, bo.getProjectId());
lqw.like(bo.getTaskTitle()!=null, SysOaTask::getTaskTitle, bo.getTaskTitle());
lqw.eq(StringUtils.isNotBlank(bo.getTaskType()),SysOaTask::getTaskType, bo.getTaskType());
return baseMapper.selectVoList(lqw);
}
/**
* 查询任务管理列表
*/
@@ -197,7 +143,7 @@ public class SysOaTaskServiceImpl implements ISysOaTaskService {
lqw.eq(bo.getState()!=null, "sot.state", bo.getState());
lqw.eq(bo.getItemStatus()!=null, "soti.status", bo.getItemStatus());
lqw.like(bo.getTaskTitle()!=null, "sot.task_title", bo.getTaskTitle());
lqw.isNotNull("sot.task_title");
lqw.like(bo.getTaskTitle()!=null, "sot.task_title", bo.getTaskTitle());
lqw.like(bo.getCreateUserNickName()!=null, "su1.nick_name", bo.getCreateUserNickName());
lqw.like(bo.getWorkerNickName()!=null, "su2.nick_name", bo.getWorkerNickName());
@@ -209,11 +155,19 @@ public class SysOaTaskServiceImpl implements ISysOaTaskService {
*/
@Override
public Boolean insertByBo(SysOaTaskBo bo) {
List<Long> workerIdList = new ArrayList<>();
// 拿到所有的执行人id列表进行遍历添加
List<Long> workerIdList = Arrays.stream( bo.getWorkerIds().split(","))
.map(Long::valueOf)
.collect(Collectors.toList());
if (bo.getWorkerId()!=null) {
workerIdList = Arrays.stream( bo.getWorkerIds().split(","))
.map(Long::valueOf)
.collect(Collectors.toList());
}else{
bo.setBeginTime(new Date());
bo.setCompletedTime(new Date());
bo.setFinishTime(new Date());
workerIdList.add(LoginHelper.getUserId());
}
boolean flag = false;
for (Long workerId : workerIdList) {
if(Objects.nonNull(bo.getAccessory())){
@@ -221,8 +175,17 @@ public class SysOaTaskServiceImpl implements ISysOaTaskService {
.map(String::valueOf)
.collect(Collectors.toList());
String fileIds = fileService.insertFiles(fileUrls);
bo.setAccessory(fileIds);
}
if (Objects.nonNull(bo.getFiles())) {
List<String> fileUrls = Arrays.stream(bo.getFiles().split(","))
.map(String::valueOf)
.collect(Collectors.toList());
String fileIds = fileService.insertFiles(fileUrls);
bo.setFiles(fileIds);
}
SysOaTask add = BeanUtil.toBean(bo, SysOaTask.class);
add.setCreateUserId(LoginHelper.getUserId());
validEntityBeforeSave(add);

View File

@@ -184,87 +184,73 @@
SELECT JSON_OBJECT(
'userCostList',
COALESCE(
(
SELECT JSON_ARRAYAGG(
JSON_OBJECT(
'userId', CAST(uc.userId AS CHAR),
'nickName', COALESCE(uc.nickName, ''),
'laborCost', ROUND(COALESCE(uc.laborCost, 0), 1),
'attendenceNum', ROUND(COALESCE(uc.attendenceNum, 0), 1)
)
)
FROM (
SELECT
a.user_id AS userId,
u.nick_name AS nickName,
COALESCE(
SUM(
ROUND((a.day_length * 9 + a.hour) / 9, 1) * u.labor_cost
),
0
) AS laborCost,
COALESCE(
ROUND(
SUM((a.day_length * 9 + a.hour) / 9), 1
),
0
) AS attendenceNum
FROM sys_oa_attendance a
INNER JOIN sys_user u
ON a.user_id = u.user_id
WHERE a.project_id = #{projectId}
AND a.del_flag = 0
GROUP BY a.user_id
) uc
),
(SELECT JSON_ARRAYAGG(
JSON_OBJECT(
'userId', CAST(uc.userId AS CHAR),
'nickName', COALESCE(uc.nickName, ''),
'laborCost', ROUND(COALESCE(uc.laborCost, 0), 1),
'attendenceNum', ROUND(COALESCE(uc.attendenceNum, 0), 1)
)
)
FROM (SELECT a.user_id AS userId,
u.nick_name AS nickName,
COALESCE(
SUM(
ROUND((a.day_length * 9 + a.hour) / 9, 1) * u.labor_cost
),
0
) AS laborCost,
COALESCE(
ROUND(
SUM((a.day_length * 9 + a.hour) / 9), 1
),
0
) AS attendenceNum
FROM sys_oa_attendance a
INNER JOIN sys_user u
ON a.user_id = u.user_id
WHERE a.project_id = #{projectId}
AND a.del_flag = 0
GROUP BY a.user_id) uc),
JSON_ARRAY()
),
'materialList',
COALESCE(
(
SELECT JSON_ARRAYAGG(
JSON_OBJECT(
'detailId', CAST(d.detail_id AS CHAR),
'detailTitle', COALESCE(d.detail_title, ''),
'price', COALESCE(d.price, 0),
'financeParties', COALESCE(f.finance_parties, ''),
'remark', COALESCE(f.remark, '')
)
)
FROM sys_oa_finance f
INNER JOIN sys_oa_detail d
ON f.finance_id = d.finance_id
WHERE f.project_id = #{projectId}
AND f.finance_type = 0
),
(SELECT JSON_ARRAYAGG(
JSON_OBJECT(
'detailId', CAST(d.detail_id AS CHAR),
'detailTitle', COALESCE(d.detail_title, ''),
'price', COALESCE(d.price, 0),
'financeParties', COALESCE(f.finance_parties, ''),
'remark', COALESCE(f.remark, '')
)
)
FROM sys_oa_finance f
INNER JOIN sys_oa_detail d
ON f.finance_id = d.finance_id
WHERE f.project_id = #{projectId}
AND f.finance_type = 0),
JSON_ARRAY()
),
'claimList',
COALESCE(
(
SELECT JSON_ARRAYAGG(
JSON_OBJECT(
'claimId', CAST(cl.claimId AS CHAR),
'nickName', COALESCE(cl.nickName, ''),
'cost', COALESCE(cl.cost, 0),
'remark', COALESCE(cl.remark, '')
)
)
FROM (
SELECT
c.claim_id AS claimId,
COALESCE(u.nick_name, '') AS nickName,
COALESCE(c.cost, 0) AS cost,
COALESCE(c.remark, '') AS remark
FROM sys_oa_claim c
INNER JOIN sys_user u
ON c.user_id = u.user_id
WHERE c.project_id = #{projectId}
AND c.del_flag = 0
) cl
),
(SELECT JSON_ARRAYAGG(
JSON_OBJECT(
'claimId', CAST(cl.claimId AS CHAR),
'nickName', COALESCE(cl.nickName, ''),
'cost', COALESCE(cl.cost, 0),
'remark', COALESCE(cl.remark, '')
)
)
FROM (SELECT c.claim_id AS claimId,
COALESCE(u.nick_name, '') AS nickName,
COALESCE(c.cost, 0) AS cost,
COALESCE(c.remark, '') AS remark
FROM sys_oa_claim c
INNER JOIN sys_user u
ON c.user_id = u.user_id
WHERE c.project_id = #{projectId}
AND c.del_flag = 0) cl),
JSON_ARRAY()
)
) AS data
@@ -310,4 +296,88 @@
</select>
<!-- 最内层 TaskItem -->
<resultMap id="TaskItemResultMap" type="com.ruoyi.oa.domain.vo.SysOaTaskItemVo">
<id property="itemId" column="item_id"/>
<result property="files" column="file_urls"/>
<result property="nickName" column="nick_name"/>
<result property="signTime" column="sign_time"/>
</resultMap>
<!-- Task, 包含 List<TaskItem> -->
<resultMap id="TaskResultMap" type="com.ruoyi.oa.domain.vo.SysOaTaskVo">
<id property="taskId" column="task_id"/>
<result property="taskType" column="task_type"/>
<result property="status" column="task_status"/>
<collection property="taskItemVoList"
resultMap="TaskItemResultMap"
column="item_id"
javaType="ArrayList" />
</resultMap>
<!-- Project, 包含 List<Task> -->
<resultMap id="ProjectResultMap" type="com.ruoyi.oa.domain.vo.SysOaProjectVo">
<id property="projectId" column="p_id"/>
<result property="projectName" column="project_name"/>
<result property="updateTime" column="update_time"/>
<collection property="taskList"
resultMap="TaskResultMap"
column="task_id"
javaType="ArrayList" />
</resultMap>
<select id="selectFileVoList" resultMap="ProjectResultMap">
SELECT
sop.project_id AS p_id,
sop.project_name AS project_name,
sop.update_time,
t.task_id AS task_id,
t.task_type AS task_type,
t.status AS task_status,
CASE
WHEN t.status = 0 THEN u0.nick_name
WHEN t.status = 1 THEN u1.nick_name
ELSE ''
END AS nick_name,
ti.item_id AS item_id,
case
when ti.sign_time is not null then ti.sign_time
else t.finish_time
end AS sign_time,
GROUP_CONCAT(
f.file_url
SEPARATOR ','
) AS file_urls
FROM sys_oa_project sop
LEFT JOIN sys_oa_task t
ON sop.project_id = t.project_id
LEFT JOIN sys_user u0
ON t.create_user_id = u0.user_id
LEFT JOIN sys_user u1
ON t.worker_id = u1.user_id
LEFT JOIN sys_oa_task_item ti
ON t.task_id = ti.task_id
LEFT JOIN sys_oa_file f
ON (
(t.status = 0 AND FIND_IN_SET(CONCAT(f.file_id, ''), t.files) > 0)
OR
(t.status = 1 AND FIND_IN_SET(CONCAT(f.file_id, ''), ti.files) > 0)
)
${ew.getCustomSqlSegment}
</select>
</mapper>

View File

View File

@@ -0,0 +1,39 @@
CREATE TABLE `oa_progress` (
`progress_id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`project_id` BIGINT NOT NULL DEFAULT 0 COMMENT '所属项目ID(可根据实际需要)',
`type` TINYINT NOT NULL DEFAULT 1 COMMENT '进度类型1-项目进度2-付款进度(可根据实际约定)',
`progress_name` VARCHAR(200) NOT NULL DEFAULT '' COMMENT '进度名称',
`parent_id` BIGINT NOT NULL DEFAULT 0 COMMENT '父进度ID0或NULL表示没有父节点',
/* 审计字段 */
`create_by` VARCHAR(40) NOT NULL DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` VARCHAR(40) NOT NULL DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`del_flag` TINYINT NOT NULL DEFAULT 0 COMMENT '删除标志0-正常1-删除',
/* 其他可选字段,比如排序、备注等 */
`sort` INT NOT NULL DEFAULT 0 COMMENT '排序字段(如需)',
`remark` VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注(如需)',
KEY `idx_project_id` (`project_id`),
KEY `idx_parent_id` (`parent_id`),
KEY `idx_type` (`type`)
) COMMENT '项目进度主表';
CREATE TABLE `oa_progress_detail` (
`detail_id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`progress_id` BIGINT NOT NULL COMMENT '关联的进度ID关联 project_progress.id',
`plan_start_date` DATE DEFAULT NULL COMMENT '计划开始日期(项目进度)',
`plan_end_date` DATE DEFAULT NULL COMMENT '计划结束日期(项目进度)',
`actual_start_date` DATE DEFAULT NULL COMMENT '实际开始日期(项目进度)',
`actual_end_date` DATE DEFAULT NULL COMMENT '实际结束日期(项目进度)',
`complete_percent` DECIMAL(5,2) NOT NULL DEFAULT 0.00 COMMENT '完成百分比(项目进度)',
`plan_pay_date` DATE DEFAULT NULL COMMENT '计划付款日期(付款进度)',
`pay_amount` DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '应付金额(付款进度)',
`paid_amount` DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '已付金额(付款进度)',
`create_by` VARCHAR(40) NOT NULL DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` VARCHAR(40) NOT NULL DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`del_flag` TINYINT NOT NULL DEFAULT 0 COMMENT '删除标志0-正常1-删除',
`remark` VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注(如需)',
KEY `idx_progress_id` (`progress_id`)
) COMMENT '项目进度/付款进度扩展表';