From d457a0f31290ba12273a51e75f6c2cc714659efc Mon Sep 17 00:00:00 2001
From: zhangback <zhangback@163.com>
Date: 星期四, 27 十一月 2025 13:26:07 +0800
Subject: [PATCH] 提交

---
 tms/src/main/resources/mapper/tms/TmsQuoteItemMapper.xml                      |  131 +
 tms/src/main/java/com/ruoyi/tms/domain/TmsFinanceDetail.java                  |   30 
 tms/src/main/java/com/ruoyi/tms/domain/TmsMessageNotify.java                  |  131 +
 ui/admin-ui3/src/api/tms/tmsQuotePlan.ts                                      |   13 
 ui/admin-ui3/src/assets/tongzhi.png                                           |    0 
 tms/src/main/java/com/ruoyi/tms/domain/TmsQuoteDetail.java                    |    9 
 ui/admin-ui3/src/api/tms/tmsMessageNotify.ts                                  |   67 
 tms/src/main/java/com/ruoyi/tms/service/impl/TmsFinanceDetailServiceImpl.java |   26 
 tms/src/main/java/com/ruoyi/tms/domain/TransportRouteVi.java                  |   53 
 tms/src/main/java/com/ruoyi/tms/domain/TmsQuoteItem.java                      |   89 +
 tms/src/main/java/com/ruoyi/tms/mapper/TransportRouteViMapper.java            |    7 
 tms/src/main/java/com/ruoyi/tms/service/impl/TmsMessageNotifyServiceImpl.java |  182 ++
 tms/src/main/java/com/ruoyi/tms/service/impl/TmsFinanceServiceImpl.java       |    2 
 tms/src/main/resources/mapper/tms/TmsMessageNotifyMapper.xml                  |  161 ++
 tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuotePlanServiceImpl.java     |   65 
 tms/src/main/resources/mapper/tms/TmsFinanceDetailMapper.xml                  |   30 
 tms/src/main/java/com/ruoyi/tms/service/ITmsQuoteItemService.java             |  102 +
 tms/src/main/java/com/ruoyi/tms/mapper/TmsQuoteItemMapper.java                |   87 +
 ui/admin-ui3/src/api/tms/tmsContract.ts                                       |    2 
 ui/admin-ui3/src/router/index.ts                                              |   13 
 tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuoteDetailServiceImpl.java   |   43 
 ui/admin-ui3/src/views/tms/tmsContract/index.vue                              |   32 
 ui/admin-ui3/src/views/tms/tmsMessageNotify/index.vue                         |  249 +++
 tms/src/main/java/com/ruoyi/tms/domain/TmsDispatchOrder.java                  |   18 
 ui/admin-ui3/src/hooks/usePagePlus.ts                                         |    4 
 tms/src/main/java/com/ruoyi/tms/domain/vo/QuoteDetailItem.java                |   17 
 tms/src/main/java/com/ruoyi/tms/domain/TmsQuotePlan.java                      |    4 
 tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuoteItemServiceImpl.java     |  182 ++
 ui/admin-ui3/src/api/tms/tmsTransportRouteVi.ts                               |   22 
 ui/admin-ui3/src/views/tms/collectionTmsQuoteDetail/index.vue                 |  627 +++++++
 ui/admin-ui3/src/views/tms/tmsDispatchOrder/index.vue                         | 1204 ++++++++------
 tms/src/main/resources/mapper/tms/TmsDispatchOrderMapper.xml                  |   42 
 tms/src/main/java/com/ruoyi/tms/controller/TmsMessageNotifyController.java    |  144 +
 tms/src/main/resources/mapper/tms/TmsQuoteDetailMapper.xml                    |   12 
 tms/src/main/java/com/ruoyi/tms/controller/TmsQuoteItemController.java        |  108 +
 ui/admin-ui3/src/api/tms/tmsQuotePlanItem.ts                                  |   76 
 common/src/main/java/com/ruoyi/common/constant/Constants.java                 |    2 
 ui/admin-ui3/src/views/tms/paymentTmsQuotePlan/index.vue                      |    2 
 ui/admin-ui3/src/views/tms/tmsProject/index.vue                               |   11 
 ui/admin-ui3/src/api/tms/tmsQuoteDetail.ts                                    |   54 
 tms/src/main/java/com/ruoyi/tms/mapper/TmsMessageNotifyMapper.java            |   87 +
 ui/admin-ui3/src/layout/components/Navbar.vue                                 |   87 +
 tms/src/main/java/com/ruoyi/tms/service/ITmsMessageNotifyService.java         |  102 +
 tms/src/main/java/com/ruoyi/tms/task/ContractExpireNotifyTask.java            |  105 +
 ui/admin-ui3/src/views/tms/collectionTmsQuotePlan/index.vue                   |  153 +
 tms/src/main/java/com/ruoyi/tms/domain/vo/FinanceDetailItem.java              |   20 
 tms/src/main/resources/mapper/tms/TransportRouteViMapper.xml                  |    5 
 ui/admin-ui3/src/api/common.ts                                                |   17 
 tms/src/main/java/com/ruoyi/tms/controller/TransportRouteViController.java    |   67 
 tms/src/main/resources/mapper/tms/TmsContractMapper.xml                       |   16 
 tms/src/main/java/com/ruoyi/tms/domain/TmsContract.java                       |    5 
 51 files changed, 4,104 insertions(+), 613 deletions(-)

diff --git a/common/src/main/java/com/ruoyi/common/constant/Constants.java b/common/src/main/java/com/ruoyi/common/constant/Constants.java
index e1bb58b..4e31953 100644
--- a/common/src/main/java/com/ruoyi/common/constant/Constants.java
+++ b/common/src/main/java/com/ruoyi/common/constant/Constants.java
@@ -163,7 +163,7 @@
     /**
      * 瀹氭椂浠诲姟鐧藉悕鍗曢厤缃紙浠呭厑璁歌闂殑鍖呭悕锛屽鍏朵粬闇�瑕佸彲浠ヨ嚜琛屾坊鍔狅級
      */
