Lin Qilong 1 semana atrás
pai
commit
fa54cc4677
22 arquivos alterados com 875 adições e 159 exclusões
  1. 3 2
      gw-admin/src/main/java/com/goldenwater/web/controller/system/ObjTendController.java
  2. 2 1
      gw-admin/src/main/java/com/goldenwater/web/controller/system/RelTendOrgController.java
  3. 1 1
      gw-common/src/main/java/com/goldenwater/common/core/domain/entity/ObjTend.java
  4. 40 0
      gw-common/src/main/java/com/goldenwater/common/core/domain/vo/ObjTendDetailVO.java
  5. 21 0
      gw-common/src/main/java/com/goldenwater/common/core/domain/vo/RelTendOrgDetailVO.java
  6. 1 0
      gw-slaj/src/main/resources/mapper/slaj/hidd/AttEngBaseMapper.xml
  7. 1 0
      gw-slaj/src/main/resources/mapper/slaj/hidd/AttOrgBaseMapper.xml
  8. 1 0
      gw-slaj/src/main/resources/mapper/slaj/hidd/ObjEngMapper.xml
  9. 11 0
      gw-system/src/main/java/com/goldenwater/system/mapper/ObjTendMapper.java
  10. 2 0
      gw-system/src/main/java/com/goldenwater/system/mapper/RelTendOrgMapper.java
  11. 3 0
      gw-system/src/main/java/com/goldenwater/system/service/IObjTendService.java
  12. 2 0
      gw-system/src/main/java/com/goldenwater/system/service/IRelTendOrgService.java
  13. 11 0
      gw-system/src/main/java/com/goldenwater/system/service/impl/ObjTendServiceImpl.java
  14. 6 0
      gw-system/src/main/java/com/goldenwater/system/service/impl/RelTendOrgServiceImpl.java
  15. 38 6
      gw-system/src/main/resources/mapper/system/ObjTendMapper.xml
  16. 13 0
      gw-system/src/main/resources/mapper/system/RelTendOrgMapper.xml
  17. 64 55
      gw-ui/src/components/OrgSelect/index.vue
  18. 14 0
      gw-ui/src/router/index.js
  19. 175 68
      gw-ui/src/views/system/dept/index.vue
  20. 181 0
      gw-ui/src/views/system/projbase/eng/index.vue
  21. 77 19
      gw-ui/src/views/system/projbase/index.vue
  22. 208 7
      gw-ui/src/views/system/projbase/tend/index.vue

+ 3 - 2
gw-admin/src/main/java/com/goldenwater/web/controller/system/ObjTendController.java

@@ -8,6 +8,7 @@ import com.goldenwater.common.annotation.Log;
 import com.goldenwater.common.core.controller.BaseController;
 import com.goldenwater.common.core.domain.AjaxResult;
 import com.goldenwater.common.core.domain.entity.ObjTend;
+import com.goldenwater.common.core.domain.vo.ObjTendDetailVO;
 import com.goldenwater.common.core.page.TableDataInfo;
 import com.goldenwater.common.enums.BusinessType;
 import com.goldenwater.system.service.IObjTendService;
@@ -23,14 +24,14 @@ public class ObjTendController extends BaseController
     @GetMapping("/list")
     public TableDataInfo list(ObjTend objTend) {
         startPage();
-        List<ObjTend> list = objTendService.selectObjTendList(objTend);
+        List<ObjTendDetailVO> list = objTendService.selectObjTendDetailList(objTend);
         return getDataTable(list);
     }
 
     @PreAuthorize("@ss.hasPermi('business:objtend:query')")
     @GetMapping("/{guid}")
     public AjaxResult getInfo(@PathVariable String guid) {
-        return success(objTendService.selectObjTendByGuid(guid));
+        return success(objTendService.selectObjTendDetailByGuid(guid));
     }
 
     @PreAuthorize("@ss.hasPermi('business:objtend:add')")

+ 2 - 1
gw-admin/src/main/java/com/goldenwater/web/controller/system/RelTendOrgController.java

@@ -8,6 +8,7 @@ import com.goldenwater.common.annotation.Log;
 import com.goldenwater.common.core.controller.BaseController;
 import com.goldenwater.common.core.domain.AjaxResult;
 import com.goldenwater.common.core.domain.entity.RelTendOrg;
+import com.goldenwater.common.core.domain.vo.RelTendOrgDetailVO;
 import com.goldenwater.common.core.page.TableDataInfo;
 import com.goldenwater.common.enums.BusinessType;
 import com.goldenwater.system.service.IRelTendOrgService;
@@ -23,7 +24,7 @@ public class RelTendOrgController extends BaseController
     @GetMapping("/list")
     public TableDataInfo list(RelTendOrg relTendOrg) {
         startPage();
-        List<RelTendOrg> list = relTendOrgService.selectRelTendOrgList(relTendOrg);
+        List<RelTendOrgDetailVO> list = relTendOrgService.selectRelTendOrgDetailList(relTendOrg);
         return getDataTable(list);
     }
 

+ 1 - 1
gw-common/src/main/java/com/goldenwater/common/core/domain/entity/ObjTend.java

