合同编辑详情开发

This commit is contained in:
朱昊天
2026-06-02 21:27:44 +08:00
parent 9f4e1c39ad
commit 323da20f2a
19 changed files with 1301 additions and 30 deletions

View File

@@ -9,12 +9,14 @@ import com.gear.mes.production.domain.vo.GearProductionTaskListVo;
import com.gear.mes.production.domain.vo.GearProductionTaskWithDetailVo;
import com.gear.mes.production.service.IGearProductionTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PutMapping;
import java.util.List;
@@ -54,4 +56,58 @@ public class GearProductionTaskController extends BaseController {
}
return R.ok();
}
@PostMapping("/{taskId}/uncomplete")
public R<Void> uncomplete(@PathVariable("taskId") Long taskId) {
boolean ok = productionTaskService.uncompleteTask(taskId);
if (!ok) {
return R.fail("撤销完成失败");
}
return R.ok();
}
@PostMapping("/{taskId}/start")
public R<Void> start(@PathVariable("taskId") Long taskId) {
boolean ok = productionTaskService.startTask(taskId);
if (!ok) {
return R.fail("开始失败");
}
return R.ok();
}
@PostMapping("/{taskId}/pause")
public R<Void> pause(@PathVariable("taskId") Long taskId) {
boolean ok = productionTaskService.pauseTask(taskId);
if (!ok) {
return R.fail("暂停失败");
}
return R.ok();
}
@PostMapping("/{taskId}/resume")
public R<Void> resume(@PathVariable("taskId") Long taskId) {
boolean ok = productionTaskService.resumeTask(taskId);
if (!ok) {
return R.fail("继续失败");
}
return R.ok();
}
@PutMapping
public R<Void> edit(@RequestBody GearProductionTaskWithDetailVo bo) {
boolean ok = productionTaskService.updateTaskWithDetail(bo);
if (!ok) {
return R.fail("修改失败");
}
return R.ok();
}
@DeleteMapping("/{taskId}")
public R<Void> remove(@PathVariable("taskId") Long taskId) {
boolean ok = productionTaskService.deleteTask(taskId);
if (!ok) {
return R.fail("删除失败");
}
return R.ok();
}
}

View File

@@ -20,4 +20,9 @@ public interface GearProductionTaskMapper {
@Param("status") String status,
@Param("updateBy") String updateBy,
@Param("updateTime") Date updateTime);
int updateDelFlag(@Param("taskId") Long taskId,
@Param("delFlag") String delFlag,
@Param("updateBy") String updateBy,
@Param("updateTime") Date updateTime);
}

View File

@@ -14,4 +14,16 @@ public interface IGearProductionTaskService {
Long insertTaskWithDetail(GearProductionTaskWithDetailVo bo);
boolean completeTask(Long taskId);
boolean uncompleteTask(Long taskId);
boolean startTask(Long taskId);
boolean pauseTask(Long taskId);
boolean resumeTask(Long taskId);
boolean updateTaskWithDetail(GearProductionTaskWithDetailVo bo);
boolean deleteTask(Long taskId);
}

View File

