From 7ffc140cf8733d4b05f1c7908009ba9b9b494672 Mon Sep 17 00:00:00 2001 From: wangyu <823267011@qq.com> Date: Tue, 16 Jun 2026 11:14:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(approval):=20=E6=96=B0=E5=A2=9E=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E5=AE=A1=E6=89=B9=E6=B5=81=E7=A8=8B=E5=8F=8A=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增审批配置主子表(biz_approval_config / biz_approval_config_user),支持或签 - 5 个业务模块接入审批: 采购订单/客户报价/供应商报价/发货单/订单异议 - 统一审批动作接口(提交/通过/驳回),status=10 表示审批中 - 新增"待我审批"聚合页面,按业务类型筛选 - 修复 logback 写本地路径报错,去除文件 appender - 修复 Redis SSL 配置在 Spring Boot 4 下需对象格式 - 补齐部分业务表缺失的 update_by/update_time 审计列 Co-Authored-By: Claude Opus 4.7 --- .../bid/BizApprovalActionController.java | 46 ++++ .../bid/BizApprovalConfigController.java | 54 +++++ .../src/main/resources/application.yml | 31 ++- ruoyi-admin/src/main/resources/logback.xml | 114 ++------- .../system/domain/bid/BizApprovalConfig.java | 29 +++ .../mapper/bid/BizApprovalActionMapper.java | 19 ++ .../mapper/bid/BizApprovalConfigMapper.java | 21 ++ .../mapper/bid/BizApprovalPendingMapper.java | 10 + .../bid/IBizApprovalActionService.java | 12 + .../bid/IBizApprovalConfigService.java | 16 ++ .../impl/BizApprovalActionServiceImpl.java | 78 +++++++ .../impl/BizApprovalConfigServiceImpl.java | 86 +++++++ .../mapper/bid/BizApprovalActionMapper.xml | 20 ++ .../mapper/bid/BizApprovalConfigMapper.xml | 77 ++++++ .../mapper/bid/BizApprovalPendingMapper.xml | 59 +++++ ruoyi-ui/public/favicon.svg | 12 + ruoyi-ui/public/index.html | 3 +- ruoyi-ui/src/api/bid/approval.js | 7 + ruoyi-ui/src/api/bid/approvalAction.js | 6 + ruoyi-ui/src/assets/logo/logo.svg | 12 + .../src/assets/styles/element-variables.scss | 4 +- ruoyi-ui/src/assets/styles/jd-variables.scss | 8 +- ruoyi-ui/src/assets/styles/ruoyi.scss | 8 +- ruoyi-ui/src/assets/styles/theme-jd.scss | 135 ++++++----- ruoyi-ui/src/assets/styles/variables.scss | 18 +- ruoyi-ui/src/components/JdFilterBar/index.vue | 2 +- ruoyi-ui/src/components/TreePanel/index.vue | 12 +- .../layout/components/HeaderNotice/index.vue | 4 +- ruoyi-ui/src/layout/components/Navbar.vue | 2 +- .../src/layout/components/Sidebar/Logo.vue | 68 ++++-- .../src/layout/components/TagsView/index.vue | 4 +- ruoyi-ui/src/views/bid/approval/index.vue | 150 ++++++++++++ ruoyi-ui/src/views/bid/approval/pending.vue | 86 +++++++ ruoyi-ui/src/views/bid/client/index.vue | 6 +- .../src/views/bid/clientDelivery/pending.vue | 31 ++- .../src/views/bid/clientDelivery/signed.vue | 8 +- .../src/views/bid/clientDelivery/transit.vue | 8 +- ruoyi-ui/src/views/bid/clientquote/detail.vue | 26 +-- .../views/bid/clientquote/history/index.vue | 8 +- ruoyi-ui/src/views/bid/clientquote/index.vue | 33 ++- ruoyi-ui/src/views/bid/comparison/detail.vue | 34 +-- ruoyi-ui/src/views/bid/comparison/index.vue | 4 +- .../material/components/CompareSection.vue | 8 +- .../material/components/SupplierQuoteTab.vue | 2 +- ruoyi-ui/src/views/bid/material/detail.vue | 8 +- ruoyi-ui/src/views/bid/material/index.vue | 2 +- ruoyi-ui/src/views/bid/objection/index.vue | 22 +- ruoyi-ui/src/views/bid/operationLog/index.vue | 4 +- ruoyi-ui/src/views/bid/order/closeDate.vue | 8 +- ruoyi-ui/src/views/bid/order/history.vue | 6 +- ruoyi-ui/src/views/bid/order/pending.vue | 8 +- ruoyi-ui/src/views/bid/order/transit.vue | 8 +- .../src/views/bid/purchaseorder/index.vue | 50 ++-- ruoyi-ui/src/views/bid/quotation/index.vue | 33 ++- .../views/bid/report/components/KpiCard.vue | 4 +- ruoyi-ui/src/views/bid/report/cost.vue | 14 +- ruoyi-ui/src/views/bid/report/dashboard.vue | 14 +- ruoyi-ui/src/views/bid/report/supplier.vue | 8 +- ruoyi-ui/src/views/bid/rfq/detail.vue | 16 +- ruoyi-ui/src/views/bid/rfq/index.vue | 12 +- ruoyi-ui/src/views/bid/supplier/index.vue | 6 +- ruoyi-ui/src/views/bid/transaction/index.vue | 2 +- ruoyi-ui/src/views/index.vue | 36 +-- ruoyi-ui/src/views/login.vue | 220 ++++++++++++------ .../src/views/system/notice/ReadUsers.vue | 2 +- ruoyi-ui/src/views/tool/build/RightPanel.vue | 4 +- ruoyi-ui/src/views/tool/build/index.vue | 6 +- sql/biz_approval_config.sql | 55 +++++ sql/menu_reorganize.sql | 80 +++++++ 69 files changed, 1563 insertions(+), 446 deletions(-) create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizApprovalActionController.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizApprovalConfigController.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/bid/BizApprovalConfig.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizApprovalActionMapper.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizApprovalConfigMapper.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizApprovalPendingMapper.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizApprovalActionService.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizApprovalConfigService.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizApprovalActionServiceImpl.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizApprovalConfigServiceImpl.java create mode 100644 ruoyi-system/src/main/resources/mapper/bid/BizApprovalActionMapper.xml create mode 100644 ruoyi-system/src/main/resources/mapper/bid/BizApprovalConfigMapper.xml create mode 100644 ruoyi-system/src/main/resources/mapper/bid/BizApprovalPendingMapper.xml create mode 100644 ruoyi-ui/public/favicon.svg create mode 100644 ruoyi-ui/src/api/bid/approval.js create mode 100644 ruoyi-ui/src/api/bid/approvalAction.js create mode 100644 ruoyi-ui/src/assets/logo/logo.svg create mode 100644 ruoyi-ui/src/views/bid/approval/index.vue create mode 100644 ruoyi-ui/src/views/bid/approval/pending.vue create mode 100644 sql/biz_approval_config.sql create mode 100644 sql/menu_reorganize.sql diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizApprovalActionController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizApprovalActionController.java new file mode 100644 index 00000000..16065044 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizApprovalActionController.java @@ -0,0 +1,46 @@ +package com.ruoyi.web.controller.bid; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.system.mapper.bid.BizApprovalPendingMapper; +import com.ruoyi.system.service.bid.IBizApprovalActionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +@RestController +@RequestMapping("/bid/approval/action") +public class BizApprovalActionController extends BaseController { + + @Autowired private IBizApprovalActionService service; + @Autowired private BizApprovalPendingMapper pendingMapper; + + @GetMapping("/pending") + public AjaxResult pending() { + return success(pendingMapper.selectPendingForUser(SecurityUtils.getUserId())); + } + + @Log(title = "提交审批", businessType = BusinessType.UPDATE) + @PostMapping("/submit/{bizType}/{id}") + public AjaxResult submit(@PathVariable String bizType, @PathVariable Long id) { + return toAjax(service.submit(bizType, id, getUsername())); + } + + @Log(title = "审批通过", businessType = BusinessType.UPDATE) + @PostMapping("/approve/{bizType}/{id}") + public AjaxResult approve(@PathVariable String bizType, @PathVariable Long id) { + return toAjax(service.approve(bizType, id, SecurityUtils.getUserId(), getUsername())); + } + + @Log(title = "审批驳回", businessType = BusinessType.UPDATE) + @PostMapping("/reject/{bizType}/{id}") + public AjaxResult reject(@PathVariable String bizType, @PathVariable Long id, + @RequestBody(required = false) Map body) { + String reason = body != null ? body.get("reason") : null; + return toAjax(service.reject(bizType, id, SecurityUtils.getUserId(), getUsername(), reason)); + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizApprovalConfigController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizApprovalConfigController.java new file mode 100644 index 00000000..9249e845 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/bid/BizApprovalConfigController.java @@ -0,0 +1,54 @@ +package com.ruoyi.web.controller.bid; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.system.domain.bid.BizApprovalConfig; +import com.ruoyi.system.service.bid.IBizApprovalConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/bid/approval") +public class BizApprovalConfigController extends BaseController { + @Autowired private IBizApprovalConfigService service; + + @PreAuthorize("@ss.hasPermi('bid:approval:list')") + @GetMapping("/list") + public TableDataInfo list(BizApprovalConfig q) { + startPage(); + return getDataTable(service.selectList(q)); + } + + @PreAuthorize("@ss.hasPermi('bid:approval:query')") + @GetMapping("/{id}") + public AjaxResult getInfo(@PathVariable Long id) { + return success(service.selectById(id)); + } + + @PreAuthorize("@ss.hasPermi('bid:approval:add')") + @Log(title = "审批配置", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody BizApprovalConfig c) { + c.setCreateBy(getUsername()); + return toAjax(service.insert(c)); + } + + @PreAuthorize("@ss.hasPermi('bid:approval:edit')") + @Log(title = "审批配置", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody BizApprovalConfig c) { + c.setUpdateBy(getUsername()); + return toAjax(service.update(c)); + } + + @PreAuthorize("@ss.hasPermi('bid:approval:remove')") + @Log(title = "审批配置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(service.deleteByIds(ids)); + } +} diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 789fe791..d74beca2 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -72,15 +72,18 @@ spring: # redis 配置 redis: # 地址 - host: localhost + host: 49.232.154.205 # 端口,默认为6379 port: 6379 # 数据库索引 database: 0 # 密码 - password: + password: WANGyu11! # 连接超时时间 - timeout: 10s + timeout: 30s + # 是否开启ssl + ssl: + enabled: false lettuce: pool: # 连接池中的最小空闲连接 @@ -92,6 +95,28 @@ spring: # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + # token配置 token: # 令牌自定义标识 diff --git a/ruoyi-admin/src/main/resources/logback.xml b/ruoyi-admin/src/main/resources/logback.xml index d69a5720..b5253d47 100644 --- a/ruoyi-admin/src/main/resources/logback.xml +++ b/ruoyi-admin/src/main/resources/logback.xml @@ -1,93 +1,21 @@ - - - - - - - - - - - ${log.pattern} - - - - - - ${log.path}/sys-info.log - - - - ${log.path}/sys-info.%d{yyyy-MM-dd}.log - - 60 - - - ${log.pattern} - - - - INFO - - ACCEPT - - DENY - - - - - ${log.path}/sys-error.log - - - - ${log.path}/sys-error.%d{yyyy-MM-dd}.log - - 60 - - - ${log.pattern} - - - - ERROR - - ACCEPT - - DENY - - - - - - ${log.path}/sys-user.log - - - ${log.path}/sys-user.%d{yyyy-MM-dd}.log - - 60 - - - ${log.pattern} - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + ${log.pattern} + + + + + + + + + + + + + + diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/bid/BizApprovalConfig.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bid/BizApprovalConfig.java new file mode 100644 index 00000000..f7ee012d --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bid/BizApprovalConfig.java @@ -0,0 +1,29 @@ +package com.ruoyi.system.domain.bid; + +import com.ruoyi.common.core.domain.BaseEntity; +import java.util.List; + +public class BizApprovalConfig extends BaseEntity { + private Long id; + private String bizType; + private String bizName; + private String signType; + private String enabled; + private List userIds; + private List userNames; + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + public String getBizType() { return bizType; } + public void setBizType(String bizType) { this.bizType = bizType; } + public String getBizName() { return bizName; } + public void setBizName(String bizName) { this.bizName = bizName; } + public String getSignType() { return signType; } + public void setSignType(String signType) { this.signType = signType; } + public String getEnabled() { return enabled; } + public void setEnabled(String enabled) { this.enabled = enabled; } + public List getUserIds() { return userIds; } + public void setUserIds(List userIds) { this.userIds = userIds; } + public List getUserNames() { return userNames; } + public void setUserNames(List userNames) { this.userNames = userNames; } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizApprovalActionMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizApprovalActionMapper.java new file mode 100644 index 00000000..1e66cc43 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizApprovalActionMapper.java @@ -0,0 +1,19 @@ +package com.ruoyi.system.mapper.bid; + +import org.apache.ibatis.annotations.Param; + +public interface BizApprovalActionMapper { + /** 仅当当前状态在 fromStatuses 中时更新业务单据状态 */ + int updateStatus(@Param("table") String table, + @Param("pk") String pk, + @Param("statusCol") String statusCol, + @Param("id") Long id, + @Param("newStatus") String newStatus, + @Param("fromStatuses") java.util.List fromStatuses, + @Param("updateBy") String updateBy); + + String selectStatus(@Param("table") String table, + @Param("pk") String pk, + @Param("statusCol") String statusCol, + @Param("id") Long id); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizApprovalConfigMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizApprovalConfigMapper.java new file mode 100644 index 00000000..7a145d64 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizApprovalConfigMapper.java @@ -0,0 +1,21 @@ +package com.ruoyi.system.mapper.bid; + +import com.ruoyi.system.domain.bid.BizApprovalConfig; +import org.apache.ibatis.annotations.Param; +import java.util.List; + +public interface BizApprovalConfigMapper { + List selectList(BizApprovalConfig query); + BizApprovalConfig selectById(Long id); + BizApprovalConfig selectByBizType(String bizType); + int insert(BizApprovalConfig record); + int update(BizApprovalConfig record); + int deleteById(Long id); + + List selectUserIds(@Param("configId") Long configId); + List selectUserNames(@Param("configId") Long configId); + int deleteUsers(@Param("configId") Long configId); + int insertUser(@Param("configId") Long configId, @Param("userId") Long userId, @Param("sortNo") Integer sortNo); + + int existsUser(@Param("bizType") String bizType, @Param("userId") Long userId); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizApprovalPendingMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizApprovalPendingMapper.java new file mode 100644 index 00000000..044e028c --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/bid/BizApprovalPendingMapper.java @@ -0,0 +1,10 @@ +package com.ruoyi.system.mapper.bid; + +import org.apache.ibatis.annotations.Param; +import java.util.List; +import java.util.Map; + +public interface BizApprovalPendingMapper { + /** 查询某用户作为审批人的、所有业务表中 status='10' 的单据 */ + List> selectPendingForUser(@Param("userId") Long userId); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizApprovalActionService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizApprovalActionService.java new file mode 100644 index 00000000..863adf9f --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizApprovalActionService.java @@ -0,0 +1,12 @@ +package com.ruoyi.system.service.bid; + +public interface IBizApprovalActionService { + /** 提交审批: 业务单据 status -> 10 */ + int submit(String bizType, Long id, String username); + + /** 通过审批(或签): 任一审批人通过即生效, 业务单据 status -> 通过状态 */ + int approve(String bizType, Long id, Long userId, String username); + + /** 驳回审批: 业务单据 status -> rejected, 备注记录原因 */ + int reject(String bizType, Long id, Long userId, String username, String reason); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizApprovalConfigService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizApprovalConfigService.java new file mode 100644 index 00000000..0c7e93ab --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/IBizApprovalConfigService.java @@ -0,0 +1,16 @@ +package com.ruoyi.system.service.bid; + +import com.ruoyi.system.domain.bid.BizApprovalConfig; +import java.util.List; + +public interface IBizApprovalConfigService { + List selectList(BizApprovalConfig query); + BizApprovalConfig selectById(Long id); + BizApprovalConfig selectByBizType(String bizType); + int insert(BizApprovalConfig record); + int update(BizApprovalConfig record); + int deleteByIds(Long[] ids); + + /** 校验当前用户是否为该业务的审批人(或签) */ + boolean canApprove(String bizType, Long userId); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizApprovalActionServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizApprovalActionServiceImpl.java new file mode 100644 index 00000000..c5b53a22 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizApprovalActionServiceImpl.java @@ -0,0 +1,78 @@ +package com.ruoyi.system.service.bid.impl; + +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.system.mapper.bid.BizApprovalActionMapper; +import com.ruoyi.system.service.bid.IBizApprovalActionService; +import com.ruoyi.system.service.bid.IBizApprovalConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class BizApprovalActionServiceImpl implements IBizApprovalActionService { + + @Autowired private BizApprovalActionMapper mapper; + @Autowired private IBizApprovalConfigService configService; + + /** 业务类型 -> 表/主键/状态列/审批通过的目标状态/可提交的初始状态 */ + static class Meta { + final String table, pk, statusCol, approvedStatus; + final List draftStatuses; + Meta(String t, String pk, String sc, String approved, List drafts) { + this.table = t; this.pk = pk; this.statusCol = sc; + this.approvedStatus = approved; this.draftStatuses = drafts; + } + } + + private static final Map META = new HashMap<>(); + static { + META.put("PURCHASE_ORDER", new Meta("biz_purchase_order", "po_id", "status", "confirmed", Arrays.asList("draft"))); + META.put("CLIENT_QUOTE", new Meta("biz_client_quote", "quote_id", "status", "confirmed", Arrays.asList("draft"))); + META.put("QUOTATION", new Meta("biz_quotation", "quotation_id", "status", "accepted", Arrays.asList("draft", "submitted"))); + META.put("DELIVERY_ORDER", new Meta("biz_delivery_order", "do_id", "delivery_status", "confirmed", Arrays.asList("pending"))); + META.put("ORDER_OBJECTION", new Meta("biz_order_objection", "objection_id", "status", "resolved", Arrays.asList("pending"))); + } + + private Meta meta(String bizType) { + Meta m = META.get(bizType); + if (m == null) throw new ServiceException("不支持的业务类型: " + bizType); + return m; + } + + @Override + public int submit(String bizType, Long id, String username) { + Meta m = meta(bizType); + int rows = mapper.updateStatus(m.table, m.pk, m.statusCol, id, "10", m.draftStatuses, username); + if (rows == 0) throw new ServiceException("当前状态不允许提交审批"); + return rows; + } + + @Override + public int approve(String bizType, Long id, Long userId, String username) { + Meta m = meta(bizType); + if (!configService.canApprove(bizType, userId)) { + throw new ServiceException("无权审批: 当前用户不是该业务的审批人"); + } + int rows = mapper.updateStatus(m.table, m.pk, m.statusCol, id, + m.approvedStatus, Collections.singletonList("10"), username); + if (rows == 0) throw new ServiceException("单据非审批中, 无法通过"); + return rows; + } + + @Override + public int reject(String bizType, Long id, Long userId, String username, String reason) { + Meta m = meta(bizType); + if (!configService.canApprove(bizType, userId)) { + throw new ServiceException("无权审批: 当前用户不是该业务的审批人"); + } + int rows = mapper.updateStatus(m.table, m.pk, m.statusCol, id, + "rejected", Collections.singletonList("10"), username); + if (rows == 0) throw new ServiceException("单据非审批中, 无法驳回"); + return rows; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizApprovalConfigServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizApprovalConfigServiceImpl.java new file mode 100644 index 00000000..481d7ac1 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/bid/impl/BizApprovalConfigServiceImpl.java @@ -0,0 +1,86 @@ +package com.ruoyi.system.service.bid.impl; + +import com.ruoyi.system.domain.bid.BizApprovalConfig; +import com.ruoyi.system.mapper.bid.BizApprovalConfigMapper; +import com.ruoyi.system.service.bid.IBizApprovalConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.util.List; + +@Service +public class BizApprovalConfigServiceImpl implements IBizApprovalConfigService { + @Autowired private BizApprovalConfigMapper mapper; + + @Override + public List selectList(BizApprovalConfig query) { + List list = mapper.selectList(query); + for (BizApprovalConfig c : list) { + c.setUserIds(mapper.selectUserIds(c.getId())); + c.setUserNames(mapper.selectUserNames(c.getId())); + } + return list; + } + + @Override + public BizApprovalConfig selectById(Long id) { + BizApprovalConfig c = mapper.selectById(id); + if (c != null) { + c.setUserIds(mapper.selectUserIds(id)); + c.setUserNames(mapper.selectUserNames(id)); + } + return c; + } + + @Override + public BizApprovalConfig selectByBizType(String bizType) { + BizApprovalConfig c = mapper.selectByBizType(bizType); + if (c != null) { + c.setUserIds(mapper.selectUserIds(c.getId())); + c.setUserNames(mapper.selectUserNames(c.getId())); + } + return c; + } + + @Override + @Transactional + public int insert(BizApprovalConfig r) { + int rows = mapper.insert(r); + saveUsers(r); + return rows; + } + + @Override + @Transactional + public int update(BizApprovalConfig r) { + int rows = mapper.update(r); + mapper.deleteUsers(r.getId()); + saveUsers(r); + return rows; + } + + private void saveUsers(BizApprovalConfig r) { + if (r.getUserIds() == null) return; + int sort = 0; + for (Long uid : r.getUserIds()) { + if (uid != null) mapper.insertUser(r.getId(), uid, sort++); + } + } + + @Override + @Transactional + public int deleteByIds(Long[] ids) { + int n = 0; + for (Long id : ids) { + mapper.deleteUsers(id); + n += mapper.deleteById(id); + } + return n; + } + + @Override + public boolean canApprove(String bizType, Long userId) { + if (bizType == null || userId == null) return false; + return mapper.existsUser(bizType, userId) > 0; + } +} diff --git a/ruoyi-system/src/main/resources/mapper/bid/BizApprovalActionMapper.xml b/ruoyi-system/src/main/resources/mapper/bid/BizApprovalActionMapper.xml new file mode 100644 index 00000000..04edc68b --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/bid/BizApprovalActionMapper.xml @@ -0,0 +1,20 @@ + + + + + + UPDATE ${table} + SET ${statusCol} = #{newStatus}, + update_by = #{updateBy}, + update_time = NOW() + WHERE ${pk} = #{id} + + AND ${statusCol} IN + #{s} + + + + + diff --git a/ruoyi-system/src/main/resources/mapper/bid/BizApprovalConfigMapper.xml b/ruoyi-system/src/main/resources/mapper/bid/BizApprovalConfigMapper.xml new file mode 100644 index 00000000..cbd59cf7 --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/bid/BizApprovalConfigMapper.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + INSERT INTO biz_approval_config(biz_type,biz_name,sign_type,enabled,remark,create_by,create_time) + VALUES(#{bizType},#{bizName},#{signType},#{enabled},#{remark},#{createBy},NOW()) + + + + UPDATE biz_approval_config + + biz_name=#{bizName}, + sign_type=#{signType}, + enabled=#{enabled}, + remark=#{remark}, + update_by=#{updateBy}, update_time=NOW() + + WHERE id=#{id} + + + DELETE FROM biz_approval_config WHERE id=#{id} + + + + + + DELETE FROM biz_approval_config_user WHERE config_id=#{configId} + + + INSERT INTO biz_approval_config_user(config_id,user_id,sort_no) + VALUES(#{configId},#{userId},#{sortNo}) + + + + diff --git a/ruoyi-system/src/main/resources/mapper/bid/BizApprovalPendingMapper.xml b/ruoyi-system/src/main/resources/mapper/bid/BizApprovalPendingMapper.xml new file mode 100644 index 00000000..4e70d2ce --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/bid/BizApprovalPendingMapper.xml @@ -0,0 +1,59 @@ + + + + + + diff --git a/ruoyi-ui/public/favicon.svg b/ruoyi-ui/public/favicon.svg new file mode 100644 index 00000000..3131656b --- /dev/null +++ b/ruoyi-ui/public/favicon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/ruoyi-ui/public/index.html b/ruoyi-ui/public/index.html index 56fd45b3..5e16872d 100644 --- a/ruoyi-ui/public/index.html +++ b/ruoyi-ui/public/index.html @@ -5,7 +5,8 @@ - + + <%= webpackConfig.name %> diff --git a/ruoyi-ui/src/layout/components/TagsView/index.vue b/ruoyi-ui/src/layout/components/TagsView/index.vue index 5e2e3c65..8b5bd4df 100644 --- a/ruoyi-ui/src/layout/components/TagsView/index.vue +++ b/ruoyi-ui/src/layout/components/TagsView/index.vue @@ -105,9 +105,9 @@ export default { }, chromeVars() { if (this.tagsViewStyle !== 'chrome') return {} - const primary = this.theme || '#409EFF' + const primary = this.theme || '#e4393c' return { - '--chrome-tab-active-bg': this.mixHexWithWhite(primary, 0.15), + '--chrome-tab-active-bg': '#ffffff', '--chrome-tab-text-active': primary, '--chrome-wing-r': '14px' } diff --git a/ruoyi-ui/src/views/bid/approval/index.vue b/ruoyi-ui/src/views/bid/approval/index.vue new file mode 100644 index 00000000..8429f3cb --- /dev/null +++ b/ruoyi-ui/src/views/bid/approval/index.vue @@ -0,0 +1,150 @@ + + + diff --git a/ruoyi-ui/src/views/bid/approval/pending.vue b/ruoyi-ui/src/views/bid/approval/pending.vue new file mode 100644 index 00000000..178f5e90 --- /dev/null +++ b/ruoyi-ui/src/views/bid/approval/pending.vue @@ -0,0 +1,86 @@ + + + diff --git a/ruoyi-ui/src/views/bid/client/index.vue b/ruoyi-ui/src/views/bid/client/index.vue index c9237789..e88ea789 100644 --- a/ruoyi-ui/src/views/bid/client/index.vue +++ b/ruoyi-ui/src/views/bid/client/index.vue @@ -277,7 +277,7 @@ export default { /* ═══════ 整体布局 ═══════ */ .client-manage { padding: 12px; - background: #f5f5f5; + background: #ffffff; min-height: calc(100vh - 84px); } .client-manage ::v-deep .el-tabs__header { @@ -342,7 +342,7 @@ export default { .dl { width: 90px; flex-shrink: 0; - background: #f5f5f5; + background: #ffffff; padding: 10px 12px; font-size: 12px; color: #666; @@ -357,7 +357,7 @@ export default { } .detail-remark { padding: 8px 12px; - background: #fff5f5; + background: #fafafa; border: 1px solid #fce4e4; border-radius: 2px; font-size: 12px; diff --git a/ruoyi-ui/src/views/bid/clientDelivery/pending.vue b/ruoyi-ui/src/views/bid/clientDelivery/pending.vue index ddccab84..d464ef52 100644 --- a/ruoyi-ui/src/views/bid/clientDelivery/pending.vue +++ b/ruoyi-ui/src/views/bid/clientDelivery/pending.vue @@ -17,11 +17,20 @@ - - + + + + @@ -32,7 +41,7 @@
发货单号{{ detailData ? detailData.doNo : '' }}
甲方客户{{ (detailData && detailData.clientName) || '-' }}
-
总金额¥{{ detailData ? detailData.totalAmount : 0 }}
+
总金额¥{{ detailData ? detailData.totalAmount : 0 }}
状态待发
交货期{{ (detailData && detailData.deliveryDate) || '-' }}
备注{{ (detailData && detailData.remark) || '-' }}
@@ -53,11 +62,12 @@ diff --git a/ruoyi-ui/src/views/bid/clientDelivery/signed.vue b/ruoyi-ui/src/views/bid/clientDelivery/signed.vue index 1c1c0fc1..24efad43 100644 --- a/ruoyi-ui/src/views/bid/clientDelivery/signed.vue +++ b/ruoyi-ui/src/views/bid/clientDelivery/signed.vue @@ -24,7 +24,7 @@
发货单号{{ detailData ? detailData.doNo : '' }}
甲方客户{{ (detailData && detailData.clientName) || '-' }}
-
总金额¥{{ detailData ? detailData.totalAmount : 0 }}
+
总金额¥{{ detailData ? detailData.totalAmount : 0 }}
状态已签收
交货期{{ (detailData && detailData.deliveryDate) || '-' }}
签收日期{{ (detailData && detailData.actualCloseDate) || '-' }}
@@ -63,17 +63,17 @@ export default { diff --git a/ruoyi-ui/src/views/bid/clientquote/detail.vue b/ruoyi-ui/src/views/bid/clientquote/detail.vue index 0d185899..af2408ca 100644 --- a/ruoyi-ui/src/views/bid/clientquote/detail.vue +++ b/ruoyi-ui/src/views/bid/clientquote/detail.vue @@ -144,7 +144,7 @@ @@ -167,7 +167,7 @@
合计: - ¥{{ grandTotal }} + ¥{{ grandTotal }} 共 {{ form.items.length }} 项
@@ -293,7 +293,7 @@ import { getClientQuote, addClientQuote, updateClientQuote, getClientQuoteHistor import { listClient } from "@/api/bid/client"; import { createRfqFromQuote } from "@/api/bid/rfq"; import { listMaterial, getSupplierQuoteReference } from "@/api/bid/material"; -import logoImg from "@/assets/logo/logo.png"; +import logoImg from "@/assets/logo/logo.svg"; import html2canvas from "html2canvas"; import jsPDF from "jspdf"; @@ -577,7 +577,7 @@ export default { .page-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:20px; padding:16px 0; border-bottom:1px solid #f0f2f5; flex-wrap:wrap; gap:10px; overflow:hidden; } .page-header-left { display:flex; align-items:center; gap:12px; } .page-header-right { display:flex; gap:10px; } -.page-title { font-size:18px; font-weight:700; color:#1a2c4e; } +.page-title { font-size:18px; font-weight:700; color:#333333; } .info-card ::v-deep .el-card__body { padding: 20px; } .total-bar { display:flex; align-items:center; justify-content:flex-end; padding:16px 20px; border-top:1px solid #f0f2f5; background:#fafbfc; } @@ -606,7 +606,7 @@ export default { /* RFQ已生成信息 */ .rfq-generated-info { padding: 4px 0; } .rfq-item { display:flex; align-items:center; gap:8px; padding:8px 10px; border:1px solid #e4e7ed; border-radius:6px; cursor:pointer; transition:all .2s; } -.rfq-item:hover { border-color:#409eff; background:#f0f7ff; } +.rfq-item:hover { border-color:#e4393c; background:#fafafa; } .rfq-title { font-size:12px; color:#606266; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:120px; } /* 物料搜索建议下拉 */ @@ -671,7 +671,7 @@ export default { } .ms-brand { - color: #409EFF; + color: #e4393c; background: #ecf5ff; padding: 2px 8px; border-radius: 3px; @@ -695,21 +695,21 @@ export default { .pdf-header { display:flex; align-items:flex-start; padding-bottom:12px; } .pdf-logo { width:52px; height:52px; object-fit:contain; margin-right:14px; } .pdf-header-text { flex:1; } -.pdf-company { font-size:22px; font-weight:700; color:#1171c4; } +.pdf-company { font-size:22px; font-weight:700; color:#e4393c; } .pdf-doc-type { font-size:14px; color:#333; margin-top:4px; font-weight:600; } .pdf-header-meta { font-size:12px; color:#888; text-align:right; } -.pdf-divider { border-top:2px solid #1171c4; margin:0 0 16px; } +.pdf-divider { border-top:2px solid #e4393c; margin:0 0 16px; } .pdf-meta-table { width:100%; border-collapse:collapse; margin-bottom:16px; td { padding:7px 10px; border:1px solid #e4e7ed; } } .meta-label { background:#f5f7fa; color:#606266; font-weight:600; width:90px; } .meta-val { color:#303133; } -.pdf-section-title { font-size:14px; font-weight:700; color:#1a2c4e; margin:0 0 10px; padding-left:8px; border-left:4px solid #1171c4; } +.pdf-section-title { font-size:14px; font-weight:700; color:#333333; margin:0 0 10px; padding-left:8px; border-left:4px solid #e4393c; } .pdf-items-table { width:100%; border-collapse:collapse; margin-bottom:20px; - th { background:#1171c4; color:#fff; padding:8px; text-align:center; font-size:12px; font-weight:600; } + th { background:#e4393c; color:#fff; padding:8px; text-align:center; font-size:12px; font-weight:600; } td { border:1px solid #e4e7ed; padding:7px 8px; text-align:center; font-size:12px; } tbody tr:nth-child(even) td { background:#f9fbff; } } -.amount-cell { color:#409EFF; font-weight:600; } -.total-cell { font-size:14px; background:#f0f7ff !important; font-weight:700; } -.pdf-note { background:#fffbf0; border:1px solid #faecd8; border-radius:4px; padding:10px 14px; font-size:12px; color:#606266; margin-bottom:16px; } +.amount-cell { color:#e4393c; font-weight:600; } +.total-cell { font-size:14px; background:#fafafa !important; font-weight:700; } +.pdf-note { background:#fafafa; border:1px solid #faecd8; border-radius:4px; padding:10px 14px; font-size:12px; color:#606266; margin-bottom:16px; } .pdf-footer { text-align:center; font-size:11px; color:#aaa; border-top:1px solid #f0f2f5; padding-top:12px; } diff --git a/ruoyi-ui/src/views/bid/clientquote/history/index.vue b/ruoyi-ui/src/views/bid/clientquote/history/index.vue index 24159ce6..af109a85 100644 --- a/ruoyi-ui/src/views/bid/clientquote/history/index.vue +++ b/ruoyi-ui/src/views/bid/clientquote/history/index.vue @@ -91,7 +91,7 @@
@@ -134,13 +134,13 @@ {{ detailForm.validityDate | date }} {{ detailForm.rfqNo || '-' }} - ¥{{ detailForm.totalAmount | money }} + ¥{{ detailForm.totalAmount | money }} {{ detailForm.remark || '-' }} -
+
报价明细
@@ -157,7 +157,7 @@ - + diff --git a/ruoyi-ui/src/views/bid/clientquote/index.vue b/ruoyi-ui/src/views/bid/clientquote/index.vue index eef6ba40..be66b246 100644 --- a/ruoyi-ui/src/views/bid/clientquote/index.vue +++ b/ruoyi-ui/src/views/bid/clientquote/index.vue @@ -93,6 +93,9 @@ 快速新建 生成RFQ + 提交审批 + 审批通过 + 审批驳回 生成发货单 删除 @@ -213,7 +216,7 @@ {{ detailData.currency || 'CNY' }} {{ detailData.validityDate | dateFmt }} - {{ detailRfqList.length }} 个 + {{ detailRfqList.length }} 个 - @@ -269,6 +272,7 @@ import { listClientQuote, getClientQuote, addClientQuote, updateClientQuote, del import { listRfq, createRfqFromQuote } from "@/api/bid/rfq"; import { listMaterial } from "@/api/bid/material"; import { addDelivery } from "@/api/bid/delivery"; +import { submitApproval, approveBiz, rejectBiz } from "@/api/bid/approvalAction"; export default { name: "ClientQuote", @@ -331,8 +335,25 @@ export default { if (cmd === 'quickCreate') this.handleQuickCreate(row); else if (cmd === 'createRfq') this.handleCreateRfq(row); else if (cmd === 'createDelivery') this.handleCreateDelivery(row); + else if (cmd === 'submitApproval') this.handleSubmitApproval(row); + else if (cmd === 'approve') this.handleApprove(row); + else if (cmd === 'reject') this.handleReject(row); else if (cmd === 'delete') this.handleDelete(row); }, + handleSubmitApproval(row) { + this.$modal.confirm("确认提交审批?").then(() => submitApproval("CLIENT_QUOTE", row.quoteId)) + .then(() => { this.$modal.msgSuccess("已提交审批"); this.getList(); this.getStats(); }); + }, + handleApprove(row) { + this.$modal.confirm("确认通过该客户报价?").then(() => approveBiz("CLIENT_QUOTE", row.quoteId)) + .then(() => { this.$modal.msgSuccess("审批通过"); this.getList(); this.getStats(); }); + }, + handleReject(row) { + this.$prompt("请输入驳回原因", "驳回", { inputPattern: /.+/, inputErrorMessage: "请填写原因" }) + .then(({ value }) => rejectBiz("CLIENT_QUOTE", row.quoteId, value)) + .then(() => { this.$modal.msgSuccess("已驳回"); this.getList(); this.getStats(); }) + .catch(() => {}); + }, handleDelete(row) { this.$modal.confirm("确认删除【" + row.quoteNo + "】?").then(() => delClientQuote(row.quoteId)).then(() => { this.$modal.msgSuccess("删除成功"); this.getList(); this.getStats(); }); }, loadRfqForDetail(quoteId) { this.detailRfqLoading = true; listRfq({ clientQuoteId: quoteId, pageSize: 50 }).then(r => { this.detailRfqList = r.rows || []; this.detailRfqLoading = false; }).catch(() => { this.detailRfqLoading = false; }); }, viewRfqDetail(rfq) { this.detailOpen = false; this.$router.push({ path: '/bid/rfq/detail', query: { rfqId: rfq.rfqId } }); }, @@ -348,22 +369,22 @@ export default { itemTotal(row) { return ((parseFloat(row.quantity)||0) * (parseFloat(row.unitPrice)||0)).toFixed(2); }, calcMargin(row) { const c = parseFloat(row.costPrice)||0; const p = parseFloat(row.unitPrice)||0; if (!p) return "0.0"; return (((p-c)/p)*100).toFixed(1); }, marginColor(row) { const m = parseFloat(this.calcMargin(row)); return m >= 20 ? "#67c23a" : m >= 10 ? "#e6a23c" : "#f56c6c"; }, - statusType(s) { return { draft:"info", sent:"primary", confirmed:"success", rejected:"danger" }[s] || ""; }, - statusLabel(s) { return { draft:"草稿", sent:"已发送", confirmed:"已确认", rejected:"已拒绝" }[s] || s; } + statusType(s) { return { draft:"info", "10":"warning", sent:"primary", confirmed:"success", rejected:"danger" }[s] || ""; }, + statusLabel(s) { return { draft:"草稿", "10":"审批中", sent:"已发送", confirmed:"已确认", rejected:"已拒绝" }[s] || s; } } }; diff --git a/ruoyi-ui/src/views/bid/comparison/index.vue b/ruoyi-ui/src/views/bid/comparison/index.vue index 5f15c80c..ebcb261e 100644 --- a/ruoyi-ui/src/views/bid/comparison/index.vue +++ b/ruoyi-ui/src/views/bid/comparison/index.vue @@ -16,8 +16,8 @@ -
- +
+ 选择询价单进行智慧比价
diff --git a/ruoyi-ui/src/views/bid/material/components/CompareSection.vue b/ruoyi-ui/src/views/bid/material/components/CompareSection.vue index c3edf443..c457dd35 100644 --- a/ruoyi-ui/src/views/bid/material/components/CompareSection.vue +++ b/ruoyi-ui/src/views/bid/material/components/CompareSection.vue @@ -418,7 +418,7 @@ export default { transform: translateY(-50%); width: 4px; height: 14px; - background: linear-gradient(180deg, #409eff 0%, #2c3e50 100%); + background: linear-gradient(180deg, #e4393c 0%, #2c3e50 100%); border-radius: 2px; } @@ -508,7 +508,7 @@ export default { .mat-name { font-size: 15px; font-weight: 700; - color: #1a2c4e; + color: #333333; line-height: 1.3; } .mat-subtitle { @@ -567,7 +567,7 @@ export default { gap: 4px; } .divider-text i { - color: #409eff; + color: #e4393c; font-size: 14px; } @@ -617,7 +617,7 @@ export default { } .quote-row.is-fastest { background: linear-gradient(90deg, #ecf5ff 0%, #d9ecff 100%); - border-left: 3px solid #409eff; + border-left: 3px solid #e4393c; } .quote-row.is-lowest.is-fastest { background: linear-gradient(90deg, #f0f9eb 0%, #e8f5e0 50%, #ecf5ff 100%); diff --git a/ruoyi-ui/src/views/bid/material/components/SupplierQuoteTab.vue b/ruoyi-ui/src/views/bid/material/components/SupplierQuoteTab.vue index 31dff717..8523491f 100644 --- a/ruoyi-ui/src/views/bid/material/components/SupplierQuoteTab.vue +++ b/ruoyi-ui/src/views/bid/material/components/SupplierQuoteTab.vue @@ -183,7 +183,7 @@ export default { .supplier-contact .phone { margin-left: 8px; - color: #409eff; + color: #e4393c; } /* 价格单元格 */ diff --git a/ruoyi-ui/src/views/bid/material/detail.vue b/ruoyi-ui/src/views/bid/material/detail.vue index 46de729b..c88606ae 100644 --- a/ruoyi-ui/src/views/bid/material/detail.vue +++ b/ruoyi-ui/src/views/bid/material/detail.vue @@ -249,7 +249,7 @@ export default { diff --git a/ruoyi-ui/src/views/bid/purchaseorder/index.vue b/ruoyi-ui/src/views/bid/purchaseorder/index.vue index a7a572d7..3af3f893 100644 --- a/ruoyi-ui/src/views/bid/purchaseorder/index.vue +++ b/ruoyi-ui/src/views/bid/purchaseorder/index.vue @@ -7,6 +7,8 @@ + + @@ -29,7 +31,7 @@ - + @@ -38,10 +40,13 @@ - + @@ -90,7 +95,7 @@ @@ -174,8 +179,9 @@ @@ -271,7 +291,7 @@ export default { .pdf-company { font-size: 20px; font-weight: 700; - color: #1171c4; + color: #e4393c; letter-spacing: 1px; } .pdf-doc-type { @@ -284,7 +304,7 @@ export default { color: #888; } .pdf-divider { - border-top: 2px solid #1171c4; + border-top: 2px solid #e4393c; margin-bottom: 16px; } .pdf-meta-table { @@ -306,17 +326,17 @@ export default { color: #303133; } .amount { - color: #409EFF; + color: #e4393c; font-weight: 700; font-size: 15px; } .pdf-section-title { font-size: 14px; font-weight: 700; - color: #1a2c4e; + color: #333333; margin: 0 0 10px; padding-left: 8px; - border-left: 4px solid #1171c4; + border-left: 4px solid #e4393c; } .pdf-items-table { width: 100%; @@ -324,7 +344,7 @@ export default { margin-bottom: 20px; } .pdf-items-table th { - background: #1171c4; + background: #e4393c; color: #fff; padding: 8px 10px; text-align: center; @@ -339,12 +359,12 @@ export default { background: #f9fbff; } .amount-cell { - color: #409EFF; + color: #e4393c; font-weight: 600; } .total-cell { font-size: 15px; - background: #f0f7ff !important; + background: #fafafa !important; } .pdf-footer { text-align: right; diff --git a/ruoyi-ui/src/views/bid/quotation/index.vue b/ruoyi-ui/src/views/bid/quotation/index.vue index 4979cb1e..9be23c77 100644 --- a/ruoyi-ui/src/views/bid/quotation/index.vue +++ b/ruoyi-ui/src/views/bid/quotation/index.vue @@ -120,6 +120,12 @@ v-if="s.row.status==='draft'">编辑 提交 + 提交审批 + 审批通过 + 审批驳回 采纳 - 报价明细 + 报价明细 @@ -372,7 +378,8 @@ import { listQuotation, getQuotation, addQuotation, updateQuotation, import { listRfq, getRfqItems } from "@/api/bid/rfq"; import { listSupplier } from "@/api/bid/supplier"; import { addDelivery } from "@/api/bid/delivery"; -import logoImg from "@/assets/logo/logo.png"; +import { submitApproval, approveBiz, rejectBiz } from "@/api/bid/approvalAction"; +import logoImg from "@/assets/logo/logo.svg"; import html2canvas from "html2canvas"; import jsPDF from "jspdf"; @@ -495,6 +502,20 @@ export default { this.$modal.confirm("确认提交报价?提交后不可修改").then(() => submitQuotation(row.quotationId)) .then(() => { this.$modal.msgSuccess("提交成功"); this.getList(); }); }, + handleSubmitApproval(row) { + this.$modal.confirm("确认提交审批?").then(() => submitApproval("QUOTATION", row.quotationId)) + .then(() => { this.$modal.msgSuccess("已提交审批"); this.getList(); }); + }, + handleApprove(row) { + this.$modal.confirm("确认通过该报价审批?").then(() => approveBiz("QUOTATION", row.quotationId)) + .then(() => { this.$modal.msgSuccess("审批通过"); this.getList(); }); + }, + handleApprovalReject(row) { + this.$prompt("请输入驳回原因", "驳回", { inputPattern: /.+/, inputErrorMessage: "请填写原因" }) + .then(({ value }) => rejectBiz("QUOTATION", row.quotationId, value)) + .then(() => { this.$modal.msgSuccess("已驳回"); this.getList(); }) + .catch(() => {}); + }, handleAccept(row) { this.$modal.confirm("确认采纳此报价?").then(() => acceptQuotation(row.quotationId)) .then(() => { this.$modal.msgSuccess("已采纳"); this.getList(); }); @@ -591,8 +612,8 @@ export default { } catch(e) { this.$message.error("导出失败:" + e.message); } finally { this.pdfLoading = false; } }, - statusType(s) { return { draft: "info", submitted: "warning", accepted: "success", rejected: "danger" }[s] || ""; }, - statusLabel(s) { return { draft: "草稿", submitted: "已提交", accepted: "已采纳", rejected: "已拒绝" }[s] || s; }, + statusType(s) { return { draft: "info", submitted: "warning", "10": "warning", accepted: "success", rejected: "danger" }[s] || ""; }, + statusLabel(s) { return { draft: "草稿", submitted: "已提交", "10": "审批中", accepted: "已采纳", rejected: "已拒绝" }[s] || s; }, statusIcon(s) { return { draft: "el-icon-edit-outline", submitted: "el-icon-time", accepted: "el-icon-circle-check", rejected: "el-icon-circle-close" }[s] || "el-icon-document"; } } }; @@ -606,7 +627,7 @@ export default { /* ── 搜索 ── */ .jd-filter-bar { - background: #f5f5f5; + background: #ffffff; padding: 12px 16px 4px; border-radius: 2px; ::v-deep .el-form-item { @@ -677,6 +698,6 @@ export default { tbody tr:nth-child(even) td { background: #f9fbff; } } .amount-cell { color: #e4393c; font-weight: 600; } -.total-cell { font-size: 15px; background: #fff5f5 !important; font-weight: 700; } +.total-cell { font-size: 15px; background: #fafafa !important; font-weight: 700; } .pdf-footer { text-align: right; font-size: 11px; color: #aaa; margin-top: 10px; border-top: 1px solid #f0f2f5; padding-top: 8px; } diff --git a/ruoyi-ui/src/views/bid/report/components/KpiCard.vue b/ruoyi-ui/src/views/bid/report/components/KpiCard.vue index d3d03e39..1238a40f 100644 --- a/ruoyi-ui/src/views/bid/report/components/KpiCard.vue +++ b/ruoyi-ui/src/views/bid/report/components/KpiCard.vue @@ -17,7 +17,7 @@