@@ -18,7 +18,7 @@ public class ObjTend {
     private String orgGuid;
     /** 工程id */
     private String engGuid;
-    /** 项目GUID,关联 ATT_PROJ_BASE.GUID(标段所属项目) */
+    /** 项目GUID(仅查询筛选用,非 obj_tend 表字段;真实关联经 eng_guid → att_eng_base.proj_guid) */
     private String projGuid;
     /** 部门(未使用) */
     private String orgProjDeptGuid;

+ 40 - 0
gw-common/src/main/java/com/goldenwater/common/core/domain/vo/ObjTendDetailVO.java

@@ -0,0 +1,40 @@
+package com.goldenwater.common.core.domain.vo;
+
+import lombok.Data;
+import java.util.Date;
+
+/**
+ * 标段详情 VO(obj_tend 融合 obj_eng 工程名 + att_org_base/uwat 单位名)
+ * 后端做数据拼接,前端只负责展示。
+ *
+ * @author goldenwater
+ */
+@Data
+public class ObjTendDetailVO {
+    // ========== obj_tend 字段 ==========
+    private String guid;
+    private String tendName;
+    private String orgGuid;
+    private String engGuid;
+    private String projGuid;
+    private String orgProjDeptGuid;
+    private String legPers;
+    private String legTel;
+    private java.math.BigDecimal conAmout;
+    private java.math.BigDecimal totalSpc;
+    private String consCont;
+    private String note;
+    private Date collTime;
+    private Date updTime;
+    private String recPers;
+    private Date toDate;
+    private String stat;
+
+    // ========== 融合字段(后台 JOIN 拼接) ==========
+    /** 工程名称(obj_eng) */
+    private String engName;
+    /** 工程编码(obj_eng) */
+    private String engCode;
+    /** 所属单位名称(att_org_base 或 att_org_uwat_base) */
+    private String orgName;
+}

+ 21 - 0
gw-common/src/main/java/com/goldenwater/common/core/domain/vo/RelTendOrgDetailVO.java

@@ -0,0 +1,21 @@
+package com.goldenwater.common.core.domain.vo;
+
+import lombok.Data;
+import java.util.Date;
+
+/**
+ * 标段与参建单位关系详情 VO(rel_tend_org 融合 att_org_uwat_base 单位名)
+ *
+ * @author goldenwater
+ */
+@Data
+public class RelTendOrgDetailVO {
+    private String guid;
+    private String tendGuid;
+    private String orgUwatGuid;
+    private Date fromDate;
+    private Date toDate;
+
+    /** 参建单位名称(后台 JOIN 拼接) */
+    private String orgName;
+}

+ 1 - 0
gw-slaj/src/main/resources/mapper/slaj/hidd/AttEngBaseMapper.xml

@@ -67,6 +67,7 @@
             <if test="engName != null and engName != ''">AND eng_name like '%' || #{engName} || '%'</if>
             <if test="engCode != null and engCode != ''">AND eng_code = #{engCode}</if>
             <if test="engGuid != null and engGuid != ''">AND eng_guid = #{engGuid}</if>
+            <if test="projGuid != null and projGuid != ''">AND proj_guid = #{projGuid}</if>
             <if test="orgGuid != null and orgGuid != ''">AND org_guid = #{orgGuid}</if>
         </where>
     </select>

+ 1 - 0
gw-slaj/src/main/resources/mapper/slaj/hidd/AttOrgBaseMapper.xml

@@ -36,6 +36,7 @@
         <where>
             <if test="orgName != null and orgName != ''">AND b.org_name like '%' || #{orgName} || '%'</if>
             <if test="orgCode != null and orgCode != ''">AND b.org_code = #{orgCode}</if>
+            <if test="orgType != null and orgType != ''">AND b.org_type = #{orgType}</if>
             <if test="pguid != null and pguid != ''">AND b.pguid = #{pguid}</if>
             <if test="wiunProp != null and wiunProp != ''">AND EXISTS (SELECT 1 FROM att_org_ext ext WHERE ext.org_guid = b.guid AND ext.wiun_prop = #{wiunProp})</if>
         </where>

+ 1 - 0
gw-slaj/src/main/resources/mapper/slaj/hidd/ObjEngMapper.xml

@@ -26,6 +26,7 @@
     <select id="selectObjEngList" parameterType="com.goldenwater.common.core.domain.obj.ObjEng" resultMap="ObjEngResult">
         <include refid="selectObjEngVo"/>
         <where>
+            <if test="engCode != null and engCode != ''">AND eng_code like '%' || #{engCode} || '%'</if>
             <if test="engName != null and engName != ''">AND eng_name like '%' || #{engName} || '%'</if>
             <if test="engType != null and engType != ''">AND eng_type = #{engType}</if>
         </where>

+ 11 - 0
gw-system/src/main/java/com/goldenwater/system/mapper/ObjTendMapper.java

@@ -3,6 +3,7 @@ package com.goldenwater.system.mapper;
 import java.util.List;
 import org.apache.ibatis.annotations.Mapper;
 import com.goldenwater.common.core.domain.entity.ObjTend;
+import com.goldenwater.common.core.domain.vo.ObjTendDetailVO;
 
 /**
  * 标段对象 数据层
@@ -23,6 +24,16 @@ public interface ObjTendMapper {
      */
     ObjTend selectObjTendByGuid(String guid);
 
+    /**
+     * 查询标段融合列表(含工程名、单位名)
+     */
+    List<ObjTendDetailVO> selectObjTendDetailList(ObjTend objTend);
+
+    /**
+     * 查询标段融合详情(含工程名、单位名)
+     */
+    ObjTendDetailVO selectObjTendDetailByGuid(String guid);
+
     /**
      * 新增标段
      * @param objTend 标段

+ 2 - 0
gw-system/src/main/java/com/goldenwater/system/mapper/RelTendOrgMapper.java

@@ -3,6 +3,7 @@ package com.goldenwater.system.mapper;
 import java.util.List;
 import org.apache.ibatis.annotations.Param;
 import com.goldenwater.common.core.domain.entity.RelTendOrg;
+import com.goldenwater.common.core.domain.vo.RelTendOrgDetailVO;
 
 /**
  * 标段与非水利机构关系表 数据层
@@ -13,6 +14,7 @@ public interface RelTendOrgMapper
 {
     public List<RelTendOrg> selectRelTendOrgList(RelTendOrg relTendOrg);
     public RelTendOrg selectRelTendOrgById(String guid);
+    public List<RelTendOrgDetailVO> selectRelTendOrgDetailList(RelTendOrg relTendOrg);
     public int insertRelTendOrg(RelTendOrg relTendOrg);
     public int updateRelTendOrg(RelTendOrg relTendOrg);
     public int deleteRelTendOrgById(String guid);

+ 3 - 0
gw-system/src/main/java/com/goldenwater/system/service/IObjTendService.java

@@ -2,6 +2,7 @@ package com.goldenwater.system.service;
 
 import java.util.List;
 import com.goldenwater.common.core.domain.entity.ObjTend;
+import com.goldenwater.common.core.domain.vo.ObjTendDetailVO;
 
 /**
  * 标段对象 服务层
@@ -12,6 +13,8 @@ public interface IObjTendService
 {
     public List<ObjTend> selectObjTendList(ObjTend objTend);
     public ObjTend selectObjTendByGuid(String guid);
+    public List<ObjTendDetailVO> selectObjTendDetailList(ObjTend objTend);
+    public ObjTendDetailVO selectObjTendDetailByGuid(String guid);
     public int insertObjTend(ObjTend objTend);
     public int updateObjTend(ObjTend objTend);
     public int deleteObjTendByGuid(String guid);

+ 2 - 0
gw-system/src/main/java/com/goldenwater/system/service/IRelTendOrgService.java

@@ -2,6 +2,7 @@ package com.goldenwater.system.service;
 
 import java.util.List;
 import com.goldenwater.common.core.domain.entity.RelTendOrg;
+import com.goldenwater.common.core.domain.vo.RelTendOrgDetailVO;
 
 /**
  * 标段与非水利机构关系表 服务层
@@ -12,6 +13,7 @@ public interface IRelTendOrgService
 {
     public List<RelTendOrg> selectRelTendOrgList(RelTendOrg relTendOrg);
     public RelTendOrg selectRelTendOrgById(String guid);
+    public List<RelTendOrgDetailVO> selectRelTendOrgDetailList(RelTendOrg relTendOrg);
     public int insertRelTendOrg(RelTendOrg relTendOrg);
     public int updateRelTendOrg(RelTendOrg relTendOrg);
     public int deleteRelTendOrgById(String guid);

+ 11 - 0
gw-system/src/main/java/com/goldenwater/system/service/impl/ObjTendServiceImpl.java

@@ -1,6 +1,7 @@
 package com.goldenwater.system.service.impl;
 
 import com.goldenwater.common.core.domain.entity.ObjTend;
+import com.goldenwater.common.core.domain.vo.ObjTendDetailVO;
 import com.goldenwater.common.utils.SecurityUtils;
 import com.goldenwater.common.utils.uuid.IdUtils;
 import com.goldenwater.system.mapper.ObjTendMapper;
@@ -31,6 +32,16 @@ public class ObjTendServiceImpl implements IObjTendService {
         return objTendMapper.selectObjTendByGuid(guid);
     }
 
+    @Override
+    public List<ObjTendDetailVO> selectObjTendDetailList(ObjTend objTend) {
+        return objTendMapper.selectObjTendDetailList(objTend);
+    }
+
+    @Override
+    public ObjTendDetailVO selectObjTendDetailByGuid(String guid) {
+        return objTendMapper.selectObjTendDetailByGuid(guid);
+    }
+
     @Override
     public int insertObjTend(ObjTend objTend) {
         objTend.setGuid(IdUtils.fastSimpleUUID());

+ 6 - 0
gw-system/src/main/java/com/goldenwater/system/service/impl/RelTendOrgServiceImpl.java

@@ -4,6 +4,7 @@ import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.goldenwater.common.core.domain.entity.RelTendOrg;
+import com.goldenwater.common.core.domain.vo.RelTendOrgDetailVO;
 import com.goldenwater.system.mapper.RelTendOrgMapper;
 import com.goldenwater.system.service.IRelTendOrgService;
 
@@ -28,6 +29,11 @@ public class RelTendOrgServiceImpl implements IRelTendOrgService
         return relTendOrgMapper.selectRelTendOrgById(guid);
     }
 
+    @Override
+    public List<RelTendOrgDetailVO> selectRelTendOrgDetailList(RelTendOrg relTendOrg) {
+        return relTendOrgMapper.selectRelTendOrgDetailList(relTendOrg);
+    }
+
     @Override
     public int insertRelTendOrg(RelTendOrg relTendOrg) {
         return relTendOrgMapper.insertRelTendOrg(relTendOrg);

+ 38 - 6
gw-system/src/main/resources/mapper/system/ObjTendMapper.xml

@@ -6,7 +6,6 @@
         <result property="tendName" column="tend_name"/>
         <result property="orgGuid" column="org_guid"/>
         <result property="engGuid" column="eng_guid"/>
-        <result property="projGuid" column="proj_guid"/>
         <result property="orgProjDeptGuid" column="org_proj_dept_guid"/>
         <result property="legPers" column="leg_pers"/>
         <result property="legTel" column="leg_tel"/>
@@ -21,7 +20,7 @@
         <result property="stat" column="stat"/>
     </resultMap>
     <sql id="selectObjTendVo">
-        select guid, tend_name, org_guid, eng_guid, proj_guid, org_proj_dept_guid,
+        select guid, tend_name, org_guid, eng_guid, org_proj_dept_guid,
                leg_pers, leg_tel, con_amout, total_spc, cons_cont,
                note, coll_time, upd_time, rec_pers, to_date, stat
         from obj_tend
@@ -31,7 +30,6 @@
         <where>
             <if test="guid != null and guid != ''">AND guid = #{guid}</if>
             <if test="engGuid != null and engGuid != ''">AND eng_guid = #{engGuid}</if>
-            <if test="projGuid != null and projGuid != ''">AND proj_guid = #{projGuid}</if>
             <if test="tendName != null and tendName != ''">AND tend_name like '%' || #{tendName} || '%'</if>
         </where>
         order by guid
@@ -40,6 +38,43 @@
         <include refid="selectObjTendVo"/>
         where guid = #{guid}
     </select>
+
+    <!-- 融合查询:标段 + 工程名 + 单位名 + 所属项目(经工程 att_eng_base 关联),后台拼接 -->
+    <select id="selectObjTendDetailList" parameterType="com.goldenwater.common.core.domain.entity.ObjTend" resultType="com.goldenwater.common.core.domain.vo.ObjTendDetailVO">
+        select t.guid, t.tend_name, t.org_guid, t.eng_guid, t.org_proj_dept_guid,
+               t.leg_pers, t.leg_tel, t.con_amout, t.total_spc, t.cons_cont,
+               t.note, t.coll_time, t.upd_time, t.rec_pers, t.to_date, t.stat,
+               e.eng_name, e.eng_code,
+               eb.proj_guid as proj_guid,
+               COALESCE(b.org_name, u.org_name) as org_name
+        from obj_tend t
+        left join obj_eng e on e.guid = t.eng_guid
+        left join att_eng_base eb on eb.guid = t.eng_guid
+        left join att_org_base b on b.guid = t.org_guid
+        left join att_org_uwat_base u on u.guid = t.org_guid
+        <where>
+            <if test="guid != null and guid != ''">AND t.guid = #{guid}</if>
+            <if test="engGuid != null and engGuid != ''">AND t.eng_guid = #{engGuid}</if>
+            <if test="projGuid != null and projGuid != ''">AND eb.proj_guid = #{projGuid}</if>
+            <if test="tendName != null and tendName != ''">AND t.tend_name like '%' || #{tendName} || '%'</if>
+        </where>
+        order by t.guid
+    </select>
+
+    <select id="selectObjTendDetailByGuid" parameterType="String" resultType="com.goldenwater.common.core.domain.vo.ObjTendDetailVO">
+        select t.guid, t.tend_name, t.org_guid, t.eng_guid, t.org_proj_dept_guid,
+               t.leg_pers, t.leg_tel, t.con_amout, t.total_spc, t.cons_cont,
+               t.note, t.coll_time, t.upd_time, t.rec_pers, t.to_date, t.stat,
+               e.eng_name, e.eng_code,
+               eb.proj_guid as proj_guid,
+               COALESCE(b.org_name, u.org_name) as org_name
+        from obj_tend t
+        left join obj_eng e on e.guid = t.eng_guid
+        left join att_eng_base eb on eb.guid = t.eng_guid
+        left join att_org_base b on b.guid = t.org_guid
+        left join att_org_uwat_base u on u.guid = t.org_guid
+        where t.guid = #{guid}
+    </select>
     <insert id="insertObjTend" parameterType="com.goldenwater.common.core.domain.entity.ObjTend">
         insert into obj_tend
         <trim prefix="(" suffix=")" suffixOverrides=",">
@@ -47,7 +82,6 @@
             <if test="tendName != null">tend_name,</if>
             <if test="orgGuid != null">org_guid,</if>
             <if test="engGuid != null">eng_guid,</if>
-            <if test="projGuid != null">proj_guid,</if>
             <if test="orgProjDeptGuid != null">org_proj_dept_guid,</if>
             <if test="legPers != null">leg_pers,</if>
             <if test="legTel != null">leg_tel,</if>
@@ -63,7 +97,6 @@
             <if test="tendName != null">#{tendName},</if>
             <if test="orgGuid != null">#{orgGuid},</if>
             <if test="engGuid != null">#{engGuid},</if>
-            <if test="projGuid != null">#{projGuid},</if>
             <if test="orgProjDeptGuid != null">#{orgProjDeptGuid},</if>
             <if test="legPers != null">#{legPers},</if>
             <if test="legTel != null">#{legTel},</if>
@@ -81,7 +114,6 @@
             <if test="tendName != null">tend_name = #{tendName},</if>
             <if test="orgGuid != null">org_guid = #{orgGuid},</if>
             <if test="engGuid != null">eng_guid = #{engGuid},</if>
-            <if test="projGuid != null">proj_guid = #{projGuid},</if>
             <if test="orgProjDeptGuid != null">org_proj_dept_guid = #{orgProjDeptGuid},</if>
             <if test="legPers != null">leg_pers = #{legPers},</if>
             <if test="legTel != null">leg_tel = #{legTel},</if>

+ 13 - 0
gw-system/src/main/resources/mapper/system/RelTendOrgMapper.xml

@@ -32,6 +32,19 @@
         where GUID = #{guid}
     </select>
 
+    <!-- 融合查询:标段关系 + 参建单位名称,按 tendGuid 精确匹配 -->
+    <select id="selectRelTendOrgDetailList" parameterType="RelTendOrg" resultType="com.goldenwater.common.core.domain.vo.RelTendOrgDetailVO">
+        select r.GUID, r.TEND_GUID, r.ORG_UWAT_GUID, r.FROM_DATE, r.TO_DATE,
+               u.ORG_NAME as org_name
+        from REL_TEND_ORG r
+        left join ATT_ORG_UWAT_BASE u on u.GUID = r.ORG_UWAT_GUID
+        <where>
+            <if test="tendGuid != null and tendGuid != ''">AND r.TEND_GUID = #{tendGuid}</if>
+            <if test="orgUwatGuid != null and orgUwatGuid != ''">AND r.ORG_UWAT_GUID = #{orgUwatGuid}</if>
+        </where>
+        order by r.GUID
+    </select>
+
     <insert id="insertRelTendOrg" parameterType="RelTendOrg">
         insert into REL_TEND_ORG(
             <if test="tendGuid != null">TEND_GUID,</if>

+ 64 - 55
gw-ui/src/components/OrgSelect/index.vue

@@ -4,54 +4,66 @@
     :prop="prop"
     :rules="required ? [{ required: true, message: label + '不能为空', trigger: 'change' }] : undefined"
   >
-    <el-select
-      :model-value="modelValue"
-      filterable
-      remote
-      clearable
-      reserve-keyword
-      :remote-method="remoteSearch"
-      :loading="loading"
-      :disabled="disabled"
-      :placeholder="placeholder"
-      style="width: 100%"
-      @update:model-value="handleChange"
-    >
-      <el-option
-        v-for="item in options"
-        :key="item.value"
-        :label="item.label"
-        :value="item.value"
-      />
-    </el-select>
+    <div style="display:flex;gap:8px">
+      <el-select v-model="currentScope" placeholder="范围" style="width:110px;flex-shrink:0" size="default" v-if="showScope">
+        <el-option label="全部" value="all"/>
+        <el-option label="水利机构" value="water"/>
+        <el-option label="非水利机构" value="uwat"/>
+      </el-select>
+      <el-select
+        :model-value="modelValue"
+        filterable
+        remote
+        clearable
+        reserve-keyword
+        :remote-method="remoteSearch"
+        :loading="loading"
+        :disabled="disabled"
+        :placeholder="placeholder"
+        style="width: 100%"
+        @update:model-value="handleChange"
+      >
+        <el-option
+          v-for="item in options"
+          :key="item.value"
+          :label="item.label"
+          :value="item.value"
+        />
+      </el-select>
+    </div>
   </el-form-item>
 </template>
 
 <script setup>
 import { ref, watch } from 'vue'
 import { listAttOrgBase, getAttOrgBase } from '@/api/slaj/hidd'
+import { listAttOrgUwatBase, getAttOrgUwatBase } from '@/api/system/attOrgUwatBase'
 
 const props = defineProps({
-  // v-model:选中的机构 GUID
   modelValue: { type: String, default: undefined },
-  // 表单字段标签,默认“组织机构”,可修改
   label: { type: String, default: '组织机构' },
-  // el-form 校验字段名
   prop: { type: String, default: undefined },
-  // 占位提示
   placeholder: { type: String, default: '请输入机构名称搜索' },
-  // 是否必填
   required: { type: Boolean, default: false },
-  // 是否禁用
   disabled: { type: Boolean, default: false },
-  // 编辑自身时排除自己(避免选自己作为上级)
-  excludeGuid: { type: String, default: undefined }
+  excludeGuid: { type: String, default: undefined },
+  // 范围筛选:all=全部, water=水利机构, uwat=非水利机构
+  scope: { type: String, default: 'all' },
+  // 是否显示范围选择器
+  showScope: { type: Boolean, default: false }
 })
 
 const emit = defineEmits(['update:modelValue'])
 
 const options = ref([])
 const loading = ref(false)
+const currentScope = ref(props.scope)
+
+// scope 变化时清空已选值
+watch(currentScope, () => {
+  emit('update:modelValue', undefined)
+  options.value = []
+})
 
 function normalize(rows) {
   return (rows || [])
@@ -60,35 +72,32 @@ function normalize(rows) {
 }
 
 function remoteSearch(query) {
-  if (!query) {
-    options.value = []
-    return
-  }
+  if (!query) { options.value = []; return }
   loading.value = true
-  listAttOrgBase({ orgName: query, pageNum: 1, pageSize: 20 })
-    .then(res => { options.value = normalize(res.rows) })
-    .finally(() => { loading.value = false })
+  let req
+  if (currentScope.value === 'uwat') {
+    req = listAttOrgUwatBase({ orgName: query, pageNum: 1, pageSize: 20 })
+      .then(res => { options.value = (res.rows || []).filter(r => !props.excludeGuid || r.guid !== props.excludeGuid).map(r => ({ value: r.guid, label: r.orgName })) })
+  } else {
+    const params = { orgName: query, pageNum: 1, pageSize: 20 }
+    if (currentScope.value === 'water') params.orgType = '1'
+    req = listAttOrgBase(params).then(res => { options.value = normalize(res.rows) })
+  }
+  req.finally(() => { loading.value = false })
 }
 
-function handleChange(val) {
-  emit('update:modelValue', val)
-}
+function handleChange(val) { emit('update:modelValue', val) }
 
-// 编辑回显:modelValue 被外部赋值时,预加载对应机构名称
-watch(
-  () => props.modelValue,
-  (val) => {
-    if (val && !options.value.some(o => o.value === val)) {
-      getAttOrgBase(val)
-        .then(res => {
-          const d = res.data
-          if (d && d.guid && (!props.excludeGuid || d.guid !== props.excludeGuid)) {
-            options.value = [{ value: d.guid, label: d.orgName }, ...options.value]
-          }
-        })
-        .catch(() => {})
-    }
-  },
-  { immediate: true }
-)
+// 编辑回显
+watch(() => props.modelValue, (val) => {
+  if (val && !options.value.some(o => o.value === val)) {
+    const fetch = currentScope.value === 'uwat' ? getAttOrgUwatBase(val) : getAttOrgBase(val)
+    fetch.then(res => {
+      const d = res.data
+      if (d && d.guid && (!props.excludeGuid || d.guid !== props.excludeGuid)) {
+        options.value = [{ value: d.guid, label: d.orgName }, ...options.value]
+      }
+    }).catch(() => {})
+  }
+}, { immediate: true })
 </script>

+ 14 - 0
gw-ui/src/router/index.js

@@ -150,6 +150,20 @@ export const dynamicRoutes = [
       }
     ]
   },
+  {
+    path: '/system/projbase-eng',
+    component: Layout,
+    hidden: true,
+    permissions: ['business:objeng:list'],
+    children: [
+      {
+        path: 'index/:projGuid',
+        component: () => import('@/views/system/projbase/eng/index'),
+        name: 'ProjBaseEng',
+        meta: { title: '项目工程', activeMenu: '/system/projbase' }
+      }
+    ]
+  },
   {
     path: '/system/projbase-tend',
     component: Layout,

+ 175 - 68
gw-ui/src/views/system/dept/index.vue

@@ -1,17 +1,17 @@
 <template>
    <div ref="containerRef" class="app-container">
       <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
-         <el-form-item label="部门名称" prop="deptName">
+         <el-form-item label="机构名称" prop="deptName">
             <el-input
                v-model="queryParams.deptName"
-               placeholder="请输入部门名称"
+               placeholder="请输入机构名称"
                clearable
                style="width: 200px"
                @keyup.enter="handleQuery"
             />
          </el-form-item>
          <el-form-item label="状态" prop="status">
-            <el-select v-model="queryParams.status" placeholder="部门状态" clearable style="width: 200px">
+            <el-select v-model="queryParams.status" placeholder="机构状态" clearable style="width: 200px">
                <el-option
                   v-for="dict in sys_normal_disable"
                   :key="dict.value"
@@ -59,7 +59,7 @@
          :load="loadChildren"
          :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
       >
-         <el-table-column prop="deptName" label="部门名称" width="300"></el-table-column>
+         <el-table-column prop="deptName" label="机构名称" width="300"></el-table-column>
          <el-table-column prop="orderNum" label="排序" width="200">
             <template #default="scope">
                <el-input-number v-model="scope.row.orderNum" controls-position="right" :min="0" style="width: 88px" />
@@ -93,59 +93,117 @@
          @pagination="getList"
       />
 
-      <!-- 添加或修改部门对话框 -->
-      <el-dialog :title="title" v-model="open" width="600px" append-to-body>
-         <el-form ref="deptRef" :model="form" :rules="rules" label-width="80px">
+      <!-- 添加或修改机构对话框 -->
+      <el-dialog :title="title" v-model="open" width="760px" append-to-body :close-on-click-modal="false">
+         <el-form ref="deptRef" :model="form" :rules="rules" label-width="100px">
+            <!-- 机构类型选择(新增时可选,修改时锁定) -->
             <el-row>
-               <el-col :span="24" v-if="form.parentId !== 0">
-                  <el-form-item label="上级部门" prop="parentId">
-                     <el-tree-select
-                        v-model="form.parentId"
-                        :data="deptOptions"
-                        :props="{ value: 'deptId', label: 'deptName', children: 'children' }"
-                        value-key="deptId"
-                        placeholder="选择上级部门"
-                        check-strictly
-                     />
+               <el-col :span="24">
+                  <el-form-item label="机构类型" prop="orgType">
+                     <el-select v-model="form.orgType" placeholder="请选择机构类型" :disabled="!!form.deptId" @change="onOrgTypeChange" style="width:100%">
+                        <el-option label="水利机构" value="1"/>
+                        <el-option label="参建单位" value="2"/>
+                        <el-option label="分包单位" value="3"/>
+                     </el-select>
                   </el-form-item>
                </el-col>
-               <el-col :span="12">
-                  <el-form-item label="部门名称" prop="deptName">
-                     <el-input v-model="form.deptName" placeholder="请输入部门名称" />
+            </el-row>
+            <!-- 公共字段 -->
+            <el-row>
+               <el-col :span="24" v-if="form.parentId !== 0">
+                  <el-form-item label="上级机构" prop="parentId">
+                     <el-tree-select v-model="form.parentId" :data="deptOptions" :props="{ value: 'deptId', label: 'deptName', children: 'children' }" value-key="deptId" placeholder="选择上级机构" check-strictly/>
                   </el-form-item>
                </el-col>
                <el-col :span="12">
-                  <el-form-item label="显示排序" prop="orderNum">
-                     <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
-                  </el-form-item>
+                  <el-form-item label="机构名称" prop="deptName"><el-input v-model="form.deptName" placeholder="请输入"/></el-form-item>
                </el-col>
                <el-col :span="12">
-                  <el-form-item label="负责人" prop="leader">
-                     <el-input v-model="form.leader" placeholder="请输入负责人" maxlength="20" />
-                  </el-form-item>
+                  <el-form-item label="负责人" prop="leader"><el-input v-model="form.leader" placeholder="请输入"/></el-form-item>
                </el-col>
                <el-col :span="12">
-                  <el-form-item label="联系电话" prop="phone">
-                     <el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
-                  </el-form-item>
+                  <el-form-item label="联系电话" prop="phone"><el-input v-model="form.phone" placeholder="请输入"/></el-form-item>
                </el-col>
                <el-col :span="12">
-                  <el-form-item label="邮箱" prop="email">
-                     <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
-                  </el-form-item>
+                  <el-form-item label="邮箱" prop="email"><el-input v-model="form.email" placeholder="请输入"/></el-form-item>
                </el-col>
                <el-col :span="12">
-                  <el-form-item label="部门状态">
+                  <el-form-item label="状态">
                      <el-radio-group v-model="form.status">
-                        <el-radio
-                           v-for="dict in sys_normal_disable"
-                           :key="dict.value"
-                           :value="dict.value"
-                        >{{ dict.label }}</el-radio>
+                        <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
                      </el-radio-group>
                   </el-form-item>
                </el-col>
+               <el-col :span="12">
+                  <el-form-item label="排序" prop="orderNum"><el-input-number v-model="form.orderNum" controls-position="right" :min="0"/></el-form-item>
+               </el-col>
+               <el-col :span="12">
+                  <el-form-item label="机构代码" prop="orgCode"><el-input v-model="form.orgCode" placeholder="请输入"/></el-form-item>
+               </el-col>
             </el-row>
+
+            <!-- 水利机构专属字段 -->
+            <template v-if="form.orgType === '1'">
+               <el-row>
+                  <el-col :span="12">
+                     <el-form-item label="单位类型"><el-select v-model="form.extOrgType" placeholder="请选择" style="width:100%"><el-option v-for="d in slaj_ext_org_type" :key="d.value" :label="d.label" :value="d.value"/></el-select></el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                     <el-form-item label="单位规格"><el-select v-model="form.extOrgLevel" placeholder="请选择" style="width:100%"><el-option v-for="d in slaj_org_level" :key="d.value" :label="d.label" :value="d.value"/></el-select></el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                     <el-form-item label="单位编码"><el-input v-model="form.extWiunCode" placeholder="请输入"/></el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                     <el-form-item label="注册名称"><el-input v-model="form.extRegName" placeholder="请输入"/></el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                     <el-form-item label="法定代表人"><el-input v-model="form.extLegRep" placeholder="请输入"/></el-form-item>
+                  </el-col>
+               </el-row>
+            </template>
+
+            <!-- 参建单位专属字段 -->
+            <template v-if="form.orgType === '2'">
+               <el-row>
+                  <el-col :span="12">
+                     <el-form-item label="单位类型"><el-select v-model="form.baseOrgType" placeholder="请选择" style="width:100%"><el-option v-for="d in slaj_org_type" :key="d.value" :label="d.label" :value="d.value"/></el-select></el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                     <el-form-item label="单位规格"><el-select v-model="form.baseOrgLevel" placeholder="请选择" style="width:100%"><el-option v-for="d in slaj_org_level" :key="d.value" :label="d.label" :value="d.value"/></el-select></el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                     <el-form-item label="顺序号"><el-input v-model="form.baseOrdernum" placeholder="请输入"/></el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                     <el-form-item label="行政区划"><el-input v-model="form.baseAdCode" placeholder="请输入"/></el-form-item>
+                  </el-col>
+               </el-row>
+            </template>
+
+            <!-- 分包单位专属字段 -->
+            <template v-if="form.orgType === '3'">
+               <el-row>
+                  <el-col :span="12">
+                     <el-form-item label="社会信用代码"><el-input v-model="form.wsubSocCreCode" placeholder="请输入"/></el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                     <el-form-item label="施工总承包资质"><el-select v-model="form.wsubContrQualGrad" placeholder="请选择" style="width:100%"><el-option v-for="d in slaj_contr_qual_grad" :key="d.value" :label="d.label" :value="d.value"/></el-select></el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                     <el-form-item label="项目负责人"><el-input v-model="form.wsubLegPers" placeholder="请输入"/></el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                     <el-form-item label="项目负责人电话"><el-input v-model="form.wsubLegPersTel" placeholder="请输入"/></el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                     <el-form-item label="安全员"><el-input v-model="form.wsubSafePers" placeholder="请输入"/></el-form-item>
+                  </el-col>
+                  <el-col :span="12">
+                     <el-form-item label="安全生产许可证编号"><el-input v-model="form.wsubSafeProdLiceCode" placeholder="请输入"/></el-form-item>
+                  </el-col>
+               </el-row>
+            </template>
          </el-form>
          <template #footer>
             <div class="dialog-footer">
@@ -159,12 +217,16 @@
 
 <script setup name="Dept">
 import { listDept, getDept, delDept, addDept, updateDept, updateDeptSort, listDeptExcludeChild, listDeptChildren } from "@/api/system/dept"
+import { addOrgWithDept } from "@/api/system/attOrgExt"
+import { addOrgUwatWithExt } from "@/api/system/attOrgUwatBase"
+import { addOrgWsubWithDept } from "@/api/system/attOrgWsub"
 import { useTableHeight } from '@/hooks/useTableHeight'
 
 const { tableHeight, containerRef } = useTableHeight()
 
 const { proxy } = getCurrentInstance()
 const { sys_normal_disable } = proxy.useDict("sys_normal_disable")
+const { slaj_ext_org_type, slaj_org_level, slaj_contr_qual_grad, slaj_org_type } = proxy.useDict("slaj_ext_org_type","slaj_org_level","slaj_contr_qual_grad","slaj_org_type")
 
 const deptList = ref([])
 const deptTableRef = ref(null)
@@ -178,7 +240,23 @@ const originalOrders = ref({})
 const total = ref(0)
 
 const data = reactive({
-  form: {},
+  form: {
+    // 公共字段
+    deptId: undefined, parentId: undefined, deptName: undefined,
+    orgType: undefined, orgCode: undefined,
+    leader: undefined, phone: undefined, email: undefined,
+    status: "0", orderNum: 0,
+    // 水利机构扩展
+    extOrgType: undefined, extOrgLevel: undefined, extWiunCode: undefined,
+    extRegName: undefined, extLegRep: undefined,
+    // 参建单位扩展
+    baseOrgType: undefined, baseOrgLevel: undefined, baseOrdernum: undefined,
+    baseAdCode: undefined,
+    // 分包单位扩展
+    wsubSocCreCode: undefined, wsubContrQualGrad: undefined,
+    wsubLegPers: undefined, wsubLegPersTel: undefined,
+    wsubSafePers: undefined, wsubSafeProdLiceCode: undefined,
+  },
   queryParams: {
     deptName: undefined,
     status: undefined,
@@ -186,8 +264,10 @@ const data = reactive({
     pageSize: 10
   },
   rules: {
-    parentId: [{ required: true, message: "上级部门不能为空", trigger: "blur" }],
-    deptName: [{ required: true, message: "部门名称不能为空", trigger: "blur" }],
+    parentId: [{ required: true, message: "上级机构不能为空", trigger: "blur" }],
+    deptName: [{ required: true, message: "机构名称不能为空", trigger: "blur" }],
+    orgType: [{ required: true, message: "机构类型不能为空", trigger: "change" }],
+    orgCode: [{ required: true, message: "机构代码不能为空", trigger: "blur" }],
     orderNum: [{ required: true, message: "显示排序不能为空", trigger: "blur" }],
     email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
     phone: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
@@ -196,7 +276,7 @@ const data = reactive({
 
 const { queryParams, form, rules } = toRefs(data)
 
-/** 查询部门列表(懒加载模式,支持搜索过滤,顶级分页) */
+/** 查询机构列表(懒加载模式,支持搜索过滤,顶级分页) */
 function getList() {
   loading.value = true
   listDeptChildren({ ...queryParams.value }).then(response => {
@@ -223,18 +303,23 @@ function cancel() {
 /** 表单重置 */
 function reset() {
   form.value = {
-    deptId: undefined,
-    parentId: undefined,
-    deptName: undefined,
-    orderNum: 0,
-    leader: undefined,
-    phone: undefined,
-    email: undefined,
-    status: "0"
+    deptId: undefined, parentId: undefined, deptName: undefined,
+    orgType: undefined, orgCode: undefined,
+    leader: undefined, phone: undefined, email: undefined,
+    status: "0", orderNum: 0,
+    extOrgType: undefined, extOrgLevel: undefined, extWiunCode: undefined,
+    extRegName: undefined, extLegRep: undefined,
+    baseOrgType: undefined, baseOrgLevel: undefined, baseOrdernum: undefined,
+    baseAdCode: undefined,
+    wsubSocCreCode: undefined, wsubContrQualGrad: undefined,
+    wsubLegPers: undefined, wsubLegPersTel: undefined,
+    wsubSafePers: undefined, wsubSafeProdLiceCode: undefined,
   }
   proxy.resetForm("deptRef")
 }
 
+function onOrgTypeChange() {}
+
 /** 搜索按钮操作 */
 function handleQuery() {
   queryParams.value.pageNum = 1
@@ -251,7 +336,7 @@ function resetQuery() {
 /** 新增按钮操作 */
 function handleAdd(row) {
   reset()
-  // 新增时加载全量部门树供选择上级
+  // 新增时加载全量机构树供选择上级
   listDept().then(response => {
     deptOptions.value = proxy.handleTree(response.data, "deptId")
   })
@@ -259,7 +344,7 @@ function handleAdd(row) {
     form.value.parentId = row.deptId
   }
   open.value = true
-  title.value = "添加部门"
+  title.value = "添加机构"
 }
 
 /** 修改按钮操作 */
@@ -271,28 +356,50 @@ function handleUpdate(row) {
   getDept(row.deptId).then(response => {
     form.value = response.data
     open.value = true
-    title.value = "修改部门"
+    title.value = "修改机构"
   })
 }
 
-/** 提交按钮 */
+/** 提交按钮:按机构类型路由到不同复合 API */
 function submitForm() {
   proxy.$refs["deptRef"].validate(valid => {
-    if (valid) {
-      if (form.value.deptId != undefined) {
-        updateDept(form.value).then(response => {
-          proxy.$modal.msgSuccess("修改成功")
-          open.value = false
-          getList()
-        })
-      } else {
-        addDept(form.value).then(response => {
-          proxy.$modal.msgSuccess("新增成功")
-          open.value = false
-          getList()
-        })
-      }
+    if (!valid) return
+    if (form.value.deptId != undefined) {
+      // 修改走原有 updateDept
+      updateDept(form.value).then(() => {
+        proxy.$modal.msgSuccess("修改成功")
+        open.value = false
+        getList()
+      })
+      return
+    }
+    // 新增:按机构类型调用不同复合接口
+    const dept = { parentId: form.value.parentId, deptName: form.value.deptName, leader: form.value.leader, phone: form.value.phone, email: form.value.email, status: form.value.status, orderNum: form.value.orderNum }
+    const orgCode = form.value.orgCode
+    const orgType = form.value.orgType
+    let promise
+    if (orgType === '1') {
+      // 水利机构
+      const ext = { wiunName: form.value.deptName, orgType: form.value.extOrgType, orgLevel: form.value.extOrgLevel, wiunCode: form.value.extWiunCode, regName: form.value.extRegName, legRep: form.value.extLegRep, proOrgGuid: form.value.parentId }
+      promise = addOrgWithDept({ dept, ext, orgCode })
+    } else if (orgType === '2') {
+      // 参建单位
+      const base = { orgName: form.value.deptName, orgCode, orgType: form.value.baseOrgType, orgLevel: form.value.baseOrgLevel, ordernum: form.value.baseOrdernum, adCode: form.value.baseAdCode, pguid: form.value.parentId, status: form.value.status }
+      const ext = { wiunName: form.value.deptName, proOrgGuid: form.value.parentId }
+      promise = addOrgUwatWithExt({ base, ext })
+    } else if (orgType === '3') {
+      // 分包单位
+      const wsub = { wiunWsubName: form.value.deptName, socCreCode: form.value.wsubSocCreCode, contrQualGrad: form.value.wsubContrQualGrad, legPers: form.value.wsubLegPers, legPersTel: form.value.wsubLegPersTel, safePers: form.value.wsubSafePers, safeProdLiceCode: form.value.wsubSafeProdLiceCode }
+      promise = addOrgWsubWithDept({ dept, wsub, orgCode, orgType: form.value.extOrgType, orgLevel: form.value.extOrgLevel })
+    } else {
+      proxy.$modal.msgWarning("请选择机构类型")
+      return
     }
+    promise.then(() => {
+      proxy.$modal.msgSuccess("新增成功")
+      open.value = false
+      getList()
+    })
   })
 }
 

+ 181 - 0
gw-ui/src/views/system/projbase/eng/index.vue

@@ -0,0 +1,181 @@
+<template>
+  <div ref="containerRef" class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="80px" class="search-form">
+      <div class="search-form-left">
+        <el-form-item label="工程名称" prop="engName">
+          <el-input v-model="queryParams.engName" placeholder="请输入工程名称" clearable @keyup.enter="handleQuery"/>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+        </el-form-item>
+      </div>
+      <div class="search-form-right">
+        <el-button type="warning" plain icon="Link" @click="handleEngLink">关联工程</el-button>
+        <el-button icon="Back" @click="goBack">返回项目列表</el-button>
+      </div>
+    </el-form>
+
+    <el-alert v-if="projName" :title="'当前项目:' + projName" type="info" :closable="false" class="proj-alert"/>
+
+    <div class="table-wrapper">
+      <el-table :height="tableHeight" v-loading="loading" :data="engList">
+        <el-table-column label="工程编码" align="center" prop="engCode" :show-overflow-tooltip="true"/>
+        <el-table-column label="工程名称" align="center" prop="engName" :show-overflow-tooltip="true"/>
+        <el-table-column label="工程类型" align="center" prop="engType" :show-overflow-tooltip="true"/>
+        <el-table-column label="工程规模" align="center" prop="engScal" :show-overflow-tooltip="true"/>
+        <el-table-column label="开工日期" align="center" prop="startDate" :show-overflow-tooltip="true"/>
+        <el-table-column label="备注" align="center" prop="note" :show-overflow-tooltip="true"/>
+
+        <el-table-column label="操作" align="center" width="120">
+          <template #default="scope">
+            <el-button link type="primary" icon="Tickets" @click="handleViewTend(scope.row)">标段</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList"/>
+
+    <!-- 关联工程 Dialog -->
+    <el-dialog title="关联工程" v-model="engLinkOpen" width="800px" append-to-body :close-on-click-modal="false">
+      <el-form :model="linkParams" :inline="true" @submit.prevent>
+        <el-form-item label="工程编码">
+          <el-input v-model="linkParams.engCode" placeholder="请输入编码" clearable style="width:140px"/>
+        </el-form-item>
+        <el-form-item label="工程名称">
+          <el-input v-model="linkParams.engName" placeholder="请输入名称" clearable style="width:160px"/>
+        </el-form-item>
+        <el-form-item label="工程类型">
+          <el-select v-model="linkParams.engType" placeholder="请选择" clearable style="width:120px">
+            <el-option label="水库" value="01"/><el-option label="水闸" value="02"/>
+            <el-option label="泵站" value="03"/><el-option label="水电站" value="04"/>
+            <el-option label="堤防" value="05"/><el-option label="灌区" value="06"/>
+            <el-option label="引调水" value="07"/><el-option label="淤地坝" value="08"/>
+            <el-option label="农村供水" value="09"/><el-option label="其他" value="10"/>
+            <el-option label="农村小水电" value="11"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="searchEngLink">搜索</el-button>
+          <el-button icon="Refresh" @click="resetLinkParams">重置</el-button>
+        </el-form-item>
+      </el-form>
+      <el-table :data="linkEngList" @selection-change="handleLinkSelection" ref="linkTableRef" max-height="360" style="margin-top:12px">
+        <el-table-column type="selection" width="50"/>
+        <el-table-column label="工程编码" prop="engCode"/>
+        <el-table-column label="工程名称" prop="engName" :show-overflow-tooltip="true"/>
+        <el-table-column label="工程类型" prop="engType" width="100"/>
+      </el-table>
+      <pagination v-show="linkTotal>0" :total="linkTotal" v-model:page="linkParams.pageNum" v-model:limit="linkParams.pageSize" @pagination="searchEngLink" />
+      <template #footer>
+        <el-button type="primary" @click="submitEngLink" :disabled="linkSelected.length===0">关联选中工程 ({{ linkSelected.length }})</el-button>
+        <el-button @click="engLinkOpen=false">取消</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="ProjBaseEng">
+import { useRoute } from 'vue-router'
+import { listEngBase, updateEngBase, listObjEng } from "@/api/slaj/eng"
+import { getAttProjBase } from "@/api/system/attProjBase"
+import { useTableHeight } from '@/hooks/useTableHeight'
+
+const { tableHeight, containerRef } = useTableHeight()
+const { proxy } = getCurrentInstance()
+const route = useRoute()
+
+const projGuid = ref(route.params.projGuid)
+const projName = ref("")
+
+const engList = ref([])
+const loading = ref(true)
+const showSearch = ref(true)
+const total = ref(0)
+
+const data = reactive({
+  queryParams: {
+    engName: undefined,
+    projGuid: undefined,
+    pageNum: 1,
+    pageSize: 10
+  }
+})
+const { queryParams } = toRefs(data)
+
+function loadProj() {
+  if (!projGuid.value) return
+  getAttProjBase(projGuid.value).then(res => {
+    projName.value = res.data && res.data.projName ? res.data.projName : ""
+  }).catch(() => {})
+}
+
+function getList() {
+  loading.value = true
+  queryParams.value.projGuid = projGuid.value
+  listEngBase(queryParams.value).then(response => {
+    engList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+function handleQuery() { queryParams.value.pageNum = 1; getList() }
+function resetQuery() { proxy.resetForm("queryRef"); handleQuery() }
+
+function handleViewTend(row) {
+  proxy.$router.push('/system/projbase-tend/index/' + projGuid.value + '?engGuid=' + (row.engGuid || row.guid))
+}
+
+function goBack() { proxy.$router.back() }
+
+// ====== 关联工程(多选列表) ======
+const engLinkOpen = ref(false)
+const linkTableRef = ref(null)
+const linkEngList = ref([])
+const linkSelected = ref([])
+const linkTotal = ref(0)
+const linkParams = reactive({ engCode: undefined, engName: undefined, engType: undefined, pageNum: 1, pageSize: 10 })
+
+function handleEngLink() {
+  linkSelected.value = []
+  resetLinkParams()
+  engLinkOpen.value = true
+  searchEngLink()
+}
+
+function resetLinkParams() {
+  linkParams.engCode = undefined; linkParams.engName = undefined; linkParams.engType = undefined
+  linkParams.pageNum = 1
+}
+
+function searchEngLink() {
+  listObjEng({ ...linkParams, pageNum: linkParams.pageNum, pageSize: linkParams.pageSize }).then(res => {
+    linkEngList.value = res.rows || []
+    linkTotal.value = res.total || 0
+  })
+}
+
+function handleLinkSelection(sel) { linkSelected.value = sel }
+
+function submitEngLink() {
+  if (linkSelected.value.length === 0) { proxy.$modal.msgWarning("请至少选择一个工程"); return }
+  const tasks = linkSelected.value.map(e => updateEngBase({ guid: e.guid, projGuid: projGuid.value }))
+  Promise.all(tasks).then(() => {
+    proxy.$modal.msgSuccess(`成功关联 ${linkSelected.value.length} 个工程`)
+    engLinkOpen.value = false
+    getList()
+  })
+}
+
+loadProj()
+getList()
+</script>
+
+<style scoped>
+.search-form { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; }
+.search-form-left { display: flex; align-items: center; flex-wrap: wrap; flex: 1; }
+.search-form-right { display: flex; align-items: center; gap: 6px; white-space: nowrap; flex-shrink: 0; }
+.proj-alert { margin-bottom: 12px; }
+</style>

+ 77 - 19
gw-ui/src/views/system/projbase/index.vue

@@ -1,6 +1,7 @@
 <template>
   <div ref="containerRef" class="app-container">
-    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="80px" class="search-form">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="80px"
+             class="search-form">
       <div class="search-form-left">
         <el-form-item label="项目代码" prop="projCode">
           <el-input v-model="queryParams.projCode" placeholder="请输入项目代码" clearable @keyup.enter="handleQuery"/>
@@ -29,30 +30,43 @@
         <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete"
                    v-hasPermi="['business:projbase:remove']">删除
         </el-button>
+        <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"
+                       storageKey="projbase-index"/>
       </div>
     </el-form>
     <div class="table-wrapper">
       <el-table :height="tableHeight" v-loading="loading" :data="attProjBaseList"
                 @selection-change="handleSelectionChange" height="calc(100% - 100px)">
         <el-table-column type="selection" width="50" align="center"/>
-        <el-table-column label="项目代码" align="center" prop="projCode" :show-overflow-tooltip="true"/>
-        <el-table-column label="项目名称" align="center" prop="projName" :show-overflow-tooltip="true"/>
-        <el-table-column label="建设单位全称" align="center" prop="conUnit" :show-overflow-tooltip="true"/>
-        <el-table-column label="年度" align="center" prop="year" :show-overflow-tooltip="true"/>
-        <el-table-column label="项目类型" align="center" prop="projType" :show-overflow-tooltip="true">
+        <el-table-column label="项目代码" align="center" prop="projCode" v-if="columns.projCode.visible"
+                         :show-overflow-tooltip="true"/>
+        <el-table-column label="项目名称" align="center" prop="projName" v-if="columns.projName.visible"
+                         :show-overflow-tooltip="true"/>
+        <el-table-column label="建设单位全称" align="center" prop="conUnit" v-if="columns.conUnit.visible"
+                         :show-overflow-tooltip="true"/>
+        <el-table-column label="年度" align="center" prop="year" v-if="columns.year.visible"
+                         :show-overflow-tooltip="true"/>
+        <el-table-column label="项目类型" align="center" prop="projType" v-if="columns.projType.visible"
+                         :show-overflow-tooltip="true">
           <template #default="scope">
             <dict-tag :options="slaj_proj_type" :value="scope.row.projType"/>
           </template>
         </el-table-column>
-        <el-table-column label="项目启动时间" align="center" prop="projBegDate" :show-overflow-tooltip="true"/>
-        <el-table-column label="项目竣工时间" align="center" prop="projCompDate" :show-overflow-tooltip="true"/>
-        <el-table-column label="备注" align="center" prop="note" :show-overflow-tooltip="true"/>
+        <el-table-column label="项目启动时间" align="center" prop="projBegDate" v-if="columns.projBegDate.visible"
+                         :show-overflow-tooltip="true"/>
+        <el-table-column label="项目竣工时间" align="center" prop="projCompDate" v-if="columns.projCompDate.visible"
+                         :show-overflow-tooltip="true"/>
+        <el-table-column label="备注" align="center" prop="note" v-if="columns.note.visible"
+                         :show-overflow-tooltip="true"/>
 
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <el-table-column label="操作" align="center" width="260" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
                        v-hasPermi="['business:projbase:edit']">修改
             </el-button>
+            <el-button link type="success" icon="Monitor" @click="handleViewEng(scope.row)"
+                       v-hasPermi="['business:objeng:list']">工程
+            </el-button>
             <el-button link type="primary" icon="Tickets" @click="handleViewTend(scope.row)"
                        v-hasPermi="['business:objtend:list']">标段
             </el-button>
@@ -164,6 +178,7 @@
         </div>
       </template>
     </el-dialog>
+
   </div>
 </template>
 
@@ -175,12 +190,23 @@ import {
   listAttProjBase,
   updateAttProjBase
 } from "@/api/system/attProjBase"
-import {useTableHeight} from '@/hooks/useTableHeight'
+import { useTableHeight } from '@/hooks/useTableHeight'
 
 const {tableHeight, containerRef} = useTableHeight()
 const {proxy} = getCurrentInstance()
 const {slaj_proj_type} = proxy.useDict("slaj_proj_type")
 
+const columns = ref({
+  projCode: {visible: true},
+  projName: {visible: true},
+  conUnit: {visible: true},
+  year: {visible: true},
+  projType: {visible: true},
+  projBegDate: {visible: true},
+  projCompDate: {visible: true},
+  note: {visible: true}
+})
+
 const attProjBaseList = ref([])
 const open = ref(false)
 const loading = ref(true)
@@ -216,8 +242,8 @@ const data = reactive({
     pageSize: 10
   },
   rules: {
-    projCode: [{ required: true, message: "项目代码不能为空", trigger: "blur" }],
-    projName: [{ required: true, message: "项目名称不能为空", trigger: "blur" }]
+    projCode: [{required: true, message: "项目代码不能为空", trigger: "blur"}],
+    projName: [{required: true, message: "项目名称不能为空", trigger: "blur"}]
   }
 })
 
@@ -288,6 +314,10 @@ function handleUpdate(row) {
   })
 }
 
+function handleViewEng(row) {
+  proxy.$router.push('/system/projbase-eng/index/' + (row.guid || ids.value))
+}
+
 function handleViewTend(row) {
   proxy.$router.push('/system/projbase-tend/index/' + (row.guid || ids.value))
 }
@@ -327,11 +357,39 @@ getList()
 </script>
 
 <style scoped>
-.search-form { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; }
-.search-form-left { display: flex; align-items: center; flex-wrap: wrap; flex: 1; }
-.search-form-right { display: flex; align-items: center; gap: 6px; white-space: nowrap; flex-shrink: 0; }
-.projbase-form .el-divider { margin: 12px 0 20px; }
-.projbase-form .el-divider__text { font-weight: 600; color: var(--el-color-primary); }
-.projbase-form .el-textarea__inner { resize: none; }
+.search-form {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  flex-wrap: wrap;
+}
+
+.search-form-left {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  flex: 1;
+}
+
+.search-form-right {
+  display: flex;
+  align-items: center;
+  gap: 6px;
+  white-space: nowrap;
+  flex-shrink: 0;
+}
+
+.projbase-form .el-divider {
+  margin: 12px 0 20px;
+}
+
+.projbase-form .el-divider__text {
+  font-weight: 600;
+  color: var(--el-color-primary);
+}
+
+.projbase-form .el-textarea__inner {
+  resize: none;
+}
 
 </style>

+ 208 - 7
gw-ui/src/views/system/projbase/tend/index.vue

@@ -25,18 +25,22 @@
       <el-table :height="tableHeight" v-loading="loading" :data="objTendList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="50" align="center"/>
         <el-table-column label="标段名称" align="center" prop="tendName" :show-overflow-tooltip="true"/>
-        <el-table-column label="工程GUID" align="center" prop="engGuid" :show-overflow-tooltip="true"/>
+        <el-table-column label="所属工程" align="center" prop="engName" :show-overflow-tooltip="true"/>
+        <el-table-column label="所属单位" align="center" prop="orgName" :show-overflow-tooltip="true"/>
         <el-table-column label="负责人" align="center" prop="legPers" :show-overflow-tooltip="true"/>
         <el-table-column label="联系电话" align="center" prop="legTel" :show-overflow-tooltip="true"/>
         <el-table-column label="合同金额" align="center" prop="conAmout" :show-overflow-tooltip="true"/>
         <el-table-column label="完工状态" align="center" prop="stat" :show-overflow-tooltip="true"/>
         <el-table-column label="备注" align="center" prop="note" :show-overflow-tooltip="true"/>
 
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="220">
           <template #default="scope">
             <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
                        v-hasPermi="['business:objtend:edit']">修改
             </el-button>
+            <el-button link type="success" icon="OfficeBuilding" @click="handleViewOrg(scope.row)"
+                       v-hasPermi="['business:reltendorg:list']">参建单位
+            </el-button>
             <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
                        v-hasPermi="['business:objtend:remove']">删除
             </el-button>
@@ -57,8 +61,32 @@
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="工程GUID" prop="engGuid">
-              <el-input v-model="form.engGuid" placeholder="请输入工程GUID"/>
+            <el-form-item label="所属工程" prop="engGuid">
+              <el-select
+                v-model="form.engGuid"
+                filterable remote clearable reserve-keyword
+                :remote-method="remoteSearchEng"
+                :loading="engLoading"
+                placeholder="请输入工程名称搜索"
+                style="width:100%">
+                <el-option v-for="item in engOptions" :key="item.guid" :label="item.engName" :value="item.guid"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <OrgSelect v-model="form.orgGuid" label="所属单位" placeholder="请输入单位名称搜索"/>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="项目部" prop="orgProjDeptGuid">
+              <el-select
+                v-model="form.orgProjDeptGuid"
+                filterable remote clearable reserve-keyword
+                :remote-method="remoteSearchProjDept"
+                :loading="projDeptLoading"
+                placeholder="请输入参建单位名称搜索"
+                style="width:100%">
+                <el-option v-for="item in projDeptOptions" :key="item.guid" :label="item.orgName" :value="item.guid"/>
+              </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -76,9 +104,17 @@
               <el-input v-model="form.conAmout" placeholder="请输入合同金额" type="number"/>
             </el-form-item>
           </el-col>
+          <el-col :span="12">
+            <el-form-item label="安全生产费用" prop="totalSpc">
+              <el-input v-model="form.totalSpc" placeholder="请输入安全生产费用总和" type="number"/>
+            </el-form-item>
+          </el-col>
           <el-col :span="12">
             <el-form-item label="完工状态" prop="stat">
-              <el-input v-model="form.stat" placeholder="请输入完工状态(2=已完工)"/>
+              <el-select v-model="form.stat" placeholder="请选择完工状态" style="width:100%">
+                <el-option label="在建" value="1"/>
+                <el-option label="已完工" value="2"/>
+              </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="24">
@@ -100,6 +136,44 @@
         </div>
       </template>
     </el-dialog>
+
+    <!-- ====== 标段参建单位关系 Dialog ====== -->
+    <el-dialog title="标段参建单位" v-model="relOpen" width="760px" append-to-body>
+      <el-alert v-if="relTendRow.tendName" :title="'当前标段:' + relTendRow.tendName" type="info" :closable="false" style="margin-bottom:12px"/>
+      <el-row class="mb8">
+        <el-col :span="24">
+          <el-form :inline="true" @submit.prevent>
+            <el-form-item label="参建单位">
+              <el-select
+                v-model="relForm.orgUwatGuid"
+                filterable remote clearable reserve-keyword
+                :remote-method="remoteSearchRelOrg"
+                :loading="relOrgLoading"
+                placeholder="请输入参建单位名称搜索"
+                style="width:240px">
+                <el-option v-for="item in relOrgOptions" :key="item.guid" :label="item.orgName" :value="item.guid"/>
+              </el-select>
+            </el-form-item>
+            <el-form-item label="建立时间">
+              <el-date-picker v-model="relForm.fromDate" type="date" value-format="YYYY-MM-DD" style="width:150px"/>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Plus" @click="submitRelForm">添加关系</el-button>
+            </el-form-item>
+          </el-form>
+        </el-col>
+      </el-row>
+      <el-table v-loading="relLoading" :data="relOrgList" border>
+        <el-table-column label="参建单位名称" align="center" prop="orgName" :show-overflow-tooltip="true"/>
+        <el-table-column label="关系建立时间" align="center" prop="fromDate" width="160"/>
+        <el-table-column label="关系终止时间" align="center" prop="toDate" width="160"/>
+        <el-table-column label="操作" align="center" width="100">
+          <template #default="scope">
+            <el-button link type="danger" icon="Delete" @click="handleRelDelete(scope.row)">解除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-dialog>
   </div>
 </template>
 
@@ -107,6 +181,10 @@
 import { useRoute } from 'vue-router'
 import { listObjTend, getObjTend, delObjTend, addObjTend, updateObjTend } from "@/api/system/objTend"
 import { getAttProjBase } from "@/api/system/attProjBase"
+import { listEngBase, getEngBase } from "@/api/slaj/eng"
+import { listAttOrgUwatBase, getAttOrgUwatBase } from "@/api/system/attOrgUwatBase"
+import { listRelTendOrg, addRelTendOrg, delRelTendOrg } from "@/api/system/relTendOrg"
+import OrgSelect from "@/components/OrgSelect"
 import { useTableHeight } from '@/hooks/useTableHeight'
 
 const { tableHeight, containerRef } = useTableHeight()
@@ -126,13 +204,23 @@ const multiple = ref(true)
 const total = ref(0)
 const title = ref("")
 
+// 所属工程远程搜索(OBJ_ENG)
+const engOptions = ref([])
+const engLoading = ref(false)
+// 项目部远程搜索(参建单位 att_org_uwat_base)
+const projDeptOptions = ref([])
+const projDeptLoading = ref(false)
+
 const data = reactive({
   form: {
     tendName: undefined,
     engGuid: undefined,
+    orgGuid: undefined,
+    orgProjDeptGuid: undefined,
     legPers: undefined,
     legTel: undefined,
     conAmout: undefined,
+    totalSpc: undefined,
     consCont: undefined,
     note: undefined,
     stat: undefined
@@ -140,6 +228,7 @@ const data = reactive({
   queryParams: {
     tendName: undefined,
     projGuid: undefined,
+    engGuid: undefined,
     pageNum: 1,
     pageSize: 10
   },
@@ -150,6 +239,42 @@ const data = reactive({
 
 const { queryParams, form, rules } = toRefs(data)
 
+/** 远程搜索所属工程(限当前项目下,按 projGuid 过滤) */
+function remoteSearchEng(query) {
+  if (!query) { engOptions.value = []; return }
+  engLoading.value = true
+  listEngBase({ projGuid: projGuid.value, engName: query, pageNum: 1, pageSize: 20 }).then(res => {
+    engOptions.value = (res.rows || []).map(r => ({ guid: r.guid, engName: r.engName }))
+  }).finally(() => { engLoading.value = false })
+}
+
+/** 编辑回显:根据 engGuid 预加载工程名称 */
+function loadEngOption(guid) {
+  if (!guid) return
+  getEngBase(guid).then(res => {
+    const d = res.data
+    if (d && d.guid) engOptions.value = [{ guid: d.guid, engName: d.engName }, ...engOptions.value]
+  }).catch(() => {})
+}
+
+/** 远程搜索项目部(参建单位) */
+function remoteSearchProjDept(query) {
+  if (!query) { projDeptOptions.value = []; return }
+  projDeptLoading.value = true
+  listAttOrgUwatBase({ orgName: query, pageNum: 1, pageSize: 20 }).then(res => {
+    projDeptOptions.value = (res.rows || []).map(r => ({ guid: r.guid, orgName: r.orgName }))
+  }).finally(() => { projDeptLoading.value = false })
+}
+
+/** 编辑回显:根据 orgProjDeptGuid 预加载参建单位名称 */
+function loadProjDeptOption(guid) {
+  if (!guid) return
+  getAttOrgUwatBase(guid).then(res => {
+    const d = res.data
+    if (d && d.guid) projDeptOptions.value = [{ guid: d.guid, orgName: d.orgName }, ...projDeptOptions.value]
+  }).catch(() => {})
+}
+
 function loadProj() {
   if (!projGuid.value) return
   getAttProjBase(projGuid.value).then(res => {
@@ -159,7 +284,14 @@ function loadProj() {
 
 function getList() {
   loading.value = true
-  queryParams.value.projGuid = projGuid.value
+  // 工程页跳转时带 engGuid 查询参数,直接按工程筛选
+  if (route.query.engGuid) {
+    queryParams.value.engGuid = route.query.engGuid
+    queryParams.value.projGuid = undefined
+  } else {
+    queryParams.value.projGuid = projGuid.value
+    queryParams.value.engGuid = undefined
+  }
   listObjTend(queryParams.value).then(response => {
     objTendList.value = response.rows
     total.value = response.total
@@ -176,13 +308,18 @@ function reset() {
   form.value = {
     tendName: undefined,
     engGuid: undefined,
+    orgGuid: undefined,
+    orgProjDeptGuid: undefined,
     legPers: undefined,
     legTel: undefined,
     conAmout: undefined,
+    totalSpc: undefined,
     consCont: undefined,
     note: undefined,
     stat: undefined
   }
+  engOptions.value = []
+  projDeptOptions.value = []
   proxy.resetForm("objTendRef")
 }
 
@@ -213,6 +350,9 @@ function handleUpdate(row) {
   const guid = row.guid || ids.value
   getObjTend(guid).then(response => {
     form.value = response.data
+    // 回显所属工程、项目部名称
+    if (form.value.engGuid) engOptions.value = [{ guid: form.value.engGuid, engName: form.value.engName }]
+    loadProjDeptOption(form.value.orgProjDeptGuid)
     open.value = true
     title.value = "修改标段"
   })
@@ -221,7 +361,6 @@ function handleUpdate(row) {
 function submitForm() {
   proxy.$refs["objTendRef"].validate(valid => {
     if (valid) {
-      form.value.projGuid = projGuid.value
       if (form.value.guid != undefined) {
         updateObjTend(form.value).then(response => {
           proxy.$modal.msgSuccess("修改成功")
@@ -254,6 +393,68 @@ function goBack() {
   proxy.$router.back()
 }
 
+// =====================================================
+// 标段参建单位关系(REL_TEND_ORG)
+// =====================================================
+const relOpen = ref(false)
+const relTendRow = ref({})
+const relOrgList = ref([])
+const relLoading = ref(false)
+const relOrgOptions = ref([])
+const relOrgLoading = ref(false)
+const relForm = ref({ orgUwatGuid: undefined, fromDate: undefined })
+
+/** 打开某标段的参建单位关系弹窗 */
+function handleViewOrg(row) {
+  relTendRow.value = row
+  relForm.value = { orgUwatGuid: undefined, fromDate: undefined }
+  relOrgOptions.value = []
+  relOpen.value = true
+  loadRelOrgList()
+}
+
+function loadRelOrgList() {
+  relLoading.value = true
+  listRelTendOrg({ tendGuid: relTendRow.value.guid, pageNum: 1, pageSize: 999 }).then(res => {
+    relOrgList.value = res.rows || []
+  }).finally(() => { relLoading.value = false })
+}
+
+/** 远程搜索参建单位(复用 att_org_uwat_base) */
+function remoteSearchRelOrg(query) {
+  if (!query) { relOrgOptions.value = []; return }
+  relOrgLoading.value = true
+  listAttOrgUwatBase({ orgName: query, pageNum: 1, pageSize: 20 }).then(res => {
+    relOrgOptions.value = (res.rows || []).map(r => ({ guid: r.guid, orgName: r.orgName }))
+  }).finally(() => { relOrgLoading.value = false })
+}
+
+/** 添加标段↔参建单位关系 */
+function submitRelForm() {
+  if (!relForm.value.orgUwatGuid) {
+    proxy.$modal.msgWarning("请选择参建单位")
+    return
+  }
+  addRelTendOrg({
+    tendGuid: relTendRow.value.guid,
+    orgUwatGuid: relForm.value.orgUwatGuid,
+    fromDate: relForm.value.fromDate
+  }).then(() => {
+    proxy.$modal.msgSuccess("添加成功")
+    relForm.value = { orgUwatGuid: undefined, fromDate: undefined }
+    relOrgOptions.value = []
+    loadRelOrgList()
+  })
+}
+
+/** 解除标段↔参建单位关系 */
+function handleRelDelete(row) {
+  proxy.$modal.confirm('确认解除该参建单位关系?').then(() => delRelTendOrg(row.guid)).then(() => {
+    loadRelOrgList()
+    proxy.$modal.msgSuccess("已解除")
+  }).catch(() => {})
+}
+
 loadProj()
 getList()
 </script>