-    public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.quartz.task" };
+    public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.quartz.task","com.ruoyi.tms.task" };
 
     /**
      * 瀹氭椂浠诲姟杩濊鐨勫瓧绗�
diff --git a/tms/src/main/java/com/ruoyi/tms/controller/TmsMessageNotifyController.java b/tms/src/main/java/com/ruoyi/tms/controller/TmsMessageNotifyController.java
new file mode 100644
index 0000000..09c51bb
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/controller/TmsMessageNotifyController.java
@@ -0,0 +1,144 @@
+package com.ruoyi.tms.controller;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.utils.file.DownloadExportUtil;
+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.tms.domain.TmsMessageNotify;
+import com.ruoyi.tms.service.ITmsMessageNotifyService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 娑堟伅閫氱煡Controller
+ *
+ * @author ruoyi
+ * @date 2025-11-26
+ */
+@RestController
+@RequestMapping("/tms/tmsMessageNotify")
+public class TmsMessageNotifyController extends BaseController
+{
+    @Autowired
+    private ITmsMessageNotifyService tmsMessageNotifyService;
+
+    @GetMapping("noCount")
+    public AjaxResult noCount(){
+        Long l = tmsMessageNotifyService.getBaseMapper().selectCount(new LambdaQueryWrapper<TmsMessageNotify>()
+                .eq(TmsMessageNotify::getReadStatus, 0));
+
+        List<TmsMessageNotify> messageNotifies = tmsMessageNotifyService.getBaseMapper().selectList(new LambdaQueryWrapper<TmsMessageNotify>()
+                .eq(TmsMessageNotify::getReadStatus, 0)
+                .orderByDesc(TmsMessageNotify::getId)
+                .last("limit 5")
+        );
+
+
+        Map<String,Object> has = new HashMap<>();
+        has.put("count",l);
+        has.put("list",messageNotifies);
+
+        return AjaxResult.success(has);
+    }
+
+    /**
+     * 鑾峰彇娑堟伅閫氱煡璇︾粏淇℃伅
+     */
+    @GetMapping(value = "/read/{id}")
+    public AjaxResult read(@PathVariable("id") Integer id)
+    {
+        tmsMessageNotifyService.updateById(new TmsMessageNotify(){{
+            setId(id);
+            setReadStatus(1);
+            setReadTime(new Date());
+        }});
+        return AjaxResult.success(tmsMessageNotifyService.selectTmsMessageNotifyById(id));
+    }
+
+    /**
+     * 鏌ヨ娑堟伅閫氱煡鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('tms:tmsMessageNotify:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(TmsMessageNotify tmsMessageNotify)
+    {
+        startPage();
+        List<TmsMessageNotify> list = tmsMessageNotifyService.selectTmsMessageNotifyList(tmsMessageNotify);
+        return getDataTable(list);
+    }
+
+    /**
+     * 瀵煎嚭娑堟伅閫氱煡鍒楄〃
+     * @param tmsMessageNotify 鏌ヨ鏉′欢瀵硅薄
+     */
+    @PreAuthorize("@ss.hasPermi('tms:tmsMessageNotify:export')")
+    @Log(title = "娑堟伅閫氱煡", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(TmsMessageNotify tmsMessageNotify,String exportKey)
+    {
+        tmsMessageNotifyService.export(tmsMessageNotify,exportKey);
+        return AjaxResult.success("瀵煎嚭璇锋眰鎴愬姛锛岃绋嶅悗鐐瑰嚮涓嬭浇...!");
+    }
+
+
+
+    /**
+     * 鑾峰彇娑堟伅閫氱煡璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('tms:tmsMessageNotify:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Integer id)
+    {
+        return AjaxResult.success(tmsMessageNotifyService.selectTmsMessageNotifyById(id));
+    }
+
+    /**
+     * 鏂板娑堟伅閫氱煡
+     */
+    @PreAuthorize("@ss.hasPermi('tms:tmsMessageNotify:add')")
+    @Log(title = "娑堟伅閫氱煡", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody TmsMessageNotify tmsMessageNotify)
+    {
+        return toAjax(tmsMessageNotifyService.insertTmsMessageNotify(tmsMessageNotify));
+    }
+
+    /**
+     * 淇敼娑堟伅閫氱煡
+     */
+    @PreAuthorize("@ss.hasPermi('tms:tmsMessageNotify:edit')")
+    @Log(title = "娑堟伅閫氱煡", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody TmsMessageNotify tmsMessageNotify)
+    {
+        return toAjax(tmsMessageNotifyService.updateTmsMessageNotify(tmsMessageNotify));
+    }
+
+    /**
+     * 鍒犻櫎娑堟伅閫氱煡
+     */
+    @PreAuthorize("@ss.hasPermi('tms:tmsMessageNotify:remove')")
+    @Log(title = "娑堟伅閫氱煡", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Integer[] ids)
+    {
+        return toAjax(tmsMessageNotifyService.deleteTmsMessageNotifyByIds(ids));
+    }
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/controller/TmsQuoteItemController.java b/tms/src/main/java/com/ruoyi/tms/controller/TmsQuoteItemController.java
new file mode 100644
index 0000000..1fefbe2
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/controller/TmsQuoteItemController.java
@@ -0,0 +1,108 @@
+package com.ruoyi.tms.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.utils.file.DownloadExportUtil;
+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.tms.domain.TmsQuoteItem;
+import com.ruoyi.tms.service.ITmsQuoteItemService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 鎶ヤ环椤圭洰Controller
+ *
+ * @author ruoyi
+ * @date 2025-11-26
+ */
+@RestController
+@RequestMapping("/tms/tmsQuoteItem")
+public class TmsQuoteItemController extends BaseController
+{
+    @Autowired
+    private ITmsQuoteItemService tmsQuoteItemService;
+
+
+
+    /**
+     * 鏌ヨ鎶ヤ环椤圭洰鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('tms:tmsQuoteItem:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(TmsQuoteItem tmsQuoteItem)
+    {
+        startPage();
+        List<TmsQuoteItem> list = tmsQuoteItemService.selectTmsQuoteItemList(tmsQuoteItem);
+        return getDataTable(list);
+    }
+
+    /**
+     * 瀵煎嚭鎶ヤ环椤圭洰鍒楄〃
+     * @param tmsQuoteItem 鏌ヨ鏉′欢瀵硅薄
+     */
+    @PreAuthorize("@ss.hasPermi('tms:tmsQuoteItem:export')")
+    @Log(title = "鎶ヤ环椤圭洰", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(TmsQuoteItem tmsQuoteItem,String exportKey)
+    {
+        tmsQuoteItemService.export(tmsQuoteItem,exportKey);
+        return AjaxResult.success("瀵煎嚭璇锋眰鎴愬姛锛岃绋嶅悗鐐瑰嚮涓嬭浇...!");
+    }
+
+
+
+    /**
+     * 鑾峰彇鎶ヤ环椤圭洰璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('tms:tmsQuoteItem:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Integer id)
+    {
+        return AjaxResult.success(tmsQuoteItemService.selectTmsQuoteItemById(id));
+    }
+
+    /**
+     * 鏂板鎶ヤ环椤圭洰
+     */
+    @PreAuthorize("@ss.hasPermi('tms:tmsQuoteItem:add')")
+    @Log(title = "鎶ヤ环椤圭洰", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody TmsQuoteItem tmsQuoteItem)
+    {
+        return toAjax(tmsQuoteItemService.insertTmsQuoteItem(tmsQuoteItem));
+    }
+
+    /**
+     * 淇敼鎶ヤ环椤圭洰
+     */
+    @PreAuthorize("@ss.hasPermi('tms:tmsQuoteItem:edit')")
+    @Log(title = "鎶ヤ环椤圭洰", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody TmsQuoteItem tmsQuoteItem)
+    {
+        return toAjax(tmsQuoteItemService.updateTmsQuoteItem(tmsQuoteItem));
+    }
+
+    /**
+     * 鍒犻櫎鎶ヤ环椤圭洰
+     */
+    @PreAuthorize("@ss.hasPermi('tms:tmsQuoteItem:remove')")
+    @Log(title = "鎶ヤ环椤圭洰", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Integer[] ids)
+    {
+        return toAjax(tmsQuoteItemService.deleteTmsQuoteItemByIds(ids));
+    }
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/controller/TransportRouteViController.java b/tms/src/main/java/com/ruoyi/tms/controller/TransportRouteViController.java
new file mode 100644
index 0000000..7d6c71f
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/controller/TransportRouteViController.java
@@ -0,0 +1,67 @@
+package com.ruoyi.tms.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.pagehelper.PageInfo;
+import com.ruoyi.common.constant.HttpStatus;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.PageDomain;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.core.page.TableSupport;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.tms.domain.TmsConsignor;
+import com.ruoyi.tms.domain.TransportRouteVi;
+import com.ruoyi.tms.mapper.TransportRouteViMapper;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@RestController
+@RequestMapping("/tms/transportRouteVi")
+public class TransportRouteViController extends BaseController {
+
+    @Resource
+    TransportRouteViMapper transportRouteViMapper;
+
+    /**
+     * 鏌ヨ鏀跺彂璐т汉绠$悊鍒楄〃
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(TransportRouteVi bo)
+    {
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+
+        Page<TransportRouteVi> pageParam = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
+
+        Page<TransportRouteVi> page = transportRouteViMapper.selectPage(pageParam,
+                new LambdaQueryWrapper<TransportRouteVi>()
+                        .like(StringUtils.isNotEmpty(bo.getTransportRoute()),TransportRouteVi::getTransportRoute, bo.getTransportRoute())
+                        .like(StringUtils.isNotEmpty(bo.getCustomerFullName()),TransportRouteVi::getCustomerFullName, bo.getCustomerFullName())
+                        .like(StringUtils.isNotEmpty(bo.getProjectName()),TransportRouteVi::getProjectName, bo.getProjectName())
+                        .like(StringUtils.isNotEmpty(bo.getContractName()),TransportRouteVi::getContractName, bo.getContractName())
+                        .eq(bo.getVehicleType()!=null,TransportRouteVi::getVehicleType, bo.getVehicleType())
+        );
+
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setMsg("鏌ヨ鎴愬姛");
+        rspData.setRows(page.getRecords());
+        rspData.setTotal(page.getTotal());
+        return rspData;
+    }
+
+
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Integer id)
+    {
+        return AjaxResult.success(transportRouteViMapper.selectById(id));
+    }
+
+
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/domain/TmsContract.java b/tms/src/main/java/com/ruoyi/tms/domain/TmsContract.java
index 32fcb9e..f21a7c9 100644
--- a/tms/src/main/java/com/ruoyi/tms/domain/TmsContract.java
+++ b/tms/src/main/java/com/ruoyi/tms/domain/TmsContract.java
@@ -294,5 +294,10 @@
     @TableField("remark")
     private String remark;
 
+    /** 鏄惁鏄复鏃跺悎鍚� */
+    @Excel(name = "鏄惁鏄复鏃跺悎鍚�")
+    @TableField("is_temp_contract")
+    private Integer isTempContract;
+
 
 }
diff --git a/tms/src/main/java/com/ruoyi/tms/domain/TmsDispatchOrder.java b/tms/src/main/java/com/ruoyi/tms/domain/TmsDispatchOrder.java
index 1e97f32..201fa73 100644
--- a/tms/src/main/java/com/ruoyi/tms/domain/TmsDispatchOrder.java
+++ b/tms/src/main/java/com/ruoyi/tms/domain/TmsDispatchOrder.java
@@ -450,4 +450,22 @@
 
     @TableField(exist = false)
     private BigDecimal paymentPlanAmount;
+
+
+    @TableField("is_customs")
+    private Integer isCustoms;
+
+    @TableField("start_region_code")
+    private String startRegionCode;
+    @TableField("end_region_code")
+    private String endRegionCode;
+
+    @TableField("quote_detail_id")
+    private Integer quoteDetailId;
+
+    @TableField("operation_mode")
+    private Integer operationMode;
+    @Excel(name = "鍏宠仈鎶ヤ环鏂规ID")
+    @TableField("quote_plan_id")
+    private Integer quotePlanId;
 }
\ No newline at end of file
diff --git a/tms/src/main/java/com/ruoyi/tms/domain/TmsFinanceDetail.java b/tms/src/main/java/com/ruoyi/tms/domain/TmsFinanceDetail.java
index 9dd65f8..6c19660 100644
--- a/tms/src/main/java/com/ruoyi/tms/domain/TmsFinanceDetail.java
+++ b/tms/src/main/java/com/ruoyi/tms/domain/TmsFinanceDetail.java
@@ -12,7 +12,9 @@
 import com.baomidou.mybatisplus.annotation.TableField;
 
 import java.util.Date;
+import java.util.List;
 
+import com.ruoyi.tms.domain.vo.FinanceDetailItem;
 import lombok.Data;
 
 /**
@@ -37,7 +39,7 @@
      */
     @Excel(name = "璐圭敤绫诲瀷")
     @TableField("fee_type")
-    private Integer feeType;
+    private String feeType;
 
 
     /**
@@ -129,6 +131,29 @@
     @TableField("update_by")
     private String updateBy;
 
+    /**
+     * 鍗曚环
+     */
+    @TableField("price")
+    private BigDecimal price;
+
+    /**
+     * 璁¤垂鍗曚綅
+     */
+    @TableField("unit")
+    private String unit;
+
+    /**
+     * 甯佺
+     */
+    @TableField("currency")
+    private String  currency;
+
+    /**
+     * 璁¤垂鏁伴噺
+     */
+    @TableField("count")
+    private Integer count;
 
     /**
      * 鏇存柊鏃堕棿
@@ -140,5 +165,8 @@
     @TableField("status")
     private Integer status;
 
+    @TableField(exist = false)
+    private List<FinanceDetailItem> items;
+
 
 }
diff --git a/tms/src/main/java/com/ruoyi/tms/domain/TmsMessageNotify.java b/tms/src/main/java/com/ruoyi/tms/domain/TmsMessageNotify.java
new file mode 100644
index 0000000..e08a1cf
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/domain/TmsMessageNotify.java
@@ -0,0 +1,131 @@
+package com.ruoyi.tms.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.util.Date;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableField;
+
+import java.util.Date;
+
+import lombok.Data;
+
+/**
+ * 娑堟伅閫氱煡瀵硅薄 tms_message_notify
+ *
+ * @author ruoyi
+ * @date 2025-11-26
+ */
+@Data
+public class TmsMessageNotify {
+
+
+    /**
+     * 涓婚敭ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+
+    /**
+     * 娑堟伅鏍囬
+     */
+    @Excel(name = "娑堟伅鏍囬")
+    @TableField("title")
+    private String title;
+
+
+    /**
+     * 娑堟伅鍐呭
+     */
+    @Excel(name = "娑堟伅鍐呭")
+    @TableField("content")
+    private String content;
+
+
+    /**
+     * 娑堟伅绫诲瀷锛�0绯荤粺閫氱煡 1涓氬姟閫氱煡 2鍛婅 3钀ラ攢
+     */
+    @Excel(name = "娑堟伅绫诲瀷锛�0绯荤粺閫氱煡 1涓氬姟閫氱煡 2鍛婅 3钀ラ攢")
+    @TableField("type")
+    private Integer type;
+
+
+    /**
+     * 鎺ユ敹鐢ㄦ埛ID锛圢ULL=鍏ㄤ綋锛�
+     */
+    @Excel(name = "鎺ユ敹鐢ㄦ埛ID", readConverterExp = "NULL=NULL=鍏ㄤ綋")
+    @TableField("target_uid")
+    private Integer targetUid;
+
+
+    /**
+     * 鍙戦�佺姸鎬侊細0寰呭彂閫� 1鎴愬姛 2澶辫触
+     */
+    @Excel(name = "鍙戦�佺姸鎬侊細0寰呭彂閫� 1鎴愬姛 2澶辫触")
+    @TableField("status")
+    private Integer status;
+
+
+    /**
+     * 闃呰鐘舵�侊細0鏈 1宸茶
+     */
+    @Excel(name = "闃呰鐘舵�侊細0鏈 1宸茶")
+    @TableField("read_status")
+    private Integer readStatus;
+
+
+    /**
+     * 璇诲彇鏃堕棿
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "璇诲彇鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    @TableField("read_time")
+    private Date readTime;
+
+
+    /**
+     * 鎵╁睍淇℃伅(JSON鏂囨湰)
+     */
+    @Excel(name = "鎵╁睍淇℃伅(JSON鏂囨湰)")
+    @TableField("extra_data")
+    private String extraData;
+
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @Excel(name = "鍒涘缓浜�")
+    @TableField("create_uid")
+    private Integer createUid;
+
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField("create_time")
+    private Date createTime;
+
+
+    /**
+     * 鏇存柊浜�
+     */
+    @Excel(name = "鏇存柊浜�")
+    @TableField("update_uid")
+    private Integer updateUid;
+
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField("update_time")
+    private Date updateTime;
+
+
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/domain/TmsQuoteDetail.java b/tms/src/main/java/com/ruoyi/tms/domain/TmsQuoteDetail.java
index b94b86b..18ec9d7 100644
--- a/tms/src/main/java/com/ruoyi/tms/domain/TmsQuoteDetail.java
+++ b/tms/src/main/java/com/ruoyi/tms/domain/TmsQuoteDetail.java
@@ -10,7 +10,9 @@
 import com.baomidou.mybatisplus.annotation.TableField;
 
 import java.util.Date;
+import java.util.List;
 
+import com.ruoyi.tms.domain.vo.QuoteDetailItem;
 import lombok.Data;
 
 /**
@@ -160,6 +162,10 @@
     @TableField("freight_price")
     private BigDecimal freightPrice;
 
+    @Excel(name = "甯佺")
+    @TableField("currency")
+    private String currency;
+
 
     /**
      * 鐘舵��
@@ -210,4 +216,7 @@
     @TableField("plan_type")
     private Integer planType;
 
+    @TableField(exist = false)
+    private List<QuoteDetailItem> quoteItems;
+
 }
diff --git a/tms/src/main/java/com/ruoyi/tms/domain/TmsQuoteItem.java b/tms/src/main/java/com/ruoyi/tms/domain/TmsQuoteItem.java
new file mode 100644
index 0000000..a965270
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/domain/TmsQuoteItem.java
@@ -0,0 +1,89 @@
+package com.ruoyi.tms.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.math.BigDecimal;
+
+import com.ruoyi.common.annotation.Excel;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableField;
+
+import java.util.Date;
+
+import lombok.Data;
+
+/**
+ * 鎶ヤ环椤圭洰瀵硅薄 tms_quote_item
+ *
+ * @author ruoyi
+ * @date 2025-11-26
+ */
+@Data
+public class TmsQuoteItem {
+
+
+    /**
+     * 涓婚敭ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+
+    /**
+     * 鍏宠仈鎶ヤ环鏂规ID
+     */
+    @Excel(name = "鍏宠仈鎶ヤ环鏂规ID")
+    @TableField("quote_plan_id")
+    private Integer quotePlanId;
+
+
+    /**
+     * 璐圭敤鍚嶇О
+     */
+    @Excel(name = "璐圭敤鍚嶇О")
+    @TableField("free_name")
+    private String freeName;
+
+
+    /**
+     * 鍗曚綅
+     */
+    @Excel(name = "鍗曚綅")
+    @TableField("unit")
+    private String unit;
+
+
+    /**
+     * 閲戦
+     */
+    @Excel(name = "閲戦")
+    @TableField("price")
+    private BigDecimal price;
+
+
+    /**
+     * 甯佸埗
+     */
+    @Excel(name = "甯佸埗")
+    @TableField("currency")
+    private String currency;
+
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField("create_time")
+    private Date createTime;
+
+
+    /**
+     * 淇敼鏃堕棿
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField("update_time")
+    private Date updateTime;
+
+
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/domain/TmsQuotePlan.java b/tms/src/main/java/com/ruoyi/tms/domain/TmsQuotePlan.java
index 72a04da..2f63b51 100644
--- a/tms/src/main/java/com/ruoyi/tms/domain/TmsQuotePlan.java
+++ b/tms/src/main/java/com/ruoyi/tms/domain/TmsQuotePlan.java
@@ -11,6 +11,7 @@
 import com.baomidou.mybatisplus.annotation.TableField;
 
 import java.util.Date;
+import java.util.List;
 
 import lombok.Data;
 
@@ -163,4 +164,7 @@
     @TableField("plan_type")
     private Integer planType;
 
+    @TableField(exist = false)
+    private List<TmsQuoteItem> quoteItems;
+
 }
diff --git a/tms/src/main/java/com/ruoyi/tms/domain/TransportRouteVi.java b/tms/src/main/java/com/ruoyi/tms/domain/TransportRouteVi.java
new file mode 100644
index 0000000..4455bf1
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/domain/TransportRouteVi.java
@@ -0,0 +1,53 @@
+package com.ruoyi.tms.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+@Data
+@TableName("transport_route_vi")
+public class TransportRouteVi {
+
+    /**
+     * 鎶ヤ环鏄庣粏ID
+     */
+    @TableId
+    private Integer quoteDetailId;
+
+    private Integer quotePlanId;
+
+    /**
+     * 璺嚎
+     */
+    private String transportRoute;
+
+
+
+    private String startRegionCode;
+    private String endRegionCode;
+
+    /**
+     * 瀹㈡埛ID
+     */
+    private Integer customerId;
+
+    /**
+     * 瀹㈡埛鍏ㄧО鍛�
+     */
+    private String customerFullName;
+
+    private Integer projectId;
+
+    private String projectName;
+
+
+    private Integer contractId;
+
+    private String contractName;
+
+    private Integer vehicleType;
+
+
+
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/domain/vo/FinanceDetailItem.java b/tms/src/main/java/com/ruoyi/tms/domain/vo/FinanceDetailItem.java
new file mode 100644
index 0000000..34713eb
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/domain/vo/FinanceDetailItem.java
@@ -0,0 +1,20 @@
+package com.ruoyi.tms.domain.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class FinanceDetailItem {
+
+    private String feeType;
+
+
+    private BigDecimal price;
+
+    private Integer count;
+
+    private String unit;
+
+
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/domain/vo/QuoteDetailItem.java b/tms/src/main/java/com/ruoyi/tms/domain/vo/QuoteDetailItem.java
new file mode 100644
index 0000000..67306ca
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/domain/vo/QuoteDetailItem.java
@@ -0,0 +1,17 @@
+package com.ruoyi.tms.domain.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class QuoteDetailItem {
+
+    private Integer vehicleType;
+
+
+    private BigDecimal freightPrice;
+
+    private String currency;
+
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/mapper/TmsMessageNotifyMapper.java b/tms/src/main/java/com/ruoyi/tms/mapper/TmsMessageNotifyMapper.java
new file mode 100644
index 0000000..597ac67
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/mapper/TmsMessageNotifyMapper.java
@@ -0,0 +1,87 @@
+package com.ruoyi.tms.mapper;
+
+import java.util.List;
+import com.ruoyi.tms.domain.TmsMessageNotify;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+
+/**
+ * 娑堟伅閫氱煡Mapper鎺ュ彛
+ * 
+ * @author ruoyi
+ * @date 2025-11-26
+ */
+public interface TmsMessageNotifyMapper  extends BaseMapper<TmsMessageNotify>
+{
+    /**
+     * 鏌ヨ娑堟伅閫氱煡
+     * 
+     * @param id 娑堟伅閫氱煡ID
+     * @return 娑堟伅閫氱煡
+     */
+    public TmsMessageNotify selectTmsMessageNotifyById(Integer id);
+
+    /**
+     * 鏌ヨ娑堟伅閫氱煡 璁板綍鏁�
+     *
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @return 娑堟伅閫氱煡闆嗗悎
+     */
+    public int selectTmsMessageNotifyCount(TmsMessageNotify tmsMessageNotify);
+
+    /**
+     * 鏌ヨ娑堟伅閫氱煡鍒楄〃
+     * 
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @return 娑堟伅閫氱煡闆嗗悎
+     */
+    public List<TmsMessageNotify> selectTmsMessageNotifyList(TmsMessageNotify tmsMessageNotify);
+
+    /**
+     * 鏂板娑堟伅閫氱煡
+     * 
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @return 缁撴灉
+     */
+    public int insertTmsMessageNotify(TmsMessageNotify tmsMessageNotify);
+
+    /**
+     * 鏂板娑堟伅閫氱煡[鎵归噺]
+     *
+     * @param tmsMessageNotifys 娑堟伅閫氱煡
+     * @return 缁撴灉
+     */
+    public int insertTmsMessageNotifyBatch(List<TmsMessageNotify> tmsMessageNotifys);
+
+    /**
+     * 淇敼娑堟伅閫氱煡
+     * 
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @return 缁撴灉
+     */
+    public int updateTmsMessageNotify(TmsMessageNotify tmsMessageNotify);
+
+    /**
+     * 淇敼娑堟伅閫氱煡[鎵归噺]
+     *
+     * @param tmsMessageNotifys 娑堟伅閫氱煡
+     * @return 缁撴灉
+     */
+    public int updateTmsMessageNotifyBatch(List<TmsMessageNotify> tmsMessageNotifys);
+
+    /**
+     * 鍒犻櫎娑堟伅閫氱煡
+     * 
+     * @param id 娑堟伅閫氱煡ID
+     * @return 缁撴灉
+     */
+    public int deleteTmsMessageNotifyById(Integer id);
+
+    /**
+     * 鎵归噺鍒犻櫎娑堟伅閫氱煡
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteTmsMessageNotifyByIds(Integer[] ids);
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/mapper/TmsQuoteItemMapper.java b/tms/src/main/java/com/ruoyi/tms/mapper/TmsQuoteItemMapper.java
new file mode 100644
index 0000000..c0fb2f7
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/mapper/TmsQuoteItemMapper.java
@@ -0,0 +1,87 @@
+package com.ruoyi.tms.mapper;
+
+import java.util.List;
+import com.ruoyi.tms.domain.TmsQuoteItem;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+
+/**
+ * 鎶ヤ环椤圭洰Mapper鎺ュ彛
+ * 
+ * @author ruoyi
+ * @date 2025-11-26
+ */
+public interface TmsQuoteItemMapper  extends BaseMapper<TmsQuoteItem>
+{
+    /**
+     * 鏌ヨ鎶ヤ环椤圭洰
+     * 
+     * @param id 鎶ヤ环椤圭洰ID
+     * @return 鎶ヤ环椤圭洰
+     */
+    public TmsQuoteItem selectTmsQuoteItemById(Integer id);
+
+    /**
+     * 鏌ヨ鎶ヤ环椤圭洰 璁板綍鏁�
+     *
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @return 鎶ヤ环椤圭洰闆嗗悎
+     */
+    public int selectTmsQuoteItemCount(TmsQuoteItem tmsQuoteItem);
+
+    /**
+     * 鏌ヨ鎶ヤ环椤圭洰鍒楄〃
+     * 
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @return 鎶ヤ环椤圭洰闆嗗悎
+     */
+    public List<TmsQuoteItem> selectTmsQuoteItemList(TmsQuoteItem tmsQuoteItem);
+
+    /**
+     * 鏂板鎶ヤ环椤圭洰
+     * 
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @return 缁撴灉
+     */
+    public int insertTmsQuoteItem(TmsQuoteItem tmsQuoteItem);
+
+    /**
+     * 鏂板鎶ヤ环椤圭洰[鎵归噺]
+     *
+     * @param tmsQuoteItems 鎶ヤ环椤圭洰
+     * @return 缁撴灉
+     */
+    public int insertTmsQuoteItemBatch(List<TmsQuoteItem> tmsQuoteItems);
+
+    /**
+     * 淇敼鎶ヤ环椤圭洰
+     * 
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @return 缁撴灉
+     */
+    public int updateTmsQuoteItem(TmsQuoteItem tmsQuoteItem);
+
+    /**
+     * 淇敼鎶ヤ环椤圭洰[鎵归噺]
+     *
+     * @param tmsQuoteItems 鎶ヤ环椤圭洰
+     * @return 缁撴灉
+     */
+    public int updateTmsQuoteItemBatch(List<TmsQuoteItem> tmsQuoteItems);
+
+    /**
+     * 鍒犻櫎鎶ヤ环椤圭洰
+     * 
+     * @param id 鎶ヤ环椤圭洰ID
+     * @return 缁撴灉
+     */
+    public int deleteTmsQuoteItemById(Integer id);
+
+    /**
+     * 鎵归噺鍒犻櫎鎶ヤ环椤圭洰
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteTmsQuoteItemByIds(Integer[] ids);
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/mapper/TransportRouteViMapper.java b/tms/src/main/java/com/ruoyi/tms/mapper/TransportRouteViMapper.java
new file mode 100644
index 0000000..9ecdffe
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/mapper/TransportRouteViMapper.java
@@ -0,0 +1,7 @@
+package com.ruoyi.tms.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.tms.domain.TransportRouteVi;
+
+public interface TransportRouteViMapper extends BaseMapper<TransportRouteVi> {
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/service/ITmsMessageNotifyService.java b/tms/src/main/java/com/ruoyi/tms/service/ITmsMessageNotifyService.java
new file mode 100644
index 0000000..7dee23e
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/service/ITmsMessageNotifyService.java
@@ -0,0 +1,102 @@
+package com.ruoyi.tms.service;
+
+import java.util.List;
+import com.ruoyi.tms.domain.TmsMessageNotify;
+import com.baomidou.mybatisplus.extension.service.IService;
+/**
+ * 娑堟伅閫氱煡Service鎺ュ彛
+ * 
+ * @author ruoyi
+ * @date 2025-11-26
+ */
+public interface ITmsMessageNotifyService extends IService<TmsMessageNotify>
+{
+    /**
+     * 鏌ヨ娑堟伅閫氱煡
+     * 
+     * @param id 娑堟伅閫氱煡ID
+     * @return 娑堟伅閫氱煡
+     */
+    public TmsMessageNotify selectTmsMessageNotifyById(Integer id);
+
+    /**
+     * 鏌ヨ娑堟伅閫氱煡 璁板綍鏁�
+     *
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @return 娑堟伅閫氱煡闆嗗悎
+     */
+    public int selectTmsMessageNotifyCount(TmsMessageNotify tmsMessageNotify);
+
+    /**
+     * 鏌ヨ娑堟伅閫氱煡鍒楄〃
+     * 
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @return 娑堟伅閫氱煡闆嗗悎
+     */
+    public List<TmsMessageNotify> selectTmsMessageNotifyList(TmsMessageNotify tmsMessageNotify);
+
+    /**
+     * 鏌ヨ娑堟伅閫氱煡鍒楄〃 寮傛 瀵煎嚭
+     *
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @param exportKey 瀵煎嚭鍔熻兘鐨勫敮涓�鏍囪瘑
+     * @return 娑堟伅閫氱煡闆嗗悎
+     */
+    public void export(TmsMessageNotify tmsMessageNotify, String exportKey) ;
+
+
+    /**
+     * 鏂板娑堟伅閫氱煡
+     * 
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @return 缁撴灉
+     */
+    public int insertTmsMessageNotify(TmsMessageNotify tmsMessageNotify);
+
+    /**
+     * 鏂板娑堟伅閫氱煡[鎵归噺]
+     *
+     * @param tmsMessageNotifys 娑堟伅閫氱煡
+     * @return 缁撴灉
+     */
+    public int insertTmsMessageNotifyBatch(List<TmsMessageNotify> tmsMessageNotifys);
+
+    /**
+     * 淇敼娑堟伅閫氱煡
+     * 
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @return 缁撴灉
+     */
+    public int updateTmsMessageNotify(TmsMessageNotify tmsMessageNotify);
+
+    /**
+     * 淇敼娑堟伅閫氱煡[鎵归噺]
+     *
+     * @param tmsMessageNotifys 娑堟伅閫氱煡
+     * @return 缁撴灉
+     */
+    public int updateTmsMessageNotifyBatch(List<TmsMessageNotify> tmsMessageNotifys);
+    /**
+     * 鎵归噺鍒犻櫎娑堟伅閫氱煡
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteTmsMessageNotifyByIds(String ids);
+
+    /**
+     * 鎵归噺鍒犻櫎娑堟伅閫氱煡
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteTmsMessageNotifyByIds(Integer[] ids);
+
+    /**
+     * 鍒犻櫎娑堟伅閫氱煡淇℃伅
+     * 
+     * @param id 娑堟伅閫氱煡ID
+     * @return 缁撴灉
+     */
+    public int deleteTmsMessageNotifyById(Integer id);
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/service/ITmsQuoteItemService.java b/tms/src/main/java/com/ruoyi/tms/service/ITmsQuoteItemService.java
new file mode 100644
index 0000000..f07c53b
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/service/ITmsQuoteItemService.java
@@ -0,0 +1,102 @@
+package com.ruoyi.tms.service;
+
+import java.util.List;
+import com.ruoyi.tms.domain.TmsQuoteItem;
+import com.baomidou.mybatisplus.extension.service.IService;
+/**
+ * 鎶ヤ环椤圭洰Service鎺ュ彛
+ * 
+ * @author ruoyi
+ * @date 2025-11-26
+ */
+public interface ITmsQuoteItemService extends IService<TmsQuoteItem>
+{
+    /**
+     * 鏌ヨ鎶ヤ环椤圭洰
+     * 
+     * @param id 鎶ヤ环椤圭洰ID
+     * @return 鎶ヤ环椤圭洰
+     */
+    public TmsQuoteItem selectTmsQuoteItemById(Integer id);
+
+    /**
+     * 鏌ヨ鎶ヤ环椤圭洰 璁板綍鏁�
+     *
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @return 鎶ヤ环椤圭洰闆嗗悎
+     */
+    public int selectTmsQuoteItemCount(TmsQuoteItem tmsQuoteItem);
+
+    /**
+     * 鏌ヨ鎶ヤ环椤圭洰鍒楄〃
+     * 
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @return 鎶ヤ环椤圭洰闆嗗悎
+     */
+    public List<TmsQuoteItem> selectTmsQuoteItemList(TmsQuoteItem tmsQuoteItem);
+
+    /**
+     * 鏌ヨ鎶ヤ环椤圭洰鍒楄〃 寮傛 瀵煎嚭
+     *
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @param exportKey 瀵煎嚭鍔熻兘鐨勫敮涓�鏍囪瘑
+     * @return 鎶ヤ环椤圭洰闆嗗悎
+     */
+    public void export(TmsQuoteItem tmsQuoteItem, String exportKey) ;
+
+
+    /**
+     * 鏂板鎶ヤ环椤圭洰
+     * 
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @return 缁撴灉
+     */
+    public int insertTmsQuoteItem(TmsQuoteItem tmsQuoteItem);
+
+    /**
+     * 鏂板鎶ヤ环椤圭洰[鎵归噺]
+     *
+     * @param tmsQuoteItems 鎶ヤ环椤圭洰
+     * @return 缁撴灉
+     */
+    public int insertTmsQuoteItemBatch(List<TmsQuoteItem> tmsQuoteItems);
+
+    /**
+     * 淇敼鎶ヤ环椤圭洰
+     * 
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @return 缁撴灉
+     */
+    public int updateTmsQuoteItem(TmsQuoteItem tmsQuoteItem);
+
+    /**
+     * 淇敼鎶ヤ环椤圭洰[鎵归噺]
+     *
+     * @param tmsQuoteItems 鎶ヤ环椤圭洰
+     * @return 缁撴灉
+     */
+    public int updateTmsQuoteItemBatch(List<TmsQuoteItem> tmsQuoteItems);
+    /**
+     * 鎵归噺鍒犻櫎鎶ヤ环椤圭洰
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteTmsQuoteItemByIds(String ids);
+
+    /**
+     * 鎵归噺鍒犻櫎鎶ヤ环椤圭洰
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteTmsQuoteItemByIds(Integer[] ids);
+
+    /**
+     * 鍒犻櫎鎶ヤ环椤圭洰淇℃伅
+     * 
+     * @param id 鎶ヤ环椤圭洰ID
+     * @return 缁撴灉
+     */
+    public int deleteTmsQuoteItemById(Integer id);
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/service/impl/TmsFinanceDetailServiceImpl.java b/tms/src/main/java/com/ruoyi/tms/service/impl/TmsFinanceDetailServiceImpl.java
index 4ca6cdb..ce3bc60 100644
--- a/tms/src/main/java/com/ruoyi/tms/service/impl/TmsFinanceDetailServiceImpl.java
+++ b/tms/src/main/java/com/ruoyi/tms/service/impl/TmsFinanceDetailServiceImpl.java
@@ -13,10 +13,12 @@
 import javax.annotation.Resource;
 
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.system.service.ISysUserService;
 import com.ruoyi.system.service.ISystemDataNoService;
 import com.ruoyi.tms.domain.TmsDispatchOrder;
 import com.ruoyi.tms.domain.TmsFinance;
+import com.ruoyi.tms.domain.vo.FinanceDetailItem;
 import com.ruoyi.tms.mapper.TmsDispatchOrderMapper;
 import com.ruoyi.tms.mapper.TmsFinanceMapper;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -158,6 +160,28 @@
                 .ne(TmsFinance::getStatus, 2)
                 .last("limit 1")
         );
+
+
+        if (StringUtils.isNotEmpty(tmsFinanceDetail.getFeeType())){
+            addItem(tmsFinance, tmsFinanceDetail);
+        }
+
+        // 1銆佹煡璇㈠綋鍓嶈皟搴﹀崟瀵瑰簲鐨勮垂鐢�
+        List<FinanceDetailItem> items = tmsFinanceDetail.getItems();
+
+        if (items != null && !items.isEmpty()){
+            items.forEach(item->{
+                TmsFinanceDetail tmsFinanceDetailNew = BeanUtil.copyProperties(tmsFinanceDetail, TmsFinanceDetail.class);
+                BeanUtil.copyProperties(item, tmsFinanceDetailNew);
+                tmsFinanceDetailNew.setActualFeeAmount(item.getPrice().multiply(BigDecimal.valueOf(item.getCount())));
+                addItem(tmsFinance, tmsFinanceDetailNew);
+            });
+        }
+        return 1;
+    }
+
+
+    public void addItem (TmsFinance tmsFinance, TmsFinanceDetail tmsFinanceDetail){
         if (tmsFinance == null){
 
             TmsDispatchOrder tmsDispatchOrder = tmsDispatchOrderMapper.selectTmsDispatchOrderById(tmsFinanceDetail.getDispatchOrderId());
@@ -189,7 +213,7 @@
         tmsFinanceDetail.setCreateId(SecurityUtils.getUserId());
         tmsFinanceDetail.setFeeCreateTime(DateUtils.getNowDate());
         tmsFinanceDetail.setCreateTime(DateUtils.getNowDate());
-        return tmsFinanceDetailMapper.insertTmsFinanceDetail(tmsFinanceDetail);
+        tmsFinanceDetailMapper.insertTmsFinanceDetail(tmsFinanceDetail);
     }
 
     /**
diff --git a/tms/src/main/java/com/ruoyi/tms/service/impl/TmsFinanceServiceImpl.java b/tms/src/main/java/com/ruoyi/tms/service/impl/TmsFinanceServiceImpl.java
index 359061d..1541a12 100644
--- a/tms/src/main/java/com/ruoyi/tms/service/impl/TmsFinanceServiceImpl.java
+++ b/tms/src/main/java/com/ruoyi/tms/service/impl/TmsFinanceServiceImpl.java
@@ -153,7 +153,7 @@
             TmsFinanceDetail tmsFinanceDetail = new TmsFinanceDetail();
             tmsFinanceDetail.setFinanceId(item.getId());
             tmsFinanceDetail.setFinanceType(item.getType());
-            tmsFinanceDetail.setFeeType(99);
+            tmsFinanceDetail.setFeeType("99");
             tmsFinanceDetail.setInitialFeeAmount(tmsQuoteDetail.getFreightPrice());
             tmsFinanceDetail.setActualFeeAmount(tmsQuoteDetail.getFreightPrice());
             tmsFinanceDetail.setDispatchOrderId(item.getDispatchId());
diff --git a/tms/src/main/java/com/ruoyi/tms/service/impl/TmsMessageNotifyServiceImpl.java b/tms/src/main/java/com/ruoyi/tms/service/impl/TmsMessageNotifyServiceImpl.java
new file mode 100644
index 0000000..4230bde
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/service/impl/TmsMessageNotifyServiceImpl.java
@@ -0,0 +1,182 @@
+package com.ruoyi.tms.service.impl;
+
+import java.util.List;
+
+import com.ruoyi.common.utils.DateUtils;
+import javax.annotation.Resource;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.stereotype.Service;
+import org.springframework.scheduling.annotation.Async;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.ruoyi.common.utils.PageUtils;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.common.core.service.BaseService;
+
+import com.ruoyi.tms.mapper.TmsMessageNotifyMapper;
+import com.ruoyi.tms.domain.TmsMessageNotify;
+import com.ruoyi.tms.service.ITmsMessageNotifyService;
+import com.ruoyi.common.core.text.Convert;
+
+/**
+ * 娑堟伅閫氱煡Service涓氬姟灞傚鐞�
+ *
+ * @author ruoyi
+ * @date 2025-11-26
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class TmsMessageNotifyServiceImpl  extends BaseService<TmsMessageNotifyMapper, TmsMessageNotify> implements ITmsMessageNotifyService
+{
+    protected final Logger logger = LoggerFactory.getLogger(getClass());
+    @Resource
+    private TmsMessageNotifyMapper tmsMessageNotifyMapper;
+
+
+    /**
+     * 鏌ヨ娑堟伅閫氱煡
+     *
+     * @param id 娑堟伅閫氱煡ID
+     * @return 娑堟伅閫氱煡
+     */
+    @DataSource(DataSourceType.SLAVE)
+    @Override
+    public TmsMessageNotify selectTmsMessageNotifyById(Integer id)
+    {
+        return tmsMessageNotifyMapper.selectTmsMessageNotifyById(id);
+    }
+
+    /**
+     * 鏌ヨ娑堟伅閫氱煡 璁板綍鏁�
+     *
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @return 娑堟伅閫氱煡闆嗗悎
+     */
+    @DataSource(DataSourceType.SLAVE)
+    @Override
+    public int selectTmsMessageNotifyCount(TmsMessageNotify tmsMessageNotify)
+    {
+        return tmsMessageNotifyMapper.selectTmsMessageNotifyCount(tmsMessageNotify);
+    }
+
+    /**
+     * 鏌ヨ娑堟伅閫氱煡鍒楄〃
+     *
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @return 娑堟伅閫氱煡
+     */
+    @DataSource(DataSourceType.SLAVE)
+    @Override
+    public List<TmsMessageNotify> selectTmsMessageNotifyList(TmsMessageNotify tmsMessageNotify)
+    {
+        return tmsMessageNotifyMapper.selectTmsMessageNotifyList(tmsMessageNotify);
+    }
+
+    /**
+     * 鏌ヨ娑堟伅閫氱煡鍒楄〃 寮傛 瀵煎嚭
+     *
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @param exportKey 瀵煎嚭鍔熻兘鐨勫敮涓�鏍囪瘑
+     * @return 娑堟伅閫氱煡闆嗗悎
+     */
+    @DataSource(DataSourceType.SLAVE)
+    @Async
+    @Override
+    public void export(TmsMessageNotify tmsMessageNotify,String exportKey) {
+
+        super.export(TmsMessageNotify.class,exportKey,"tmsMessageNotifyData",(pageNum)->{
+            PageUtils.startPage(pageNum, Constants.EXPORT_PATE_SIZE);
+            return selectTmsMessageNotifyList(tmsMessageNotify);
+        });
+    }
+
+
+    /**
+     * 鏂板娑堟伅閫氱煡
+     *
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertTmsMessageNotify(TmsMessageNotify tmsMessageNotify)
+    {
+        tmsMessageNotify.setCreateTime(DateUtils.getNowDate());
+        return tmsMessageNotifyMapper.insertTmsMessageNotify(tmsMessageNotify);
+    }
+
+    /**
+     * 鏂板娑堟伅閫氱煡[鎵归噺]
+     *
+     * @param tmsMessageNotifys 娑堟伅閫氱煡
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertTmsMessageNotifyBatch(List<TmsMessageNotify> tmsMessageNotifys)
+    {
+        int rows = tmsMessageNotifyMapper.insertTmsMessageNotifyBatch(tmsMessageNotifys);
+        return rows;
+    }
+
+    /**
+     * 淇敼娑堟伅閫氱煡
+     *
+     * @param tmsMessageNotify 娑堟伅閫氱煡
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateTmsMessageNotify(TmsMessageNotify tmsMessageNotify)
+    {
+        tmsMessageNotify.setUpdateTime(DateUtils.getNowDate());
+        return tmsMessageNotifyMapper.updateTmsMessageNotify(tmsMessageNotify);
+    }
+
+    /**
+     * 淇敼娑堟伅閫氱煡[鎵归噺]
+     *
+     * @param tmsMessageNotifys 娑堟伅閫氱煡
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateTmsMessageNotifyBatch(List<TmsMessageNotify> tmsMessageNotifys){
+        return tmsMessageNotifyMapper.updateTmsMessageNotifyBatch(tmsMessageNotifys);
+    }
+
+    /**
+     * 鍒犻櫎娑堟伅閫氱煡瀵硅薄
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteTmsMessageNotifyByIds(String ids)
+    {
+        return deleteTmsMessageNotifyByIds(Convert.toIntArray(ids));
+    }
+
+    /**
+     * 鍒犻櫎娑堟伅閫氱煡瀵硅薄
+     *
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteTmsMessageNotifyByIds(Integer[] ids)
+    {
+        return tmsMessageNotifyMapper.deleteTmsMessageNotifyByIds(ids);
+    }
+
+    /**
+     * 鍒犻櫎娑堟伅閫氱煡淇℃伅
+     *
+     * @param id 娑堟伅閫氱煡ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteTmsMessageNotifyById(Integer id)
+    {
+        return tmsMessageNotifyMapper.deleteTmsMessageNotifyById(id);
+    }
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuoteDetailServiceImpl.java b/tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuoteDetailServiceImpl.java
index 580ef51..aa27ac6 100644
--- a/tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuoteDetailServiceImpl.java
+++ b/tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuoteDetailServiceImpl.java
@@ -2,6 +2,7 @@
 
 import java.util.List;
 
+import cn.hutool.core.bean.BeanUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.common.enums.SystemDataNoEnum;
 import com.ruoyi.common.utils.DateUtils;
@@ -10,6 +11,7 @@
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.system.service.ISystemDataNoService;
 import com.ruoyi.tms.domain.TmsQuotePlan;
+import com.ruoyi.tms.domain.vo.QuoteDetailItem;
 import com.ruoyi.tms.mapper.TmsQuotePlanMapper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
@@ -111,16 +113,46 @@
      * @return 缁撴灉
      */
     @Override
-    public int insertTmsQuoteDetail(TmsQuoteDetail tmsQuoteDetail)
-    {
+    public int insertTmsQuoteDetail(TmsQuoteDetail tmsQuoteDetail) {
+
         Integer quotePlanId = tmsQuoteDetail.getQuotePlanId();
-        if (quotePlanId == null){
+        if (quotePlanId == null) {
             throw new RuntimeException("璇峰厛閫夋嫨鎶ヤ环鏂规涓嶈兘涓虹┖");
         }
+
         TmsQuotePlan tmsQuotePlan = tmsQuotePlanMapper.selectTmsQuotePlanById(quotePlanId);
-        if (tmsQuotePlan == null){
+        if (tmsQuotePlan == null) {
             throw new RuntimeException("鎶ヤ环鏂规涓嶅瓨鍦�");
         }
+
+        // 杞﹀瀷鎶ヤ环绫诲瀷
+        if (tmsQuotePlan.getPlanType() == 0) {
+            List<QuoteDetailItem> quoteItems = tmsQuoteDetail.getQuoteItems();
+            if (quoteItems == null || quoteItems.isEmpty()) {
+                throw new RuntimeException("璇峰~鍐欒溅鍨嬫姤浠�");
+            }
+
+            int count = 0;
+            for (QuoteDetailItem item : quoteItems) {
+
+                // 鎷疯礉涓诲璞″浐瀹氬睘鎬�
+                TmsQuoteDetail newDetail = BeanUtil.copyProperties(tmsQuoteDetail, TmsQuoteDetail.class);
+
+                // 鎷疯礉 item 灞炴��
+                BeanUtil.copyProperties(item ,newDetail);
+
+                // 鎻掑叆
+                addDetail(quotePlanId, tmsQuotePlan, newDetail);
+                count++;
+            }
+            return count;
+        }
+
+        // 鏅�氱被鍨�
+        return addDetail(quotePlanId, tmsQuotePlan, tmsQuoteDetail);
+    }
+
+    public int addDetail(Integer quotePlanId, TmsQuotePlan tmsQuotePlan, TmsQuoteDetail tmsQuoteDetail){
         // 1銆佸悓涓�鎶ヤ环娓呭崟锛屼笉鑳芥坊鍔犵浉鍚屻�愯矾绾�-杞﹀瀷銆戞暟鎹�
         Long l = tmsQuoteDetailMapper.selectCount(new LambdaQueryWrapper<TmsQuoteDetail>()
                 .eq(TmsQuoteDetail::getQuotePlanId, quotePlanId)
@@ -155,8 +187,11 @@
         tmsQuoteDetail.setPlanType(tmsQuotePlan.getPlanType());
         tmsQuoteDetail.setCustomerId(tmsQuotePlan.getCustomerId());
         return tmsQuoteDetailMapper.insertTmsQuoteDetail(tmsQuoteDetail);
+
     }
 
+
+
     /**
      * 鏂板鎶ヤ环鏄庣粏[鎵归噺]
      *
diff --git a/tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuoteItemServiceImpl.java b/tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuoteItemServiceImpl.java
new file mode 100644
index 0000000..542235a
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuoteItemServiceImpl.java
@@ -0,0 +1,182 @@
+package com.ruoyi.tms.service.impl;
+
+import java.util.List;
+
+import com.ruoyi.common.utils.DateUtils;
+import javax.annotation.Resource;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.stereotype.Service;
+import org.springframework.scheduling.annotation.Async;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.ruoyi.common.utils.PageUtils;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.common.core.service.BaseService;
+
+import com.ruoyi.tms.mapper.TmsQuoteItemMapper;
+import com.ruoyi.tms.domain.TmsQuoteItem;
+import com.ruoyi.tms.service.ITmsQuoteItemService;
+import com.ruoyi.common.core.text.Convert;
+
+/**
+ * 鎶ヤ环椤圭洰Service涓氬姟灞傚鐞�
+ *
+ * @author ruoyi
+ * @date 2025-11-26
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class TmsQuoteItemServiceImpl  extends BaseService<TmsQuoteItemMapper, TmsQuoteItem> implements ITmsQuoteItemService
+{
+    protected final Logger logger = LoggerFactory.getLogger(getClass());
+    @Resource
+    private TmsQuoteItemMapper tmsQuoteItemMapper;
+
+
+    /**
+     * 鏌ヨ鎶ヤ环椤圭洰
+     *
+     * @param id 鎶ヤ环椤圭洰ID
+     * @return 鎶ヤ环椤圭洰
+     */
+    @DataSource(DataSourceType.SLAVE)
+    @Override
+    public TmsQuoteItem selectTmsQuoteItemById(Integer id)
+    {
+        return tmsQuoteItemMapper.selectTmsQuoteItemById(id);
+    }
+
+    /**
+     * 鏌ヨ鎶ヤ环椤圭洰 璁板綍鏁�
+     *
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @return 鎶ヤ环椤圭洰闆嗗悎
+     */
+    @DataSource(DataSourceType.SLAVE)
+    @Override
+    public int selectTmsQuoteItemCount(TmsQuoteItem tmsQuoteItem)
+    {
+        return tmsQuoteItemMapper.selectTmsQuoteItemCount(tmsQuoteItem);
+    }
+
+    /**
+     * 鏌ヨ鎶ヤ环椤圭洰鍒楄〃
+     *
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @return 鎶ヤ环椤圭洰
+     */
+    @DataSource(DataSourceType.SLAVE)
+    @Override
+    public List<TmsQuoteItem> selectTmsQuoteItemList(TmsQuoteItem tmsQuoteItem)
+    {
+        return tmsQuoteItemMapper.selectTmsQuoteItemList(tmsQuoteItem);
+    }
+
+    /**
+     * 鏌ヨ鎶ヤ环椤圭洰鍒楄〃 寮傛 瀵煎嚭
+     *
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @param exportKey 瀵煎嚭鍔熻兘鐨勫敮涓�鏍囪瘑
+     * @return 鎶ヤ环椤圭洰闆嗗悎
+     */
+    @DataSource(DataSourceType.SLAVE)
+    @Async
+    @Override
+    public void export(TmsQuoteItem tmsQuoteItem,String exportKey) {
+
+        super.export(TmsQuoteItem.class,exportKey,"tmsQuoteItemData",(pageNum)->{
+            PageUtils.startPage(pageNum, Constants.EXPORT_PATE_SIZE);
+            return selectTmsQuoteItemList(tmsQuoteItem);
+        });
+    }
+
+
+    /**
+     * 鏂板鎶ヤ环椤圭洰
+     *
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertTmsQuoteItem(TmsQuoteItem tmsQuoteItem)
+    {
+        tmsQuoteItem.setCreateTime(DateUtils.getNowDate());
+        return tmsQuoteItemMapper.insertTmsQuoteItem(tmsQuoteItem);
+    }
+
+    /**
+     * 鏂板鎶ヤ环椤圭洰[鎵归噺]
+     *
+     * @param tmsQuoteItems 鎶ヤ环椤圭洰
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertTmsQuoteItemBatch(List<TmsQuoteItem> tmsQuoteItems)
+    {
+        int rows = tmsQuoteItemMapper.insertTmsQuoteItemBatch(tmsQuoteItems);
+        return rows;
+    }
+
+    /**
+     * 淇敼鎶ヤ环椤圭洰
+     *
+     * @param tmsQuoteItem 鎶ヤ环椤圭洰
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateTmsQuoteItem(TmsQuoteItem tmsQuoteItem)
+    {
+        tmsQuoteItem.setUpdateTime(DateUtils.getNowDate());
+        return tmsQuoteItemMapper.updateTmsQuoteItem(tmsQuoteItem);
+    }
+
+    /**
+     * 淇敼鎶ヤ环椤圭洰[鎵归噺]
+     *
+     * @param tmsQuoteItems 鎶ヤ环椤圭洰
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateTmsQuoteItemBatch(List<TmsQuoteItem> tmsQuoteItems){
+        return tmsQuoteItemMapper.updateTmsQuoteItemBatch(tmsQuoteItems);
+    }
+
+    /**
+     * 鍒犻櫎鎶ヤ环椤圭洰瀵硅薄
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteTmsQuoteItemByIds(String ids)
+    {
+        return deleteTmsQuoteItemByIds(Convert.toIntArray(ids));
+    }
+
+    /**
+     * 鍒犻櫎鎶ヤ环椤圭洰瀵硅薄
+     *
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteTmsQuoteItemByIds(Integer[] ids)
+    {
+        return tmsQuoteItemMapper.deleteTmsQuoteItemByIds(ids);
+    }
+
+    /**
+     * 鍒犻櫎鎶ヤ环椤圭洰淇℃伅
+     *
+     * @param id 鎶ヤ环椤圭洰ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteTmsQuoteItemById(Integer id)
+    {
+        return tmsQuoteItemMapper.deleteTmsQuoteItemById(id);
+    }
+}
diff --git a/tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuotePlanServiceImpl.java b/tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuotePlanServiceImpl.java
index 0427c84..6074947 100644
--- a/tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuotePlanServiceImpl.java
+++ b/tms/src/main/java/com/ruoyi/tms/service/impl/TmsQuotePlanServiceImpl.java
@@ -1,6 +1,7 @@
 package com.ruoyi.tms.service.impl;
 
 import java.util.List;
+import java.util.stream.Collectors;
 
 import com.ruoyi.common.enums.SystemDataNoEnum;
 import com.ruoyi.common.utils.DateUtils;
@@ -8,6 +9,8 @@
 
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.system.service.ISystemDataNoService;
+import com.ruoyi.tms.domain.TmsQuoteItem;
+import com.ruoyi.tms.service.ITmsQuoteItemService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.stereotype.Service;
@@ -38,6 +41,8 @@
     protected final Logger logger = LoggerFactory.getLogger(getClass());
     @Resource
     private TmsQuotePlanMapper tmsQuotePlanMapper;
+    @Autowired
+    private ITmsQuoteItemService tmsQuoteItemService;
 
     @Autowired
     ISystemDataNoService systemDataNoService;
@@ -51,7 +56,9 @@
     @Override
     public TmsQuotePlan selectTmsQuotePlanById(Integer id)
     {
-        return tmsQuotePlanMapper.selectTmsQuotePlanById(id);
+        TmsQuotePlan tmsQuotePlan = tmsQuotePlanMapper.selectTmsQuotePlanById(id);
+        tmsQuotePlan.setQuoteItems(tmsQuoteItemService.selectTmsQuoteItemList(new TmsQuoteItem(){{setQuotePlanId(id);}}));
+        return tmsQuotePlan;
     }
 
     /**
@@ -113,7 +120,22 @@
         tmsQuotePlan.setSystemCode(noByKey);
         tmsQuotePlan.setCreateBy(SecurityUtils.getUsername());
         tmsQuotePlan.setCreateTime(DateUtils.getNowDate());
-        return tmsQuotePlanMapper.insertTmsQuotePlan(tmsQuotePlan);
+        tmsQuotePlanMapper.insertTmsQuotePlan(tmsQuotePlan);
+        if (tmsQuotePlan.getPlanType() == 0){
+
+            List<TmsQuoteItem> quoteItems = tmsQuotePlan.getQuoteItems();
+            if (quoteItems != null && !quoteItems.isEmpty()){
+                quoteItems.forEach(tmsQuoteItem -> {
+                    tmsQuoteItem.setQuotePlanId(tmsQuotePlan.getId());
+                });
+                tmsQuoteItemService.insertTmsQuoteItemBatch(quoteItems);
+            }else{
+                throw new RuntimeException("璇疯嚦灏戦�夋嫨涓�涓姤浠锋柟妗�");
+            }
+
+        }
+
+        return 1;
     }
 
     /**
@@ -140,7 +162,44 @@
     {
         tmsQuotePlan.setUpdateBy(SecurityUtils.getUsername());
         tmsQuotePlan.setUpdateTime(DateUtils.getNowDate());
-        return tmsQuotePlanMapper.updateTmsQuotePlan(tmsQuotePlan);
+        int i = tmsQuotePlanMapper.updateTmsQuotePlan(tmsQuotePlan);
+
+
+        if (tmsQuotePlan.getPlanType() == 0){
+            List<TmsQuoteItem> quoteItems = tmsQuotePlan.getQuoteItems();
+            if (quoteItems != null && !quoteItems.isEmpty()){
+                List<TmsQuoteItem> tmsQuoteItems = tmsQuoteItemService.selectTmsQuoteItemList(new TmsQuoteItem() {{
+                    setQuotePlanId(tmsQuotePlan.getId());
+                }});
+
+                // 1銆佸垹闄ゆ湰娆℃彁浜ゆ病鏈夌殑鏁版嵁
+                List<Integer> collect = quoteItems.stream().map(TmsQuoteItem::getId).collect(Collectors.toList());
+                tmsQuoteItems.removeIf(tmsQuoteItem -> collect.contains(tmsQuoteItem.getId()));
+                List<Integer> collect1 = tmsQuoteItems.stream().map(TmsQuoteItem::getId).collect(Collectors.toList());
+                if (!collect1.isEmpty()){
+                    tmsQuoteItemService.getBaseMapper().deleteBatchIds(collect1);
+                }
+
+                // 2銆佹洿鏂版湰娆℃彁浜ゆ湁鐨勬暟鎹�
+                List<TmsQuoteItem> collect2 = quoteItems.stream().filter(tmsQuoteItem -> tmsQuoteItem.getId() != null).collect(Collectors.toList());
+                if (!collect2.isEmpty()){
+                    tmsQuoteItemService.updateTmsQuoteItemBatch(collect2);
+                }
+                // 3銆佹柊澧炴湰娆℃彁浜ゆ病鏈夌殑鏁版嵁
+                List<TmsQuoteItem> collect3 = quoteItems.stream().
+                        filter(tmsQuoteItem -> tmsQuoteItem.getId() == null).collect(Collectors.toList());
+
+                if (!collect3.isEmpty()){
+                    collect3.forEach(tmsQuoteItem -> tmsQuoteItem.setQuotePlanId(tmsQuotePlan.getId()));
+                    tmsQuoteItemService.insertTmsQuoteItemBatch(collect3);
+                }
+
+
+            }else{
+                throw new RuntimeException("璇疯嚦灏戦�夋嫨涓�涓姤浠锋柟妗�");
+            }
+        }
+        return i;
     }
 
     /**
diff --git a/tms/src/main/java/com/ruoyi/tms/task/ContractExpireNotifyTask.java b/tms/src/main/java/com/ruoyi/tms/task/ContractExpireNotifyTask.java
new file mode 100644
index 0000000..3845f5c
--- /dev/null
+++ b/tms/src/main/java/com/ruoyi/tms/task/ContractExpireNotifyTask.java
@@ -0,0 +1,105 @@
+package com.ruoyi.tms.task;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.ruoyi.tms.domain.TmsContract;
+import com.ruoyi.tms.domain.TmsMessageNotify;
+import com.ruoyi.tms.service.ITmsContractService;
+import com.ruoyi.tms.service.ITmsMessageNotifyService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.stream.Collectors;
+@Slf4j
+@Component("contractExpireNotifyTask")
+public class ContractExpireNotifyTask {
+
+    @Autowired
+    ITmsContractService tmsContractService;
+
+    @Autowired
+    ITmsMessageNotifyService tmsMessageNotifyService;
+
+    /**
+     * 妫�鏌ュ悎鍚屽嵆灏嗗埌鏈�
+     */
+    public void checkContractExpire() {
+        LocalDate today = LocalDate.now();
+        LocalDate targetDate = today.plusDays(90);
+
+        List<TmsContract> tmsContracts = tmsContractService.getBaseMapper().selectList(new LambdaQueryWrapper<TmsContract>()
+                        .eq(TmsContract::getContractStatus, 0)
+                .between(TmsContract::getContractEndDate, today, targetDate)
+        );
+        if (tmsContracts.isEmpty()){
+            return;
+        }
+        log.info("鍗冲皢鍒版湡鐨勫悎鍚屾湁{}涓�", tmsContracts.size());
+        // 鎻愬彇鍚堝悓ID
+        List<Integer> ids = tmsContracts.stream()
+                .map(TmsContract::getId)
+                .collect(Collectors.toList());
+
+        // 鎵归噺鏇存柊涓衡�滀复鏈熲��
+        tmsContractService.getBaseMapper().update(
+                new LambdaUpdateWrapper<TmsContract>()
+                        .in(TmsContract::getId, ids)
+                        .set(TmsContract::getContractStatus, 1)  // 1 = 涓存湡
+        );
+
+        List<TmsMessageNotify> messageNotifies = tmsContracts.stream().map(item -> {
+            TmsMessageNotify notify = new TmsMessageNotify();
+            notify.setTitle("鍚堝悓鍒版湡鎻愰啋");
+            notify.setContent("銆愬悎鍚岀紪鍙�" + item.getContractCode() + "銆戝嵆灏嗗埌鏈�");
+            notify.setType(0);
+            notify.setStatus(0);
+            notify.setReadStatus(0);
+            notify.setExtraData("{\"contactStatus\":1,\"contractId\":\"" + item.getId() + "\"}");
+            return notify;
+        }).collect(Collectors.toList());
+        tmsMessageNotifyService.insertTmsMessageNotifyBatch(messageNotifies);
+    }
+    /**
+     * 妫�鏌ュ悎鍚屽凡鍒版湡
+     */
+    public void handleExpiredContracts() {
+        LocalDate today = LocalDate.now();
+
+        List<TmsContract> tmsContracts = tmsContractService.getBaseMapper().selectList(new LambdaQueryWrapper<TmsContract>()
+                .ne(TmsContract::getContractStatus, 2)
+                .le(TmsContract::getContractEndDate, today)
+        );
+        if (tmsContracts.isEmpty()){
+            return;
+        }
+        log.info("宸插埌鏈熺殑鍚堝悓鏈墈}涓�", tmsContracts.size());
+        // 鎻愬彇鍚堝悓ID
+        List<Integer> ids = tmsContracts.stream()
+                .map(TmsContract::getId)
+                .collect(Collectors.toList());
+
+        // 鎵归噺鏇存柊涓衡�滀复鏈熲��
+        tmsContractService.getBaseMapper().update(
+                new LambdaUpdateWrapper<TmsContract>()
+                        .in(TmsContract::getId, ids)
+                        .set(TmsContract::getContractStatus, 2)  // 1 = 涓存湡
+        );
+
+        List<TmsMessageNotify> messageNotifies = tmsContracts.stream().map(item -> {
+            TmsMessageNotify notify = new TmsMessageNotify();
+            notify.setTitle("鍚堝悓鍒版湡鎻愰啋");
+            notify.setContent("銆愬悎鍚岀紪鍙�" + item.getContractCode() + "銆戝凡鍒版湡");
+            notify.setType(0);
+            notify.setStatus(0);
+            notify.setReadStatus(0);
+            notify.setExtraData("{\"contactStatus\":2, \"contractId\":\"" + item.getId() + "\"}");
+            return notify;
+        }).collect(Collectors.toList());
+        tmsMessageNotifyService.insertTmsMessageNotifyBatch(messageNotifies);
+    }
+
+
+}
diff --git a/tms/src/main/resources/mapper/tms/TmsContractMapper.xml b/tms/src/main/resources/mapper/tms/TmsContractMapper.xml
index aeac506..ba83d3c 100644
--- a/tms/src/main/resources/mapper/tms/TmsContractMapper.xml
+++ b/tms/src/main/resources/mapper/tms/TmsContractMapper.xml
@@ -41,10 +41,12 @@
         <result property="updateBy"    column="update_by"    />
         <result property="updateTime"    column="update_time"    />
         <result property="remark"    column="remark"    />
+        <result property="isTempContract"    column="is_temp_contract"    />
+
     </resultMap>
 
     <sql id="selectTmsContractVo">
-        select thisTab.id, thisTab.system_code, thisTab.contract_code, thisTab.contract_name, thisTab.contract_type, thisTab.sign_date, thisTab.contract_start_date, thisTab.contract_end_date, thisTab.contract_status, thisTab.party_a_name, thisTab.party_a_id, thisTab.party_a_contact, thisTab.party_a_contact_info, thisTab.party_b_name, thisTab.party_b_id, thisTab.party_b_contact, thisTab.party_b_contact_info, thisTab.contract_amount, thisTab.payment_method, thisTab.payment_cycle, thisTab.paid_amount, thisTab.unpaid_amount, thisTab.invoice_status, thisTab.fulfillment_status, thisTab.fulfillment_progress, thisTab.acceptance_status, thisTab.attachment_name, thisTab.attachment_path, thisTab.uploaded_by, thisTab.upload_time, thisTab.status, thisTab.create_by, thisTab.create_time, thisTab.update_by, thisTab.update_time, thisTab.remark from tms_contract AS thisTab
+        select thisTab.id, thisTab.system_code, thisTab.contract_code, thisTab.contract_name, thisTab.contract_type, thisTab.sign_date, thisTab.contract_start_date, thisTab.contract_end_date, thisTab.contract_status, thisTab.party_a_name, thisTab.party_a_id, thisTab.party_a_contact, thisTab.party_a_contact_info, thisTab.party_b_name, thisTab.party_b_id, thisTab.party_b_contact, thisTab.party_b_contact_info, thisTab.contract_amount, thisTab.payment_method, thisTab.payment_cycle, thisTab.paid_amount, thisTab.unpaid_amount, thisTab.invoice_status, thisTab.fulfillment_status, thisTab.fulfillment_progress, thisTab.acceptance_status, thisTab.attachment_name, thisTab.attachment_path, thisTab.uploaded_by, thisTab.upload_time, thisTab.status, thisTab.create_by, thisTab.create_time, thisTab.update_by, thisTab.update_time, thisTab.remark,thisTab.is_temp_contract from tms_contract AS thisTab
     </sql>
     <sql id="selectTmsContractVoCount">
         select count(0) from tms_contract as thisTab
@@ -70,6 +72,8 @@
         <if test="fulfillmentStatus != null "> and thisTab.fulfillment_status = #{fulfillmentStatus}</if>
         <if test="acceptanceStatus != null "> and thisTab.acceptance_status = #{acceptanceStatus}</if>
         <if test="status != null "> and thisTab.status = #{status}</if>
+        <if test="isTempContract != null "> and thisTab.is_temp_contract = #{isTempContract}</if>
+
     </sql>
 
     <!--鏌ヨ-->
@@ -132,6 +136,8 @@
             <if test="updateBy != null">update_by,</if>
             <if test="updateTime != null">update_time,</if>
             <if test="remark != null">remark,</if>
+            <if test="isTempContract != null">is_temp_contract,</if>
+
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="systemCode != null and systemCode != ''">#{systemCode},</if>
@@ -169,17 +175,19 @@
             <if test="updateBy != null">#{updateBy},</if>
             <if test="updateTime != null">#{updateTime},</if>
             <if test="remark != null">#{remark},</if>
+            <if test="isTempContract != null">#{isTempContract},</if>
+
         </trim>
     </insert>
 
     <insert id="insertTmsContractBatch" parameterType="java.util.List"  useGeneratedKeys="true" keyProperty="id">
         insert into tms_contract
         <trim prefix="(" suffix=") values" suffixOverrides=",">
-            id,system_code,contract_code,contract_name,contract_type,sign_date,contract_start_date,contract_end_date,contract_status,party_a_name,party_a_id,party_a_contact,party_a_contact_info,party_b_name,party_b_id,party_b_contact,party_b_contact_info,contract_amount,payment_method,payment_cycle,paid_amount,unpaid_amount,invoice_status,fulfillment_status,fulfillment_progress,acceptance_status,attachment_name,attachment_path,uploaded_by,upload_time,status,create_by,create_time,update_by,update_time,remark,
+            id,system_code,contract_code,contract_name,contract_type,sign_date,contract_start_date,contract_end_date,contract_status,party_a_name,party_a_id,party_a_contact,party_a_contact_info,party_b_name,party_b_id,party_b_contact,party_b_contact_info,contract_amount,payment_method,payment_cycle,paid_amount,unpaid_amount,invoice_status,fulfillment_status,fulfillment_progress,acceptance_status,attachment_name,attachment_path,uploaded_by,upload_time,status,create_by,create_time,update_by,update_time,remark,is_temp_contract,
         </trim>
         <foreach item="item" index="index" collection="list" separator=",">
             <trim prefix="(" suffix=") " suffixOverrides=",">
-                #{item.id},#{item.systemCode},#{item.contractCode},#{item.contractName},#{item.contractType},#{item.signDate},#{item.contractStartDate},#{item.contractEndDate},#{item.contractStatus},#{item.partyAName},#{item.partyAId},#{item.partyAContact},#{item.partyAContactInfo},#{item.partyBName},#{item.partyBId},#{item.partyBContact},#{item.partyBContactInfo},#{item.contractAmount},#{item.paymentMethod},#{item.paymentCycle},#{item.paidAmount},#{item.unpaidAmount},#{item.invoiceStatus},#{item.fulfillmentStatus},#{item.fulfillmentProgress},#{item.acceptanceStatus},#{item.attachmentName},#{item.attachmentPath},#{item.uploadedBy},#{item.uploadTime},#{item.status},#{item.createBy},#{item.createTime},#{item.updateBy},#{item.updateTime},#{item.remark},
+                #{item.id},#{item.systemCode},#{item.contractCode},#{item.contractName},#{item.contractType},#{item.signDate},#{item.contractStartDate},#{item.contractEndDate},#{item.contractStatus},#{item.partyAName},#{item.partyAId},#{item.partyAContact},#{item.partyAContactInfo},#{item.partyBName},#{item.partyBId},#{item.partyBContact},#{item.partyBContactInfo},#{item.contractAmount},#{item.paymentMethod},#{item.paymentCycle},#{item.paidAmount},#{item.unpaidAmount},#{item.invoiceStatus},#{item.fulfillmentStatus},#{item.fulfillmentProgress},#{item.acceptanceStatus},#{item.attachmentName},#{item.attachmentPath},#{item.uploadedBy},#{item.uploadTime},#{item.status},#{item.createBy},#{item.createTime},#{item.updateBy},#{item.updateTime},#{item.remark},#{item.isTempContract},
             </trim>
         </foreach>
     </insert>
@@ -223,6 +231,7 @@
             <if test="updateBy != null">update_by = #{updateBy},</if>
             <if test="updateTime != null">update_time = #{updateTime},</if>
             <if test="remark != null">remark = #{remark},</if>
+            <if test="isTempContract != null">is_temp_contract = #{isTempContract},</if>
         </trim>
         where id = #{id}
     </update>
@@ -266,6 +275,7 @@
                 <if test="item.updateBy != null">update_by = #{item.updateBy},</if>
                 <if test="item.updateTime != null">update_time = #{item.updateTime},</if>
                 <if test="item.remark != null">remark = #{item.remark},</if>
+                <if test="item.isTempContract != null">is_temp_contract = #{item.isTempContract},</if>
             </trim>
             where id = #{item.id}
         </foreach>
diff --git a/tms/src/main/resources/mapper/tms/TmsDispatchOrderMapper.xml b/tms/src/main/resources/mapper/tms/TmsDispatchOrderMapper.xml
index 7595d06..864fae6 100644
--- a/tms/src/main/resources/mapper/tms/TmsDispatchOrderMapper.xml
+++ b/tms/src/main/resources/mapper/tms/TmsDispatchOrderMapper.xml
@@ -81,10 +81,16 @@
         <result property="accountsPayableStatus"    column="accounts_payable_status"    />
         <result property="collectionPlanId"    column="collection_plan_id"    />
         <result property="paymentPlanId"    column="payment_plan_id"    />
+        <result property="isCustoms"    column="is_customs"    />
+        <result property="startRegionCode"    column="start_region_code"    />
+        <result property="endRegionCode"    column="end_region_code"    />
+        <result property="quoteDetailId"    column="quote_detail_id"    />
+        <result property="operationMode"    column="operation_mode"    />
+        <result property="quotePlanId"    column="quote_plan_id"    />
     </resultMap>
 
     <sql id="selectTmsDispatchOrderVo">
-        select thisTab.id, thisTab.dispatch_no, thisTab.customer_id, thisTab.customer_name, thisTab.customer_code, thisTab.project_id, thisTab.project_name, thisTab.contract_id, thisTab.contract_name, thisTab.order_type, thisTab.transport_line, thisTab.sign_type, thisTab.vehicle_provider_id, thisTab.vehicle_provider_name, thisTab.loading_service_provider_id, thisTab.loading_service_provider_name, thisTab.customs_service_provider_id, thisTab.customs_service_provider_name, thisTab.is_urgent, thisTab.transport_type, thisTab.load_method, thisTab.main_driver_id, thisTab.main_driver_name, thisTab.assistant_driver_id, thisTab.required_vehicle_types, thisTab.assistant_driver_name, thisTab.vehicle_id, thisTab.container_no, thisTab.license_plate, thisTab.shipper_id, thisTab.earliest_departure, thisTab.shipper_name, thisTab.latest_departure, thisTab.shipper_mobile, thisTab.earliest_arrival, thisTab.shipper_address, thisTab.latest_arrival, thisTab.departure_address, thisTab.shipper_region_code, thisTab.receiver_id, thisTab.destination_address, thisTab.receiver_name, thisTab.actual_vehicle_type, thisTab.receiver_mobile, thisTab.actual_load_start, thisTab.shipper_region_label, thisTab.receiver_address, thisTab.actual_unload_end, thisTab.receiver_region_code, thisTab.actual_departure, thisTab.actual_arrival, thisTab.actual_quantity, thisTab.actual_weight, thisTab.receiver_region_label, thisTab.actual_volume, thisTab.reweigh_weight, thisTab.container_id, thisTab.electronic_lock, thisTab.empty_mileage, thisTab.shelf_id, thisTab.empty_fuel, thisTab.shelf_code, thisTab.loaded_mileage, thisTab.loaded_fuel, thisTab.shift_no, thisTab.line_no, thisTab.status, thisTab.create_by, thisTab.create_time, thisTab.update_by, thisTab.update_time, thisTab.remark, thisTab.accounts_receivable_status, thisTab.accounts_payable_status, thisTab.collection_plan_id, thisTab.payment_plan_id from tms_dispatch_order AS thisTab
+        select thisTab.id, thisTab.dispatch_no, thisTab.customer_id, thisTab.customer_name, thisTab.customer_code, thisTab.project_id, thisTab.project_name, thisTab.contract_id, thisTab.contract_name, thisTab.order_type, thisTab.transport_line, thisTab.sign_type, thisTab.vehicle_provider_id, thisTab.vehicle_provider_name, thisTab.loading_service_provider_id, thisTab.loading_service_provider_name, thisTab.customs_service_provider_id, thisTab.customs_service_provider_name, thisTab.is_urgent, thisTab.transport_type, thisTab.load_method, thisTab.main_driver_id, thisTab.main_driver_name, thisTab.assistant_driver_id, thisTab.required_vehicle_types, thisTab.assistant_driver_name, thisTab.vehicle_id, thisTab.container_no, thisTab.license_plate, thisTab.shipper_id, thisTab.earliest_departure, thisTab.shipper_name, thisTab.latest_departure, thisTab.shipper_mobile, thisTab.earliest_arrival, thisTab.shipper_address, thisTab.latest_arrival, thisTab.departure_address, thisTab.shipper_region_code, thisTab.receiver_id, thisTab.destination_address, thisTab.receiver_name, thisTab.actual_vehicle_type, thisTab.receiver_mobile, thisTab.actual_load_start, thisTab.shipper_region_label, thisTab.receiver_address, thisTab.actual_unload_end, thisTab.receiver_region_code, thisTab.actual_departure, thisTab.actual_arrival, thisTab.actual_quantity, thisTab.actual_weight, thisTab.receiver_region_label, thisTab.actual_volume, thisTab.reweigh_weight, thisTab.container_id, thisTab.electronic_lock, thisTab.empty_mileage, thisTab.shelf_id, thisTab.empty_fuel, thisTab.shelf_code, thisTab.loaded_mileage, thisTab.loaded_fuel, thisTab.shift_no, thisTab.line_no, thisTab.status, thisTab.create_by, thisTab.create_time, thisTab.update_by, thisTab.update_time, thisTab.remark, thisTab.accounts_receivable_status, thisTab.accounts_payable_status, thisTab.collection_plan_id, thisTab.payment_plan_id , thisTab.is_customs, thisTab.start_region_code, thisTab.end_region_code, thisTab.quote_detail_id, thisTab.operation_mode, thisTab.quote_plan_id from tms_dispatch_order AS thisTab
     </sql>
     <sql id="selectTmsDispatchOrderVoCount">
         select count(0) from tms_dispatch_order as thisTab
@@ -138,6 +144,12 @@
         <if test="accountsPayableStatus != null "> and thisTab.accounts_payable_status = #{accountsPayableStatus}</if>
         <if test="collectionPlanId != null "> and thisTab.collection_plan_id = #{collectionPlanId}</if>
         <if test="paymentPlanId != null "> and thisTab.payment_plan_id = #{paymentPlanId}</if>
+        <if test="isCustoms != null "> and thisTab.is_customs = #{isCustoms}</if>
+        <if test="startRegionCode != null "> and thisTab.start_region_code = #{startRegionCode}</if>
+        <if test="endRegionCode != null "> and thisTab.end_region_code = #{endRegionCode}</if>
+        <if test="quoteDetailId != null "> and thisTab.quote_detail_id = #{quoteDetailId}</if>
+        <if test="operationMode != null "> and thisTab.operation_mode = #{operationMode}</if>
+        <if test="quotePlanId != null "> and thisTab.quote_plan_id = #{quotePlanId}</if>
     </sql>
 
     <!--鏌ヨ-->
@@ -238,6 +250,12 @@
             <if test="accountsPayableStatus != null">accounts_payable_status,</if>
             <if test="collectionPlanId != null">collection_plan_id,</if>
             <if test="paymentPlanId != null">payment_plan_id,</if>
+            <if test="isCustoms != null">is_customs,</if>
+            <if test="startRegionCode != null">start_region_code,</if>
+            <if test="endRegionCode != null">end_region_code,</if>
+            <if test="quoteDetailId != null">quote_detail_id,</if>
+            <if test="operationMode != null">operation_mode,</if>
+            <if test="quotePlanId != null">quote_plan_id,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="dispatchNo != null and dispatchNo != ''">#{dispatchNo},</if>
@@ -315,17 +333,23 @@
             <if test="accountsPayableStatus != null">#{accountsPayableStatus},</if>
             <if test="collectionPlanId != null">#{collectionPlanId},</if>
             <if test="paymentPlanId != null">#{paymentPlanId},</if>
+            <if test="isCustoms != null">#{isCustoms},</if>
+            <if test="startRegionCode != null">#{startRegionCode},</if>
+            <if test="endRegionCode != null">#{endRegionCode},</if>
+            <if test="quoteDetailId != null">#{quoteDetailId},</if>
+            <if test="operationMode != null">#{operationMode},</if>
+            <if test="quotePlanId != null">#{quotePlanId},</if>
         </trim>
     </insert>
 
     <insert id="insertTmsDispatchOrderBatch" parameterType="java.util.List"  useGeneratedKeys="true" keyProperty="id">
         insert into tms_dispatch_order
         <trim prefix="(" suffix=") values" suffixOverrides=",">
-            id,dispatch_no,customer_id,customer_name,customer_code,project_id,project_name,contract_id,contract_name,order_type,transport_line,sign_type,vehicle_provider_id,vehicle_provider_name,loading_service_provider_id,loading_service_provider_name,customs_service_provider_id,customs_service_provider_name,is_urgent,transport_type,load_method,main_driver_id,main_driver_name,assistant_driver_id,required_vehicle_types,assistant_driver_name,vehicle_id,container_no,license_plate,shipper_id,earliest_departure,shipper_name,latest_departure,shipper_mobile,earliest_arrival,shipper_address,latest_arrival,departure_address,shipper_region_code,receiver_id,destination_address,receiver_name,actual_vehicle_type,receiver_mobile,actual_load_start,shipper_region_label,receiver_address,actual_unload_end,receiver_region_code,actual_departure,actual_arrival,actual_quantity,actual_weight,receiver_region_label,actual_volume,reweigh_weight,container_id,electronic_lock,empty_mileage,shelf_id,empty_fuel,shelf_code,loaded_mileage,loaded_fuel,shift_no,line_no,status,create_by,create_time,update_by,update_time,remark,accounts_receivable_status,accounts_payable_status,collection_plan_id,payment_plan_id,
+            id,dispatch_no,customer_id,customer_name,customer_code,project_id,project_name,contract_id,contract_name,order_type,transport_line,sign_type,vehicle_provider_id,vehicle_provider_name,loading_service_provider_id,loading_service_provider_name,customs_service_provider_id,customs_service_provider_name,is_urgent,transport_type,load_method,main_driver_id,main_driver_name,assistant_driver_id,required_vehicle_types,assistant_driver_name,vehicle_id,container_no,license_plate,shipper_id,earliest_departure,shipper_name,latest_departure,shipper_mobile,earliest_arrival,shipper_address,latest_arrival,departure_address,shipper_region_code,receiver_id,destination_address,receiver_name,actual_vehicle_type,receiver_mobile,actual_load_start,shipper_region_label,receiver_address,actual_unload_end,receiver_region_code,actual_departure,actual_arrival,actual_quantity,actual_weight,receiver_region_label,actual_volume,reweigh_weight,container_id,electronic_lock,empty_mileage,shelf_id,empty_fuel,shelf_code,loaded_mileage,loaded_fuel,shift_no,line_no,status,create_by,create_time,update_by,update_time,remark,accounts_receivable_status,accounts_payable_status,collection_plan_id,payment_plan_id,is_customs,start_region_code,end_region_code,quote_detail_id,operation_mode,quote_plan_id,
         </trim>
         <foreach item="item" index="index" collection="list" separator=",">
             <trim prefix="(" suffix=") " suffixOverrides=",">
-                #{item.id},#{item.dispatchNo},#{item.customerId},#{item.customerName},#{item.customerCode},#{item.projectId},#{item.projectName},#{item.contractId},#{item.contractName},#{item.orderType},#{item.transportLine},#{item.signType},#{item.vehicleProviderId},#{item.vehicleProviderName},#{item.loadingServiceProviderId},#{item.loadingServiceProviderName},#{item.customsServiceProviderId},#{item.customsServiceProviderName},#{item.isUrgent},#{item.transportType},#{item.loadMethod},#{item.mainDriverId},#{item.mainDriverName},#{item.assistantDriverId},#{item.requiredVehicleTypes},#{item.assistantDriverName},#{item.vehicleId},#{item.containerNo},#{item.licensePlate},#{item.shipperId},#{item.earliestDeparture},#{item.shipperName},#{item.latestDeparture},#{item.shipperMobile},#{item.earliestArrival},#{item.shipperAddress},#{item.latestArrival},#{item.departureAddress},#{item.shipperRegionCode},#{item.receiverId},#{item.destinationAddress},#{item.receiverName},#{item.actualVehicleType},#{item.receiverMobile},#{item.actualLoadStart},#{item.shipperRegionLabel},#{item.receiverAddress},#{item.actualUnloadEnd},#{item.receiverRegionCode},#{item.actualDeparture},#{item.actualArrival},#{item.actualQuantity},#{item.actualWeight},#{item.receiverRegionLabel},#{item.actualVolume},#{item.reweighWeight},#{item.containerId},#{item.electronicLock},#{item.emptyMileage},#{item.shelfId},#{item.emptyFuel},#{item.shelfCode},#{item.loadedMileage},#{item.loadedFuel},#{item.shiftNo},#{item.lineNo},#{item.status},#{item.createBy},#{item.createTime},#{item.updateBy},#{item.updateTime},#{item.remark},#{item.accountsReceivableStatus},#{item.accountsPayableStatus},#{item.collectionPlanId},#{item.paymentPlanId},
+                #{item.id},#{item.dispatchNo},#{item.customerId},#{item.customerName},#{item.customerCode},#{item.projectId},#{item.projectName},#{item.contractId},#{item.contractName},#{item.orderType},#{item.transportLine},#{item.signType},#{item.vehicleProviderId},#{item.vehicleProviderName},#{item.loadingServiceProviderId},#{item.loadingServiceProviderName},#{item.customsServiceProviderId},#{item.customsServiceProviderName},#{item.isUrgent},#{item.transportType},#{item.loadMethod},#{item.mainDriverId},#{item.mainDriverName},#{item.assistantDriverId},#{item.requiredVehicleTypes},#{item.assistantDriverName},#{item.vehicleId},#{item.containerNo},#{item.licensePlate},#{item.shipperId},#{item.earliestDeparture},#{item.shipperName},#{item.latestDeparture},#{item.shipperMobile},#{item.earliestArrival},#{item.shipperAddress},#{item.latestArrival},#{item.departureAddress},#{item.shipperRegionCode},#{item.receiverId},#{item.destinationAddress},#{item.receiverName},#{item.actualVehicleType},#{item.receiverMobile},#{item.actualLoadStart},#{item.shipperRegionLabel},#{item.receiverAddress},#{item.actualUnloadEnd},#{item.receiverRegionCode},#{item.actualDeparture},#{item.actualArrival},#{item.actualQuantity},#{item.actualWeight},#{item.receiverRegionLabel},#{item.actualVolume},#{item.reweighWeight},#{item.containerId},#{item.electronicLock},#{item.emptyMileage},#{item.shelfId},#{item.emptyFuel},#{item.shelfCode},#{item.loadedMileage},#{item.loadedFuel},#{item.shiftNo},#{item.lineNo},#{item.status},#{item.createBy},#{item.createTime},#{item.updateBy},#{item.updateTime},#{item.remark},#{item.accountsReceivableStatus},#{item.accountsPayableStatus},#{item.collectionPlanId},#{item.paymentPlanId},#{item.isCustoms},#{item.startRegionCode},#{item.endRegionCode},#{item.quoteDetailId},#{item.operationMode},#{item.quotePlanId},
             </trim>
         </foreach>
     </insert>
@@ -409,6 +433,12 @@
             <if test="accountsPayableStatus != null">accounts_payable_status = #{accountsPayableStatus},</if>
             <if test="collectionPlanId != null">collection_plan_id = #{collectionPlanId},</if>
             <if test="paymentPlanId != null">payment_plan_id = #{paymentPlanId},</if>
+            <if test="isCustoms != null">is_customs = #{isCustoms},</if>
+            <if test="startRegionCode != null">start_region_code = #{startRegionCode},</if>
+            <if test="endRegionCode != null">end_region_code = #{endRegionCode},</if>
+            <if test="quoteDetailId != null">quote_detail_id = #{quoteDetailId},</if>
+            <if test="operationMode != null">operation_mode = #{operationMode},</if>
+            <if test="quotePlanId != null">quote_plan_id = #{quotePlanId},</if>
         </trim>
         where id = #{id}
     </update>
@@ -492,6 +522,12 @@
                 <if test="item.accountsPayableStatus != null">accounts_payable_status = #{item.accountsPayableStatus},</if>
                 <if test="item.collectionPlanId != null">collection_plan_id = #{item.collectionPlanId},</if>
                 <if test="item.paymentPlanId != null">payment_plan_id = #{item.paymentPlanId},</if>
+                <if test="item.isCustoms != null">is_customs = #{isCustoms},</if>
+                <if test="item.startRegionCode != null">start_region_code = #{startRegionCode},</if>
+                <if test="item.endRegionCode != null">end_region_code = #{endRegionCode},</if>
+                <if test="item.quoteDetailId != null">quote_detail_id = #{quoteDetailId},</if>
+                <if test="item.operationMode != null">operation_mode = #{operationMode},</if>
+                <if test="item.quotePlanId != null">quote_plan_id = #{quotePlanId},</if>
             </trim>
             where id = #{item.id}
         </foreach>
diff --git a/tms/src/main/resources/mapper/tms/TmsFinanceDetailMapper.xml b/tms/src/main/resources/mapper/tms/TmsFinanceDetailMapper.xml
index 1ab5313..d3dd4bf 100644
--- a/tms/src/main/resources/mapper/tms/TmsFinanceDetailMapper.xml
+++ b/tms/src/main/resources/mapper/tms/TmsFinanceDetailMapper.xml
@@ -21,10 +21,14 @@
         <result property="updateBy"    column="update_by"    />
         <result property="updateTime"    column="update_time"    />
         <result property="status"    column="status"    />
+        <result property="price"    column="price"    />
+        <result property="unit"    column="unit"    />
+        <result property="currency"    column="currency"    />
+        <result property="count"    column="count"    />
     </resultMap>
 
     <sql id="selectTmsFinanceDetailVo">
-        select thisTab.id, thisTab.fee_type, thisTab.finance_id, thisTab.finance_type, thisTab.dispatch_order_id, thisTab.data_source, thisTab.create_id, thisTab.initial_fee_amount, thisTab.actual_fee_amount, thisTab.fee_voucher_url, thisTab.fee_create_time, thisTab.create_by, thisTab.create_time, thisTab.update_by, thisTab.update_time , thisTab.status from tms_finance_detail AS thisTab
+        select thisTab.id, thisTab.fee_type, thisTab.finance_id, thisTab.finance_type, thisTab.dispatch_order_id, thisTab.data_source, thisTab.create_id, thisTab.initial_fee_amount, thisTab.actual_fee_amount, thisTab.fee_voucher_url, thisTab.fee_create_time, thisTab.create_by, thisTab.create_time, thisTab.update_by, thisTab.update_time , thisTab.status, thisTab.price, thisTab.unit, thisTab.currency, thisTab.count from tms_finance_detail AS thisTab
     </sql>
     <sql id="selectTmsFinanceDetailVoCount">
         select count(0) from tms_finance_detail as thisTab
@@ -42,6 +46,10 @@
         <if test="feeVoucherUrl != null  and feeVoucherUrl != ''"> and thisTab.fee_voucher_url = #{feeVoucherUrl}</if>
         <if test="feeCreateTime != null "> and thisTab.fee_create_time = #{feeCreateTime}</if>
         <if test="status != null "> and thisTab.status = #{status}</if>
+        <if test="price != null "> and thisTab.price = #{price}</if>
+        <if test="unit != null "> and thisTab.unit = #{unit}</if>
+        <if test="currency != null "> and thisTab.currency = #{currency}</if>
+        <if test="count != null "> and thisTab.count = #{count}</if>
     </sql>
 
     <!--鏌ヨ-->
@@ -84,6 +92,10 @@
             <if test="updateBy != null and updateBy != ''">update_by,</if>
             <if test="updateTime != null">update_time,</if>
             <if test="status != null">status,</if>
+            <if test="price != null">price,</if>
+            <if test="unit != null">unit,</if>
+            <if test="currency != null">currency,</if>
+            <if test="count != null">count,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="feeType != null">#{feeType},</if>
@@ -101,17 +113,21 @@
             <if test="updateBy != null and updateBy != ''">#{updateBy},</if>
             <if test="updateTime != null">#{updateTime},</if>
             <if test="status != null">#{status},</if>
+            <if test="price != null">#{price},</if>
+            <if test="unit != null">#{unit},</if>
+            <if test="currency != null">#{currency},</if>
+            <if test="count != null">#{count},</if>
         </trim>
     </insert>
 
     <insert id="insertTmsFinanceDetailBatch" parameterType="java.util.List"  useGeneratedKeys="true" keyProperty="id">
         insert into tms_finance_detail
         <trim prefix="(" suffix=") values" suffixOverrides=",">
-            fee_type,finance_id,finance_type,dispatch_order_id,data_source,create_id,initial_fee_amount,actual_fee_amount,fee_voucher_url,fee_create_time,create_by,create_time,status,
+            fee_type,finance_id,finance_type,dispatch_order_id,data_source,create_id,initial_fee_amount,actual_fee_amount,fee_voucher_url,fee_create_time,create_by,create_time,status,price,unit,currency,count
         </trim>
         <foreach item="item" index="index" collection="list" separator=",">
             <trim prefix="(" suffix=") " suffixOverrides=",">
-               #{item.feeType},#{item.financeId},#{item.financeType},#{item.dispatchOrderId},#{item.dataSource},#{item.createId},#{item.initialFeeAmount},#{item.actualFeeAmount},#{item.feeVoucherUrl},#{item.feeCreateTime},#{item.createBy},#{item.createTime},#{item.status},
+               #{item.feeType},#{item.financeId},#{item.financeType},#{item.dispatchOrderId},#{item.dataSource},#{item.createId},#{item.initialFeeAmount},#{item.actualFeeAmount},#{item.feeVoucherUrl},#{item.feeCreateTime},#{item.createBy},#{item.createTime},#{item.status},#{item.price},#{item.unit},#{item.currency},#{item.count}
             </trim>
         </foreach>
     </insert>
@@ -135,6 +151,10 @@
             <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
             <if test="updateTime != null">update_time = #{updateTime},</if>
             <if test="status != null">status = #{status},</if>
+            <if test="price != null">price = #{price},</if>
+            <if test="unit != null">unit = #{unit},</if>
+            <if test="currency != null">currency = #{currency},</if>
+            <if test="count != null">count = #{count},</if>
         </trim>
         where id = #{id}
     </update>
@@ -158,6 +178,10 @@
                 <if test="item.updateBy != null and item.updateBy != ''">update_by = #{item.updateBy},</if>
                 <if test="item.updateTime != null">update_time = #{item.updateTime},</if>
                 <if test="item.status != null">status = #{item.status},</if>
+                <if test="item.count != null">count = #{item.count},</if>
+                <if test="item.currency != null">currency = #{item.currency},</if>
+                <if test="item.unit != null">unit = #{item.unit},</if>
+                <if test="item.price != null">price = #{item.price},</if>
             </trim>
             where id = #{item.id}
         </foreach>
diff --git a/tms/src/main/resources/mapper/tms/TmsMessageNotifyMapper.xml b/tms/src/main/resources/mapper/tms/TmsMessageNotifyMapper.xml
new file mode 100644
index 0000000..18d586e
--- /dev/null
+++ b/tms/src/main/resources/mapper/tms/TmsMessageNotifyMapper.xml
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.tms.mapper.TmsMessageNotifyMapper">
+
+    <resultMap type="com.ruoyi.tms.domain.TmsMessageNotify" id="TmsMessageNotifyResult">
+        <result property="id"    column="id"    />
+        <result property="title"    column="title"    />
+        <result property="content"    column="content"    />
+        <result property="type"    column="type"    />
+        <result property="targetUid"    column="target_uid"    />
+        <result property="status"    column="status"    />
+        <result property="readStatus"    column="read_status"    />
+        <result property="readTime"    column="read_time"    />
+        <result property="extraData"    column="extra_data"    />
+        <result property="createUid"    column="create_uid"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateUid"    column="update_uid"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectTmsMessageNotifyVo">
+        select thisTab.id, thisTab.title, thisTab.content, thisTab.type, thisTab.target_uid, thisTab.status, thisTab.read_status, thisTab.read_time, thisTab.extra_data, thisTab.create_uid, thisTab.create_time, thisTab.update_uid, thisTab.update_time from tms_message_notify AS thisTab
+    </sql>
+    <sql id="selectTmsMessageNotifyVoCount">
+        select count(0) from tms_message_notify as thisTab
+    </sql>
+
+    <sql id="whereCondition">
+        <if test="title != null  and title != ''"> and thisTab.title = #{title}</if>
+        <if test="content != null  and content != ''"> and thisTab.content = #{content}</if>
+        <if test="type != null "> and thisTab.type = #{type}</if>
+        <if test="targetUid != null "> and thisTab.target_uid = #{targetUid}</if>
+        <if test="status != null "> and thisTab.status = #{status}</if>
+        <if test="readStatus != null "> and thisTab.read_status = #{readStatus}</if>
+        <if test="readTime != null "> and thisTab.read_time = #{readTime}</if>
+        <if test="extraData != null  and extraData != ''"> and thisTab.extra_data = #{extraData}</if>
+        <if test="createUid != null "> and thisTab.create_uid = #{createUid}</if>
+        <if test="updateUid != null "> and thisTab.update_uid = #{updateUid}</if>
+    </sql>
+
+    <!--鏌ヨ-->
+    <select id="selectTmsMessageNotifyById" parameterType="Integer" resultMap="TmsMessageNotifyResult">
+        <include refid="selectTmsMessageNotifyVo"/>
+        where id = #{id}
+    </select>
+
+    <select id="selectTmsMessageNotifyCount" parameterType="com.ruoyi.tms.domain.TmsMessageNotify" resultType="int">
+        <include refid="selectTmsMessageNotifyVoCount"/>
+        <where>
+            <include refid="whereCondition"/>
+        </where>
+    </select>
+
+    <select id="selectTmsMessageNotifyList" parameterType="com.ruoyi.tms.domain.TmsMessageNotify" resultMap="TmsMessageNotifyResult">
+        <include refid="selectTmsMessageNotifyVo"/>
+        <where>
+            <include refid="whereCondition"/>
+        </where>
+        order by thisTab.id desc
+    </select>
+
+    <!-- 鏂板 -->
+    <insert id="insertTmsMessageNotify" parameterType="com.ruoyi.tms.domain.TmsMessageNotify"  useGeneratedKeys="true" keyProperty="id">
+        insert into tms_message_notify
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="title != null and title != ''">title,</if>
+            <if test="content != null and content != ''">content,</if>
+            <if test="type != null">type,</if>
+            <if test="targetUid != null">target_uid,</if>
+            <if test="status != null">status,</if>
+            <if test="readStatus != null">read_status,</if>
+            <if test="readTime != null">read_time,</if>
+            <if test="extraData != null">extra_data,</if>
+            <if test="createUid != null">create_uid,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateUid != null">update_uid,</if>
+            <if test="updateTime != null">update_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="title != null and title != ''">#{title},</if>
+            <if test="content != null and content != ''">#{content},</if>
+            <if test="type != null">#{type},</if>
+            <if test="targetUid != null">#{targetUid},</if>
+            <if test="status != null">#{status},</if>
+            <if test="readStatus != null">#{readStatus},</if>
+            <if test="readTime != null">#{readTime},</if>
+            <if test="extraData != null">#{extraData},</if>
+            <if test="createUid != null">#{createUid},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateUid != null">#{updateUid},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <insert id="insertTmsMessageNotifyBatch" parameterType="java.util.List"  useGeneratedKeys="true" keyProperty="id">
+        insert into tms_message_notify
+        <trim prefix="(" suffix=") values" suffixOverrides=",">
+            id,title,content,type,target_uid,status,read_status,read_time,extra_data,
+        </trim>
+        <foreach item="item" index="index" collection="list" separator=",">
+            <trim prefix="(" suffix=") " suffixOverrides=",">
+                #{item.id},#{item.title},#{item.content},#{item.type},#{item.targetUid},#{item.status},#{item.readStatus},#{item.readTime},#{item.extraData},
+            </trim>
+        </foreach>
+    </insert>
+
+    <!-- 淇敼 -->
+    <update id="updateTmsMessageNotify" parameterType="com.ruoyi.tms.domain.TmsMessageNotify">
+        update tms_message_notify
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="title != null and title != ''">title = #{title},</if>
+            <if test="content != null and content != ''">content = #{content},</if>
+            <if test="type != null">type = #{type},</if>
+            <if test="targetUid != null">target_uid = #{targetUid},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="readStatus != null">read_status = #{readStatus},</if>
+            <if test="readTime != null">read_time = #{readTime},</if>
+            <if test="extraData != null">extra_data = #{extraData},</if>
+            <if test="createUid != null">create_uid = #{createUid},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateUid != null">update_uid = #{updateUid},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+    <!-- 淇敼 -->
+    <update id="updateTmsMessageNotifyBatch" parameterType="java.util.List">
+        <foreach collection="list" item="item" index="index" separator=";">
+            update tms_message_notify
+            <trim prefix="SET" suffixOverrides=",">
+                <if test="item.title != null and item.title != ''">title = #{item.title},</if>
+                <if test="item.content != null and item.content != ''">content = #{item.content},</if>
+                <if test="item.type != null">type = #{item.type},</if>
+                <if test="item.targetUid != null">target_uid = #{item.targetUid},</if>
+                <if test="item.status != null">status = #{item.status},</if>
+                <if test="item.readStatus != null">read_status = #{item.readStatus},</if>
+                <if test="item.readTime != null">read_time = #{item.readTime},</if>
+                <if test="item.extraData != null">extra_data = #{item.extraData},</if>
+                <if test="item.createUid != null">create_uid = #{item.createUid},</if>
+                <if test="item.createTime != null">create_time = #{item.createTime},</if>
+                <if test="item.updateUid != null">update_uid = #{item.updateUid},</if>
+                <if test="item.updateTime != null">update_time = #{item.updateTime},</if>
+            </trim>
+        where id = #{item.id}
+        </foreach>
+    </update>
+
+    <!--鍒犻櫎-->
+    <delete id="deleteTmsMessageNotifyById" parameterType="Integer">
+        delete from tms_message_notify where id = #{id}
+    </delete>
+    <delete id="deleteTmsMessageNotifyByIds" parameterType="Integer">
+        delete from tms_message_notify where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+</mapper>
\ No newline at end of file
diff --git a/tms/src/main/resources/mapper/tms/TmsQuoteDetailMapper.xml b/tms/src/main/resources/mapper/tms/TmsQuoteDetailMapper.xml
index 6dc4ed2..fdf7c05 100644
--- a/tms/src/main/resources/mapper/tms/TmsQuoteDetailMapper.xml
+++ b/tms/src/main/resources/mapper/tms/TmsQuoteDetailMapper.xml
@@ -30,10 +30,11 @@
         <result property="remark"    column="remark"    />
         <result property="planType"    column="plan_type"    />
         <result property="customerId"    column="customer_id"    />
+        <result property="currency"    column="currency"    />
     </resultMap>
 
     <sql id="selectTmsQuoteDetailVo">
-        select thisTab.id, thisTab.system_code, thisTab.quote_plan_id, thisTab.quote_plan_code, thisTab.vehicle_provider_id, thisTab.vehicle_provider_name, thisTab.transport_route, thisTab.start_region_code, thisTab.start_region, thisTab.start_warehouse, thisTab.end_region_code, thisTab.end_region, thisTab.end_warehouse, thisTab.vehicle_type, thisTab.transport_mode, thisTab.route_type, thisTab.freight_price, thisTab.status, thisTab.create_by, thisTab.create_time, thisTab.update_by, thisTab.update_time, thisTab.remark,thisTab.plan_type, thisTab.customer_id from tms_quote_detail AS thisTab
+        select thisTab.id, thisTab.system_code, thisTab.quote_plan_id, thisTab.quote_plan_code, thisTab.vehicle_provider_id, thisTab.vehicle_provider_name, thisTab.transport_route, thisTab.start_region_code, thisTab.start_region, thisTab.start_warehouse, thisTab.end_region_code, thisTab.end_region, thisTab.end_warehouse, thisTab.vehicle_type, thisTab.transport_mode, thisTab.route_type, thisTab.freight_price, thisTab.status, thisTab.create_by, thisTab.create_time, thisTab.update_by, thisTab.update_time, thisTab.remark,thisTab.plan_type, thisTab.customer_id , thisTab.currency from tms_quote_detail AS thisTab
     </sql>
     <sql id="selectTmsQuoteDetailVoCount">
         select count(0) from tms_quote_detail as thisTab
@@ -59,6 +60,7 @@
         <if test="status != null "> and thisTab.status = #{status}</if>
         <if test="planType != null "> and thisTab.plan_type = #{planType}</if>
         <if test="customerId != null "> and thisTab.customer_id = #{customerId}</if>
+        <if test="currency != null "> and thisTab.currency = #{currency}</if>
     </sql>
 
     <!--鏌ヨ-->
@@ -123,6 +125,7 @@
             <if test="remark != null">remark,</if>
             <if test="planType != null">plan_type,</if>
             <if test="customerId != null">customer_id,</if>
+            <if test="currency != null">currency,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="systemCode != null and systemCode != ''">#{systemCode},</if>
@@ -149,17 +152,18 @@
             <if test="remark != null">#{remark},</if>
             <if test="planType != null">#{planType},</if>
             <if test="customerId != null">#{customerId},</if>
+            <if test="currency != null">#{currency},</if>
         </trim>
     </insert>
 
     <insert id="insertTmsQuoteDetailBatch" parameterType="java.util.List"  useGeneratedKeys="true" keyProperty="id">
         insert into tms_quote_detail
         <trim prefix="(" suffix=") values" suffixOverrides=",">
-            id,system_code,quote_plan_id,quote_plan_code,vehicle_provider_id,vehicle_provider_name,transport_route,start_region_code,start_region,start_warehouse,end_region_code,end_region,end_warehouse,vehicle_type,transport_mode,route_type,freight_price,status,create_by,create_time,update_by,update_time,remark,plan_type,customer_id,
+            id,system_code,quote_plan_id,quote_plan_code,vehicle_provider_id,vehicle_provider_name,transport_route,start_region_code,start_region,start_warehouse,end_region_code,end_region,end_warehouse,vehicle_type,transport_mode,route_type,freight_price,status,create_by,create_time,update_by,update_time,remark,plan_type,customer_id,currency,
         </trim>
         <foreach item="item" index="index" collection="list" separator=",">
             <trim prefix="(" suffix=") " suffixOverrides=",">
-                #{item.id},#{item.systemCode},#{item.quotePlanId},#{item.quotePlanCode},#{item.vehicleProviderId},#{item.vehicleProviderName},#{item.transportRoute},#{item.startRegionCode},#{item.startRegion},#{item.startWarehouse},#{item.endRegionCode},#{item.endRegion},#{item.endWarehouse},#{item.vehicleType},#{item.transportMode},#{item.routeType},#{item.freightPrice},#{item.status},#{item.createBy},#{item.createTime},#{item.updateBy},#{item.updateTime},#{item.remark},#{item.planType},#{item.customerId},
+                #{item.id},#{item.systemCode},#{item.quotePlanId},#{item.quotePlanCode},#{item.vehicleProviderId},#{item.vehicleProviderName},#{item.transportRoute},#{item.startRegionCode},#{item.startRegion},#{item.startWarehouse},#{item.endRegionCode},#{item.endRegion},#{item.endWarehouse},#{item.vehicleType},#{item.transportMode},#{item.routeType},#{item.freightPrice},#{item.status},#{item.createBy},#{item.createTime},#{item.updateBy},#{item.updateTime},#{item.remark},#{item.planType},#{item.customerId},#{item.currency},
             </trim>
         </foreach>
     </insert>
@@ -192,6 +196,7 @@
             <if test="remark != null">remark = #{remark},</if>
             <if test="planType != null">plan_type = #{planType},</if>
             <if test="customerId != null">customer_id = #{customerId},</if>
+            <if test="currency != null">currency = #{currency},</if>
         </trim>
         where id = #{id}
     </update>
@@ -224,6 +229,7 @@
                 <if test="item.remark != null">remark = #{item.remark},</if>
                 <if test="item.planType != null">plan_type = #{item.planType},</if>
                 <if test="item.customerId != null">customer_id = #{item.customerId},</if>
+                <if test="item.currency != null">currency = #{item.currency},</if>
             </trim>
             where id = #{item.id}
         </foreach>
diff --git a/tms/src/main/resources/mapper/tms/TmsQuoteItemMapper.xml b/tms/src/main/resources/mapper/tms/TmsQuoteItemMapper.xml
new file mode 100644
index 0000000..d1c509e
--- /dev/null
+++ b/tms/src/main/resources/mapper/tms/TmsQuoteItemMapper.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.tms.mapper.TmsQuoteItemMapper">
+
+    <resultMap type="com.ruoyi.tms.domain.TmsQuoteItem" id="TmsQuoteItemResult">
+        <result property="id"    column="id"    />
+        <result property="quotePlanId"    column="quote_plan_id"    />
+        <result property="freeName"    column="free_name"    />
+        <result property="unit"    column="unit"    />
+        <result property="price"    column="price"    />
+        <result property="currency"    column="currency"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectTmsQuoteItemVo">
+        select thisTab.id, thisTab.quote_plan_id, thisTab.free_name, thisTab.unit, thisTab.price, thisTab.currency, thisTab.create_time, thisTab.update_time from tms_quote_item AS thisTab
+    </sql>
+    <sql id="selectTmsQuoteItemVoCount">
+        select count(0) from tms_quote_item as thisTab
+    </sql>
+
+    <sql id="whereCondition">
+        <if test="quotePlanId != null "> and thisTab.quote_plan_id = #{quotePlanId}</if>
+        <if test="freeName != null  and freeName != ''"> and  thisTab.free_name like concat('%', #{freeName}, '%')</if>
+        <if test="unit != null  and unit != ''"> and thisTab.unit = #{unit}</if>
+        <if test="price != null "> and thisTab.price = #{price}</if>
+        <if test="currency != null  and currency != ''"> and thisTab.currency = #{currency}</if>
+    </sql>
+
+    <!--鏌ヨ-->
+    <select id="selectTmsQuoteItemById" parameterType="Integer" resultMap="TmsQuoteItemResult">
+        <include refid="selectTmsQuoteItemVo"/>
+        where id = #{id}
+    </select>
+
+    <select id="selectTmsQuoteItemCount" parameterType="com.ruoyi.tms.domain.TmsQuoteItem" resultType="int">
+        <include refid="selectTmsQuoteItemVoCount"/>
+        <where>
+            <include refid="whereCondition"/>
+        </where>
+    </select>
+
+    <select id="selectTmsQuoteItemList" parameterType="com.ruoyi.tms.domain.TmsQuoteItem" resultMap="TmsQuoteItemResult">
+        <include refid="selectTmsQuoteItemVo"/>
+        <where>
+            <include refid="whereCondition"/>
+        </where>
+        order by thisTab.id desc
+    </select>
+
+    <!-- 鏂板 -->
+    <insert id="insertTmsQuoteItem" parameterType="com.ruoyi.tms.domain.TmsQuoteItem"  useGeneratedKeys="true" keyProperty="id">
+        insert into tms_quote_item
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="quotePlanId != null">quote_plan_id,</if>
+            <if test="freeName != null and freeName != ''">free_name,</if>
+            <if test="unit != null">unit,</if>
+            <if test="price != null">price,</if>
+            <if test="currency != null">currency,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="quotePlanId != null">#{quotePlanId},</if>
+            <if test="freeName != null and freeName != ''">#{freeName},</if>
+            <if test="unit != null">#{unit},</if>
+            <if test="price != null">#{price},</if>
+            <if test="currency != null">#{currency},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <insert id="insertTmsQuoteItemBatch" parameterType="java.util.List"  useGeneratedKeys="true" keyProperty="id">
+        insert into tms_quote_item
+        <trim prefix="(" suffix=") values" suffixOverrides=",">
+            id,quote_plan_id,free_name,unit,price,currency,
+        </trim>
+        <foreach item="item" index="index" collection="list" separator=",">
+            <trim prefix="(" suffix=") " suffixOverrides=",">
+                #{item.id},#{item.quotePlanId},#{item.freeName},#{item.unit},#{item.price},#{item.currency},
+            </trim>
+        </foreach>
+    </insert>
+
+    <!-- 淇敼 -->
+    <update id="updateTmsQuoteItem" parameterType="com.ruoyi.tms.domain.TmsQuoteItem">
+        update tms_quote_item
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="quotePlanId != null">quote_plan_id = #{quotePlanId},</if>
+            <if test="freeName != null and freeName != ''">free_name = #{freeName},</if>
+            <if test="unit != null">unit = #{unit},</if>
+            <if test="price != null">price = #{price},</if>
+            <if test="currency != null">currency = #{currency},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+    <!-- 淇敼 -->
+    <update id="updateTmsQuoteItemBatch" parameterType="java.util.List">
+        <foreach collection="list" item="item" index="index" separator=";">
+            update tms_quote_item
+            <trim prefix="SET" suffixOverrides=",">
+                <if test="item.quotePlanId != null">quote_plan_id = #{item.quotePlanId},</if>
+                <if test="item.freeName != null and item.freeName != ''">free_name = #{item.freeName},</if>
+                <if test="item.unit != null">unit = #{item.unit},</if>
+                <if test="item.price != null">price = #{item.price},</if>
+                <if test="item.currency != null">currency = #{item.currency},</if>
+                <if test="item.createTime != null">create_time = #{item.createTime},</if>
+                <if test="item.updateTime != null">update_time = #{item.updateTime},</if>
+            </trim>
+        where id = #{item.id}
+        </foreach>
+    </update>
+
+    <!--鍒犻櫎-->
+    <delete id="deleteTmsQuoteItemById" parameterType="Integer">
+        delete from tms_quote_item where id = #{id}
+    </delete>
+    <delete id="deleteTmsQuoteItemByIds" parameterType="Integer">
+        delete from tms_quote_item where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+</mapper>
\ No newline at end of file
diff --git a/tms/src/main/resources/mapper/tms/TransportRouteViMapper.xml b/tms/src/main/resources/mapper/tms/TransportRouteViMapper.xml
new file mode 100644
index 0000000..61fb3be
--- /dev/null
+++ b/tms/src/main/resources/mapper/tms/TransportRouteViMapper.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.tms.mapper.TransportRouteViMapper">
+
+</mapper>
diff --git a/ui/admin-ui3/src/api/common.ts b/ui/admin-ui3/src/api/common.ts
new file mode 100644
index 0000000..d03d9d4
--- /dev/null
+++ b/ui/admin-ui3/src/api/common.ts
@@ -0,0 +1,17 @@
+import request, {requestType} from "@/utils/request";
+
+
+
+export const getNoCountApi: requestType = () => {
+    return request({
+        url: '/tms/tmsMessageNotify/noCount',
+        method: 'get'
+    })
+}
+
+export const getReadApi: requestType = (id) => {
+    return request({
+        url: '/tms/tmsMessageNotify/read/'+id,
+        method: 'get'
+    })
+}
\ No newline at end of file
diff --git a/ui/admin-ui3/src/api/tms/tmsContract.ts b/ui/admin-ui3/src/api/tms/tmsContract.ts
index 301d942..07707e6 100644
--- a/ui/admin-ui3/src/api/tms/tmsContract.ts
+++ b/ui/admin-ui3/src/api/tms/tmsContract.ts
@@ -10,7 +10,7 @@
     signDate?: string,
     contractStartDate?: string,
     contractEndDate?: string,
-    contractStatus?: number,
+    contractStatus?: string,
     partyAId?: number,
     partyAName?: string,
     partyAContact?: string,
diff --git a/ui/admin-ui3/src/api/tms/tmsMessageNotify.ts b/ui/admin-ui3/src/api/tms/tmsMessageNotify.ts
new file mode 100644
index 0000000..1500756
--- /dev/null
+++ b/ui/admin-ui3/src/api/tms/tmsMessageNotify.ts
@@ -0,0 +1,67 @@
+import request,{download,requestType} from "@/utils/request";
+import {BaseEntityInterface} from "@/utils/globalInterface";
+export interface TmsMessageNotifyI extends BaseEntityInterface{
+            id ?:  number   ,            title ?:  string   ,            content ?:  string   ,            type ?:  number   ,            targetUid ?:  number   ,            status ?:  number   ,            readStatus ?:  number   ,            readTime ?:  string   ,            extraData ?:  string   ,            createUid ?:  number   ,            createTime ?:  string   ,            updateUid ?:  number   ,            updateTime ?:  string       }
+
+
+/**
+ * 鏌ヨ娑堟伅閫氱煡鍒楄〃
+ */
+export const listTmsMessageNotify:requestType = (query) => {
+    return request({
+        url: '/tms/tmsMessageNotify/list',
+        method:'get',
+        params:query
+    })
+}
+/**
+ * 鏌ヨ娑堟伅閫氱煡璇︾粏
+ */
+export const getTmsMessageNotify:requestType = (id) => {
+    return request({
+        url: '/tms/tmsMessageNotify/' + id,
+        method:'get'
+    })
+}
+
+/**
+ * 鏂板娑堟伅閫氱煡
+ */
+export const addTmsMessageNotify:requestType = (data) => {
+    return request({
+        url: '/tms/tmsMessageNotify',
+        method: 'post',
+        data
+    })
+}
+
+/**
+ * 淇敼娑堟伅閫氱煡
+ */
+export const updateTmsMessageNotify:requestType = (data) => {
+    return request({
+        url: '/tms/tmsMessageNotify',
+        method: 'put',
+        data
+    })
+}
+
+/**
+ * 鍒犻櫎娑堟伅閫氱煡
+ */
+export const delTmsMessageNotify:requestType = (id) => {
+    return request({
+        url: '/tms/tmsMessageNotify/' + id,
+        method: 'delete'
+    })
+}
+
+
+/**
+ * 瀵煎嚭娑堟伅閫氱煡
+ */
+export const exportTmsMessageNotify:requestType = (query) => {
+    return new Promise<any>(()=>{
+        download('/tms/tmsMessageNotify/export',query);
+    })
+}
diff --git a/ui/admin-ui3/src/api/tms/tmsQuoteDetail.ts b/ui/admin-ui3/src/api/tms/tmsQuoteDetail.ts
index 0f06274..30a0128 100644
--- a/ui/admin-ui3/src/api/tms/tmsQuoteDetail.ts
+++ b/ui/admin-ui3/src/api/tms/tmsQuoteDetail.ts
@@ -1,33 +1,59 @@
-import request,{download,requestType} from "@/utils/request";
+import request, {download, requestType} from "@/utils/request";
 import {BaseEntityInterface} from "@/utils/globalInterface";
-export interface TmsQuoteDetailI extends BaseEntityInterface{
-            id ?:  number   ,            systemCode ?:  string   ,            quotePlanId ?:  number   ,            quotePlanCode ?:  string   ,            vehicleProviderId ?:  number   ,            vehicleProviderName ?:  string   ,            transportRoute ?:  string   ,            startRegionCode ?:  string   ,            startRegion ?:  string   ,            startWarehouse ?:  number   ,            endRegionCode ?:  string   ,            endRegion ?:  string   ,            endWarehouse ?:  number   ,            vehicleType ?:  number   ,            transportMode ?:  number   ,            routeType ?:  number   ,            freightPrice ?:  string   ,            status ?:  number   ,            createBy ?:  string   ,            createTime ?:  string   ,            updateBy ?:  string   ,            updateTime ?:  string   ,            remark ?:  string       }
+
+export interface TmsQuoteDetailI extends BaseEntityInterface {
+    id?: number,
+    systemCode?: string,
+    quotePlanId?: number,
+    quotePlanCode?: string,
+    vehicleProviderId?: number,
+    vehicleProviderName?: string,
+    transportRoute?: string,
+    startRegionCode?: string,
+    startRegion?: string,
+    startWarehouse?: number,
+    endRegionCode?: string,
+    endRegion?: string,
+    endWarehouse?: number,
+    vehicleType?: number,
+    transportMode?: number,
+    routeType?: number,
+    freightPrice?: string,
+    status?: number,
+    createBy?: string,
+    createTime?: string,
+    updateBy?: string,
+    updateTime?: string,
+    remark?: string,
+    items?: any
+
+}
 
 
 /**
  * 鏌ヨ鎶ヤ环鏄庣粏鍒楄〃
  */
-export const listTmsQuoteDetail:requestType = (query) => {
+export const listTmsQuoteDetail: requestType = (query) => {
     return request({
         url: '/tms/tmsQuoteDetail/list',
-        method:'get',
-        params:query
+        method: 'get',
+        params: query
     })
 }
 /**
  * 鏌ヨ鎶ヤ环鏄庣粏璇︾粏
  */
-export const getTmsQuoteDetail:requestType = (id) => {
+export const getTmsQuoteDetail: requestType = (id) => {
     return request({
         url: '/tms/tmsQuoteDetail/' + id,
-        method:'get'
+        method: 'get'
     })
 }
 
 /**
  * 鏂板鎶ヤ环鏄庣粏
  */
-export const addTmsQuoteDetail:requestType = (data) => {
+export const addTmsQuoteDetail: requestType = (data) => {
     return request({
         url: '/tms/tmsQuoteDetail',
         method: 'post',
@@ -38,7 +64,7 @@
 /**
  * 淇敼鎶ヤ环鏄庣粏
  */
-export const updateTmsQuoteDetail:requestType = (data) => {
+export const updateTmsQuoteDetail: requestType = (data) => {
     return request({
         url: '/tms/tmsQuoteDetail',
         method: 'put',
@@ -49,7 +75,7 @@
 /**
  * 鍒犻櫎鎶ヤ环鏄庣粏
  */
-export const delTmsQuoteDetail:requestType = (id) => {
+export const delTmsQuoteDetail: requestType = (id) => {
     return request({
         url: '/tms/tmsQuoteDetail/' + id,
         method: 'delete'
@@ -60,8 +86,8 @@
 /**
  * 瀵煎嚭鎶ヤ环鏄庣粏
  */
-export const exportTmsQuoteDetail:requestType = (query) => {
-    return new Promise<any>(()=>{
-        download('/tms/tmsQuoteDetail/export',query);
+export const exportTmsQuoteDetail: requestType = (query) => {
+    return new Promise<any>(() => {
+        download('/tms/tmsQuoteDetail/export', query);
     })
 }
diff --git a/ui/admin-ui3/src/api/tms/tmsQuotePlan.ts b/ui/admin-ui3/src/api/tms/tmsQuotePlan.ts
index bf97bdc..023df64 100644
--- a/ui/admin-ui3/src/api/tms/tmsQuotePlan.ts
+++ b/ui/admin-ui3/src/api/tms/tmsQuotePlan.ts
@@ -1,6 +1,18 @@
 import request, {download, requestType} from "@/utils/request";
 import {BaseEntityInterface} from "@/utils/globalInterface";
 
+export interface TmsQuoteItemI extends BaseEntityInterface {
+    id?: number,
+    quotePlanId?: number,
+    freeName?: string,
+    unit?: string,
+    price?: string,
+    currency?: string,
+    createTime?: string,
+    updateTime?: string
+}
+
+
 export interface TmsQuotePlanI extends BaseEntityInterface {
     id?: number,
     systemCode?: string,
@@ -20,6 +32,7 @@
     updateTime?: string,
     remark?: string,
     planType?: string,
+    items?: TmsQuoteItemI[],
 }
 
 
diff --git a/ui/admin-ui3/src/api/tms/tmsQuotePlanItem.ts b/ui/admin-ui3/src/api/tms/tmsQuotePlanItem.ts
new file mode 100644
index 0000000..14401b5
--- /dev/null
+++ b/ui/admin-ui3/src/api/tms/tmsQuotePlanItem.ts
@@ -0,0 +1,76 @@
+import request, {download, requestType} from "@/utils/request";
+import {BaseEntityInterface} from "@/utils/globalInterface";
+
+export interface TmsQuoteItemI extends BaseEntityInterface {
+    id?: number,
+    quotePlanId?: number,
+    freeName?: string,
+    unit?: string,
+    price?: string,
+    currency?: string,
+    createTime?: string,
+    updateTime?: string
+}
+
+
+/**
+ * 鏌ヨ鎶ヤ环鏂规绠$悊鍒楄〃
+ */
+export const listTmsQuoteItem: requestType = (query) => {
+    return request({
+        url: '/tms/tmsQuoteItem/list',
+        method: 'get',
+        params: query
+    })
+}
+/**
+ * 鏌ヨ鎶ヤ环鏂规绠$悊璇︾粏
+ */
+export const getTmsQuoteItem: requestType = (id) => {
+    return request({
+        url: '/tms/tmsQuoteItem/' + id,
+        method: 'get'
+    })
+}
+
+/**
+ * 鏂板鎶ヤ环鏂规绠$悊
+ */
+export const addTmsQuoteItem: requestType = (data) => {
+    return request({
+        url: '/tms/tmsQuoteItem',
+        method: 'post',
+        data
+    })
+}
+
+/**
+ * 淇敼鎶ヤ环鏂规绠$悊
+ */
+export const updateTmsQuoteItem: requestType = (data) => {
+    return request({
+        url: '/tms/tmsQuoteItem',
+        method: 'put',
+        data
+    })
+}
+
+/**
+ * 鍒犻櫎鎶ヤ环鏂规绠$悊
+ */
+export const delTmsQuoteItem: requestType = (id) => {
+    return request({
+        url: '/tms/tmsQuoteItem/' + id,
+        method: 'delete'
+    })
+}
+
+
+/**
+ * 瀵煎嚭鎶ヤ环鏂规绠$悊
+ */
+export const exportTmsQuoteItem: requestType = (query) => {
+    return new Promise<any>(() => {
+        download('/tms/tmsQuoteItem/export', query);
+    })
+}
diff --git a/ui/admin-ui3/src/api/tms/tmsTransportRouteVi.ts b/ui/admin-ui3/src/api/tms/tmsTransportRouteVi.ts
new file mode 100644
index 0000000..0d32bb3
--- /dev/null
+++ b/ui/admin-ui3/src/api/tms/tmsTransportRouteVi.ts
@@ -0,0 +1,22 @@
+import request, {download, requestType} from "@/utils/request";
+
+
+/**
+ * 鏌ヨ鍚堝悓绠$悊鍒楄〃
+ */
+export const listTransportRouteVi: requestType = (query) => {
+    return request({
+        url: '/tms/transportRouteVi/list',
+        method: 'get',
+        params: query
+    })
+}
+/**
+ * 鏌ヨ鍚堝悓绠$悊璇︾粏
+ */
+export const getTransportRouteVi: requestType = (id) => {
+    return request({
+        url: '/tms/transportRouteVi/' + id,
+        method: 'get'
+    })
+}
diff --git a/ui/admin-ui3/src/assets/tongzhi.png b/ui/admin-ui3/src/assets/tongzhi.png
new file mode 100644
index 0000000..168620b
--- /dev/null
+++ b/ui/admin-ui3/src/assets/tongzhi.png
Binary files differ
diff --git a/ui/admin-ui3/src/hooks/usePagePlus.ts b/ui/admin-ui3/src/hooks/usePagePlus.ts
index b424829..dd0c40d 100644
--- a/ui/admin-ui3/src/hooks/usePagePlus.ts
+++ b/ui/admin-ui3/src/hooks/usePagePlus.ts
@@ -101,7 +101,7 @@
     /** 鏂板鎿嶄綔 */
     const rowSave = (row:any, done:any, loading:any) => {
         if (opts.rowSaveBegin){
-            opts.rowSaveBegin!(row);
+            opts.rowSaveBegin!(row,loading);
         }
         opts.addApi!(row).then(()=>{
             ElMessage({
@@ -118,7 +118,7 @@
     /** 淇敼鎿嶄綔 */
     const rowUpdate = (row:any, index:any, done:any, loading:any) => {
         if (opts.rowUpdateBegin){
-            opts.rowUpdateBegin!(row);
+            opts.rowUpdateBegin!(row,loading);
         }
         opts.updateApi!(row).then((response:any) => {
             ElMessage({
diff --git a/ui/admin-ui3/src/layout/components/Navbar.vue b/ui/admin-ui3/src/layout/components/Navbar.vue
index 385d488..362753d 100644
--- a/ui/admin-ui3/src/layout/components/Navbar.vue
+++ b/ui/admin-ui3/src/layout/components/Navbar.vue
@@ -5,6 +5,36 @@
     <top-nav id="topmenu-container" class="topmenu-container" v-if="settingsStore.topNav" />
 
     <div class="right-menu">
+      <el-dropdown>
+        <el-badge :value="noCount" class="item" :hidden="noCount == 0" :offset="[-1, 15]">
+          <el-image style="width: 30px;height: 30px;" :src="tongzhi"></el-image>
+          <!--        <el-button>comments</el-button>-->
+        </el-badge>
+        <template #dropdown>
+          <el-dropdown-menu>
+            <el-dropdown-item disabled v-if="noCount == 0" >
+              <div style="margin: 0 auto;width: 325px;">
+                <el-empty :image-size="30" description="鏆傛棤閫氱煡" />
+              </div>
+            </el-dropdown-item>
+            <el-dropdown-item v-for="(item,index) in noList"
+      @click="itemClick(item)"
+                              :key="index" :divided="index > 0">
+              <div style="width: 200px;">
+                <div style="line-height: 16px;font-size: 14px;margin-top: 10px;">{{ item.createTime }}</div>
+                <div>
+                  <div style="line-height: 24px;font-size: 16px;font-weight: 700;">{{ item.title }}</div>
+                  <div
+                      style="line-height: 16px;display: block;font-size: 10px;  width: 100%;text-overflow: ellipsis;white-space: nowrap;overflow: hidden;">
+                    {{ item.content }}</div>
+                </div>
+              </div>
+            </el-dropdown-item>
+            <el-dropdown-item v-if="noCount != 0">鏌ョ湅鏇村娑堟伅 銆�</el-dropdown-item>
+          </el-dropdown-menu>
+        </template>
+      </el-dropdown>
+
       <template v-if="device !== 'mobile'">
         <screenfull id="screenfull" class="right-menu-item hover-effect" />
 
@@ -32,6 +62,19 @@
         </el-dropdown>
       </div>
     </div>
+
+    <el-dialog :title="onDetail.title" v-model="open" class="avue-dialog avue-dialog--top" width="50%">
+      <div style="font-size: 14px">
+        {{onDetail.content}}
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary"   @click="goToDetail">
+            鏌ョ湅璇︽儏
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
@@ -42,11 +85,13 @@
 import Hamburger from '@/components/Hamburger/index.vue'
 import Screenfull from '@/components/Screenfull/index.vue'
 
-import {computed} from "vue";
+import {computed,ref} from "vue";
 import {useAppStore} from "@/store/modules/app";
 import {useSettingsStore} from "@/store/modules/settings";
 import {useUserStore} from "@/store/modules/user";
-
+import tongzhi from "@/assets/tongzhi.png"
+import {getNoCountApi, getReadApi} from "@/api/common";
+import router from "@/router";
 const userStore = useUserStore();
 const appStore = useAppStore();
 const settingsStore = useSettingsStore();
@@ -88,6 +133,39 @@
 function setLayout() {
   emits('setLayout');
 }
+const noCount = ref(0);
+const noList = ref([]);
+const onDetail = ref<any>({});
+const open = ref(false);
+
+/**
+ * 鏌ヨ鏈
+ */
+const getMessage = () => {
+  getNoCountApi().then(res=>{
+    let resData = res.data || {};
+    noCount.value = resData.count ;
+    noList.value  = resData.list;
+  })
+}
+getMessage();
+const itemClick = (item:any)=>{
+  getReadApi(item.id).then(res=>{
+    open.value = true;
+    onDetail.value = res.data || {};
+    getMessage();
+  })
+}
+
+const goToDetail = () => {
+  open.value =false;
+  let extraData:any = {};
+  if (onDetail.value.extraData){
+    extraData = JSON.parse(onDetail.value.extraData)
+  }
+  router.push("/customer/tmsContract?contactStatus=" + extraData.contactStatus);
+}
+
 </script>
 
 <style lang='scss' scoped>
@@ -178,4 +256,9 @@
     }
   }
 }
+.item {
+  display: flex;
+  align-items: center;
+  //margin-right: 20px;
+}
 </style>
diff --git a/ui/admin-ui3/src/router/index.ts b/ui/admin-ui3/src/router/index.ts
index 39e2f3a..5834a0f 100644
--- a/ui/admin-ui3/src/router/index.ts
+++ b/ui/admin-ui3/src/router/index.ts
@@ -97,6 +97,19 @@
         ]
     },
     {
+        path:'/collectionTmsQuotePlan',
+        component:Layout,
+        hidden:true,
+        children:[
+            {
+                path: "collectionTmsQuotePlanItem",
+                component:()=> import("@/views/tms/collectionTmsQuoteDetail/index.vue"),
+                name: "CollectionTmsQuotePlanItem",
+                meta: {title: '杩愯垂鎶ヤ环',activeMenu:'/Quotation/collectionTmsQuotePlan'}
+            }
+        ]
+    },
+    {
         path:'/monitor/job-log',
         component:Layout,
         hidden:true,
diff --git a/ui/admin-ui3/src/views/tms/collectionTmsQuoteDetail/index.vue b/ui/admin-ui3/src/views/tms/collectionTmsQuoteDetail/index.vue
new file mode 100644
index 0000000..0b89c66
--- /dev/null
+++ b/ui/admin-ui3/src/views/tms/collectionTmsQuoteDetail/index.vue
@@ -0,0 +1,627 @@
+<template>
+  <basicContainer>
+    <avue-crud
+        :option="option"
+        :table-loading="pageF.loading"
+        :data="tableData"
+        :page="page"
+        :permission="permissionList"
+        :before-open="beforeOpen"
+        v-model="form" v-model:search="queryParams"
+        ref="crudRef"
+        @row-update="rowUpdate"
+        @row-save="rowSave"
+        @refresh-change="refreshChange"
+        @row-del="rowDel"
+        @search-change="searchChange"
+        @search-reset="searchReset"
+        @selection-change="selectionChange"
+        @current-change="currentChange"
+        @size-change="sizeChange"
+        @on-load="onLoad"
+    >
+      <template #menu-left>
+        <el-button
+            type="success"
+            icon="Edit"
+            :disabled="pageF.single"
+            v-hasPermi="['tms:tmsQuoteDetail:edit']"
+            @click="handleUpdate">淇敼
+        </el-button>
+        <el-button
+            type="danger"
+            icon="Delete"
+            :disabled="pageF.multiple"
+            @click="handleDelete"
+            v-hasPermi="['tms:tmsQuoteDetail:remove']"
+        >鍒犻櫎
+        </el-button>
+        <el-button
+            type="warning"
+            plain
+            icon="Download"
+            @click="handleExport"
+            v-hasPermi="['tms:tmsQuoteDetail:export']"
+        >瀵煎嚭
+        </el-button>
+        <el-button
+            type="default"
+            plain
+            icon="Back"
+            @click="handleBack"
+        >杩斿洖
+        </el-button>
+      </template>
+      <template #items-form="scope">
+        <avue-crud
+            :option="{...itemsTableOption,selection: !scope.disabled}"          @selection-change="selectionChange2"
+
+            :data="form.items" ref="itemsCrudRef"
+        >
+          <template #freightPrice="{row}">
+            <el-input v-model="row.freightPrice" :min="1" :disabled="scope.disabled" type="number" placeholder="璇疯緭鍏ラ噾棰�"></el-input>
+          </template>
+          <template #currency="{row}">
+            <el-radio-group v-model="row.currency"  :disabled="scope.disabled">
+              <el-radio
+                  v-for="dict in sys_currency"
+                  :key="dict.value"
+                  :label="dict.value"
+              >{{ dict.label }}</el-radio>
+            </el-radio-group>
+          </template>
+
+        </avue-crud>
+      </template>
+    </avue-crud>
+
+
+  </basicContainer>
+</template>
+
+<script setup name="tmsQuoteDetail" lang="ts">
+import {
+  TmsQuoteDetailI,
+  addTmsQuoteDetail,
+  delTmsQuoteDetail,
+  exportTmsQuoteDetail,
+  getTmsQuoteDetail,
+  listTmsQuoteDetail,
+  updateTmsQuoteDetail
+} from "@/api/tms/tmsQuoteDetail";
+import useCurrentInstance from "@/utils/useCurrentInstance";
+import {computed, reactive, ref, toRefs,onBeforeMount} from "vue";
+import {PagesInterface, PageQueryInterface} from "@/utils/globalInterface";
+import {usePagePlus} from "@/hooks/usePagePlus";
+import {hasPermission} from "@/utils/permissionUtils";
+import {getTmsServiceProvider, listTmsServiceProvider} from "@/api/tms/tmsServiceProvider";
+import {getArea, getCity, getProvince, getStreet} from "@/api/tms/tmsRegion";
+import {useRoute,useRouter } from "vue-router";
+import {randomId} from "@smallwei/avue";
+
+const {proxy} = useCurrentInstance();
+const crudRef = ref();
+const route = useRoute();
+const router  = useRouter();
+
+const {vehicle_type,sys_currency} =
+    proxy.useDict("vehicle_type","sys_currency");
+
+const permissionList = computed(() => {
+  return {
+    addBtn: hasPermission(["tms:tmsQuoteDetail:add"]),
+    delBtn: hasPermission(["tms:tmsQuoteDetail:remove"]),
+    editBtn: hasPermission(["tms:tmsQuoteDetail:edit"]),
+    viewBtn: hasPermission(["tms:tmsQuoteDetail:query"]),
+  }
+})
+
+const data = reactive({
+  form: <TmsQuoteDetailI>{},
+  queryParams: <TmsQuoteDetailI & PageQueryInterface>{},
+  page: <PagesInterface>{
+    pageSize: 10,
+    total: 0,
+    currentPage: 1,
+  },
+  selectionList: [],
+  selectionList2:<any>[]
+})
+const {queryParams, form, page, selectionList,selectionList2} = toRefs(data);
+const option = ref({
+  pageKey: 'TmsQuoteDetail',
+  rowKey: 'id',
+  labelWidth: 120,
+  group:[
+    {
+      label:"鍩虹淇℃伅",
+      prop: 'jcxx',
+      column:{
+        systemCode: {
+          label: '绯荤粺缂栧彿',
+          addDisplay: false,
+          editDisplay: false,
+          viewDisplay: true,
+        },
+        quotePlanCode: {
+          label: '鍏宠仈鎶ヤ环鏂规缂栧彿',
+          addDisplay: false,
+          editDisplay: false,
+          viewDisplay: true,
+        },
+
+        startRegionCode: {
+          label: '璧风偣琛屾斂鍖哄煙',
+          addDisplay: true,
+          editDisplay: true,dataType: 'string',
+          viewDisplay: true,
+          type:'cascader',
+          rules: [
+            {
+              required: true,
+              message: "璧风偣琛屾斂鍖哄煙涓嶈兘涓虹┖", trigger: "blur"
+            }
+          ],
+          lazy: true,
+          props: {
+            label: 'name',
+            value: 'code'
+          },
+          change:({value=[]}:{value:any})=>{
+            if (value && value.length>0){
+              const cascader = crudRef.value?.getPropRef?.('startRegionCode')?.$refs?.temp;
+              console.log('cascader.getCheckedNodes()',cascader.getCheckedNodes())
+              if (cascader.getCheckedNodes() && cascader.getCheckedNodes().length >0){
+
+                form.value.startRegionCode= cascader.getCheckedNodes()[0].pathValues.toString();
+                form.value.startRegion= cascader.getCheckedNodes()[0].text!;
+                form.value.transportRoute = `${form.value.startRegion}->${form.value.endRegion}`;
+              }
+            }
+          },
+          lazyLoad (node:any, resolve:any) {
+            const stopLevel = 3;
+            const level = node.level;
+            const data = node.data || {};
+            const code = data.code;
+            let list:any = [];
+            const callback = () => {
+              resolve((list || []).map((ele:any) => ({
+                ...ele,
+                leaf: level >= stopLevel
+              })));
+            };
+            if (level === 0) {
+              getProvince().then(res => {
+                list = res.data || [];
+                callback();
+              });
+            } else if (level === 1) {
+              getCity(code).then(res => {
+                list = res.data ||[];
+                callback();
+              });
+            } else if (level === 2) {
+              getArea(code).then(res => {
+                list = res.data ||  [];
+                callback();
+              });
+            }else if (level === 3) {
+              getStreet(code).then(res => {
+                list = res.data || [];
+                callback();
+              });
+            } else {
+              callback();
+            }
+          }
+        },
+        // startWarehouse: {
+        //   label: '璧风偣浠撳簱',
+        //   addDisplay: true,
+        //   editDisplay: true,
+        //   viewDisplay: true,
+        //   type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/sys_warehouse',
+        //
+        // },
+        endRegionCode: {
+          label: '缁堢偣琛屾斂鍖哄煙',
+          addDisplay: true,
+          editDisplay: true,
+          viewDisplay: true,dataType: 'string',
+          type:'cascader',
+          rules: [
+            {
+              required: true,
+              message: "缁堢偣琛屾斂鍖哄煙涓嶈兘涓虹┖", trigger: "blur"
+            }
+          ],
+          lazy: true,
+          props: {
+            label: 'name',
+            value: 'code'
+          },
+          change:({value=[]}:{value:any})=>{
+            if (value && value.length>0){
+              const cascader = crudRef.value?.getPropRef?.('endRegionCode')?.$refs?.temp;
+              if (cascader.getCheckedNodes() && cascader.getCheckedNodes().length >0){
+                form.value.endRegionCode= cascader.getCheckedNodes()[0].pathValues.toString();
+                form.value.endRegion= cascader.getCheckedNodes()[0].text!;
+                form.value.transportRoute = `${form.value.startRegion}->${form.value.endRegion}`;
+              }
+            }
+          },
+          lazyLoad (node:any, resolve:any) {
+            const stopLevel = 3;
+            const level = node.level;
+            const data = node.data || {};
+            const code = data.code;
+            let list:any = [];
+            const callback = () => {
+              resolve((list || []).map((ele:any) => ({
+                ...ele,
+                leaf: level >= stopLevel
+              })));
+            };
+            if (level === 0) {
+              getProvince().then(res => {
+                list = res.data || [];
+                callback();
+              });
+            } else if (level === 1) {
+              getCity(code).then(res => {
+                list = res.data ||[];
+                callback();
+              });
+            } else if (level === 2) {
+              getArea(code).then(res => {
+                list = res.data ||  [];
+                callback();
+              });
+            }else if (level === 3) {
+              getStreet(code).then(res => {
+                list = res.data || [];
+                callback();
+              });
+            } else {
+              callback();
+            }
+          }
+        },
+        // endWarehouse: {
+        //   label: '缁堢偣浠撳簱',
+        //   addDisplay: true,
+        //   editDisplay: true,
+        //   viewDisplay: true,
+        //   type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/sys_warehouse',
+        //
+        // },
+        transportRoute: {
+          label: '杩愯緭绾胯矾',span:24,
+          disabled: true,
+          // type: 'textarea', minRows: 3, maxRows: 5,
+          addDisplay: true,
+          editDisplay: true,
+          viewDisplay: true,
+          hide: false,
+          search: true,
+          rules: [
+            {
+              required: true,
+              message: "杩愯緭绾胯矾涓嶈兘涓虹┖", trigger: "blur"
+            }
+          ],
+        },
+        vehicleType: {
+          label: '杞﹀瀷',
+          addDisplay: false,
+          editDisplay: true,
+          viewDisplay: true,
+          type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/vehicle_type',
+          rules: [
+            {
+              required: true,
+              message: "杞﹀瀷涓嶈兘涓虹┖", trigger: "change"
+            }
+          ],
+        },
+        // transportMode: {
+        //   label: '杩愯緭鏂瑰紡',
+        //   addDisplay: true,
+        //   editDisplay: true,
+        //   viewDisplay: true,
+        //   type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/transport_mode',
+        //
+        // },
+        // routeType: {
+        //   label: '绾胯矾绫诲瀷',
+        //   addDisplay: true,
+        //   editDisplay: true,
+        //   viewDisplay: true,
+        //   type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/route_type',
+        //
+        // },
+        freightPrice: {
+          label: '杩愯垂鎶ヤ环',
+          addDisplay: false,
+          editDisplay: true,
+          viewDisplay: true,type: 'number',
+          rules: [
+            {
+              required: true,
+              message: "杩愯垂鎶ヤ环涓嶈兘涓虹┖", trigger: "blur"
+            }
+          ],
+        },
+      }
+    },
+    {
+      label: '杞﹀瀷鎶ヤ环',
+      prop: 'cxbj', addDisplay: true,editDisplay: false,viewDisplay: false,
+      column: {
+        items:{
+          label: '',labelWidth:0,span:24,
+        }
+      }
+    },
+
+    {
+      label: '鍏朵粬淇℃伅',
+      prop: 'qtxx',
+      column: {
+        status: {
+          label: '鐘舵��',
+          type: 'radio', dicUrl: '/system/dict/data/type/sys_normal_disable',
+          addDisplay: false,dataType:'string',
+          editDisplay: true,
+          viewDisplay: true,
+          hide: false,
+          search: true,
+          rules: [
+            {
+              required: true,
+              message: "鐘舵�佷笉鑳戒负绌�", trigger: "blur"
+            }
+          ],
+        },
+        createBy: {
+          label: '鍒涘缓浜�',
+          addDisplay: false,
+          editDisplay: false,
+          viewDisplay: true,
+          hide: true,
+          search: false,
+        },
+        createTime: {
+          label: '鍒涘缓鏃堕棿',
+          type: 'date', valueFormat: 'YYYY-MM-DD',
+          addDisplay: false,
+          editDisplay: false,
+          viewDisplay: true,
+          hide: true,
+          search: false,
+        },
+        updateBy: {
+          label: '鏇存柊浜�',
+          addDisplay: false,
+          editDisplay: false,
+          viewDisplay: true,
+          hide: false,
+          search: false,
+        },
+        updateTime: {
+          label: '鏇存柊鏃堕棿',
+          type: 'date', valueFormat: 'YYYY-MM-DD',
+          addDisplay: false,
+          editDisplay: false,
+          viewDisplay: true,
+          hide: false,
+          search: false,
+        },
+        remark: {
+          label: '澶囨敞',
+          type: 'textarea', minRows: 3, maxRows: 5,
+          addDisplay: true,span:24,
+          editDisplay: true,
+          viewDisplay: true,
+          hide: true,
+          search: false,
+        },
+      }
+    }
+  ],
+  column: {
+    systemCode: {
+      label: '绯荤粺缂栧彿',minWidth:150,
+      display: false,
+      hide: false,
+      search: true,
+    },
+    quotePlanCode: {
+      label: '鎶ヤ环鏂规缂栧彿',minWidth:150,
+      display: false,
+    },
+    // vehicleProviderName: {
+    //   label: '杞﹁締鏈嶅姟鍟�',minWidth:150,
+    //   display: false,
+    //   hide: quotePlanType.value != 1,
+    //   search: quotePlanType.value == 1,
+    // },
+    transportRoute: {
+      label: '杩愯緭绾胯矾',minWidth:150,
+      display: false,overHidden: true,
+      hide: false,
+    },
+    startRegion: {
+      label: '璧风偣琛屾斂鍖哄煙',
+      display: false,minWidth:150,
+      hide: false,overHidden: true,
+      search: false,
+    },
+    // startWarehouse: {
+    //   label: '璧风偣浠撳簱',   display: false,
+    //   hide: false,minWidth:150,
+    //   search: true,
+    //   type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/sys_warehouse',
+    //
+    // },
+    endRegion: {
+      label: '缁堢偣琛屾斂鍖哄煙',overHidden: true,
+      display: false,minWidth:150,
+      hide: false,
+    },
+    // endWarehouse: {
+    //   label: '缁堢偣浠撳簱',
+    //   display: false,minWidth:150,
+    //   type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/sys_warehouse',
+    //   search: true,
+    // },
+    vehicleType: {
+      label: '杞﹀瀷',
+      display: false,minWidth:150,
+      type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/vehicle_type',
+      search: true,
+    },
+    // transportMode: {
+    //   label: '杩愯緭鏂瑰紡',minWidth:150,
+    //   display: false,
+    //   hide: false,
+    //   search: true,
+    //   type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/transport_mode',
+    //
+    // },
+    // routeType: {
+    //   label: '绾胯矾绫诲瀷',
+    //   display: false,
+    //   hide: false,minWidth:150,
+    //   search: true,
+    //   type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/route_type',
+    //
+    // },
+    freightPrice: {
+      label: '杩愯垂鎶ヤ环',
+      display: false,
+      hide: false,minWidth:150,
+    },
+    currency: {
+      label: '甯佸埗',
+      display: false,
+      hide: false,minWidth:150,
+      search: true,
+      type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/sys_currency',
+
+    },
+    status: {
+      label: '鐘舵��',
+      type: 'radio',dataType:'string',  dicUrl: '/system/dict/data/type/sys_normal_disable',
+      display: false,
+      hide: false,
+      search: true,minWidth:150,
+    },
+    updateBy: {
+      label: '鏇存柊浜�',
+      display: false,minWidth:150,
+    },
+    updateTime: {
+      label: '鏇存柊鏃堕棿',
+      display: false,minWidth:180,
+    },
+  }
+})
+
+const itemsTableOption = ref({
+  pageKey: 'itemsTable',
+  rowKey: 'rowKey',
+  header: false,
+  addBtn: false,menu: false,
+  column:{
+    vehicleType:{
+      label: '杞﹀瀷',
+      type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/vehicle_type',
+    },
+    freightPrice:{
+      label: '*杩愯垂鎶ヤ环',
+    },
+    currency:{
+      label: '甯佸埗',
+    }
+  }
+})
+const itemsCrudRef =ref()
+
+
+const {
+  tableData,
+  pageF,
+  rowSave,
+  rowUpdate,
+  rowDel,
+  beforeOpen,
+  searchChange,
+  searchReset,
+  selectionChange,
+  onLoad,
+  currentChange,
+  sizeChange,
+  handleDelete,
+  handleExport,
+  handleUpdate,
+  refreshChange
+} = usePagePlus({
+  form: form,
+  option: option,
+  queryParams: queryParams,
+  idKey: 'id',
+  page: page.value,
+  getListApi: listTmsQuoteDetail,
+  getDetailApi: getTmsQuoteDetail,
+  exportApi: exportTmsQuoteDetail,
+  deleteApi: delTmsQuoteDetail,
+  addApi: addTmsQuoteDetail,
+  updateApi: updateTmsQuoteDetail,
+  handleUpdateFunc: () => {
+    crudRef.value.rowEdit(selectionList.value[0]);
+  },
+  handleSelectionChangeFunc: (selection: any) => {
+    selectionList.value = selection;
+  },
+  getBeginListFunc(params:any = {}){
+    params.quotePlanId = (route.query?.quotePlanId||'') as string;
+    return params;
+  },
+  rowSaveBegin:(row:any,loading:any)=>{
+    row.quotePlanId = (route.query?.quotePlanId||'') as string;
+    if (selectionList2.value.length == 0){
+      proxy.$modal.msgError("璇疯嚦灏戦�夋嫨涓�鏉¤溅鍨嬫姤浠�");
+      loading();
+      throw new Error("璇疯嚦灏戦�夋嫨涓�鏉¤溅鍨嬫姤浠�");
+
+    }
+    let filter = selectionList2.value.filter((item:any)=>{
+      return !item.freightPrice || !item.currency
+    });
+    if (filter.length > 0){
+      proxy.$modal.msgError("璇峰~鍐欐墍鏈夊繀濉」");
+      loading();
+      throw new Error("璇峰~鍐欐墍鏈夊繀濉」")
+    }
+    row.quoteItems = selectionList2.value;
+  },
+  handleBeforeOpenFunc:(type:string)=>{
+    form.value.items = [];
+    if (type === 'add'){
+      form.value.items = vehicle_type.value.map((item:any)=>{
+        return { rowKey: randomId() ,vehicleType: item.value,}
+      })
+    }
+  },
+
+})
+const handleBack = () => {
+  router.back()
+}
+
+const selectionChange2 = (selection?: any[]) => {
+  selectionList2.value = selection;
+}
+</script>
diff --git a/ui/admin-ui3/src/views/tms/collectionTmsQuotePlan/index.vue b/ui/admin-ui3/src/views/tms/collectionTmsQuotePlan/index.vue
index 98cdbeb..b1e380a 100644
--- a/ui/admin-ui3/src/views/tms/collectionTmsQuotePlan/index.vue
+++ b/ui/admin-ui3/src/views/tms/collectionTmsQuotePlan/index.vue
@@ -46,8 +46,40 @@
         </el-button>
       </template>
       <template #menu-before="{row}">
-        <el-link size="small" type="primary" @click="goToDetail(row)"  class="link-btn" :underline="false" icon="el-icon-d-arrow-right">鎶ヤ环鏄庣粏</el-link>
+        <el-link size="small" type="primary" @click="goToDetail(row)"  class="link-btn" :underline="false" icon="el-icon-d-arrow-right">杩愯垂鎶ヤ环</el-link>
       </template>
+      <template #items-form="scope">
+        <avue-crud
+            :option="{...itemsTableOption,selection: !scope.disabled}"          @selection-change="selectionChange2"
+
+            :data="form.items" ref="itemsCrudRef"
+        >
+          <template #unit="{row}">
+            <el-select  v-model="row.unit" :disabled="scope.disabled" placeholder="璇烽�夋嫨璁¤垂鍗曚綅">
+              <el-option
+                  v-for="dict in sys_unit"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+              ></el-option>
+            </el-select>
+          </template>
+          <template #price="{row}">
+            <el-input v-model="row.price" :min="1" :disabled="scope.disabled" type="number" placeholder="璇疯緭鍏ラ噾棰�"></el-input>
+          </template>
+          <template #currency="{row}">
+            <el-radio-group v-model="row.currency"  :disabled="scope.disabled">
+              <el-radio
+                  v-for="dict in sys_currency"
+                  :key="dict.value"
+                  :label="dict.value"
+              >{{ dict.label }}</el-radio>
+            </el-radio-group>
+          </template>
+
+        </avue-crud>
+      </template>
+
     </avue-crud>
   </basicContainer>
 </template>
@@ -63,16 +95,19 @@
   updateTmsQuotePlan
 } from "@/api/tms/tmsQuotePlan";
 import useCurrentInstance from "@/utils/useCurrentInstance";
-import {computed, reactive, ref, toRefs} from "vue";
+import {computed, reactive, ref, toRefs,nextTick} from "vue";
 import {PagesInterface, PageQueryInterface} from "@/utils/globalInterface";
 import {usePagePlus} from "@/hooks/usePagePlus";
 import {hasPermission} from "@/utils/permissionUtils";
 import {getTmsProject, listTmsProject} from "@/api/tms/tmsProject";
 import router from "@/router";
+import {getDicts} from "@/api/system/dict/data";
+import { randomId } from "@smallwei/avue";
 
 const {proxy} = useCurrentInstance();
 const crudRef = ref();
-
+const {sys_quotation_items,sys_unit,sys_currency} =
+    proxy.useDict("sys_quotation_items","sys_unit","sys_currency");
 const permissionList = computed(() => {
   return {
     addBtn: hasPermission(["tms:tmsQuotePlan:add"]),
@@ -91,8 +126,10 @@
     currentPage: 1,
   },
   selectionList: [],
+  selectionList2: <any>[],
+
 })
-const {queryParams, form, page, selectionList} = toRefs(data);
+const {queryParams, form, page, selectionList,selectionList2} = toRefs(data);
 const option = ref({
   pageKey: 'TmsQuotePlan',
   rowKey: 'id',
@@ -236,6 +273,15 @@
       }
     },
     {
+      label: '搴旀敹璐圭敤鎶ヤ环',
+      prop: 'bjxm',
+      column:{
+        items:{
+          label: '', labelWidth:0,span:24,
+        }
+      }
+    },
+    {
       label: '鍏朵粬淇℃伅',
       prop: 'qtxx',
       column:{
@@ -339,6 +385,30 @@
   }
 })
 
+const itemsTableOption = ref({
+  pageKey: 'itemsTable',
+  rowKey: 'rowKey',
+  header: false,
+  addBtn: false,menu: false,
+  column:{
+    freeName:{
+      label: '璐圭敤鍚嶇О',
+    },
+    unit:{
+      label: '*璁¢噺鍗曚綅',
+    },
+    price:{
+      label: '*璁¤垂閲戦',
+    },
+    currency:{
+      label: '甯佸埗',
+    }
+  }
+})
+const itemsCrudRef =ref()
+
+
+
 const {
   tableData,
   pageF,
@@ -376,11 +446,84 @@
   },
   getBeginListFunc:()=>{
     queryParams.value.planType = '0'
+  },
+  handleBeforeOpenFunc:(type:string)=>{
+    form.value.items = [];
+    if (type === 'add'){
+      form.value.items = sys_quotation_items.value.map((item:any)=>{
+        return { rowKey: randomId() ,freeName: item.label,unit: '娆�'}
+      })
+    }
+  },
+  rowSaveBegin:(row:any,loading:any)=>{
+      if (selectionList2.value.length == 0){
+        proxy.$modal.msgError("璇疯嚦灏戦�夋嫨涓�鏉″簲鏀惰垂鐢ㄦ姤浠烽」");
+        loading();
+        throw new Error("璇疯嚦灏戦�夋嫨涓�鏉″簲鏀惰垂鐢ㄦ姤浠烽」");
+
+      }
+      let filter = selectionList2.value.filter((item:any)=>{
+         return !item.price || !item.currency
+       });
+      if (filter.length > 0){
+        proxy.$modal.msgError("璇峰~鍐欐墍鏈夊繀濉」");
+        loading();
+        throw new Error("璇峰~鍐欐墍鏈夊繀濉」")
+      }
+      row.quoteItems = selectionList2.value;
+
+  },
+  rowUpdateBegin(row:any,loading:any){
+    if (selectionList2.value.length == 0){
+      proxy.$modal.msgError("璇疯嚦灏戦�夋嫨涓�鏉″簲鏀惰垂鐢ㄦ姤浠烽」");
+      loading();
+      throw new Error("璇疯嚦灏戦�夋嫨涓�鏉″簲鏀惰垂鐢ㄦ姤浠烽」");
+
+    }
+    let filter = selectionList2.value.filter((item:any)=>{
+      return !item.price || !item.currency
+    });
+    if (filter.length > 0){
+      proxy.$modal.msgError("璇峰~鍐欐墍鏈夊繀濉」");
+      loading();
+      throw new Error("璇峰~鍐欐墍鏈夊繀濉」")
+    }
+    row.quoteItems = selectionList2.value;
+  },
+  handleEndOpenFunc:(type:string,res:any)=>{
+    if (type === 'edit'){
+      selectionList2.value = (res.data.quoteItems || []).map((item:any)=>{
+        item.rowKey =randomId()
+        return item;
+      });
+      form.value.items = sys_quotation_items.value.map((item:any)=>{
+        let find = selectionList2.value.find((ele:any)=>
+          ele.freeName === item.label
+        );
+        if ( find){
+          return find;
+        }else{
+          return { rowKey: randomId() ,freeName: item.label,unit: '娆�'}
+        }
+      })
+      nextTick( ()=>{
+        selectionList2.value.map((find:any)=>{
+          itemsCrudRef.value.toggleRowSelection(find,true)
+        })
+
+      })
+    }else{
+      form.value.items = res.data.quoteItems || [];
+    }
   }
 })
 
 const goToDetail = (row?:any) => {
-  router.push("/basic/tmsQuoteDetail?quotePlanId=" + row.id);
+  router.push("/collectionTmsQuotePlan/collectionTmsQuotePlanItem?quotePlanType=0&quotePlanId=" + row.id);
 }
+const selectionChange2 = (selection?: any[]) => {
+  selectionList2.value = selection;
+}
+
 
 </script>
diff --git a/ui/admin-ui3/src/views/tms/paymentTmsQuotePlan/index.vue b/ui/admin-ui3/src/views/tms/paymentTmsQuotePlan/index.vue
index c3cbd8d..d688bd4 100644
--- a/ui/admin-ui3/src/views/tms/paymentTmsQuotePlan/index.vue
+++ b/ui/admin-ui3/src/views/tms/paymentTmsQuotePlan/index.vue
@@ -380,7 +380,7 @@
 })
 
 const goToDetail = (row?:any) => {
-  router.push("/basic/tmsQuoteDetail?quotePlanId=" + row.id);
+  router.push("/basic/tmsQuoteDetail?quotePlanType=1&quotePlanId=" + row.id);
 }
 
 </script>
diff --git a/ui/admin-ui3/src/views/tms/tmsContract/index.vue b/ui/admin-ui3/src/views/tms/tmsContract/index.vue
index 52730ea..cab7a94 100644
--- a/ui/admin-ui3/src/views/tms/tmsContract/index.vue
+++ b/ui/admin-ui3/src/views/tms/tmsContract/index.vue
@@ -68,6 +68,7 @@
 import dayjs from 'dayjs';
 import {formatDate} from "@/utils/ruoyi";
 import {getTmsSettlementEntity, listTmsSettlementEntity} from "@/api/tms/tmsSettlementEntity";
+import router from "@/router";
 const {proxy} = useCurrentInstance();
 const crudRef = ref();
 
@@ -110,6 +111,19 @@
             {
               required: true,
               message: "绯荤粺缂栧彿涓嶈兘涓虹┖", trigger: "blur"
+            }
+          ],
+        },
+        isTempContract: {
+          label: '涓存椂鍚堝悓',
+          type: 'radio', dataType: 'string', dicUrl: '/system/dict/data/type/sys_number_is',
+          addDisplay: true,value:'1',
+          editDisplay: true,
+          viewDisplay: true,
+          rules: [
+            {
+              required: true,
+              message: "鏄惁涓存椂鍚堝悓涓嶈兘涓虹┖", trigger: "change"
             }
           ],
         },
@@ -156,12 +170,6 @@
           addDisplay: true,
           editDisplay: true,
           viewDisplay: true,
-          rules: [
-            {
-              required: true,
-              message: "绛剧害鏃ユ湡涓嶈兘涓虹┖", trigger: "blur"
-            }
-          ],
         },
         contractDate: {
           label: '鍚堝悓鏈熼檺',
@@ -629,6 +637,13 @@
       hide: false,
       search: true,
     },
+    isTempContract: {
+      label: '涓存椂鍚堝悓',
+      type: 'radio', dataType: 'string', dicUrl: '/system/dict/data/type/sys_number_is',
+      display: false,minWidth:150,
+      hide: false,
+      search: true,
+    },
     contractType: {
       label: '鍚堝悓绫诲瀷',
       type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/contract_type',
@@ -779,6 +794,9 @@
   deleteApi: delTmsContract,
   addApi: addTmsContract,
   updateApi: updateTmsContract,
+  getBeginListFunc:()=>{
+    queryParams.value.contractStatus = <any>router.currentRoute.value.query.contactStatus || undefined;
+  },
   handleUpdateFunc: () => {
     crudRef.value.rowEdit(selectionList.value[0]);
   },
@@ -786,7 +804,7 @@
     selectionList.value = selection;
   },
 })
-
+console.log(router.currentRoute.value.query.contactStatus)
 
 
 </script>
diff --git a/ui/admin-ui3/src/views/tms/tmsDispatchOrder/index.vue b/ui/admin-ui3/src/views/tms/tmsDispatchOrder/index.vue
index 05e1e27..caa27e8 100644
--- a/ui/admin-ui3/src/views/tms/tmsDispatchOrder/index.vue
+++ b/ui/admin-ui3/src/views/tms/tmsDispatchOrder/index.vue
@@ -103,6 +103,17 @@
       </template>
     </avue-crud>
     <el-dialog :title="pageF.title" v-model="pageF.open" class="avue-dialog avue-dialog--top" width="80%">
+      <h2 v-if="optionType == 'addFinance'">鎶ヤ环璐圭敤</h2>
+      <avue-crud v-if="optionType == 'addFinance'"
+          :option="itemsTableOption"
+          :data="itemsTableData"
+                 @selection-change="selectionChange2"
+      >
+        <template #count="{row}">
+          <el-input-number v-model="row.count" @change="countChange(row)" placeholder="璇疯緭鍏ヨ璐规暟閲�" min="0"></el-input-number>
+        </template>
+      </avue-crud>
+      <h2 v-if="optionType == 'addFinance'">瀹炴姤瀹為攢璐圭敤</h2>
       <avue-form v-if="optionType == 'addItinerary' || optionType == 'addFinance'" v-model="boxForm" ref="boxFormRef" :option="boxFormOption">
 
       </avue-form>
@@ -236,6 +247,8 @@
 import {addTmsFinanceDetail, listTmsFinanceDetail, updateTmsFinanceDetail} from "@/api/tms/tmsFinanceDetail";
 import {getTmsProductInfo, listTmsProductInfo} from "@/api/tms/tmsProductInfo";
 import {addTmsGoodsDetail, delTmsGoodsDetail, listTmsGoodsDetail, updateTmsGoodsDetail} from "@/api/tms/tmsGoodsDetail";
+import {getTransportRouteVi, listTransportRouteVi} from "@/api/tms/tmsTransportRouteVi";
+import {listTmsQuoteItem} from "@/api/tms/tmsQuotePlanItem";
 
 const {proxy} = useCurrentInstance();
 const crudRef = ref();
@@ -275,6 +288,7 @@
   open: false,
   open2:false,
   goodsTableData: <any>[],
+  selectionList2: <any>[],
   goodsForm:<any>{},
   open3: false,
   actualForm:<any>{},
@@ -282,7 +296,7 @@
 const {queryParams, form, page, selectionList,open3,
   boxTableData, optionType,
   boxFormOption,boxForm,boxTableOption,title,open,open2,
-  goodsTableData,goodsForm,actualForm
+  goodsTableData,goodsForm,actualForm,selectionList2
 } = toRefs(data);
 const option = ref({
   pageKey: 'TmsDispatchOrder',
@@ -296,77 +310,75 @@
       label: '鍩烘湰淇℃伅',
       prop: 'jbxx',
       column: {
-        projectId: {
-          label: '鍏宠仈椤圭洰',
+
+        quoteDetailId: {
+          label: '杩愯緭绾胯矾', span: 24,
           display: true,
           rules: [
             {
               required: true,
-              message: "鍏宠仈椤圭洰涓嶈兘涓虹┖", trigger: "change"
+              message: "璇烽�夋嫨杩愯緭璺嚎", trigger: "change"
             }
           ],
+          type: 'table', suffixIcon: 'search',
           change: (val: any) => {
-            const table = crudRef.value?.getPropRef?.('projectId')?.$refs?.temp;
+            const table = crudRef.value?.getPropRef?.('quoteDetailId')?.$refs?.temp;
             if (!table) return;
             let active = table.active;
             if (Array.isArray(active)) active = active[0];
             if (active) {
               Object.assign(form.value, {
-                projectId: active.id,
+                quoteDetailId: active.quoteDetailId,
+                transportLine: active.transportRoute,
+                startRegionCode: active.startRegionCode,
+                endRegionCode: active.endRegionCode,
+                projectId: active.projectId,
                 projectName: active.projectName,
-                customerId: active.relatedCustomerId,
-                customerName: active.relatedCustomerName,
-                customerCode: active.relatedCustomerCode,
-                contractId: active.relatedContractId,
-                contractName: active.relatedContractName,
+                customerId: active.customerId,
+                customerName: active.customerFullName,
+                customerCode: active.customerCode,
+                contractId: active.contractId,
+                contractName: active.contractName,
+                requiredVehicleTypes: active.vehicleType,
+                quotePlanId: active.quotePlanId,
               });
             }
           },
-          type: 'table', suffixIcon: 'search',
           children: {
             border: true,
             searchMenuSpan: 5,
             column: {
+              transportRoute: {
+                label: '杩愯緭璺嚎', minWidth: 130,
+                search: true,
+              },
+              customerFullName: {
+                label: '瀹㈡埛鍏ㄧ▼', minWidth: 120,
+                search: true,
+              },
               projectName: {
-                label: '椤圭洰鍚嶇О', minWidth: 130,
-                search: true,
-              },
-              projectCode: {
-                label: '椤圭洰缂栧彿', minWidth: 120,
-                search: true,
-              },
-              relatedContractName: {
-                label: '鍏宠仈鍚堝悓',
+                label: '鍏宠仈椤圭洰',
                 display: false, minWidth: 150,
                 search: true,
               },
 
-              relatedCustomerName: {
-                label: '鍏宠仈瀹㈡埛',
+              contractName: {
+                label: '鍏宠仈鍚堝悓',
                 display: false, minWidth: 150,
                 search: true,
               },
-              status: {
-                label: '鐘舵��', dataType: 'string',
-                type: 'radio', dicUrl: '/system/dict/data/type/data_status',
-                addDisplay: false, minWidth: 150,
-                editDisplay: false,
-                viewDisplay: true,
+              vehicleType: {
+                label: '杞﹀瀷', dataType: 'string',
+                type: 'select', dicUrl: '/system/dict/data/type/vehicle_type', minWidth: 150,
                 hide: false,
                 search: true,
-                rules: [
-                  {
-                    required: true,
-                    message: "鐘舵�佷笉鑳戒负绌�", trigger: "blur"
-                  }
-                ],
               },
             },
 
           },
           props: {
-            label: 'projectName',
-            value: 'id'
+            label: 'transportRoute',
+            value: 'quoteDetailId'
           },
           onLoad: ({page, value, data}: { page: any, value: any, data: any }, callback: any) => {
             if (value) {
@@ -374,11 +386,11 @@
               if (Array.isArray(value)) {
                 id = value[0]
               }
-              getTmsProject(id).then(res => {
+              getTransportRouteVi(id).then(res => {
                 return callback(res.data || {})
               })
             } else {
-              listTmsProject({pageSize: page.pageSize, pageNum: page.currentPage, ...data}).then(res => {
+              listTransportRouteVi({pageSize: page.pageSize, pageNum: page.currentPage, ...data}).then(res => {
                 return callback({
                   total: res.total,
                   data: res.rows || [],
@@ -387,10 +399,13 @@
             }
 
           }
-
         },
         customerName: {
           label: '瀹㈡埛鍚嶇О',
+          display: true, disabled: true
+        },
+        projectName: {
+          label: '鍏宠仈椤圭洰',
           display: true, disabled: true
         },
         // customerCode: {
@@ -398,10 +413,19 @@
         //   display: true,disabled:true
         // },
         contractName: {
-          label: '鍏宠仈鍚堝悓鍚嶇О',
+          label: '鍏宠仈鍚堝悓',
           display: true, disabled: true
         },
-
+        requiredVehicleTypes: {
+          label: '涓嬪崟杞﹀瀷',disabled: true,
+          display: true, type: 'select', dicUrl: '/system/dict/data/type/vehicle_type', dataType: 'string',
+          rules: [
+            {
+              required: true,
+              message: "涓嬪崟杞﹀瀷涓嶈兘涓虹┖", trigger: "blur"
+            }
+          ],
+        },
         orderType: {
           label: '璁㈠崟绫诲瀷',
           display: true,
@@ -414,15 +438,221 @@
             }
           ],
         },
-        signType: {
-          label: '绛炬敹绫诲瀷',
+        // signType: {
+        //   label: '绛炬敹绫诲瀷',
+        //   display: true,
+        //   type: 'select', dataType: 'string',
+        //   dicUrl: '/system/dict/data/type/sign_type',
+        //   rules: [
+        //     {
+        //       required: true,
+        //       message: "绛炬敹绫诲瀷涓嶈兘涓虹┖", trigger: "change"
+        //     }
+        //   ],
+        // },
+
+        // loadingServiceProviderId: {
+        //   label: '瑁呰揣鏈嶅姟鍟�',
+        //   display: true,
+        //   rules: [
+        //     {
+        //       required: true,
+        //       message: "瑁呰揣鏈嶅姟鍟嗕笉鑳戒负绌�", trigger: "change"
+        //     }
+        //   ],
+        //   change: (val: any) => {
+        //     const table = crudRef.value?.getPropRef?.('loadingServiceProviderId')?.$refs?.temp;
+        //     if (!table) return;
+        //     let active = table.active;
+        //     if (Array.isArray(active)) active = active[0];
+        //     if (active) {
+        //       Object.assign(form.value, {
+        //         loadingServiceProviderId: active.id,
+        //         loadingServiceProviderName: active.serviceShortName,
+        //       });
+        //     }
+        //   },
+        //   type: 'table', suffixIcon: 'search',
+        //   children: {
+        //     border: true,
+        //     searchLabelWidth: 100,
+        //     searchMenuSpan: 5,
+        //     column: {
+        //       serviceCode: {
+        //         label: '鏈嶅姟鍟嗙紪鐮�', minWidth: 130,
+        //         search: true,
+        //       },
+        //       serviceShortName: {
+        //         label: '鏈嶅姟鍟嗙畝绉�', minWidth: 120,
+        //         search: true,
+        //       },
+        //       serviceType: {
+        //         label: '鏈嶅姟绫诲瀷', multiple: true,
+        //         type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/service_type',
+        //         minWidth: 150,
+        //       },
+        //       contactName: {
+        //         label: '鑱旂郴浜哄鍚�', minWidth: 120,
+        //       },
+        //     },
+        //
+        //   },
+        //   props: {
+        //     label: 'serviceShortName',
+        //     value: 'id'
+        //   },
+        //   onLoad: ({page, value, data}: { page: any, value: any, data: any }, callback: any) => {
+        //     if (value) {
+        //       let id = value;
+        //       if (Array.isArray(value)) {
+        //         id = value[0]
+        //       }
+        //       getTmsLoadingServiceProvider(id).then(res => {
+        //         return callback(res.data || {})
+        //       })
+        //     } else {
+        //       listTmsLoadingServiceProvider({pageSize: page.pageSize, pageNum: page.currentPage, ...data}).then(res => {
+        //         return callback({
+        //           total: res.total,
+        //           data: res.rows || [],
+        //         })
+        //       })
+        //     }
+        //
+        //   }
+        //
+        // },
+        // customsServiceProviderId: {
+        //   label: '鎶ュ叧鏈嶅姟鍟�',
+        //   display: true,
+        //   rules: [
+        //     {
+        //       required: true,
+        //       message: "鎶ュ叧鏈嶅姟鍟嗕笉鑳戒负绌�", trigger: "change"
+        //     }
+        //   ],
+        //   change: (val: any) => {
+        //     const table = crudRef.value?.getPropRef?.('customsServiceProviderId')?.$refs?.temp;
+        //     if (!table) return;
+        //     let active = table.active;
+        //     if (Array.isArray(active)) active = active[0];
+        //     if (active) {
+        //       Object.assign(form.value, {
+        //         customsServiceProviderId: active.id,
+        //         customsServiceProviderName: active.serviceShortName,
+        //       });
+        //     }
+        //   },
+        //   type: 'table', suffixIcon: 'search',
+        //   children: {
+        //     border: true,
+        //     searchLabelWidth: 100,
+        //     searchMenuSpan: 5,
+        //     column: {
+        //       serviceCode: {
+        //         label: '鏈嶅姟鍟嗙紪鐮�', minWidth: 130,
+        //         search: true,
+        //       },
+        //       serviceShortName: {
+        //         label: '鏈嶅姟鍟嗙畝绉�', minWidth: 120,
+        //         search: true,
+        //       },
+        //       serviceType: {
+        //         label: '鏈嶅姟绫诲瀷', multiple: true,
+        //         type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/service_type',
+        //         minWidth: 150,
+        //       },
+        //       contactName: {
+        //         label: '鑱旂郴浜哄鍚�', minWidth: 120,
+        //       },
+        //     },
+        //
+        //   },
+        //   props: {
+        //     label: 'serviceShortName',
+        //     value: 'id'
+        //   },
+        //   onLoad: ({page, value, data}: { page: any, value: any, data: any }, callback: any) => {
+        //     if (value) {
+        //       let id = value;
+        //       if (Array.isArray(value)) {
+        //         id = value[0]
+        //       }
+        //       getTmsCustomsServiceProvider(id).then(res => {
+        //         return callback(res.data || {})
+        //       })
+        //     } else {
+        //       listTmsCustomsServiceProvider({pageSize: page.pageSize, pageNum: page.currentPage, ...data}).then(res => {
+        //         return callback({
+        //           total: res.total,
+        //           data: res.rows || [],
+        //         })
+        //       })
+        //     }
+        //
+        //   }
+        // },
+        isCustoms: {
+          label: '濮旀墭鎶ュ叧',
           display: true,
-          type: 'select', dataType: 'string',
-          dicUrl: '/system/dict/data/type/sign_type',
+          type: 'radio', dicUrl: '/system/dict/data/type/sys_number_is', dataType: 'string',
           rules: [
             {
               required: true,
-              message: "绛炬敹绫诲瀷涓嶈兘涓虹┖", trigger: "change"
+              message: "濮旀墭鎶ュ叧涓嶈兘涓虹┖", trigger: "blur"
+            }
+          ],
+        },
+        isUrgent: {
+          label: '鏄惁绱ф��',
+          display: true,
+          type: 'radio', dicUrl: '/system/dict/data/type/sys_number_is', dataType: 'string',
+          rules: [
+            {
+              required: true,
+              message: "鏄惁绱ф�ヤ笉鑳戒负绌�", trigger: "blur"
+            }
+          ],
+        },
+        // transportType: {
+        //   label: '杩愯緭鏂瑰紡',
+        //   display: true, type: 'select', dicUrl: '/system/dict/data/type/dispatch_transport_mode', dataType: 'string',
+        //
+        // },
+        // loadMethod: {
+        //   label: '閰嶈浇鏂瑰紡',
+        //   display: true, type: 'select', dicUrl: '/system/dict/data/type/load_method', dataType: 'string',
+        // },
+        latestDeparture: {
+          label: '瑕佹眰鏈�鏅氬嚭鍙戞椂闂�',
+          type: 'datetime',  // 鏀逛负 datetime 绫诲瀷
+          format: 'YYYY-MM-DD HH:mm:ss',
+          valueFormat: 'YYYY-MM-DD HH:mm:ss',
+          display: true,
+        },
+        latestArrival: {
+          label: '瑕佹眰鏈�鏅氬埌杈炬椂闂�',
+          type: 'datetime',  // 鏀逛负 datetime 绫诲瀷
+          format: 'YYYY-MM-DD HH:mm:ss',
+          valueFormat: 'YYYY-MM-DD HH:mm:ss',
+          display: true,
+        },
+
+
+
+      }
+    },
+    {
+      label: '娲捐溅淇℃伅',
+      prop: 'pcxx',
+      column: {
+        operationMode:{
+          label: '鏄惁鏄嚜钀ヨ溅闃�',
+          type: 'radio', dataType: 'string', dicUrl: '/system/dict/data/type/sys_number_is',
+          rules: [
+            {
+              required: true,
+              message: "鏄惁鏄嚜钀ヨ溅闃熶笉鑳戒负绌�", trigger: "change"
             }
           ],
         },
@@ -511,167 +741,6 @@
 
           }
 
-        },
-        loadingServiceProviderId: {
-          label: '瑁呰揣鏈嶅姟鍟�',
-          display: true,
-          rules: [
-            {
-              required: true,
-              message: "瑁呰揣鏈嶅姟鍟嗕笉鑳戒负绌�", trigger: "change"
-            }
-          ],
-          change: (val: any) => {
-            const table = crudRef.value?.getPropRef?.('loadingServiceProviderId')?.$refs?.temp;
-            if (!table) return;
-            let active = table.active;
-            if (Array.isArray(active)) active = active[0];
-            if (active) {
-              Object.assign(form.value, {
-                loadingServiceProviderId: active.id,
-                loadingServiceProviderName: active.serviceShortName,
-              });
-            }
-          },
-          type: 'table', suffixIcon: 'search',
-          children: {
-            border: true,
-            searchLabelWidth: 100,
-            searchMenuSpan: 5,
-            column: {
-              serviceCode: {
-                label: '鏈嶅姟鍟嗙紪鐮�', minWidth: 130,
-                search: true,
-              },
-              serviceShortName: {
-                label: '鏈嶅姟鍟嗙畝绉�', minWidth: 120,
-                search: true,
-              },
-              serviceType: {
-                label: '鏈嶅姟绫诲瀷', multiple: true,
-                type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/service_type',
-                minWidth: 150,
-              },
-              contactName: {
-                label: '鑱旂郴浜哄鍚�', minWidth: 120,
-              },
-            },
-
-          },
-          props: {
-            label: 'serviceShortName',
-            value: 'id'
-          },
-          onLoad: ({page, value, data}: { page: any, value: any, data: any }, callback: any) => {
-            if (value) {
-              let id = value;
-              if (Array.isArray(value)) {
-                id = value[0]
-              }
-              getTmsLoadingServiceProvider(id).then(res => {
-                return callback(res.data || {})
-              })
-            } else {
-              listTmsLoadingServiceProvider({pageSize: page.pageSize, pageNum: page.currentPage, ...data}).then(res => {
-                return callback({
-                  total: res.total,
-                  data: res.rows || [],
-                })
-              })
-            }
-
-          }
-
-        },
-        customsServiceProviderId: {
-          label: '鎶ュ叧鏈嶅姟鍟�',
-          display: true,
-          rules: [
-            {
-              required: true,
-              message: "鎶ュ叧鏈嶅姟鍟嗕笉鑳戒负绌�", trigger: "change"
-            }
-          ],
-          change: (val: any) => {
-            const table = crudRef.value?.getPropRef?.('customsServiceProviderId')?.$refs?.temp;
-            if (!table) return;
-            let active = table.active;
-            if (Array.isArray(active)) active = active[0];
-            if (active) {
-              Object.assign(form.value, {
-                customsServiceProviderId: active.id,
-                customsServiceProviderName: active.serviceShortName,
-              });
-            }
-          },
-          type: 'table', suffixIcon: 'search',
-          children: {
-            border: true,
-            searchLabelWidth: 100,
-            searchMenuSpan: 5,
-            column: {
-              serviceCode: {
-                label: '鏈嶅姟鍟嗙紪鐮�', minWidth: 130,
-                search: true,
-              },
-              serviceShortName: {
-                label: '鏈嶅姟鍟嗙畝绉�', minWidth: 120,
-                search: true,
-              },
-              serviceType: {
-                label: '鏈嶅姟绫诲瀷', multiple: true,
-                type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/service_type',
-                minWidth: 150,
-              },
-              contactName: {
-                label: '鑱旂郴浜哄鍚�', minWidth: 120,
-              },
-            },
-
-          },
-          props: {
-            label: 'serviceShortName',
-            value: 'id'
-          },
-          onLoad: ({page, value, data}: { page: any, value: any, data: any }, callback: any) => {
-            if (value) {
-              let id = value;
-              if (Array.isArray(value)) {
-                id = value[0]
-              }
-              getTmsCustomsServiceProvider(id).then(res => {
-                return callback(res.data || {})
-              })
-            } else {
-              listTmsCustomsServiceProvider({pageSize: page.pageSize, pageNum: page.currentPage, ...data}).then(res => {
-                return callback({
-                  total: res.total,
-                  data: res.rows || [],
-                })
-              })
-            }
-
-          }
-        },
-        isUrgent: {
-          label: '鏄惁绱ф��',
-          display: true,
-          type: 'select', dicUrl: '/system/dict/data/type/sys_number_is', dataType: 'string',
-          rules: [
-            {
-              required: true,
-              message: "鏄惁绱ф�ヤ笉鑳戒负绌�", trigger: "blur"
-            }
-          ],
-        },
-        transportType: {
-          label: '杩愯緭鏂瑰紡',
-          display: true, type: 'select', dicUrl: '/system/dict/data/type/dispatch_transport_mode', dataType: 'string',
-
-        },
-        loadMethod: {
-          label: '閰嶈浇鏂瑰紡',
-          display: true, type: 'select', dicUrl: '/system/dict/data/type/load_method', dataType: 'string',
         },
         mainDriverId: {
           label: '涓婚┚椹跺憳',
@@ -802,20 +871,6 @@
           }
 
         },
-        requiredVehicleTypes: {
-          label: '瑕佹眰杞﹀瀷',
-          display: true, type: 'select', dicUrl: '/system/dict/data/type/vehicle_type', dataType: 'string',
-          rules: [
-            {
-              required: true,
-              message: "瑕佹眰杞﹀瀷涓嶈兘涓虹┖", trigger: "blur"
-            }
-          ],
-        },
-        actualVehicleType: {
-          label: '瀹為檯杩愯緭宸ュ叿绫诲瀷',
-          display: true, type: 'select', dicUrl: '/system/dict/data/type/vehicle_type', dataType: 'string',
-        },
         vehicleId: {
           label: '杞︾墝鍙�',dataType: 'string',
           display: true,
@@ -894,6 +949,250 @@
 
           }
 
+        },
+        actualVehicleType: {
+          label: '娲惧嚭杞﹀瀷',
+          display: true, type: 'select', dicUrl: '/system/dict/data/type/vehicle_type', dataType: 'string',
+        },
+        shipperId: {
+          label: '瑁呰揣鐐�',dataType:'string',
+          display: true,
+          change: (val: any) => {
+            const table = crudRef.value?.getPropRef?.('shipperId')?.$refs?.temp;
+            if (!table) return;
+            let active = table.active;
+            if (Array.isArray(active)) active = active[0];
+            if (active) {
+              let shipperRegionCode = '';
+              if (active.provinceId){
+                shipperRegionCode = active.provinceId;
+              }
+              if (active.cityId){
+                shipperRegionCode =shipperRegionCode+ ","+active.cityId;
+
+              }
+              if (active.districtId){
+                shipperRegionCode =shipperRegionCode+ ","+active.districtId;
+
+              }
+              if (active.streetId){
+                shipperRegionCode =shipperRegionCode+ ","+active.streetId;
+              }
+              Object.assign(form.value, {
+                shipperId: active.id,
+                shipperName: active.consignorName,
+                shipperRegionLabel: active.regionLabel,
+                shipperAddress: active.addressDetail,
+                shipperMobile: active.contactPhone,
+                shipperRegionCode:shipperRegionCode
+              });
+             }
+          },
+          rules: [
+            {
+              required: true,
+              message: "瑁呰揣鐐逛笉鑳戒负绌�", trigger: "change"
+            }
+          ],
+          type: 'table', suffixIcon: 'search',
+          children: {
+            border: true,
+            searchLabelWidth: 100,
+            searchMenuSpan: 5,
+            column: {
+              consignorCode: {
+                label: '鏀惰璐х偣缂栫爜', minWidth: 130,
+                search: true,
+              },
+              consignorName: {
+                label: '鏀惰璐х偣鍚嶇О', minWidth: 130,
+                search: true,
+              },
+              consignorType: {
+                label: '鏀惰璐х偣绫诲瀷', minWidth: 80,
+                type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/consignor_type',
+                display: false,
+                hide: false,
+                search: true,
+              },
+              contactName: {
+                label: '鑱旂郴浜哄鍚�', minWidth: 110,
+                display: false,
+                hide: false,
+                search: true,
+              },
+              contactPhone: {
+                label: '鑱旂郴浜虹數璇�', minWidth: 110,
+                display: false,
+                hide: false,
+                search: true,
+              },
+              regionLabel: {
+                label: '琛屾斂鍖哄煙', minWidth: 180,
+                display: false,
+                hide: false,
+                search: true,
+              },
+            },
+
+          },
+          props: {
+            label: 'consignorName',
+            value: 'id'
+          },
+          onLoad: ({page, value, data}: { page: any, value: any, data: any }, callback: any) => {
+            if (value) {
+              let id = value;
+              if (Array.isArray(value)) {
+                id = value[0]
+              }
+              getTmsConsignor(id).then(res => {
+                return callback(res.data || {})
+              })
+            } else {
+              listTmsConsignor({pageSize: page.pageSize, pageNum: page.currentPage, ...data}).then(res => {
+                return callback({
+                  total: res.total,
+                  data: res.rows || [],
+                })
+              })
+            }
+
+          }
+
+        },
+        shipperRegionLabel: {
+          label: '瑁呰揣鐐硅鏀垮尯鍩�',
+          display: true, disabled: true
+
+        },
+        shipperAddress: {
+          label: '瑁呰揣鐐硅缁嗗湴鍧�',
+          display: true, disabled: true
+        },
+        shipperMobile: {
+          label: '瑁呰揣鐐硅仈绯绘柟寮�',
+          display: true, disabled: true
+        },
+        receiverId: {
+          label: '鍗歌揣鐐�',
+          display: true, dataType:'string',
+          rules: [
+            {
+              required: true,
+              message: "鍗歌揣鐐逛笉鑳戒负绌�", trigger: "change"
+            }
+          ],
+          change: (val: any) => {
+            const table = crudRef.value?.getPropRef?.('receiverId')?.$refs?.temp;
+            if (!table) return;
+            let active = table.active;
+            if (Array.isArray(active)) active = active[0];
+            if (active) {
+              let receiverRegionCode = '';
+              if (active.provinceId){
+                receiverRegionCode = active.provinceId;
+              }
+              if (active.cityId){
+                receiverRegionCode =receiverRegionCode+ ","+active.cityId;
+
+              }
+              if (active.districtId){
+                receiverRegionCode =receiverRegionCode+ ","+active.districtId;
+
+              }
+              if (active.streetId){
+                receiverRegionCode =receiverRegionCode+ ","+active.streetId;
+              }
+
+              Object.assign(form.value, {
+                receiverId: active.id,
+                receiverName: active.consignorName,
+                receiverRegionLabel: active.regionLabel,
+                receiverAddress: active.addressDetail,
+                receiverMobile: active.contactPhone,
+                receiverRegionCode:receiverRegionCode,
+              });
+            }
+          },
+          type: 'table', suffixIcon: 'search',
+          children: {
+            border: true,
+            searchLabelWidth: 100,
+            searchMenuSpan: 5,
+            column: {
+              consignorCode: {
+                label: '鏀惰璐х偣缂栫爜', minWidth: 130,
+                search: true,
+              },
+              consignorName: {
+                label: '鏀惰璐х偣鍚嶇О', minWidth: 130,
+                search: true,
+              },
+              consignorType: {
+                label: '鏀惰璐х偣绫诲瀷', minWidth: 80,
+                type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/consignor_type',
+                display: false,
+                hide: false,
+                search: true,
+              },
+              contactName: {
+                label: '鑱旂郴浜哄鍚�', minWidth: 110,
+                display: false,
+                hide: false,
+                search: true,
+              },
+              contactPhone: {
+                label: '鑱旂郴浜虹數璇�', minWidth: 110,
+                display: false,
+                hide: false,
+                search: true,
+              },
+              regionLabel: {
+                label: '琛屾斂鍖哄煙', minWidth: 180,
+                display: false,
+                hide: false,
+                search: true,
+              },
+            },
+
+          },
+          props: {
+            label: 'consignorName',
+            value: 'id'
+          },
+          onLoad: ({page, value, data}: { page: any, value: any, data: any }, callback: any) => {
+            if (value) {
+              let id = value;
+              if (Array.isArray(value)) {
+                id = value[0]
+              }
+              getTmsConsignor(id).then(res => {
+                return callback(res.data || {})
+              })
+            } else {
+              listTmsConsignor({pageSize: page.pageSize, pageNum: page.currentPage, ...data}).then(res => {
+                return callback({
+                  total: res.total,
+                  data: res.rows || [],
+                })
+              })
+            }
+
+          }
+
+        },
+        receiverRegionLabel: {
+          label: '鍗歌揣鐐硅鏀垮尯鍩�',
+          display: true, disabled: true
+        },
+        receiverAddress: {
+          label: '鍗歌揣鐐硅缁嗗湴鍧�',
+          display: true, disabled: true
+        },
+        receiverMobile: {
+          label: '鍗歌揣鐐硅仈绯绘柟寮�',
+          display: true, disabled: true
         },
         containerId: {
           label: '鍏宠仈闆嗚绠变俊鎭�',
@@ -1022,338 +1321,83 @@
           }
 
         },
-      }
-    },
-    {
-      label: '鏀惰璐х偣淇℃伅',
-      prop: 'shffxrxx',
-      column: {
-        shipperId: {
-          label: '瑁呰揣鐐�',dataType:'string',
-          display: true,
-          change: (val: any) => {
-            const table = crudRef.value?.getPropRef?.('shipperId')?.$refs?.temp;
-            if (!table) return;
-            let active = table.active;
-            if (Array.isArray(active)) active = active[0];
-            if (active) {
-              let shipperRegionCode = '';
-              if (active.provinceId){
-                shipperRegionCode = active.provinceId;
-              }
-              if (active.cityId){
-                shipperRegionCode =shipperRegionCode+ ","+active.cityId;
-
-              }
-              if (active.districtId){
-                shipperRegionCode =shipperRegionCode+ ","+active.districtId;
-
-              }
-              if (active.streetId){
-                shipperRegionCode =shipperRegionCode+ ","+active.streetId;
-              }
-              Object.assign(form.value, {
-                shipperId: active.id,
-                shipperName: active.consignorName,
-                shipperRegionLabel: active.regionLabel,
-                shipperAddress: active.addressDetail,
-                shipperMobile: active.contactPhone,
-                shipperRegionCode:shipperRegionCode
-              });
-              form.value.transportLine = form.value.shipperRegionLabel
-                  + (form.value.receiverRegionLabel ? '>' + form.value.receiverRegionLabel : '');
-            }
-          },
-          rules: [
-            {
-              required: true,
-              message: "瑁呰揣鐐逛笉鑳戒负绌�", trigger: "change"
-            }
-          ],
-          type: 'table', suffixIcon: 'search',
-          children: {
-            border: true,
-            searchLabelWidth: 100,
-            searchMenuSpan: 5,
-            column: {
-              consignorCode: {
-                label: '鏀惰璐х偣缂栫爜', minWidth: 130,
-                search: true,
-              },
-              consignorName: {
-                label: '鏀惰璐х偣鍚嶇О', minWidth: 130,
-                search: true,
-              },
-              consignorType: {
-                label: '鏀惰璐х偣绫诲瀷', minWidth: 80,
-                type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/consignor_type',
-                display: false,
-                hide: false,
-                search: true,
-              },
-              contactName: {
-                label: '鑱旂郴浜哄鍚�', minWidth: 110,
-                display: false,
-                hide: false,
-                search: true,
-              },
-              contactPhone: {
-                label: '鑱旂郴浜虹數璇�', minWidth: 110,
-                display: false,
-                hide: false,
-                search: true,
-              },
-              regionLabel: {
-                label: '琛屾斂鍖哄煙', minWidth: 180,
-                display: false,
-                hide: false,
-                search: true,
-              },
-            },
-
-          },
-          props: {
-            label: 'consignorName',
-            value: 'id'
-          },
-          onLoad: ({page, value, data}: { page: any, value: any, data: any }, callback: any) => {
-            if (value) {
-              let id = value;
-              if (Array.isArray(value)) {
-                id = value[0]
-              }
-              getTmsConsignor(id).then(res => {
-                return callback(res.data || {})
-              })
-            } else {
-              listTmsConsignor({pageSize: page.pageSize, pageNum: page.currentPage, ...data}).then(res => {
-                return callback({
-                  total: res.total,
-                  data: res.rows || [],
-                })
-              })
-            }
-
-          }
-
-        },
-        shipperRegionLabel: {
-          label: '瑁呰揣鐐硅鏀垮尯鍩�',
-          display: true, disabled: true
-
-        },
-        shipperAddress: {
-          label: '瑁呰揣鐐硅缁嗗湴鍧�',
-          display: true, disabled: true
-        },
-        shipperMobile: {
-          label: '瑁呰揣鐐硅仈绯绘柟寮�',
-          display: true, disabled: true
-        },
-        receiverId: {
-          label: '鍗歌揣鐐�',
-          display: true, dataType:'string',
-          rules: [
-            {
-              required: true,
-              message: "鍗歌揣鐐逛笉鑳戒负绌�", trigger: "change"
-            }
-          ],
-          change: (val: any) => {
-            const table = crudRef.value?.getPropRef?.('receiverId')?.$refs?.temp;
-            if (!table) return;
-            let active = table.active;
-            if (Array.isArray(active)) active = active[0];
-            if (active) {
-              let receiverRegionCode = '';
-              if (active.provinceId){
-                receiverRegionCode = active.provinceId;
-              }
-              if (active.cityId){
-                receiverRegionCode =receiverRegionCode+ ","+active.cityId;
-
-              }
-              if (active.districtId){
-                receiverRegionCode =receiverRegionCode+ ","+active.districtId;
-
-              }
-              if (active.streetId){
-                receiverRegionCode =receiverRegionCode+ ","+active.streetId;
-              }
-
-              Object.assign(form.value, {
-                receiverId: active.id,
-                receiverName: active.consignorName,
-                receiverRegionLabel: active.regionLabel,
-                receiverAddress: active.addressDetail,
-                receiverMobile: active.contactPhone,
-                receiverRegionCode:receiverRegionCode,
-              });
-              form.value.transportLine =
-                  (form.value.shipperRegionLabel ? form.value.shipperRegionLabel + '>' : '') + form.value.receiverRegionLabel;
-
-            }
-          },
-          type: 'table', suffixIcon: 'search',
-          children: {
-            border: true,
-            searchLabelWidth: 100,
-            searchMenuSpan: 5,
-            column: {
-              consignorCode: {
-                label: '鏀惰璐х偣缂栫爜', minWidth: 130,
-                search: true,
-              },
-              consignorName: {
-                label: '鏀惰璐х偣鍚嶇О', minWidth: 130,
-                search: true,
-              },
-              consignorType: {
-                label: '鏀惰璐х偣绫诲瀷', minWidth: 80,
-                type: 'select', dataType: 'string', dicUrl: '/system/dict/data/type/consignor_type',
-                display: false,
-                hide: false,
-                search: true,
-              },
-              contactName: {
-                label: '鑱旂郴浜哄鍚�', minWidth: 110,
-                display: false,
-                hide: false,
-                search: true,
-              },
-              contactPhone: {
-                label: '鑱旂郴浜虹數璇�', minWidth: 110,
-                display: false,
-                hide: false,
-                search: true,
-              },
-              regionLabel: {
-                label: '琛屾斂鍖哄煙', minWidth: 180,
-                display: false,
-                hide: false,
-                search: true,
-              },
-            },
-
-          },
-          props: {
-            label: 'consignorName',
-            value: 'id'
-          },
-          onLoad: ({page, value, data}: { page: any, value: any, data: any }, callback: any) => {
-            if (value) {
-              let id = value;
-              if (Array.isArray(value)) {
-                id = value[0]
-              }
-              getTmsConsignor(id).then(res => {
-                return callback(res.data || {})
-              })
-            } else {
-              listTmsConsignor({pageSize: page.pageSize, pageNum: page.currentPage, ...data}).then(res => {
-                return callback({
-                  total: res.total,
-                  data: res.rows || [],
-                })
-              })
-            }
-
-          }
-
-        },
-        receiverRegionLabel: {
-          label: '鍗歌揣鐐硅鏀垮尯鍩�',
-          display: true, disabled: true
-        },
-        receiverAddress: {
-          label: '鍗歌揣鐐硅缁嗗湴鍧�',
-          display: true, disabled: true
-        },
-        receiverMobile: {
-          label: '鍗歌揣鐐硅仈绯绘柟寮�',
-          display: true, disabled: true
-        },
-        transportLine: {
-          label: '杩愯緭绾胯矾', span: 24,
-          display: true, disabled: true
-        },
-      }
-    },
-    {
-      label: '杩愯緭瑕佹眰淇℃伅',
-      prop: 'ysyqxx',
-      column: {
-        earliestDeparture: {
-          label: '瑕佹眰鏈�鏃╁嚭鍙戞椂闂�',
-          type: 'datetime',  // 鏀逛负 datetime 绫诲瀷
-          format: 'YYYY-MM-DD HH:mm:ss',
-          valueFormat: 'YYYY-MM-DD HH:mm:ss',
-          display: true,
-        },
-        latestDeparture: {
-          label: '瑕佹眰鏈�鏅氬嚭鍙戞椂闂�',
-          type: 'datetime',  // 鏀逛负 datetime 绫诲瀷
-          format: 'YYYY-MM-DD HH:mm:ss',
-          valueFormat: 'YYYY-MM-DD HH:mm:ss',
-          display: true,
-        },
-        earliestArrival: {
-          label: '瑕佹眰鏈�鏃╁埌杈炬椂闂�',
-          type: 'datetime',  // 鏀逛负 datetime 绫诲瀷
-          format: 'YYYY-MM-DD HH:mm:ss',
-          valueFormat: 'YYYY-MM-DD HH:mm:ss',
-          display: true,
-        },
-        latestArrival: {
-          label: '瑕佹眰鏈�鏅氬埌杈炬椂闂�',
-          type: 'datetime',  // 鏀逛负 datetime 绫诲瀷
-          format: 'YYYY-MM-DD HH:mm:ss',
-          valueFormat: 'YYYY-MM-DD HH:mm:ss',
-          display: true,
-        },
-      }
-    },
-    {
-      label: '杞﹁締淇℃伅',
-      prop: 'clxx',
-      column: {
-        emptyMileage: {
-          label: '绌鸿浇閲岀▼', append: 'Km',
-          display: true,
-        },
-        emptyFuel: {
-          label: '绌鸿浇娌硅��', append: 'L',
-          display: true,
-        },
-        loadedMileage: {
-          label: '閲嶈浇閲岀▼', append: 'Km',
-          display: true,
-        },
-        loadedFuel: {
-          label: '閲嶈浇娌硅��', append: 'L',
-          display: true,
-        },
-      }
-    },
-    {
-      label: '鍏朵粬淇℃伅',
-      prop: 'qtyxx',
-      column: {
-        shiftNo: {
-          label: '鐝鍙�',
-          display: true,
-        },
-        lineNo: {
-          label: '绾胯矾鍙�',
-          display: true,
-        },
         remark: {
           label: '澶囨敞', span: 24,
           type: 'textarea', minRows: 3, maxRows: 5,
           display: true,
         },
-      }
-    }
+      },
+    },
+
+    // {
+    //   label: '杩愯緭瑕佹眰淇℃伅',
+    //   prop: 'ysyqxx',
+    //   column: {
+    //     earliestDeparture: {
+    //       label: '瑕佹眰鏈�鏃╁嚭鍙戞椂闂�',
+    //       type: 'datetime',  // 鏀逛负 datetime 绫诲瀷
+    //       format: 'YYYY-MM-DD HH:mm:ss',
+    //       valueFormat: 'YYYY-MM-DD HH:mm:ss',
+    //       display: true,
+    //     },
+    //     latestDeparture: {
+    //       label: '瑕佹眰鏈�鏅氬嚭鍙戞椂闂�',
+    //       type: 'datetime',  // 鏀逛负 datetime 绫诲瀷
+    //       format: 'YYYY-MM-DD HH:mm:ss',
+    //       valueFormat: 'YYYY-MM-DD HH:mm:ss',
+    //       display: true,
+    //     },
+    //     earliestArrival: {
+    //       label: '瑕佹眰鏈�鏃╁埌杈炬椂闂�',
+    //       type: 'datetime',  // 鏀逛负 datetime 绫诲瀷
+    //       format: 'YYYY-MM-DD HH:mm:ss',
+    //       valueFormat: 'YYYY-MM-DD HH:mm:ss',
+    //       display: true,
+    //     },
+    //
+    //   }
+    // },
+    // {
+    //   label: '杞﹁締淇℃伅',
+    //   prop: 'clxx',
+    //   column: {
+    //     emptyMileage: {
+    //       label: '绌鸿浇閲岀▼', append: 'Km',
+    //       display: true,
+    //     },
+    //     emptyFuel: {
+    //       label: '绌鸿浇娌硅��', append: 'L',
+    //       display: true,
+    //     },
+    //     loadedMileage: {
+    //       label: '閲嶈浇閲岀▼', append: 'Km',
+    //       display: true,
+    //     },
+    //     loadedFuel: {
+    //       label: '閲嶈浇娌硅��', append: 'L',
+    //       display: true,
+    //     },
+    //   }
+    // },
+    // {
+    //   label: '鍏朵粬淇℃伅',
+    //   prop: 'qtyxx',
+    //   column: {
+    //     shiftNo: {
+    //       label: '鐝鍙�',
+    //       display: true,
+    //     },
+    //     lineNo: {
+    //       label: '绾胯矾鍙�',
+    //       display: true,
+    //     },
+    //     remark: {
+    //       label: '澶囨敞', span: 24,
+    //       type: 'textarea', minRows: 3, maxRows: 5,
+    //       display: true,
+    //     },
+    //   }
+    // }
   ],
   column: {
 
@@ -2119,6 +2163,35 @@
 })
 
 
+const itemsTableOption = ref({
+  pageKey: 'itemsTable',
+  rowKey: 'rowKey',
+  header: false,
+  addBtn: false,menu: false,
+  column:{
+    feeType:{
+      label: '璐圭敤鍚嶇О',
+    },
+    unit:{
+      label: '*璁¢噺鍗曚綅',
+    },
+    price:{
+      label: '*璁¤垂閲戦',
+    },
+    currency:{
+      label: '甯佸埗',
+    },
+    count:{
+      label: '璁¤垂鏁伴噺',minWidth:130,
+    },
+    sum:{
+      label: '鎬婚噾棰�',
+    }
+  }
+})
+const itemsCrudRef =ref()
+const itemsTableData = ref<any>([])
+
 const {
   tableData,
   pageF,
@@ -2248,6 +2321,14 @@
     if (Array.isArray(boxForm.value.feeVoucherUrl)) {
       boxForm.value.feeVoucherUrl = boxForm.value.feeVoucherUrl.toString();
     }
+    let filter = selectionList2.value.filter((item:any)=>{
+      return !item.count
+    });
+    if (filter.length > 0){
+      proxy.$modal.msgError("鍕鹃�夋姤浠疯垂鐢ㄨ濉啓璁¤垂鏁伴噺");
+      return;
+    }
+    boxForm.value.items = selectionList2.value;
     addTmsFinanceDetail(boxForm.value).then(res=>{
       ElMessage({
         message: "鎿嶄綔鎴愬姛锛�",
@@ -2276,13 +2357,29 @@
   })
 }
 
-const handleAddFinance = (row:any)=>{
+const handleAddFinance = async (row:any)=>{
   optionType.value = 'addFinance';
   boxFormOption.value = financeOption.value;
   boxTableOption.value = financeTableOption.value;
+  const quotePlanItemRes = await listTmsQuoteItem({quotePlanId:row.quotePlanId,pageNum: 1, pageSize: 999});
+  let items = quotePlanItemRes.rows || [];
+  itemsTableData.value = items.map((item:any) => {
+    return {
+      rowKey: item.id,
+      feeType: item.freeName,
+      unit: item.unit,
+      price: item.price,
+      currency: item.currency,
+      count:  0,
+      sum: 0,
+    }
+  })
+
   listTmsFinanceDetail({
     dispatchOrderId: row.id,financeType:2,
     pageNum: 1, pageSize: 999}).then(res => {
+
+
     boxTableData.value = res.rows || [];
     pageF.open = true;
     pageF.title = '璐圭敤鐧昏';
@@ -2440,6 +2537,13 @@
     onLoad(page.value)
   })
 }
+const countChange = (row:any) => {
+  row.sum = Number(row.price) * Number(row.count);
+}
+
+const selectionChange2 = (selection?: any[]) => {
+  selectionList2.value = selection;
+}
 
 
 </script>
\ No newline at end of file
diff --git a/ui/admin-ui3/src/views/tms/tmsMessageNotify/index.vue b/ui/admin-ui3/src/views/tms/tmsMessageNotify/index.vue
new file mode 100644
index 0000000..d841d6e
--- /dev/null
+++ b/ui/admin-ui3/src/views/tms/tmsMessageNotify/index.vue
@@ -0,0 +1,249 @@
+<template>
+  <basicContainer >
+    <avue-crud
+        :option="option"
+        :table-loading="pageF.loading"
+        :data="tableData"
+        :page="page"
+        :permission="permissionList"
+        :before-open="beforeOpen"
+        v-model="form" v-model:search="queryParams"
+        ref="crudRef"
+        @row-update="rowUpdate"
+        @row-save="rowSave"
+        @refresh-change="refreshChange"
+        @row-del="rowDel"
+        @search-change="searchChange"
+        @search-reset="searchReset"
+        @selection-change="selectionChange"
+        @current-change="currentChange"
+        @size-change="sizeChange"
+        @on-load="onLoad"
+    >
+      <template #menu-left>
+        <el-button
+            type="success"
+            icon="Edit"
+            :disabled="pageF.single"
+            v-hasPermi="['tms:tmsMessageNotify:edit']"
+            @click="handleUpdate">淇敼
+        </el-button>
+        <el-button
+            type="danger"
+            icon="Delete"
+            :disabled="pageF.multiple"
+            @click="handleDelete"
+            v-hasPermi="['tms:tmsMessageNotify:remove']"
+        >鍒犻櫎
+        </el-button>
+        <el-button
+            type="warning"
+            plain
+            icon="Download"
+            @click="handleExport"
+            v-hasPermi="['tms:tmsMessageNotify:export']"
+        >瀵煎嚭
+        </el-button>
+      </template>
+    </avue-crud>
+  </basicContainer>
+</template>
+
+<script setup name="tmsMessageNotify" lang="ts">
+  import {TmsMessageNotifyI,addTmsMessageNotify, delTmsMessageNotify, exportTmsMessageNotify, getTmsMessageNotify, listTmsMessageNotify, updateTmsMessageNotify} from "@/api/tms/tmsMessageNotify";
+  import useCurrentInstance from "@/utils/useCurrentInstance";
+  import {computed,reactive, ref, toRefs} from "vue";
+  import {PagesInterface, PageQueryInterface} from "@/utils/globalInterface";
+  import {usePagePlus} from "@/hooks/usePagePlus";
+  import {hasPermission} from "@/utils/permissionUtils";
+
+  const { proxy } = useCurrentInstance();
+  const crudRef = ref();
+
+  const permissionList = computed(()=>{
+    return {
+      addBtn: hasPermission(["tms:tmsMessageNotify:add"]),
+      delBtn: hasPermission(["tms:tmsMessageNotify:remove"]),
+      editBtn: hasPermission(["tms:tmsMessageNotify:edit"]),
+      viewBtn: hasPermission(["tms:tmsMessageNotify:query"]),
+    }
+  })
+
+  const data = reactive({
+    form:<TmsMessageNotifyI>{},
+    queryParams:<TmsMessageNotifyI&PageQueryInterface>{},
+    page: <PagesInterface>{
+      pageSize: 10,
+      total: 0,
+      currentPage: 1,
+    },
+    selectionList:[],
+  })
+  const {queryParams,form,page,selectionList} = toRefs(data);
+  const option = ref({
+    pageKey: 'TmsMessageNotify',
+    rowKey: 'id',
+    column: {
+                                id: {
+          label: '涓婚敭ID',
+                  addDisplay :true,
+        editDisplay : false,
+        viewDisplay : false,
+        hide : true,
+        search : false,
+                  },
+                                title: {
+          label: '娑堟伅鏍囬',
+                  addDisplay :true,
+        editDisplay :true,
+        viewDisplay :true,
+        hide :false,
+        search :true,
+                      rules: [
+              {
+                required: true,
+                message: "娑堟伅鏍囬涓嶈兘涓虹┖", trigger: "blur" }
+            ],                  },
+                                content: {
+          label: '娑堟伅鍐呭',
+                  addDisplay :true,
+        editDisplay :true,
+        viewDisplay :true,
+        hide :false,
+        search :true,
+                      rules: [
+              {
+                required: true,
+                message: "娑堟伅鍐呭涓嶈兘涓虹┖", trigger: "blur" }
+            ],                  },
+                                type: {
+          label: '娑堟伅绫诲瀷锛�0绯荤粺閫氱煡 1涓氬姟閫氱煡 2鍛婅 3钀ラ攢',
+                  addDisplay :true,
+        editDisplay :true,
+        viewDisplay :true,
+        hide :false,
+        search :true,
+                      rules: [
+              {
+                required: true,
+                message: "娑堟伅绫诲瀷锛�0绯荤粺閫氱煡 1涓氬姟閫氱煡 2鍛婅 3钀ラ攢涓嶈兘涓虹┖", trigger: "change"
+                 }
+            ],                  },
+                                targetUid: {
+          label: '鎺ユ敹鐢ㄦ埛ID',
+                  addDisplay :true,
+        editDisplay :true,
+        viewDisplay :true,
+        hide :false,
+        search :true,
+                  },
+                                status: {
+          label: '鍙戦�佺姸鎬侊細0寰呭彂閫� 1鎴愬姛 2澶辫触',
+                  addDisplay :true,
+        editDisplay :true,
+        viewDisplay :true,
+        hide :false,
+        search :true,
+                      rules: [
+              {
+                required: true,
+                message: "鍙戦�佺姸鎬侊細0寰呭彂閫� 1鎴愬姛 2澶辫触涓嶈兘涓虹┖", trigger: "blur" }
+            ],                  },
+                                readStatus: {
+          label: '闃呰鐘舵�侊細0鏈 1宸茶',
+                  addDisplay :true,
+        editDisplay :true,
+        viewDisplay :true,
+        hide :false,
+        search :true,
+                      rules: [
+              {
+                required: true,
+                message: "闃呰鐘舵�侊細0鏈 1宸茶涓嶈兘涓虹┖", trigger: "blur" }
+            ],                  },
+                                readTime: {
+          label: '璇诲彇鏃堕棿',
+                      type: 'date', valueFormat: 'YYYY-MM-DD',
+                  addDisplay :true,
+        editDisplay :true,
+        viewDisplay :true,
+        hide :false,
+        search :true,
+                  },
+                                extraData: {
+          label: '鎵╁睍淇℃伅(JSON鏂囨湰)',
+                      type: 'textarea', minRows: 3, maxRows: 5,
+                  addDisplay :true,
+        editDisplay :true,
+        viewDisplay :true,
+        hide :false,
+        search :true,
+                  },
+                                createUid: {
+          label: '鍒涘缓浜�',
+                  addDisplay :true,
+        editDisplay :true,
+        viewDisplay :true,
+        hide :false,
+        search :true,
+                  },
+                                createTime: {
+          label: '鍒涘缓鏃堕棿',
+                      type: 'date', valueFormat: 'YYYY-MM-DD',
+                  addDisplay :true,
+        editDisplay : false,
+        viewDisplay : false,
+        hide : true,
+        search : false,
+                      rules: [
+              {
+                required: true,
+                message: "鍒涘缓鏃堕棿涓嶈兘涓虹┖", trigger: "blur" }
+            ],                  },
+                                updateUid: {
+          label: '鏇存柊浜�',
+                  addDisplay :true,
+        editDisplay :true,
+        viewDisplay :true,
+        hide :false,
+        search :true,
+                  },
+                                updateTime: {
+          label: '鏇存柊鏃堕棿',
+                      type: 'date', valueFormat: 'YYYY-MM-DD',
+                  addDisplay :true,
+        editDisplay :true,
+        viewDisplay : false,
+        hide : true,
+        search : false,
+                      rules: [
+              {
+                required: true,
+                message: "鏇存柊鏃堕棿涓嶈兘涓虹┖", trigger: "blur" }
+            ]                  },
+          }
+  })
+
+  const { tableData,pageF,rowSave,rowUpdate,rowDel,beforeOpen,searchChange,
+    searchReset,selectionChange,onLoad,currentChange,sizeChange,handleDelete,handleExport,handleUpdate,refreshChange} = usePagePlus({
+    form:form,
+    option:option,
+    queryParams:queryParams,
+    idKey:'id',
+    page:page.value,
+    getListApi:listTmsMessageNotify,
+    getDetailApi:getTmsMessageNotify,
+    exportApi:exportTmsMessageNotify,
+    deleteApi:delTmsMessageNotify,
+    addApi:addTmsMessageNotify,
+    updateApi:updateTmsMessageNotify,
+    handleUpdateFunc:()=>{
+      crudRef.value.rowEdit(selectionList.value[0]);
+    },
+    handleSelectionChangeFunc:(selection:any)=>{
+      selectionList.value = selection;
+    }
+  })
+
+
+</script>
diff --git a/ui/admin-ui3/src/views/tms/tmsProject/index.vue b/ui/admin-ui3/src/views/tms/tmsProject/index.vue
index 6db1da5..e582100 100644
--- a/ui/admin-ui3/src/views/tms/tmsProject/index.vue
+++ b/ui/admin-ui3/src/views/tms/tmsProject/index.vue
@@ -111,12 +111,7 @@
         projectCode: {
           label: '椤圭洰缂栧彿',
           display: true,
-          rules: [
-            {
-              required: true,
-              message: "椤圭洰缂栧彿涓嶈兘涓虹┖", trigger: "blur"
-            }
-          ],
+
         },
         relatedCustomerId: {
           label: '鍏宠仈瀹㈡埛',
@@ -283,7 +278,7 @@
       column:{
         status: {
           label: '鐘舵��',dataType: 'string',
-          type: 'radio', dicUrl: '/system/dict/data/type/data_status',
+          type: 'radio', dicUrl: '/system/dict/data/type/project_status',
           addDisplay: false,minWidth: 150,
           editDisplay: false,
           viewDisplay: true,
@@ -353,7 +348,7 @@
     },
     status: {
       label: '鐘舵��',dataType: 'string',
-      type: 'radio', dicUrl: '/system/dict/data/type/data_status',
+      type: 'radio', dicUrl: '/system/dict/data/type/project_status',
       display: false,minWidth: 150,
       search: true,
     },

--
Gitblit v1.8.0