修改工作计划显示方式

This commit is contained in:
userName 2024-02-20 14:28:19 +08:00
parent 10d23a388c
commit 41871341c9
21 changed files with 1659 additions and 513 deletions

View File

@ -0,0 +1,108 @@
package com.ruoyi.mts.controller;
import java.util.List;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.mts.domain.vo.MesPlanBomVo;
import com.ruoyi.mts.domain.bo.MesPlanBomBo;
import com.ruoyi.mts.service.IMesPlanBomService;
/**
* 物料清单
*
* @author jiangzhe
* @date 2024-02-20
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/mts/planBom")
public class MesPlanBomController extends BaseController {
private final IMesPlanBomService iMesPlanBomService;
/**
* 查询物料清单列表
*/
@SaCheckPermission("mts:planBom:list")
@GetMapping("/list")
public R<List<MesPlanBomVo>> list(MesPlanBomBo bo) {
List<MesPlanBomVo> list = iMesPlanBomService.queryList(bo);
return R.ok(list);
}
/**
* 导出物料清单列表
*/
@SaCheckPermission("mts:planBom:export")
@Log(title = "物料清单", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(MesPlanBomBo bo, HttpServletResponse response) {
List<MesPlanBomVo> list = iMesPlanBomService.queryList(bo);
ExcelUtil.exportExcel(list, "物料清单", MesPlanBomVo.class, response);
}
/**
* 获取物料清单详细信息
*
* @param id 主键
*/
@SaCheckPermission("mts:planBom:query")
@GetMapping("/{id}")
public R<MesPlanBomVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(iMesPlanBomService.queryById(id));
}
/**
* 新增物料清单
*/
@SaCheckPermission("mts:planBom:add")
@Log(title = "物料清单", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody MesPlanBomBo bo) {
return toAjax(iMesPlanBomService.insertByBo(bo));
}
/**
* 修改物料清单
*/
@SaCheckPermission("mts:planBom:edit")
@Log(title = "物料清单", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody MesPlanBomBo bo) {
return toAjax(iMesPlanBomService.updateByBo(bo));
}
/**
* 删除物料清单
*
* @param ids 主键串
*/
@SaCheckPermission("mts:planBom:remove")
@Log(title = "物料清单", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(iMesPlanBomService.deleteWithValidByIds(Arrays.asList(ids), true));
}
}

View File

@ -0,0 +1,90 @@
package com.ruoyi.mts.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.TreeEntity;
/**
* 物料清单对象 mes_plan_bom
*
* @author jiangzhe
* @date 2024-02-20
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("mes_plan_bom")
public class MesPlanBom extends TreeEntity<MesPlanBom> {
private static final long serialVersionUID=1L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 详情任务id
*/
private Long detailId;
/**
* 层级
*/
private Integer deep;
/**
* 物资名称
*/
private String name;
/**
* 图号及标准号
*/
private String standardNo;
/**
* 材质
*/
private String material;
/**
* 数量
*/
private Integer num;
/**
* 单位
*/
private String unit;
/**
* 工序
*/
private String process;
/**
* 备注
*/
private String remark;
/**
* 应到日期
*/
private Date dueDate;
/**
* 实到日期
*/
private Date actualDate;
/**
* 供应商
*/
private String supplier;
/**
* oss对应id
*/
private Long ossId;
/**
* 删除标志(0存在2删除)
*/
@TableLogic
private String delFlag;
}

View File