@@ -7,7 +7,9 @@ import com.gear.mes.production.domain.GearProductionTaskProduct;
import com.gear.mes.production.domain.vo.GearProductionTaskListVo;
import com.gear.mes.production.domain.vo.GearProductionTaskMaterialVo;
import com.gear.mes.production.domain.vo.GearProductionTaskWithDetailVo;
import com.gear.mes.production.domain.vo.GearProductionTaskProductVo;
import com.gear.common.utils.DateUtils;
import com.gear.common.helper.LoginHelper;
import com.gear.mes.production.mapper.GearProductionTaskMapper;
import com.gear.mes.production.mapper.GearProductionTaskMaterialMapper;
import com.gear.mes.production.mapper.GearProductionTaskProductMapper;
@@ -72,8 +74,11 @@ public class GearProductionTaskServiceImpl implements IGearProductionTaskService
task.setDelFlag("0");
}
if (task.getStatus() == null || String.valueOf(task.getStatus()).trim().isEmpty()) {
task.setStatus("1");
task.setStatus("0");
}
String username = LoginHelper.getUsername();
task.setCreateBy(username);
task.setUpdateBy(username);
task.setCreateTime(DateUtils.getNowDate());
task.setUpdateTime(DateUtils.getNowDate());
taskMapper.insertTask(task);
@@ -131,7 +136,8 @@ public class GearProductionTaskServiceImpl implements IGearProductionTaskService
if ("2".equals(String.valueOf(task.getStatus()))) {
return true;
}
int updated = taskMapper.updateTaskStatus(taskId, "2", task.getUpdateBy(), DateUtils.getNowDate());
String username = LoginHelper.getUsername();
int updated = taskMapper.updateTaskStatus(taskId, "2", username, DateUtils.getNowDate());
if (updated <= 0) {
GearProductionTask after = taskMapper.selectTaskById(taskId);
return after != null && "2".equals(String.valueOf(after.getStatus()));
@@ -140,6 +146,159 @@ public class GearProductionTaskServiceImpl implements IGearProductionTaskService
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean uncompleteTask(Long taskId) {
if (taskId == null) {
return false;
}
GearProductionTask task = taskMapper.selectTaskById(taskId);
if (task == null) {
return false;
}
if (!"2".equals(String.valueOf(task.getStatus()))) {
return true;
}
String username = LoginHelper.getUsername();
int updated = taskMapper.updateTaskStatus(taskId, "1", username, DateUtils.getNowDate());
if (updated <= 0) {
GearProductionTask after = taskMapper.selectTaskById(taskId);
return after != null && !"2".equals(String.valueOf(after.getStatus()));
}
materialMapper.deleteByTaskId(taskId);
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean startTask(Long taskId) {
return setStatus(taskId, "1");
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean pauseTask(Long taskId) {
return setStatus(taskId, "3");
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean resumeTask(Long taskId) {
return setStatus(taskId, "1");
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateTaskWithDetail(GearProductionTaskWithDetailVo bo) {
if (bo == null || bo.getTask() == null || bo.getTask().getTaskId() == null) {
return false;
}
Long taskId = bo.getTask().getTaskId();
GearProductionTask existed = taskMapper.selectTaskById(taskId);
if (existed == null) {
return false;
}
GearProductionTask task = bo.getTask();
task.setStatus(existed.getStatus());
task.setDelFlag(existed.getDelFlag());
task.setUpdateBy(LoginHelper.getUsername());
task.setUpdateTime(DateUtils.getNowDate());
taskMapper.updateTask(task);
Map<Long, GearProductionTaskProductVo> existingProducts = new LinkedHashMap<>();
List<GearProductionTaskProductVo> existList = productMapper.selectByTaskId(taskId);
if (existList != null) {
existList.forEach(p -> {
if (p != null && p.getProductId() != null) {
existingProducts.put(p.getProductId(), p);
}
});
}
productMapper.deleteByTaskId(taskId);
List<GearProductionTaskProduct> rows = mergeProductsForSave(taskId, bo.getProducts(), existingProducts);
if (!rows.isEmpty()) {
productMapper.insertBatch(rows);
}
if ("2".equals(String.valueOf(existed.getStatus()))) {
regenerateReceiptMaterials(taskId);
}
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deleteTask(Long taskId) {
if (taskId == null) {
return false;
}
String username = LoginHelper.getUsername();
int updated = taskMapper.updateDelFlag(taskId, "1", username, DateUtils.getNowDate());
if (updated <= 0) {
return false;
}
return true;
}
private boolean setStatus(Long taskId, String targetStatus) {
if (taskId == null) {
return false;
}
GearProductionTask task = taskMapper.selectTaskById(taskId);
if (task == null) {
return false;
}
if (targetStatus.equals(String.valueOf(task.getStatus()))) {
return true;
}
if ("2".equals(String.valueOf(task.getStatus())) && !"2".equals(targetStatus)) {
return false;
}
String username = LoginHelper.getUsername();
int updated = taskMapper.updateTaskStatus(taskId, targetStatus, username, DateUtils.getNowDate());
if (updated <= 0) {
GearProductionTask after = taskMapper.selectTaskById(taskId);
return after != null && targetStatus.equals(String.valueOf(after.getStatus()));
}
return true;
}
private List<GearProductionTaskProduct> mergeProductsForSave(Long taskId,
List<GearProductionTaskProductVo> incoming,
Map<Long, GearProductionTaskProductVo> existed) {
Map<Long, GearProductionTaskProduct> map = new LinkedHashMap<>();
if (incoming != null) {
incoming.forEach(p -> {
if (p == null || p.getProductId() == null) return;
GearProductionTaskProduct hit = map.get(p.getProductId());
BigDecimal planQty = p.getPlanQty() == null ? BigDecimal.ZERO : p.getPlanQty();
if (hit == null) {
GearProductionTaskProduct row = new GearProductionTaskProduct();
row.setLineId(IdUtil.getSnowflakeNextId());
row.setTaskId(taskId);
row.setProductId(p.getProductId());
row.setPlanQty(planQty);
GearProductionTaskProductVo old = existed != null ? existed.get(p.getProductId()) : null;
row.setFinishedQty(old != null && old.getFinishedQty() != null ? old.getFinishedQty() : BigDecimal.ZERO);
row.setBadQty(old != null && old.getBadQty() != null ? old.getBadQty() : BigDecimal.ZERO);
String unit = (p.getUnit() != null && !p.getUnit().trim().isEmpty()) ? p.getUnit() : (old != null ? old.getUnit() : null);
row.setUnit(unit);
row.setRemark(p.getRemark());
map.put(p.getProductId(), row);
return;
}
hit.setPlanQty((hit.getPlanQty() == null ? BigDecimal.ZERO : hit.getPlanQty()).add(planQty));
if ((hit.getUnit() == null || hit.getUnit().trim().isEmpty()) && p.getUnit() != null && !p.getUnit().trim().isEmpty()) {
hit.setUnit(p.getUnit());
}
if ((hit.getRemark() == null || hit.getRemark().trim().isEmpty()) && p.getRemark() != null && !p.getRemark().trim().isEmpty()) {
hit.setRemark(p.getRemark());
}
});
}
return new ArrayList<>(map.values());
}
private void regenerateReceiptMaterials(Long taskId) {
materialMapper.deleteByTaskId(taskId);
List<GearProductionTaskMaterial> required = materialMapper.selectRequirementByTaskId(taskId);

View File

@@ -121,4 +121,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND status <![CDATA[<>]]> #{status}
</update>
<update id="updateDelFlag">
UPDATE gear_production_task
SET
del_flag = #{delFlag},
update_by = #{updateBy},
update_time = #{updateTime}
WHERE task_id = #{taskId}
AND del_flag = '0'
</update>
</mapper>

View File

@@ -0,0 +1,71 @@
package com.gear.oa.controller;
import com.gear.common.annotation.Log;
import com.gear.common.annotation.RepeatSubmit;
import com.gear.common.core.controller.BaseController;
import com.gear.common.core.domain.PageQuery;
import com.gear.common.core.domain.R;
import com.gear.common.core.page.TableDataInfo;
import com.gear.common.core.validate.AddGroup;
import com.gear.common.core.validate.EditGroup;
import com.gear.common.enums.BusinessType;
import com.gear.common.utils.poi.ExcelUtil;
import com.gear.oa.domain.bo.GearContractBo;
import com.gear.oa.domain.vo.GearContractVo;
import com.gear.oa.service.IGearContractService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/oa/contract")
public class GearContractController extends BaseController {
private final IGearContractService iGearContractService;
@GetMapping("/list")
public TableDataInfo<GearContractVo> list(GearContractBo bo, PageQuery pageQuery) {
return iGearContractService.queryPageList(bo, pageQuery);
}
@Log(title = "合同编辑详情", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(GearContractBo bo, HttpServletResponse response) {
List<GearContractVo> list = iGearContractService.queryList(bo);
ExcelUtil.exportExcel(list, "合同编辑详情", GearContractVo.class, response);
}
@GetMapping("/{contractId}")
public R<GearContractVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long contractId) {
return R.ok(iGearContractService.queryById(contractId));
}
@Log(title = "合同编辑详情", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody GearContractBo bo) {
return toAjax(iGearContractService.insertByBo(bo));
}
@Log(title = "合同编辑详情", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody GearContractBo bo) {
return toAjax(iGearContractService.updateByBo(bo));
}
@Log(title = "合同编辑详情", businessType = BusinessType.DELETE)
@DeleteMapping("/{contractIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] contractIds) {
return toAjax(iGearContractService.deleteWithValidByIds(Arrays.asList(contractIds), true));
}
}

View File

@@ -0,0 +1,45 @@
package com.gear.oa.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.gear.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("gear_contract")
public class GearContract extends BaseEntity {
private static final long serialVersionUID = 1L;
@TableId(value = "contract_id")
private Long contractId;
private String contractNo;
private String partyA;
private String partyB;
private String effectiveFlag;
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date signDate;
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date deliveryDate;
private String signPlace;
private String partyAAddress;
private String partyBAddress;
@TableLogic(value = "0", delval = "2")
private String delFlag;
}

View File

@@ -0,0 +1,54 @@
package com.gear.oa.domain.bo;
import com.gear.common.core.domain.BaseEntity;
import com.gear.common.core.validate.AddGroup;
import com.gear.common.core.validate.EditGroup;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class GearContractBo extends BaseEntity {
@NotNull(message = "合同ID不能为空", groups = {EditGroup.class})
private Long contractId;
@NotBlank(message = "合同号不能为空", groups = {AddGroup.class, EditGroup.class})
private String contractNo;
private String partyA;
private String partyB;
private String effectiveFlag;
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date signDate;
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date deliveryDate;
private String signPlace;
private String partyAAddress;
private String partyBAddress;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date signDateStart;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date signDateEnd;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date deliveryDateStart;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date deliveryDateEnd;
}

View File

@@ -0,0 +1,49 @@
package com.gear.oa.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.gear.common.core.domain.BaseEntity;
import lombok.Data;
import java.util.Date;
@Data
@ExcelIgnoreUnannotated
public class GearContractVo extends BaseEntity {
private static final long serialVersionUID = 1L;
@ExcelProperty(value = "合同ID")
private Long contractId;
@ExcelProperty(value = "合同号")
private String contractNo;
@ExcelProperty(value = "甲方/供方")
private String partyA;
@ExcelProperty(value = "乙方/需方")
private String partyB;
@ExcelProperty(value = "是否生效")
private String effectiveFlag;
@ExcelProperty(value = "签订日期")
private Date signDate;
@ExcelProperty(value = "交货日期")
private Date deliveryDate;
@ExcelProperty(value = "签订地点")
private String signPlace;
@ExcelProperty(value = "甲方地址")
private String partyAAddress;
@ExcelProperty(value = "乙方地址")
private String partyBAddress;
@ExcelProperty(value = "备注")
private String remark;
}

View File

@@ -0,0 +1,9 @@
package com.gear.oa.mapper;
import com.gear.common.core.mapper.BaseMapperPlus;
import com.gear.oa.domain.GearContract;
import com.gear.oa.domain.vo.GearContractVo;
public interface GearContractMapper extends BaseMapperPlus<GearContractMapper, GearContract, GearContractVo> {
}

View File

@@ -0,0 +1,25 @@
package com.gear.oa.service;
import com.gear.common.core.domain.PageQuery;
import com.gear.common.core.page.TableDataInfo;
import com.gear.oa.domain.bo.GearContractBo;
import com.gear.oa.domain.vo.GearContractVo;
import java.util.Collection;
import java.util.List;
public interface IGearContractService {
GearContractVo queryById(Long contractId);
TableDataInfo<GearContractVo> queryPageList(GearContractBo bo, PageQuery pageQuery);
List<GearContractVo> queryList(GearContractBo bo);
Boolean insertByBo(GearContractBo bo);
Boolean updateByBo(GearContractBo bo);
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -0,0 +1,108 @@
package com.gear.oa.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gear.common.core.domain.PageQuery;
import com.gear.common.core.page.TableDataInfo;
import com.gear.common.utils.StringUtils;
import com.gear.oa.domain.GearContract;
import com.gear.oa.domain.bo.GearContractBo;
import com.gear.oa.domain.vo.GearContractVo;
import com.gear.oa.mapper.GearContractMapper;
import com.gear.oa.service.IGearContractService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@RequiredArgsConstructor
@Service
public class GearContractServiceImpl implements IGearContractService {
private final GearContractMapper baseMapper;
@Override
public GearContractVo queryById(Long contractId) {
return baseMapper.selectVoById(contractId);
}
@Override
public TableDataInfo<GearContractVo> queryPageList(GearContractBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<GearContract> lqw = buildQueryWrapper(bo);
Page<GearContractVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
@Override
public List<GearContractVo> queryList(GearContractBo bo) {
LambdaQueryWrapper<GearContract> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<GearContract> buildQueryWrapper(GearContractBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<GearContract> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getContractId() != null, GearContract::getContractId, bo.getContractId());
lqw.like(StringUtils.isNotBlank(bo.getContractNo()), GearContract::getContractNo, bo.getContractNo());
lqw.like(StringUtils.isNotBlank(bo.getPartyA()), GearContract::getPartyA, bo.getPartyA());
lqw.like(StringUtils.isNotBlank(bo.getPartyB()), GearContract::getPartyB, bo.getPartyB());
lqw.eq(StringUtils.isNotBlank(bo.getEffectiveFlag()), GearContract::getEffectiveFlag, bo.getEffectiveFlag());
lqw.like(StringUtils.isNotBlank(bo.getSignPlace()), GearContract::getSignPlace, bo.getSignPlace());
lqw.ge(bo.getSignDateStart() != null, GearContract::getSignDate, bo.getSignDateStart());
lqw.le(bo.getSignDateEnd() != null, GearContract::getSignDate, bo.getSignDateEnd());
lqw.ge(bo.getDeliveryDateStart() != null, GearContract::getDeliveryDate, bo.getDeliveryDateStart());
lqw.le(bo.getDeliveryDateEnd() != null, GearContract::getDeliveryDate, bo.getDeliveryDateEnd());
lqw.orderByDesc(GearContract::getSignDate);
lqw.orderByDesc(GearContract::getCreateTime);
return lqw;
}
@Override
public Boolean insertByBo(GearContractBo bo) {
GearContract add = BeanUtil.toBean(bo, GearContract.class);
validEntityBeforeSave(add);
boolean ok = baseMapper.insert(add) > 0;
if (ok) {
bo.setContractId(add.getContractId());
}
return ok;
}
@Override
public Boolean updateByBo(GearContractBo bo) {
GearContract update = BeanUtil.toBean(bo, GearContract.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
private void validEntityBeforeSave(GearContract entity) {
boolean isInsert = entity.getContractId() == null;
if (entity.getContractId() == null) {
entity.setContractId(IdUtil.getSnowflakeNextId());
}
if (StringUtils.isBlank(entity.getContractNo())) {
entity.setContractNo("CON_" + IdUtil.getSnowflakeNextIdStr());
}
if (StringUtils.isBlank(entity.getEffectiveFlag())) {
entity.setEffectiveFlag("0");
}
if (isInsert) {
if (StringUtils.isBlank(entity.getDelFlag())) {
entity.setDelFlag("0");
}
}
}
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -29,3 +29,46 @@ export function completeProductionTask(taskId) {
method: 'post'
})
}
export function uncompleteProductionTask(taskId) {
return request({
url: '/mes/production/task/' + taskId + '/uncomplete',
method: 'post'
})
}
export function startProductionTask(taskId) {
return request({
url: '/mes/production/task/' + taskId + '/start',
method: 'post'
})
}
export function pauseProductionTask(taskId) {
return request({
url: '/mes/production/task/' + taskId + '/pause',
method: 'post'
})
}
export function resumeProductionTask(taskId) {
return request({
url: '/mes/production/task/' + taskId + '/resume',
method: 'post'
})
}
export function updateProductionTask(data) {
return request({
url: '/mes/production/task',
method: 'put',
data
})
}
export function deleteProductionTask(taskId) {
return request({
url: '/mes/production/task/' + taskId,
method: 'delete'
})
}

View File

@@ -0,0 +1,40 @@
import request from '@/utils/request'
export function listContract(query) {
return request({
url: '/oa/contract/list',
method: 'get',
params: query
})
}
export function getContract(contractId) {
return request({
url: '/oa/contract/' + contractId,
method: 'get'
})
}
export function addContract(data) {
return request({
url: '/oa/contract',
method: 'post',
data: data
})
}
export function updateContract(data) {
return request({
url: '/oa/contract',
method: 'put',
data: data
})
}
export function delContract(contractId) {
return request({
url: '/oa/contract/' + contractId,
method: 'delete'
})
}

View File

@@ -49,6 +49,7 @@
<el-form :inline="true" class="filter-form">
<el-form-item label="状态">
<el-select v-model="filters.status" placeholder="全部" clearable style="width: 140px;">
<el-option label="未开始" value="0" />
<el-option label="进行中" value="1" />
<el-option label="已完成" value="2" />
<el-option label="已暂停" value="3" />
@@ -101,7 +102,7 @@
<div class="task-item__meta">
<span v-if="t.planStartTime || t.planEndTime">计划 {{ formatTimeRange(t.planStartTime, t.planEndTime) }}</span>
<span v-if="t.createBy" style="margin-left: 10px;">创建 {{ t.createBy }}</span>
<span v-if="t.updateTime" style="margin-left: 10px;">更新 {{ formatTime(t.updateTime) }}</span>
<span v-if="t.updateTime" style="margin-left: 10px;">状态 {{ statusLabel(t.status) }} {{ formatTime(t.updateTime) }}</span>
</div>
<el-progress :percentage="taskProgressPercent(t)" :stroke-width="8" :show-text="false" />
</div>
@@ -120,15 +121,15 @@
<span class="meta-main">{{ selectedTask.taskName || selectedTask.taskCode || ('任务' + selectedTask.taskId) }}</span>
<el-tag size="small" :type="statusTagType(selectedTask.status)" effect="light" style="margin-left: 8px;">{{ statusLabel(selectedTask.status) }}</el-tag>
</div>
<el-button
v-if="String(selectedTask.status) === '1'"
size="small"
type="primary"
:loading="completeLoading"
@click="completeSelectedTask"
>
完成任务
</el-button>
<div class="task-actions">
<el-button v-if="String(selectedTask.status) === '0'" size="small" type="success" :loading="statusLoading" @click="startSelectedTask">开始</el-button>
<el-button v-if="String(selectedTask.status) === '1'" size="small" type="warning" :loading="statusLoading" @click="pauseSelectedTask">暂停</el-button>
<el-button v-if="String(selectedTask.status) === '3'" size="small" type="success" :loading="statusLoading" @click="resumeSelectedTask">继续</el-button>
<el-button v-if="String(selectedTask.status) !== '2'" size="small" type="primary" :loading="completeLoading" @click="completeSelectedTask">完成</el-button>
<el-button v-if="String(selectedTask.status) === '2'" size="small" type="warning" :loading="statusLoading" @click="uncompleteSelectedTask">撤销完成</el-button>
<el-button v-if="String(selectedTask.status) !== '2'" size="small" @click="openEdit">编辑</el-button>
<el-button size="small" type="danger" :loading="deleteLoading" @click="deleteSelectedTask">删除</el-button>
</div>
</div>
</div>
</template>
@@ -225,8 +226,8 @@
<el-col :span="8">
<el-form-item label="状态" prop="status">
<el-select v-model="addForm.status" placeholder="请选择">
<el-option label="未开始" value="0" />
<el-option label="进行中" value="1" />
<el-option label="已完成" value="2" />
<el-option label="已暂停" value="3" />
</el-select>
</el-form-item>
@@ -288,12 +289,83 @@
<el-button type="primary" :loading="addSaving" @click="submitAdd">保存</el-button>
</template>
</el-dialog>
<el-dialog v-model="editOpen" title="编辑生产任务" width="1100px" top="5vh" append-to-body>
<el-form ref="editFormRef" :model="editForm" :rules="addRules" label-width="100px">
<el-row :gutter="12">
<el-col :span="8">
<el-form-item label="任务编号" prop="taskCode">
<el-input v-model="editForm.taskCode" placeholder="可不填" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="任务名称" prop="taskName">
<el-input v-model="editForm.taskName" placeholder="请输入任务名称" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="计划开始" prop="planStartTime">
<el-date-picker v-model="editForm.planStartTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="计划结束" prop="planEndTime">
<el-date-picker v-model="editForm.planEndTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="editForm.remark" type="textarea" :rows="2" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-divider content-position="left">生产产品明细</el-divider>
<div style="margin-bottom: 8px;">
<el-button type="primary" @click="addEditProductLine">新增产品行</el-button>
</div>
<el-table :data="editProducts" border size="small" :header-cell-style="{ background: '#f5f7fa' }">
<el-table-column label="产品" min-width="220">
<template #default="scope">
<el-select v-model="scope.row.productId" filterable clearable placeholder="请选择" style="width: 100%;" @change="onProductPicked(scope.row)">
<el-option v-for="p in productOptions" :key="p.productId" :label="p.productName" :value="p.productId" />
</el-select>
</template>
</el-table-column>
<el-table-column label="计划数量" width="140" align="right">
<template #default="scope">
<el-input-number v-model="scope.row.planQty" :min="0" :precision="4" controls-position="right" style="width: 120px;" />
</template>
</el-table-column>
<el-table-column label="单位" width="140">
<template #default="scope">
<el-input v-model="scope.row.unit" placeholder="单位" />
</template>
</el-table-column>
<el-table-column label="备注" min-width="200">
<template #default="scope">
<el-input v-model="scope.row.remark" placeholder="备注" />
</template>
</el-table-column>
<el-table-column label="操作" width="90" align="center">
<template #default="scope">
<el-button type="danger" link @click="removeEditProductLine(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<el-button @click="editOpen = false">取消</el-button>
<el-button type="primary" :loading="editSaving" @click="submitEdit">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup name="Production">
import { computed, onMounted, ref } from 'vue'
import { addProductionTask, completeProductionTask, getProductionTask, listProductionTask } from '@/api/mes/productionTask'
import { addProductionTask, completeProductionTask, deleteProductionTask, getProductionTask, listProductionTask, pauseProductionTask, resumeProductionTask, startProductionTask, uncompleteProductionTask, updateProductionTask } from '@/api/mes/productionTask'
import { listProductBase } from '@/api/mat/product'
import { ElMessage, ElMessageBox } from 'element-plus'
@@ -315,11 +387,13 @@ const filters = ref({
const addOpen = ref(false)
const addSaving = ref(false)
const completeLoading = ref(false)
const statusLoading = ref(false)
const deleteLoading = ref(false)
const addFormRef = ref()
const addForm = ref({
taskCode: '',
taskName: '',
status: '1',
status: '0',
planStartTime: '',
planEndTime: '',
remark: ''
@@ -330,6 +404,18 @@ const addRules = {
const productOptions = ref([])
const addProducts = ref([])
const editOpen = ref(false)
const editSaving = ref(false)
const editFormRef = ref()
const editForm = ref({
taskId: null,
taskCode: '',
taskName: '',
planStartTime: '',
planEndTime: '',
remark: ''
})
const editProducts = ref([])
function toNumber(v) {
const n = Number(v)
@@ -457,6 +543,7 @@ function onCustomRangePicked(v) {
function statusLabel(v) {
const s = String(v || '')
if (s === '0') return '未开始'
if (s === '1') return '进行中'
if (s === '2') return '已完成'
if (s === '3') return '已暂停'
@@ -465,6 +552,7 @@ function statusLabel(v) {
function statusTagType(v) {
const s = String(v || '')
if (s === '0') return 'info'
if (s === '1') return 'success'
if (s === '2') return 'danger'
if (s === '3') return 'warning'
@@ -548,7 +636,7 @@ function openAdd() {
addForm.value = {
taskCode: '',
taskName: '',
status: '1',
status: '0',
planStartTime: '',
planEndTime: '',
remark: ''
@@ -625,6 +713,7 @@ function submitAdd() {
const taskId = res && res.data ? res.data : null
ElMessage.success('已新增')
addOpen.value = false
filters.value.status = ''
return loadTasks().then(() => {
if (taskId != null) {
selectedTaskId.value = taskId
@@ -638,6 +727,75 @@ function submitAdd() {
})
}
function openEdit() {
const taskId = selectedTaskId.value
if (taskId == null) return
ensureProductOptions()
loading.value = true
return getProductionTask(taskId)
.then((res) => {
const data = res && res.data ? res.data : {}
const task = data.task || {}
editForm.value = {
taskId: task.taskId,
taskCode: task.taskCode || '',
taskName: task.taskName || '',
planStartTime: task.planStartTime || '',
planEndTime: task.planEndTime || '',
remark: task.remark || ''
}
const rows = Array.isArray(data.products) ? data.products : []
editProducts.value = rows.map((p) => ({
productId: p.productId,
planQty: p.planQty || 0,
unit: p.unit || '',
remark: p.remark || ''
}))
if (!editProducts.value.length) {
editProducts.value = [{ productId: null, planQty: 0, unit: '', remark: '' }]
}
editOpen.value = true
})
.finally(() => {
loading.value = false
})
}
function addEditProductLine() {
editProducts.value.push({ productId: null, planQty: 0, unit: '', remark: '' })
}
function removeEditProductLine(idx) {
editProducts.value.splice(idx, 1)
}
function submitEdit() {
if (!editFormRef.value) return
editFormRef.value.validate((valid) => {
if (!valid) return
const task = Object.assign({}, editForm.value)
const products = mergeProductLines(editProducts.value).map((p) => ({
productId: p.productId,
planQty: p.planQty || 0,
unit: p.unit || '',
remark: p.remark || ''
}))
editSaving.value = true
updateProductionTask({ task, products })
.then(() => {
ElMessage.success('已保存')
editOpen.value = false
const taskId = selectedTaskId.value
return loadTasks().then(() => {
if (taskId != null) return selectTask(taskId)
})
})
.finally(() => {
editSaving.value = false
})
})
}
function completeSelectedTask() {
const task = selectedTask.value
const taskId = selectedTaskId.value
@@ -664,6 +822,101 @@ function completeSelectedTask() {
})
}
function uncompleteSelectedTask() {
const taskId = selectedTaskId.value
if (taskId == null) return
statusLoading.value = true
return ElMessageBox.confirm('撤销完成后将回到进行中,且回执会清空(再次完成会重新生成),是否继续?', '确认撤销', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => uncompleteProductionTask(taskId))
.then(() => {
ElMessage.success('已撤销完成')
return loadTasks().then(() => selectTask(taskId))
})
.catch((e) => {
const s = String(e || '')
if (s && s !== 'cancel' && s !== 'close') {
ElMessage.error('操作失败')
}
})
.finally(() => {
statusLoading.value = false
})
}
function startSelectedTask() {
const taskId = selectedTaskId.value
if (taskId == null) return
statusLoading.value = true
return startProductionTask(taskId)
.then(() => {
ElMessage.success('已开始')
return loadTasks().then(() => selectTask(taskId))
})
.finally(() => {
statusLoading.value = false
})
}
function pauseSelectedTask() {
const taskId = selectedTaskId.value
if (taskId == null) return
statusLoading.value = true
return pauseProductionTask(taskId)
.then(() => {
ElMessage.success('已暂停')
return loadTasks().then(() => selectTask(taskId))
})
.finally(() => {
statusLoading.value = false
})
}
function resumeSelectedTask() {
const taskId = selectedTaskId.value
if (taskId == null) return
statusLoading.value = true
return resumeProductionTask(taskId)
.then(() => {
ElMessage.success('已继续')
return loadTasks().then(() => selectTask(taskId))
})
.finally(() => {
statusLoading.value = false
})
}
function deleteSelectedTask() {
const taskId = selectedTaskId.value
if (taskId == null) return
deleteLoading.value = true
return ElMessageBox.confirm('删除后将不在列表展示,是否继续?', '确认删除', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => deleteProductionTask(taskId))
.then(() => {
ElMessage.success('已删除')
selectedTaskId.value = null
productRows.value = []
materialRows.value = []
return loadTasks()
})
.catch((e) => {
const s = String(e || '')
if (s && s !== 'cancel' && s !== 'close') {
ElMessage.error('操作失败')
}
})
.finally(() => {
deleteLoading.value = false
})
}
onMounted(() => {
applyDatePreset()
})
@@ -695,6 +948,12 @@ onMounted(() => {
min-width: 0;
}
.task-actions {
display: flex;
align-items: center;
gap: 8px;
}
.card-meta {
display: flex;
align-items: center;

View File

@@ -0,0 +1,284 @@
<template>
<div class="app-container">
<el-form ref="queryRef" :model="queryParams" :inline="true" v-show="showSearch" label-width="80px">
<el-form-item label="合同号" prop="contractNo">
<el-input v-model="queryParams.contractNo" placeholder="请输入合同号" clearable @keyup.enter="handleQuery" style="width: 200px" />
</el-form-item>
<el-form-item label="供方" prop="partyA">
<el-input v-model="queryParams.partyA" placeholder="请输入供方" clearable @keyup.enter="handleQuery" style="width: 200px" />
</el-form-item>
<el-form-item label="需方" prop="partyB">
<el-input v-model="queryParams.partyB" placeholder="请输入需方" clearable @keyup.enter="handleQuery" style="width: 200px" />
</el-form-item>
<el-form-item label="已生效" prop="effectiveFlag">
<el-select v-model="queryParams.effectiveFlag" placeholder="全部" clearable style="width: 140px">
<el-option label="否" value="0" />
<el-option label="是" value="1" />
</el-select>
</el-form-item>
<el-form-item label="签订日期">
<el-date-picker
v-model="queryParams.signDateRange"
type="daterange"
range-separator="-"
start-placeholder="开始"
end-placeholder="结束"
value-format="YYYY-MM-DD"
style="width: 260px"
/>
</el-form-item>
<el-form-item label="交货日期">
<el-date-picker
v-model="queryParams.deliveryDateRange"
type="daterange"
range-separator="-"
start-placeholder="开始"
end-placeholder="结束"
value-format="YYYY-MM-DD"
style="width: 260px"
/>
</el-form-item>
<el-form-item label="签订地点" prop="signPlace">
<el-input v-model="queryParams.signPlace" placeholder="请输入签订地点" clearable @keyup.enter="handleQuery" style="width: 200px" />
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button size="small" icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb8 toolbar">
<el-button size="small" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
<div class="toolbar-right">
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
</div>
</div>
<el-table v-loading="loading" :data="contractList">
<el-table-column label="合同号" prop="contractNo" min-width="150">
<template #default="{ row }">
<el-input v-if="isEditing(row)" v-model="editRow.contractNo" />
<span v-else>{{ row.contractNo }}</span>
</template>
</el-table-column>
<el-table-column label="供方" prop="partyA" min-width="220">
<template #default="{ row }">
<el-input v-if="isEditing(row)" v-model="editRow.partyA" />
<span v-else>{{ row.partyA }}</span>
</template>
</el-table-column>
<el-table-column label="需方" prop="partyB" min-width="220">
<template #default="{ row }">
<el-input v-if="isEditing(row)" v-model="editRow.partyB" />
<span v-else>{{ row.partyB }}</span>
</template>
</el-table-column>
<el-table-column label="签订日期" prop="signDate" width="140" align="center">
<template #default="{ row }">
<el-date-picker
v-if="isEditing(row)"
v-model="editRow.signDate"
type="date"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
style="width: 120px"
/>
<span v-else>{{ formatDate(row.signDate) }}</span>
</template>
</el-table-column>
<el-table-column label="交货日期" prop="deliveryDate" width="140" align="center">
<template #default="{ row }">
<el-date-picker
v-if="isEditing(row)"
v-model="editRow.deliveryDate"
type="date"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
style="width: 120px"
/>
<span v-else>{{ formatDate(row.deliveryDate) }}</span>
</template>
</el-table-column>
<el-table-column label="签订地点" prop="signPlace" min-width="160">
<template #default="{ row }">
<el-input v-if="isEditing(row)" v-model="editRow.signPlace" />
<span v-else>{{ row.signPlace }}</span>
</template>
</el-table-column>
<el-table-column label="供方地址" prop="partyAAddress" min-width="260" :show-overflow-tooltip="true">
<template #default="{ row }">
<el-input v-if="isEditing(row)" v-model="editRow.partyAAddress" />
<span v-else>{{ row.partyAAddress }}</span>
</template>
</el-table-column>
<el-table-column label="已生效" prop="effectiveFlag" width="100" align="center">
<template #default="{ row }">
<el-select v-if="isEditing(row)" v-model="editRow.effectiveFlag" style="width: 90px">
<el-option label="否" value="0" />
<el-option label="是" value="1" />
</el-select>
<el-tag v-else :type="row.effectiveFlag === '1' ? 'success' : 'info'" effect="light">{{ row.effectiveFlag === '1' ? '是' : '否' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="160" align="center" class-name="small-padding fixed-width">
<template #default="{ row }">
<template v-if="isEditing(row)">
<el-button link type="primary" icon="Check" :loading="saving" @click="saveRow">保存</el-button>
<el-button link type="primary" icon="Close" :disabled="saving" @click="cancelEdit">取消</el-button>
</template>
<template v-else>
<el-button link type="primary" icon="Edit" :disabled="editingId !== null" @click="startEdit(row)">修改</el-button>
<el-button link type="primary" icon="Delete" :disabled="editingId !== null" @click="deleteRow(row)">删除</el-button>
</template>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</div>
</template>
<script setup name="ContractEdit">
import { getCurrentInstance, onMounted, ref } from 'vue'
import { delContract, listContract, updateContract } from '@/api/oms/contract'
const { proxy } = getCurrentInstance()
const showSearch = ref(true)
const loading = ref(false)
const total = ref(0)
const contractList = ref([])
const queryRef = ref()
const queryParams = ref({
pageNum: 1,
pageSize: 10,
contractNo: '',
partyA: '',
partyB: '',
effectiveFlag: '',
signDateRange: [],
deliveryDateRange: [],
signPlace: ''
})
const editingId = ref(null)
const editRow = ref({})
const saving = ref(false)
function buildQuery() {
const q = { ...queryParams.value }
const signRange = Array.isArray(q.signDateRange) ? q.signDateRange : []
const deliveryRange = Array.isArray(q.deliveryDateRange) ? q.deliveryDateRange : []
delete q.signDateRange
delete q.deliveryDateRange
q.signDateStart = signRange[0] ? `${signRange[0]} 00:00:00` : ''
q.signDateEnd = signRange[1] ? `${signRange[1]} 23:59:59` : ''
q.deliveryDateStart = deliveryRange[0] ? `${deliveryRange[0]} 00:00:00` : ''
q.deliveryDateEnd = deliveryRange[1] ? `${deliveryRange[1]} 23:59:59` : ''
return q
}
function getList() {
loading.value = true
return listContract(buildQuery())
.then((res) => {
contractList.value = res?.rows || []
total.value = res?.total || 0
})
.finally(() => {
loading.value = false
})
}
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
function resetQuery() {
queryRef.value?.resetFields()
queryParams.value.signDateRange = []
queryParams.value.deliveryDateRange = []
handleQuery()
}
function isEditing(row) {
return row && editingId.value != null && String(row.contractId) === String(editingId.value)
}
function startEdit(row) {
editingId.value = row.contractId
editRow.value = {
contractId: row.contractId,
contractNo: row.contractNo || '',
partyA: row.partyA || '',
partyB: row.partyB || '',
effectiveFlag: row.effectiveFlag != null ? String(row.effectiveFlag) : '0',
signDate: row.signDate ? formatDate(row.signDate) : '',
deliveryDate: row.deliveryDate ? formatDate(row.deliveryDate) : '',
signPlace: row.signPlace || '',
partyAAddress: row.partyAAddress || '',
partyBAddress: row.partyBAddress || '',
remark: row.remark || ''
}
}
function cancelEdit() {
editingId.value = null
editRow.value = {}
}
function saveRow() {
if (!editRow.value?.contractId) return
saving.value = true
return updateContract({ ...editRow.value })
.then(() => {
proxy.$modal.msgSuccess('保存成功')
cancelEdit()
return getList()
})
.finally(() => {
saving.value = false
})
}
function deleteRow(row) {
if (!row?.contractId) return
proxy.$modal.confirm('是否确认删除该合同?').then(() => {
return delContract(row.contractId)
}).then(() => {
proxy.$modal.msgSuccess('删除成功')
cancelEdit()
getList()
})
}
function handleExport() {
proxy.download('oa/contract/export', {
...buildQuery()
}, `contract_${new Date().getTime()}.xlsx`)
}
function formatDate(v) {
if (!v) return ''
const d = new Date(v)
if (Number.isNaN(d.getTime())) return ''
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${y}-${m}-${day}`
}
onMounted(() => {
getList()
})
</script>
<style scoped>
.toolbar {
display: flex;
align-items: center;
justify-content: space-between;
}
</style>

View File

@@ -500,21 +500,26 @@ function handleAdd() {
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const userId = row.userId || ids.value
// let userId
// if (row && row.userId) {
// userId = row.userId
// } else if (ids.value && ids.value.length > 0) {
// userId = ids.value[0]
// } else {
// return
// }
let userId
if (row && row.userId) {
userId = row.userId
} else if (ids.value && ids.value.length > 0) {
userId = ids.value[0]
} else {
return
}
getUser(userId).then(response => {
form.value = response.data
postOptions.value = response.data.posts
roleOptions.value = response.data.roles
form.value.postIds = response.data.postIds
form.value.roleIds = response.data.roleIds
const data = response && response.data ? response.data : {}
const user = data.user ? data.user : {}
form.value = {
...form.value,
...user,
deptId: user.deptId != null ? Number(user.deptId) : undefined,
postIds: Array.isArray(data.postIds) ? data.postIds.map((v) => Number(v)) : [],
roleIds: Array.isArray(data.roleIds) ? data.roleIds.map((v) => Number(v)) : []
}
postOptions.value = data.posts || []
roleOptions.value = data.roles || []
open.value = true
title.value = "修改用户"
form.value.password = ""

View File

@@ -0,0 +1,35 @@
-- ================================
-- 合同编辑(用于“销售管理 -> 合同编辑详情”)
-- 目标:提供合同基础信息维护与快速编辑能力(列表行内修改/保存)
-- 说明:
-- 1) 单表存储合同主信息;与订单/客户关系后续可扩展
-- 2) 逻辑删除使用 del_flag0存在 2删除
-- ================================
DROP TABLE IF EXISTS gear_contract;
CREATE TABLE gear_contract (
contract_id bigint(20) NOT NULL COMMENT '合同ID',
contract_no varchar(64) NOT NULL COMMENT '合同号(唯一)',
party_a varchar(255) DEFAULT '' COMMENT '甲方/供方',
party_b varchar(255) DEFAULT '' COMMENT '乙方/需方',
effective_flag char(1) NOT NULL DEFAULT '0' COMMENT '是否生效0否 1是',
sign_date date COMMENT '签订日期',
delivery_date date COMMENT '交货日期',
sign_place varchar(255) DEFAULT '' COMMENT '签订地点',
party_a_address varchar(255) DEFAULT '' COMMENT '甲方地址',
party_b_address varchar(255) DEFAULT '' COMMENT '乙方地址',
remark varchar(500) DEFAULT NULL COMMENT '备注',
del_flag char(1) NOT NULL DEFAULT '0' COMMENT '删除标志0存在 2删除',
create_by varchar(64) DEFAULT '' COMMENT '创建者',
create_time datetime COMMENT '创建时间',
update_by varchar(64) DEFAULT '' COMMENT '更新者',
update_time datetime COMMENT '更新时间',
PRIMARY KEY (contract_id),
UNIQUE KEY uk_contract_no (contract_no),
KEY idx_sign_date (sign_date),
KEY idx_delivery_date (delivery_date),
KEY idx_effective_flag (effective_flag),
KEY idx_party_a (party_a),
KEY idx_party_b (party_b)
) ENGINE=InnoDB COMMENT='合同表(编辑详情)';

View File

@@ -204,3 +204,5 @@ INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2041777949048430593, '工人管理', 1952975318515830785, 21, 'worker', 'oms/worker/index', NULL, 1, 0, 'C', '0', '0', NULL, 'user', 'admin', '2026-04-08 15:19:32', 'admin', '2026-04-13 16:32:20', '');
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2041786163248885761, '薪资录入', 1952975318515830785, 97, 'wageEntryDetail', 'oms/wageEntryDetail/index', NULL, 1, 0, 'C', '0', '0', NULL, 'edit', 'admin', '2026-04-08 15:52:11', 'admin', '2026-04-08 15:52:11', '');
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2041816674390265858, '薪资补录', 1952975318515830785, 98, 'wageMakeup', 'oms/wageMakeup/index', NULL, 1, 0, 'C', '0', '0', NULL, 'edit', 'admin', '2026-04-08 17:53:25', 'admin', '2026-04-08 17:53:25', '');
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2060000000000000001, '合同编辑', 1962721165348478977, 8, 'contract', NULL, NULL, 1, 0, 'M', '0', '0', NULL, 'edit', 'admin', '2026-05-28 10:00:00', 'admin', '2026-05-28 10:00:00', '');
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2060000000000000002, '合同编辑详情', 2060000000000000001, 1, 'editDetail', 'oms/contractEdit/index', NULL, 1, 0, 'C', '0', '0', NULL, 'table', 'admin', '2026-05-28 10:00:00', 'admin', '2026-05-28 10:00:00', '');