@ -3,11 +3,13 @@ package com.ruoyi.mts.domain;
import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.annotation.*;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.TreeEntity; import com.ruoyi.common.core.domain.TreeEntity;
@ -22,7 +24,7 @@ import com.ruoyi.common.core.domain.TreeEntity;
@TableName("mes_plan_detail") @TableName("mes_plan_detail")
public class MesPlanDetail extends TreeEntity<MesPlanDetail> { public class MesPlanDetail extends TreeEntity<MesPlanDetail> {
private static final long serialVersionUID=1L; private static final long serialVersionUID = 1L;
/** /**
* 主键 * 主键
@ -38,13 +40,29 @@ public class MesPlanDetail extends TreeEntity<MesPlanDetail> {
*/ */
private String name; private String name;
/** /**
* 计划时间 * 计划开始时间
*/ */
private Date planDate; private Date planStartDate;
/** /**
* 实际时间 * 计划结束时间
*/ */
private Date actualDate; private Date planEndDate;
/**
* 实际开始时间
*/
private Date actualStartDate;
/**
* 实际结束时间
*/
private Date actualEndDate;
/**
* 甘特图颜色
*/
private String ganttColor;
/** /**
* 删除标志(0存在2删除) * 删除标志(0存在2删除)
*/ */

View File

@ -0,0 +1,110 @@
package com.ruoyi.mts.domain.bo;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.TreeEntity;
/**
* 物料清单业务对象 mes_plan_bom
*
* @author jiangzhe
* @date 2024-02-20
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class MesPlanBomBo extends TreeEntity<MesPlanBomBo> {
/**
* 主键
*/
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
private Long id;
/**
* 详情任务id
*/
@NotNull(message = "详情任务id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long detailId;
/**
* 层级
*/
private Integer deep;
/**
* 物资名称
*/
@NotBlank(message = "物资名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String name;
/**
* 图号及标准号
*/
@NotBlank(message = "图号及标准号不能为空", groups = { AddGroup.class, EditGroup.class })
private String standardNo;
/**
* 材质
*/
@NotBlank(message = "材质不能为空", groups = { AddGroup.class, EditGroup.class })
private String material;
/**
* 数量
*/
@NotNull(message = "数量不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer num;
/**
* 单位
*/
@NotBlank(message = "单位不能为空", groups = { AddGroup.class, EditGroup.class })
private String unit;
/**
* 工序
*/
@NotBlank(message = "工序不能为空", groups = { AddGroup.class, EditGroup.class })
private String process;
/**
* 备注
*/
@NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
private String remark;
/**
* 应到日期
*/
@NotNull(message = "应到日期不能为空", groups = { AddGroup.class, EditGroup.class })
private Date dueDate;
/**
* 实到日期
*/
@NotNull(message = "实到日期不能为空", groups = { AddGroup.class, EditGroup.class })
private Date actualDate;
/**
* 供应商
*/
@NotBlank(message = "供应商不能为空", groups = { AddGroup.class, EditGroup.class })
private String supplier;
/**
* oss对应id
*/
@NotNull(message = "oss对应id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long ossId;
}

View File

@ -4,11 +4,13 @@ import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup; import com.ruoyi.common.core.validate.EditGroup;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import javax.validation.constraints.*; import javax.validation.constraints.*;
import java.util.Date; import java.util.Date;
import java.util.Date; import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.TreeEntity; import com.ruoyi.common.core.domain.TreeEntity;
@ -26,32 +28,43 @@ public class MesPlanDetailBo extends TreeEntity<MesPlanDetailBo> {
/** /**
* 主键 * 主键
*/ */
@NotNull(message = "主键不能为空", groups = { EditGroup.class }) @NotNull(message = "主键不能为空", groups = {EditGroup.class})
private Long id; private Long id;
/** /**
* 主表id * 主表id
*/ */
@NotNull(message = "主表id不能为空", groups = { AddGroup.class, EditGroup.class }) @NotNull(message = "主表id不能为空", groups = {AddGroup.class, EditGroup.class})
private Long mainId; private Long mainId;
/** /**
* 名称 * 名称
*/ */
@NotBlank(message = "名称不能为空", groups = { AddGroup.class, EditGroup.class }) @NotBlank(message = "名称不能为空", groups = {AddGroup.class, EditGroup.class})
private String name; private String name;
/** /**
* 计划时间 * 计划开始时间
*/ */
@NotNull(message = "计划时间不能为空", groups = { AddGroup.class, EditGroup.class }) private Date planStartDate;
private Date planDate;
/** /**
* 实际时间 * 计划结束时间
*/ */
@NotNull(message = "实际时间不能为空", groups = { AddGroup.class, EditGroup.class }) private Date planEndDate;
private Date actualDate;
/**
* 实际开始时间
*/
private Date actualStartDate;
/**
* 实际结束时间
*/
private Date actualEndDate;
/**
* 甘特图颜色
*/
private String ganttColor;
} }

View File

@ -0,0 +1,117 @@
package com.ruoyi.mts.domain.vo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
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 lombok.Data;
import java.util.Date;
import java.io.Serializable;
/**
* 物料清单视图对象 mes_plan_bom
*
* @author jiangzhe
* @date 2024-02-20
*/
@Data
@ExcelIgnoreUnannotated
public class MesPlanBomVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ExcelProperty(value = "主键")
private Long id;
/**
* 父id
*/
@ExcelProperty(value = "父id")
private Long parentId;
/**
* 详情任务id
*/
@ExcelProperty(value = "详情任务id")
private Long detailId;
/**
* 层级
*/
@ExcelProperty(value = "层级")
private Integer deep;
/**
* 物资名称
*/
@ExcelProperty(value = "物资名称")
private String name;
/**
* 图号及标准号
*/
@ExcelProperty(value = "图号及标准号")
private String standardNo;
/**
* 材质
*/
@ExcelProperty(value = "材质")
private String material;
/**
* 数量
*/
@ExcelProperty(value = "数量")
private Integer num;
/**
* 单位
*/
@ExcelProperty(value = "单位")
private String unit;
/**
* 工序
*/
@ExcelProperty(value = "工序")
private String process;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 应到日期
*/
@ExcelProperty(value = "应到日期")
private Date dueDate;
/**
* 实到日期
*/
@ExcelProperty(value = "实到日期")
private Date actualDate;
/**
* 供应商
*/
@ExcelProperty(value = "供应商")
private String supplier;
/**
* oss对应id
*/
@ExcelProperty(value = "oss对应id")
private Long ossId;
}

View File

@ -48,16 +48,27 @@ public class MesPlanDetailVo implements Serializable {
private String name; private String name;
/** /**
* 计划时间 * 计划开始时间
*/ */
@ExcelProperty(value = "计划时间") private Date planStartDate;
private Date planDate;
/** /**
* 实际时间 * 计划结束时间
*/ */
@ExcelProperty(value = "实际时间") private Date planEndDate;
private Date actualDate;
/**
* 实际开始时间
*/
private Date actualStartDate;
/**
* 实际结束时间
*/
private Date actualEndDate;
/**
* 甘特图颜色
*/
private String ganttColor;
} }

View File

@ -0,0 +1,15 @@
package com.ruoyi.mts.mapper;
import com.ruoyi.mts.domain.MesPlanBom;
import com.ruoyi.mts.domain.vo.MesPlanBomVo;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
/**
* 物料清单Mapper接口
*
* @author jiangzhe
* @date 2024-02-20
*/
public interface MesPlanBomMapper extends BaseMapperPlus<MesPlanBomMapper, MesPlanBom, MesPlanBomVo> {
}

View File

@ -0,0 +1,43 @@
package com.ruoyi.mts.service;
import com.ruoyi.mts.domain.MesPlanBom;
import com.ruoyi.mts.domain.vo.MesPlanBomVo;
import com.ruoyi.mts.domain.bo.MesPlanBomBo;
import java.util.Collection;
import java.util.List;
/**
* 物料清单Service接口
*
* @author jiangzhe
* @date 2024-02-20
*/
public interface IMesPlanBomService {
/**
* 查询物料清单
*/
MesPlanBomVo queryById(Long id);
/**
* 查询物料清单列表
*/
List<MesPlanBomVo> queryList(MesPlanBomBo bo);
/**
* 新增物料清单
*/
Boolean insertByBo(MesPlanBomBo bo);
/**
* 修改物料清单
*/
Boolean updateByBo(MesPlanBomBo bo);
/**
* 校验并批量删除物料清单信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -0,0 +1,109 @@
package com.ruoyi.mts.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.ruoyi.mts.domain.bo.MesPlanBomBo;
import com.ruoyi.mts.domain.vo.MesPlanBomVo;
import com.ruoyi.mts.domain.MesPlanBom;
import com.ruoyi.mts.mapper.MesPlanBomMapper;
import com.ruoyi.mts.service.IMesPlanBomService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 物料清单Service业务层处理
*
* @author jiangzhe
* @date 2024-02-20
*/
@RequiredArgsConstructor
@Service
public class MesPlanBomServiceImpl implements IMesPlanBomService {
private final MesPlanBomMapper baseMapper;
/**
* 查询物料清单
*/
@Override
public MesPlanBomVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 查询物料清单列表
*/
@Override
public List<MesPlanBomVo> queryList(MesPlanBomBo bo) {
LambdaQueryWrapper<MesPlanBom> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<MesPlanBom> buildQueryWrapper(MesPlanBomBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<MesPlanBom> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getParentId() != null, MesPlanBom::getParentId, bo.getParentId());
lqw.eq(bo.getDetailId() != null, MesPlanBom::getDetailId, bo.getDetailId());
lqw.eq(bo.getDeep() != null, MesPlanBom::getDeep, bo.getDeep());
lqw.like(StringUtils.isNotBlank(bo.getName()), MesPlanBom::getName, bo.getName());
lqw.eq(StringUtils.isNotBlank(bo.getStandardNo()), MesPlanBom::getStandardNo, bo.getStandardNo());
lqw.eq(StringUtils.isNotBlank(bo.getMaterial()), MesPlanBom::getMaterial, bo.getMaterial());
lqw.eq(bo.getNum() != null, MesPlanBom::getNum, bo.getNum());
lqw.eq(StringUtils.isNotBlank(bo.getUnit()), MesPlanBom::getUnit, bo.getUnit());
lqw.eq(StringUtils.isNotBlank(bo.getProcess()), MesPlanBom::getProcess, bo.getProcess());
lqw.eq(bo.getDueDate() != null, MesPlanBom::getDueDate, bo.getDueDate());
lqw.eq(bo.getActualDate() != null, MesPlanBom::getActualDate, bo.getActualDate());
lqw.eq(StringUtils.isNotBlank(bo.getSupplier()), MesPlanBom::getSupplier, bo.getSupplier());
lqw.eq(bo.getOssId() != null, MesPlanBom::getOssId, bo.getOssId());
return lqw;
}
/**
* 新增物料清单
*/
@Override
public Boolean insertByBo(MesPlanBomBo bo) {
MesPlanBom add = BeanUtil.toBean(bo, MesPlanBom.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改物料清单
*/
@Override
public Boolean updateByBo(MesPlanBomBo bo) {
MesPlanBom update = BeanUtil.toBean(bo, MesPlanBom.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(MesPlanBom entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除物料清单
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@ -65,8 +65,8 @@ public class MesPlanDetailServiceImpl implements IMesPlanDetailService {
lqw.eq(bo.getParentId() != null, MesPlanDetail::getParentId, bo.getParentId()); lqw.eq(bo.getParentId() != null, MesPlanDetail::getParentId, bo.getParentId());
lqw.eq(bo.getMainId() != null, MesPlanDetail::getMainId, bo.getMainId()); lqw.eq(bo.getMainId() != null, MesPlanDetail::getMainId, bo.getMainId());
lqw.like(StringUtils.isNotBlank(bo.getName()), MesPlanDetail::getName, bo.getName()); lqw.like(StringUtils.isNotBlank(bo.getName()), MesPlanDetail::getName, bo.getName());
lqw.eq(bo.getPlanDate() != null, MesPlanDetail::getPlanDate, bo.getPlanDate()); lqw.eq(bo.getPlanStartDate() != null, MesPlanDetail::getPlanStartDate, bo.getPlanStartDate());
lqw.eq(bo.getActualDate() != null, MesPlanDetail::getActualDate, bo.getActualDate()); lqw.eq(bo.getPlanEndDate() != null, MesPlanDetail::getPlanEndDate, bo.getPlanEndDate());
return lqw; return lqw;
} }

View File

@ -0,0 +1,31 @@
<?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.ruoyi.mts.mapper.MesPlanBomMapper">
<resultMap type="com.ruoyi.mts.domain.MesPlanBom" id="MesPlanBomResult">
<result property="id" column="id"/>
<result property="parentId" column="parent_id"/>
<result property="detailId" column="detail_id"/>
<result property="deep" column="deep"/>
<result property="name" column="name"/>
<result property="standardNo" column="standard_no"/>
<result property="material" column="material"/>
<result property="num" column="num"/>
<result property="unit" column="unit"/>
<result property="process" column="process"/>
<result property="remark" column="remark"/>
<result property="dueDate" column="due_date"/>
<result property="actualDate" column="actual_date"/>
<result property="supplier" column="supplier"/>
<result property="ossId" column="oss_id"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="delFlag" column="del_flag"/>
</resultMap>
</mapper>

View File

@ -9,8 +9,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="parentId" column="parent_id"/> <result property="parentId" column="parent_id"/>
<result property="mainId" column="main_id"/> <result property="mainId" column="main_id"/>
<result property="name" column="name"/> <result property="name" column="name"/>
<result property="planDate" column="plan_date"/> <result property="planStartDate" column="plan_start_date"/>
<result property="actualDate" column="actual_date"/> <result property="planEndDate" column="plan_end_date"/>
<result property="actualStartDate" column="actual_start_date"/>
<result property="actualEndDate" column="actual_end_date"/>
<result property="ganttColor" column="gantt_color"/>
<result property="createBy" column="create_by"/> <result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/> <result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/> <result property="updateBy" column="update_by"/>

View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询物料清单列表
export function listPlanBom(query) {
return request({
url: '/mts/planBom/list',
method: 'get',
params: query
})
}
// 查询物料清单详细
export function getPlanBom(id) {
return request({
url: '/mts/planBom/' + id,
method: 'get'
})
}
// 新增物料清单
export function addPlanBom(data) {
return request({
url: '/mts/planBom',
method: 'post',
data: data
})
}
// 修改物料清单
export function updatePlanBom(data) {
return request({
url: '/mts/planBom',
method: 'put',
data: data
})
}
// 删除物料清单
export function delPlanBom(id) {
return request({
url: '/mts/planBom/' + id,
method: 'delete'
})
}

View File

@ -1,6 +1,6 @@
import { createWebHistory, createRouter } from 'vue-router' import { createWebHistory, createRouter } from "vue-router";
/* Layout */ /* Layout */
import Layout from '@/layout' import Layout from "@/layout";
/** /**
* Note: 路由配置项 * Note: 路由配置项
@ -27,64 +27,64 @@ import Layout from '@/layout'
// 公共路由 // 公共路由
export const constantRoutes = [ export const constantRoutes = [
{ {
path: '/redirect', path: "/redirect",
component: Layout, component: Layout,
hidden: true, hidden: true,
children: [ children: [
{ {
path: '/redirect/:path(.*)', path: "/redirect/:path(.*)",
component: () => import('@/views/redirect/index.vue') component: () => import("@/views/redirect/index.vue"),
} },
] ],
}, },
{ {
path: '/login', path: "/login",
component: () => import('@/views/login'), component: () => import("@/views/login"),
hidden: true hidden: true,
}, },
{ {
path: '/register', path: "/register",
component: () => import('@/views/register'), component: () => import("@/views/register"),
hidden: true hidden: true,
}, },
{ {
path: "/:pathMatch(.*)*", path: "/:pathMatch(.*)*",
component: () => import('@/views/error/404'), component: () => import("@/views/error/404"),
hidden: true hidden: true,
}, },
{ {
path: '/401', path: "/401",
component: () => import('@/views/error/401'), component: () => import("@/views/error/401"),
hidden: true hidden: true,
}, },
{ {
path: '', path: "",
component: Layout, component: Layout,
redirect: '/index', redirect: "/index",
children: [ children: [
{ {
path: '/index', path: "/index",
component: () => import('@/views/index'), component: () => import("@/views/index"),
name: 'Index', name: "Index",
meta: { title: '首页', icon: 'dashboard', affix: true } meta: { title: "首页", icon: "dashboard", affix: true },
} },
] ],
}, },
{ {
path: '/user', path: "/user",
component: Layout, component: Layout,
hidden: true, hidden: true,
redirect: 'noredirect', redirect: "noredirect",
children: [ children: [
{ {
path: 'profile', path: "profile",
component: () => import('@/views/system/user/profile/index'), component: () => import("@/views/system/user/profile/index"),
name: 'Profile', name: "Profile",
meta: { title: '个人中心', icon: 'user' } meta: { title: "个人中心", icon: "user" },
} },
] ],
} },
] ];
// 动态路由,基于用户权限动态去加载 // 动态路由,基于用户权限动态去加载
export const dynamicRoutes = [ export const dynamicRoutes = [
@ -139,8 +139,22 @@ export const dynamicRoutes = [
{ {
path: "index/:mainId(\\d+)", path: "index/:mainId(\\d+)",
component: () => import("@/views/mts/planDetail"), component: () => import("@/views/mts/planDetail"),
name: "detail", name: "plan-detail",
meta: { title: "计划任务", activeMenu: "/mts/planMain" }, meta: { title: "计划任务", activeMenu: "/mts/planDetail" },
},
],
},
{
path: "/mts/detail-bom",
component: Layout,
hidden: true,
permissions: ["mts:planMain:list"],
children: [
{
path: "index/:detailId(\\d+)",
component: () => import("@/views/mts/planBom"),
name: "detail-bom",
meta: { title: "物料清单", activeMenu: "/mts/planBom" },
}, },
], ],
}, },
@ -179,9 +193,9 @@ const router = createRouter({
routes: constantRoutes, routes: constantRoutes,
scrollBehavior(to, from, savedPosition) { scrollBehavior(to, from, savedPosition) {
if (savedPosition) { if (savedPosition) {
return savedPosition return savedPosition;
} else { } else {
return { top: 0 } return { top: 0 };
} }
}, },
}); });

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="app-container home"> <div class="app-container">
</div> </div>
</template> </template>

View File

@ -0,0 +1,356 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="物资名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入物资名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="图号及标准号" prop="standardNo">
<el-input v-model="queryParams.standardNo" placeholder="请输入图号及标准号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="材质" prop="material">
<el-input v-model="queryParams.material" placeholder="请输入材质" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="应到日期" prop="dueDate">
<el-date-picker clearable v-model="queryParams.dueDate" type="date" value-format="YYYY-MM-DD"
placeholder="选择应到日期">
</el-date-picker>
</el-form-item>
<el-form-item label="实到日期" prop="actualDate">
<el-date-picker clearable v-model="queryParams.actualDate" type="date" value-format="YYYY-MM-DD"
placeholder="选择实到日期">
</el-date-picker>
</el-form-item>
<el-form-item label="供应商" prop="supplier">
<el-input v-model="queryParams.supplier" placeholder="请输入供应商" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['mts:planBom:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="Sort" @click="toggleExpandAll">展开/折叠</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-if="refreshTable" v-loading="loading" :data="planBomList" row-key="id" :default-expand-all="isExpandAll"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }">
<el-table-column label="物资名称" align="center" prop="name" />
<el-table-column label="图号及标准号" align="center" prop="standardNo" />
<el-table-column label="材质" align="center" prop="material" />
<el-table-column label="数量" align="center" prop="num" />
<el-table-column label="单位" align="center" prop="unit" />
<el-table-column label="工序" align="center" prop="process" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="应到日期" align="center" prop="dueDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.dueDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="实到日期" align="center" prop="actualDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.actualDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="供应商" align="center" prop="supplier" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['mts:planBom:edit']">修改</el-button>
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)"
v-hasPermi="['mts:planBom:add']">新增</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['mts:planBom:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改物料清单对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="planBomRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="父级" prop="parentId">
<el-tree-select v-model="form.parentId" :data="planBomOptions"
:props="{ value: 'id', label: 'name', children: 'children' }" value-key="id" placeholder="请选择父id"
check-strictly />
</el-form-item>
<el-form-item label="物资名称" prop="name">
<el-input v-model="form.name" placeholder="请输入物资名称" />
</el-form-item>
<el-form-item label="图号及标准号" prop="standardNo">
<el-input v-model="form.standardNo" placeholder="请输入图号及标准号" />
</el-form-item>
<el-form-item label="材质" prop="material">
<el-input v-model="form.material" placeholder="请输入材质" />
</el-form-item>
<el-form-item label="数量" prop="num">
<el-input v-model="form.num" placeholder="请输入数量" />
</el-form-item>
<el-form-item label="单位" prop="unit">
<el-input v-model="form.unit" placeholder="请输入单位" />
</el-form-item>
<el-form-item label="工序" prop="process">
<el-input v-model="form.process" placeholder="请输入工序" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
<el-form-item label="应到日期" prop="dueDate">
<el-date-picker clearable v-model="form.dueDate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss"
placeholder="选择应到日期">
</el-date-picker>
</el-form-item>
<el-form-item label="实到日期" prop="actualDate">
<el-date-picker clearable v-model="form.actualDate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss"
placeholder="选择实到日期">
</el-date-picker>
</el-form-item>
<el-form-item label="供应商" prop="supplier">
<el-input v-model="form.supplier" placeholder="请输入供应商" />
</el-form-item>
<el-form-item label="oss对应id" prop="ossId">
<file-upload v-model="form.ossId" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="PlanBom">
import { useRoute } from 'vue-router'
import { listPlanBom, getPlanBom, delPlanBom, addPlanBom, updatePlanBom } from "@/api/mts/planBom";
const { proxy } = getCurrentInstance();
const route = useRoute();
const detailId = route.params.detailId;
const planBomList = ref([]);
const planBomOptions = ref([]);
const open = ref(false);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const title = ref("");
const isExpandAll = ref(true);
const refreshTable = ref(true);
const data = reactive({
form: {},
queryParams: {
parentId: undefined,
detailId: detailId,
deep: undefined,
name: undefined,
standardNo: undefined,
material: undefined,
num: undefined,
unit: undefined,
process: undefined,
dueDate: undefined,
actualDate: undefined,
supplier: undefined,
ossId: undefined,
},
rules: {
id: [
{ required: true, message: "主键不能为空", trigger: "blur" }
],
detailId: [
{ required: true, message: "详情任务id不能为空", trigger: "blur" }
],
name: [
{ required: true, message: "物资名称不能为空", trigger: "blur" }
],
standardNo: [
{ required: true, message: "图号及标准号不能为空", trigger: "blur" }
],
material: [
{ required: true, message: "材质不能为空", trigger: "blur" }
],
num: [
{ required: true, message: "数量不能为空", trigger: "blur" }
],
unit: [
{ required: true, message: "单位不能为空", trigger: "blur" }
],
process: [
{ required: true, message: "工序不能为空", trigger: "blur" }
],
remark: [
{ required: true, message: "备注不能为空", trigger: "blur" }
],
dueDate: [
{ required: true, message: "应到日期不能为空", trigger: "blur" }
],
actualDate: [
{ required: true, message: "实到日期不能为空", trigger: "blur" }
],
supplier: [
{ required: true, message: "供应商不能为空", trigger: "blur" }
],
ossId: [
{ required: true, message: "oss对应id不能为空", trigger: "blur" }
],
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询物料清单列表 */
function getList() {
loading.value = true;
listPlanBom(queryParams.value).then(response => {
planBomList.value = proxy.handleTree(response.data, "id", "parentId");
loading.value = false;
});
}
/** 查询物料清单下拉树结构 */
function getTreeselect() {
listPlanBom().then(response => {
planBomOptions.value = [];
const data = { id: 0, name: '顶级节点', children: [] };
data.children = proxy.handleTree(response.data, "id", "parentId");
planBomOptions.value.push(data);
});
}
//
function cancel() {
open.value = false;
reset();
}
//
function reset() {
form.value = {
id: null,
parentId: null,
detailId: null,
deep: null,
name: null,
standardNo: null,
material: null,
num: null,
unit: null,
process: null,
remark: null,
dueDate: null,
actualDate: null,
supplier: null,
ossId: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
delFlag: null
};
proxy.resetForm("planBomRef");
}
/** 搜索按钮操作 */
function handleQuery() {
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd(row) {
reset();
getTreeselect();
if (row != null && row.id) {
form.value.parentId = row.id;
} else {
form.value.parentId = 0;
}
form.value.detailId = detailId
open.value = true;
title.value = "添加物料清单";
}
/** 展开/折叠操作 */
function toggleExpandAll() {
refreshTable.value = false;
isExpandAll.value = !isExpandAll.value;
nextTick(() => {
refreshTable.value = true;
});
}
/** 修改按钮操作 */
async function handleUpdate(row) {
loading.value = true;
reset();
await getTreeselect();
if (row != null) {
form.value.parentId = row.parentId;
}
form.value.detailId = detailId
getPlanBom(row.id).then(response => {
loading.value = false;
form.value = response.data;
open.value = true;
title.value = "修改物料清单";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["planBomRef"].validate(valid => {
if (valid) {
buttonLoading.value = true;
if (form.value.id != null) {
updatePlanBom(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
} else {
addPlanBom(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
proxy.$modal.confirm('是否确认删除物料清单编号为"' + row.id + '"的数据项?').then(function () {
loading.value = true;
return delPlanBom(row.id);
}).then(() => {
loading.value = false;
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
loading.value = false;
});
}
getList();
</script>

View File

@ -1,173 +1,350 @@
<template> <template>
<div class="container"> <div class="app-container">
<div class="right-container"> <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<div class="gantt-selected-info"> <el-form-item label="名称" prop="name">
<div v-if="selectedTask"> <el-input v-model="queryParams.name" placeholder="请输入名称" clearable @keyup.enter="handleQuery" />
<h2>{{ selectedTask.text }}</h2> </el-form-item>
<span><b>编号: </b>{{ selectedTask.id }}</span><br /> <el-form-item label="计划时间" prop="planDate">
<span><b>进度: </b> {{ progressPercentage }}</span><br /> <el-date-picker clearable v-model="queryParams.planDate" type="date" value-format="YYYY-MM-DD"
<span><b>开始时间: </b>{{ formattedStartDate }}</span><br /> placeholder="选择计划时间">
<span><b>结束时间: </b>{{ formattedEndDate }}</span><br /> </el-date-picker>
</el-form-item>
<el-form-item label="实际时间" prop="actualDate">
<el-date-picker clearable v-model="queryParams.actualDate" type="date" value-format="YYYY-MM-DD"
placeholder="选择实际时间">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['mts:planDetail:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="Sort" @click="toggleExpandAll">展开/折叠</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-if="refreshTable" v-loading="loading" :data="planDetailList" row-key="id"
:default-expand-all="isExpandAll" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
:cell-style="handleChangeCellStyle">
<el-table-column label="名称" align="left" prop="name" width="180">
<template #default="scope">
<router-link :to="'/mts/detail-bom/index/' + scope.row.id" class="link-type">
<span>{{ scope.row.name }}</span>
</router-link>
</template>
</el-table-column>
<!-- <el-table-column label="计划时间" align="center" prop="planDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.planDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="实际时间" align="center" prop="actualDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.actualDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column> -->
<el-table-column v-for="item in dateColumns" :label="item.label" align="left" :prop="item.prop" width="100">
</el-table-column>
<el-table-column fixed="right" label="操作" align="center" class-name="small-padding fixed-width" width="210">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['mts:planDetail:edit']">修改</el-button>
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)"
v-hasPermi="['mts:planDetail:add']">新增</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['mts:planDetail:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改生产计划明细对话框 -->
<el-dialog :title="title" v-model="open" width="550px" append-to-body>
<el-form ref="planDetailRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="上级" prop="parentId">
<el-tree-select style="width: 100%;" v-model="form.parentId" :data="planDetailOptions"
:props="{ value: 'id', label: 'name', children: 'children' }" value-key="id" placeholder="请选择父id"
check-strictly />
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" placeholder="请输入名称" />
</el-form-item>
<el-form-item label="计划开始时间" prop="planStartDate">
<el-date-picker style="width: 100%;" clearable v-model="form.planStartDate" type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择时间">
</el-date-picker>
</el-form-item>
<el-form-item label="计划结束时间" prop="planEndDate">
<el-date-picker style="width: 100%;" clearable v-model="form.planEndDate" type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择时间">
</el-date-picker>
</el-form-item>
<el-form-item label="实际开始时间" prop="actualStartDate">
<el-date-picker style="width: 100%;" clearable v-model="form.actualStartDate" type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择时间">
</el-date-picker>
</el-form-item>
<el-form-item label="实际开始时间" prop="actualEndDate">
<el-date-picker style="width: 100%;" clearable v-model="form.actualEndDate" type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择时间">
</el-date-picker>
</el-form-item>
<el-form-item label="甘特图颜色" prop="ganttColor">
<el-color-picker v-model="form.ganttColor" size="large" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div> </div>
<div v-else class="select-task-prompt"> </template>
<h2>点击任务显示明细</h2> </el-dialog>
</div>
</div>
<ul class="gantt-messages">
<li class="gantt-message" v-for="(message, index) in messages" v-bind:key="index">
{{ message }}
</li>
</ul>
</div>
<GanttComponent ref="ganttContainer" class="left-container" :tasks="tasks" @task-updated="logTaskUpdate"
@link-updated="logLinkUpdate" @task-selected="selectTask"></GanttComponent>
</div> </div>
</template> </template>
<script> <script setup name="PlanDetail">
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import GanttComponent from "./components/GanttComponent.vue"; import { listPlanDetail, getPlanDetail, delPlanDetail, addPlanDetail, updatePlanDetail } from "@/api/mts/planDetail";
import { queryGanttList, listPlanDetail, getPlanDetail, delPlanDetail, addPlanDetail, updatePlanDetail } from "@/api/mts/planDetail";
const { proxy } = getCurrentInstance();
const route = useRoute();
const planDetailList = ref([]);
const planDetailOptions = ref([]);
const open = ref(false);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const title = ref("");
const isExpandAll = ref(true);
const refreshTable = ref(true);
const data = reactive({
form: {
export default {
name: "app",
components: { GanttComponent },
data() {
return {
tasks: {
data: [],
links: [],
},
selectedTask: null,
messages: [],
};
}, },
mounted() { queryParams: {
this.queryGanttList(); parentId: undefined,
mainId: route.params.mainId,
name: undefined,
planDate: undefined,
actualDate: undefined,
}, },
computed: { rules: {
progressPercentage() { id: [
let taskProgress = this.selectedTask.progress; { required: true, message: "主键不能为空", trigger: "blur" }
if (!taskProgress) { ],
return "0"; parentId: [
{ required: true, message: "父id不能为空", trigger: "blur" }
],
mainId: [
{ required: true, message: "主表id不能为空", trigger: "blur" }
],
name: [
{ required: true, message: "名称不能为空", trigger: "blur" }
],
planDate: [
{ required: true, message: "计划时间不能为空", trigger: "blur" }
],
actualDate: [
{ required: true, message: "实际时间不能为空", trigger: "blur" }
],
}
});
const { queryParams, form, rules } = toRefs(data);
const dateColumns = ref([])
onMounted(() => {
//
const startDate = dayjs('2024-02-01');
const endDate = dayjs('2024-02-25');
//
const allDates = [];
for (const date of datesBetween(startDate, endDate)) {
allDates.push(date.format('YYYY-MM-DD'));
dateColumns.value.push({
label: date.format('YYYY-MM-DD'),
prop: date.format('YYYY-MM-DD')
})
}
})
//
function* datesBetween(start, end) {
let currentDate = start;
while (currentDate.isBefore(end)) {
yield currentDate;
currentDate = currentDate.add(1, 'day');
}
}
/**
* 改变表格单元格颜色
*/
function handleChangeCellStyle({ row, column, rowIndex, columnIndex }) {
let cellStyle = {}
if (column.label == dayjs(row.planStartDate).format('YYYY-MM-DD')) {
cellStyle.backgroundColor = '#FFC000'
if (rowIndex % 2 == 0) {
cellStyle.backgroundColor = '#00B050'
}
} else {
cellStyle.backgroundColor = 'white'
}
return cellStyle
}
/** 查询生产计划明细列表 */
function getList() {
loading.value = true;
listPlanDetail(queryParams.value).then(response => {
planDetailList.value = proxy.handleTree(response.data, "id", "parentId");
loading.value = false;
});
}
/** 查询生产计划明细下拉树结构 */
function getTreeselect() {
listPlanDetail().then(response => {
planDetailOptions.value = [];
const data = { id: 0, name: '顶级节点', children: [] };
data.children = proxy.handleTree(response.data, "id", "parentId");
planDetailOptions.value.push(data);
});
}
//
function cancel() {
open.value = false;
reset();
}
//
function reset() {
form.value = {
id: null,
parentId: null,
mainId: null,
name: null,
planDate: null,
actualDate: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
delFlag: null
};
proxy.resetForm("planDetailRef");
}
/** 搜索按钮操作 */
function handleQuery() {
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd(row) {
reset();
getTreeselect();
if (row != null && row.id) {
form.value.parentId = row.id;
} else {
form.value.parentId = 0;
}
form.value.mainId = route.params.mainId;
open.value = true;
title.value = "添加生产计划明细";
}
/** 展开/折叠操作 */
function toggleExpandAll() {
refreshTable.value = false;
isExpandAll.value = !isExpandAll.value;
nextTick(() => {
refreshTable.value = true;
});
}
/** 修改按钮操作 */
async function handleUpdate(row) {
loading.value = true;
reset();
await getTreeselect();
if (row != null) {
form.value.parentId = row.parentId;
}
form.value.mainId = route.params.mainId;
getPlanDetail(row.id).then(response => {
loading.value = false;
form.value = response.data;
open.value = true;
title.value = "修改生产计划明细";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["planDetailRef"].validate(valid => {
if (valid) {
buttonLoading.value = true;
if (form.value.id != null) {
updatePlanDetail(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
} else {
addPlanDetail(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
} }
return `${Math.round(+taskProgress * 100)} %`; }
}, });
formattedStartDate() { }
let taskStart = this.selectedTask.start_date;
return `${taskStart.getFullYear()} / ${taskStart.getMonth() + 1} / ${taskStart.getDate()}`;
},
formattedEndDate() {
let taskEnd = this.selectedTask.end_date;
return `${taskEnd.getFullYear()} / ${taskEnd.getMonth() + 1} / ${taskEnd.getDate()}`;
},
},
methods: {
async queryGanttList() {
const route = this.$route;
const res = await queryGanttList({ mainId: route.params.mainId })
res.data.forEach(item => { /** 删除按钮操作 */
item.start_date = dayjs(item.start_date).toDate(); function handleDelete(row) {
}); proxy.$modal.confirm('是否确认删除生产计划明细编号为"' + row.id + '"的数据项?').then(function () {
this.tasks.data = res.data; loading.value = true;
return delPlanDetail(row.id);
}).then(() => {
loading.value = false;
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
loading.value = false;
});
}
this.$refs.ganttContainer.$init(); getList();
},
selectTask(task) {
this.selectedTask = task;
},
addMessage(message) {
console.log(message)
message = message.replace('Task update', '操作任务日志')
message = message.replace('Task create', '新建任务日志')
this.messages.unshift(message);
if (this.messages.length > 40) {
this.messages.pop();
}
},
logTaskUpdate(id, mode, task) {
console.log(id, mode, task)
let text = task && task.text ? ` (${task.text})` : "";
let message = `Task ${mode}: ${id} ${text}`;
this.addMessage(message);
},
logLinkUpdate(id, mode, link) {
let message = `Link ${mode}: ${id}`;
if (link) {
message += ` ( source: ${link.source}, target: ${link.target} )`;
}
this.addMessage(message);
},
},
};
</script> </script>
<style> <style scoped lang="scss"></style>
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
.container {
height: 100vh;
width: 100%;
}
.left-container {
overflow: hidden;
position: relative;
height: 100%;
}
.right-container {
border-right: 1px solid #cecece;
float: right;
height: 100%;
width: 340px;
box-shadow: 0 0 5px 2px #aaa;
position: relative;
z-index: 2;
}
.gantt-messages {
list-style-type: none;
height: 50%;
margin: 0;
overflow-x: hidden;
overflow-y: auto;
padding-left: 5px;
}
.gantt-messages>.gantt-message {
background-color: #f4f4f4;
box-shadow: inset 5px 0 #d69000;
font-family: Geneva, Arial, Helvetica, sans-serif;
font-size: 14px;
margin: 5px 0;
padding: 8px 0 8px 10px;
}
.gantt-selected-info {
border-bottom: 1px solid #cecece;
box-sizing: border-box;
font-family: Geneva, Arial, Helvetica, sans-serif;
height: 50%;
line-height: 28px;
padding: 10px;
}
.gantt-selected-info h2 {
border-bottom: 1px solid #cecece;
}
.select-task-prompt h2 {
color: #d9d9d9;
}
</style>

View File

@ -1,286 +0,0 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="计划时间" prop="planDate">
<el-date-picker clearable v-model="queryParams.planDate" type="date" value-format="YYYY-MM-DD"
placeholder="选择计划时间">
</el-date-picker>
</el-form-item>
<el-form-item label="实际时间" prop="actualDate">
<el-date-picker clearable v-model="queryParams.actualDate" type="date" value-format="YYYY-MM-DD"
placeholder="选择实际时间">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['mts:planDetail:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="Sort" @click="toggleExpandAll">展开/折叠</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-if="refreshTable" v-loading="loading" :data="planDetailList" row-key="id"
:default-expand-all="isExpandAll" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }">
<el-table-column label="名称" align="left" prop="name" />
<el-table-column label="计划时间" align="center" prop="planDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.planDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="实际时间" align="center" prop="actualDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.actualDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['mts:planDetail:edit']">修改</el-button>
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)"
v-hasPermi="['mts:planDetail:add']">新增</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['mts:planDetail:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改生产计划明细对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="planDetailRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="父id" prop="parentId">
<el-tree-select v-model="form.parentId" :data="planDetailOptions"
:props="{ value: 'id', label: 'name', children: 'children' }" value-key="id" placeholder="请选择父id"
check-strictly />
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" placeholder="请输入名称" />
</el-form-item>
<el-form-item label="计划时间" prop="planDate">
<el-date-picker clearable v-model="form.planDate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss"
placeholder="选择计划时间">
</el-date-picker>
</el-form-item>
<el-form-item label="实际时间" prop="actualDate">
<el-date-picker clearable v-model="form.actualDate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss"
placeholder="选择实际时间">
</el-date-picker>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="PlanDetail">
import {ref, onMounted} from 'vue'
import { useRoute } from 'vue-router'
import { listPlanDetail, getPlanDetail, delPlanDetail, addPlanDetail, updatePlanDetail } from "@/api/mts/planDetail";
const { proxy } = getCurrentInstance();
const route = useRoute();
const planDetailList = ref([]);
const planDetailOptions = ref([]);
const open = ref(false);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const title = ref("");
const isExpandAll = ref(true);
const refreshTable = ref(true);
const data = reactive({
form: {
},
queryParams: {
parentId: undefined,
mainId: route.params.mainId,
name: undefined,
planDate: undefined,
actualDate: undefined,
},
rules: {
id: [
{ required: true, message: "主键不能为空", trigger: "blur" }
],
parentId: [
{ required: true, message: "父id不能为空", trigger: "blur" }
],
mainId: [
{ required: true, message: "主表id不能为空", trigger: "blur" }
],
name: [
{ required: true, message: "名称不能为空", trigger: "blur" }
],
planDate: [
{ required: true, message: "计划时间不能为空", trigger: "blur" }
],
actualDate: [
{ required: true, message: "实际时间不能为空", trigger: "blur" }
],
}
});
const { queryParams, form, rules } = toRefs(data);
const dateColumns =[]
onMounted(() => {
// dateColumns.values.push()
})
/** 查询生产计划明细列表 */
function getList() {
loading.value = true;
listPlanDetail(queryParams.value).then(response => {
planDetailList.value = proxy.handleTree(response.data, "id", "parentId");
loading.value = false;
});
}
/** 查询生产计划明细下拉树结构 */
function getTreeselect() {
listPlanDetail().then(response => {
planDetailOptions.value = [];
const data = { id: 0, name: '顶级节点', children: [] };
data.children = proxy.handleTree(response.data, "id", "parentId");
planDetailOptions.value.push(data);
});
}
//
function cancel() {
open.value = false;
reset();
}
//
function reset() {
form.value = {
id: null,
parentId: null,
mainId: null,
name: null,
planDate: null,
actualDate: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
delFlag: null
};
proxy.resetForm("planDetailRef");
}
/** 搜索按钮操作 */
function handleQuery() {
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd(row) {
reset();
getTreeselect();
if (row != null && row.id) {
form.value.parentId = row.id;
} else {
form.value.parentId = 0;
}
form.value.mainId = route.params.mainId;
open.value = true;
title.value = "添加生产计划明细";
}
/** 展开/折叠操作 */
function toggleExpandAll() {
refreshTable.value = false;
isExpandAll.value = !isExpandAll.value;
nextTick(() => {
refreshTable.value = true;
});
}
/** 修改按钮操作 */
async function handleUpdate(row) {
loading.value = true;
reset();
await getTreeselect();
if (row != null) {
form.value.parentId = row.parentId;
}
form.value.mainId = route.params.mainId;
getPlanDetail(row.id).then(response => {
loading.value = false;
form.value = response.data;
open.value = true;
title.value = "修改生产计划明细";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["planDetailRef"].validate(valid => {
if (valid) {
buttonLoading.value = true;
if (form.value.id != null) {
updatePlanDetail(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
} else {
addPlanDetail(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
proxy.$modal.confirm('是否确认删除生产计划明细编号为"' + row.id + '"的数据项?').then(function () {
loading.value = true;
return delPlanDetail(row.id);
}).then(() => {
loading.value = false;
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
loading.value = false;
});
}
getList();
</script>

View File

@ -0,0 +1,173 @@
<template>
<div class="container">
<div class="right-container">
<div class="gantt-selected-info">
<div v-if="selectedTask">
<h2>{{ selectedTask.text }}</h2>
<span><b>编号: </b>{{ selectedTask.id }}</span><br />
<span><b>进度: </b> {{ progressPercentage }}</span><br />
<span><b>开始时间: </b>{{ formattedStartDate }}</span><br />
<span><b>结束时间: </b>{{ formattedEndDate }}</span><br />
</div>
<div v-else class="select-task-prompt">
<h2>点击任务显示明细</h2>
</div>
</div>
<ul class="gantt-messages">
<li class="gantt-message" v-for="(message, index) in messages" v-bind:key="index">
{{ message }}
</li>
</ul>
</div>
<GanttComponent ref="ganttContainer" class="left-container" :tasks="tasks" @task-updated="logTaskUpdate"
@link-updated="logLinkUpdate" @task-selected="selectTask"></GanttComponent>
</div>
</template>
<script>
import dayjs from 'dayjs'
import GanttComponent from "./components/GanttComponent.vue";
import { queryGanttList, listPlanDetail, getPlanDetail, delPlanDetail, addPlanDetail, updatePlanDetail } from "@/api/mts/planDetail";
export default {
name: "app",
components: { GanttComponent },
data() {
return {
tasks: {
data: [],
links: [],
},
selectedTask: null,
messages: [],
};
},
mounted() {
this.queryGanttList();
},
computed: {
progressPercentage() {
let taskProgress = this.selectedTask.progress;
if (!taskProgress) {
return "0";
}
return `${Math.round(+taskProgress * 100)} %`;
},
formattedStartDate() {
let taskStart = this.selectedTask.start_date;
return `${taskStart.getFullYear()} / ${taskStart.getMonth() + 1} / ${taskStart.getDate()}`;
},
formattedEndDate() {
let taskEnd = this.selectedTask.end_date;
return `${taskEnd.getFullYear()} / ${taskEnd.getMonth() + 1} / ${taskEnd.getDate()}`;
},
},
methods: {
async queryGanttList() {
const route = this.$route;
const res = await queryGanttList({ mainId: route.params.mainId })
res.data.forEach(item => {
item.start_date = dayjs(item.start_date).toDate();
});
this.tasks.data = res.data;
this.$refs.ganttContainer.$init();
},
selectTask(task) {
this.selectedTask = task;
},
addMessage(message) {
console.log(message)
message = message.replace('Task update', '操作任务日志')
message = message.replace('Task create', '新建任务日志')
this.messages.unshift(message);
if (this.messages.length > 40) {
this.messages.pop();
}
},
logTaskUpdate(id, mode, task) {
console.log(id, mode, task)
let text = task && task.text ? ` (${task.text})` : "";
let message = `Task ${mode}: ${id} ${text}`;
this.addMessage(message);
},
logLinkUpdate(id, mode, link) {
let message = `Link ${mode}: ${id}`;
if (link) {
message += ` ( source: ${link.source}, target: ${link.target} )`;
}
this.addMessage(message);
},
},
};
</script>
<style>
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
.container {
height: 100vh;
width: 100%;
}
.left-container {
overflow: hidden;
position: relative;
height: 100%;
}
.right-container {
border-right: 1px solid #cecece;
float: right;
height: 100%;
width: 340px;
box-shadow: 0 0 5px 2px #aaa;
position: relative;
z-index: 2;
}
.gantt-messages {
list-style-type: none;
height: 50%;
margin: 0;
overflow-x: hidden;
overflow-y: auto;
padding-left: 5px;
}
.gantt-messages>.gantt-message {
background-color: #f4f4f4;
box-shadow: inset 5px 0 #d69000;
font-family: Geneva, Arial, Helvetica, sans-serif;
font-size: 14px;
margin: 5px 0;
padding: 8px 0 8px 10px;
}
.gantt-selected-info {
border-bottom: 1px solid #cecece;
box-sizing: border-box;
font-family: Geneva, Arial, Helvetica, sans-serif;
height: 50%;
line-height: 28px;
padding: 10px;
}
.gantt-selected-info h2 {
border-bottom: 1px solid #cecece;
}
.select-task-prompt h2 {
color: #d9d9d9;
}
</style>

View File

@ -80,12 +80,12 @@
</el-form-item> </el-form-item>
<el-form-item label="开始时间" prop="startDate"> <el-form-item label="开始时间" prop="startDate">
<el-date-picker clearable v-model="form.startDate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" <el-date-picker clearable v-model="form.startDate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择开始时间"> style="width: 100%" placeholder="请选择开始时间">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="结束时间" prop="endDate"> <el-form-item label="结束时间" prop="endDate">
<el-date-picker clearable v-model="form.endDate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" <el-date-picker clearable v-model="form.endDate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择结束时间"> style="width: 100%" placeholder="请选择结束时间">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
@ -204,7 +204,7 @@ function handleSelectionChange(selection) {
function handleAdd() { function handleAdd() {
reset(); reset();
open.value = true; open.value = true;
title.value = "添加生产计划"; title.value = "添加生产计划";
} }
/** 修改按钮操作 */ /** 修改按钮操作 */
@ -216,7 +216,7 @@ function handleUpdate(row) {
loading.value = false; loading.value = false;
form.value = response.data; form.value = response.data;
open.value = true; open.value = true;
title.value = "修改生产计划"; title.value = "修改生产计划";
}); });
} }