Просмотр исходного кода

Merge remote-tracking branch 'origin/dev' into wuguojie

# Conflicts:
#	src/api/modules/role.ts
#	src/router/modules/externalAgreement.ts
#	src/views/personnel/roleManagement.vue
wuguojie 1 год назад
Родитель
Сommit
fb6a054cc0
27 измененных файлов с 4750 добавлено и 157 удалено
  1. 47 2
      src/api/modules/agreement.ts
  2. 5 6
      src/api/modules/role.ts
  3. 6 7
      src/components/LoginForm/index.vue
  4. 24 6
      src/components/complexTable/index.vue
  5. 22 20
      src/components/ruleConditionContainer/index.vue
  6. 11 1
      src/router/modules/externalAgreement.ts
  7. 10 10
      src/router/modules/quoteConfig.ts
  8. 22 6
      src/router/modules/representative.ts
  9. 429 0
      src/views/externalAgreement/agreement/agreementAdd.vue
  10. 727 0
      src/views/externalAgreement/agreement/agreementDetails.vue
  11. 473 11
      src/views/externalAgreement/agreement/agreementIndex.vue
  12. 83 0
      src/views/externalAgreement/agreement/components/agreementAuth.vue
  13. 485 0
      src/views/externalAgreement/agreement/components/contactPersonFeeDialog.vue
  14. 317 0
      src/views/externalAgreement/agreement/components/contactPersonFeeDialogEdit.vue
  15. 110 0
      src/views/externalAgreement/agreement/components/managerModal.vue
  16. 522 0
      src/views/externalAgreement/costManagement.vue
  17. 1 2
      src/views/personnel/roleManagement.vue
  18. 25 8
      src/views/quoteConfig/agreement/agreementAdd.vue
  19. 236 0
      src/views/quoteConfig/agreement/agreementCopy.vue
  20. 29 18
      src/views/quoteConfig/agreement/agreementIndex.vue
  21. 5 4
      src/views/quoteConfig/agreement/components/managerModal.vue
  22. 134 0
      src/views/quoteConfig/agreement/components/orderAccount.vue
  23. 4 4
      src/views/quoteConfig/agreement/components/ruleFeeDialog.vue
  24. 89 24
      src/views/quoteConfig/agreement/components/ruleFeeDialogEdit.vue
  25. 34 28
      src/views/quoteConfig/costManagement.vue
  26. 396 0
      src/views/representative/externalCostApproval.vue
  27. 504 0
      src/views/representative/quoteApproval.vue

+ 47 - 2
src/api/modules/agreement.ts

@@ -16,7 +16,7 @@ const agreementApi = (axiosInstance: ApiInstance) => ({
   //协议授权保存
   authSave: (data: Types.authSaveRequest) => axiosInstance.post('agreement/authSave', data),
   //根据机构获取后线人员列表
-  getUserByDeptId: (deptId?: string,searchValue?:string) => axiosInstance.get(`agreement/getUserByDeptId?deptId=${deptId}&searchValue=${searchValue}`),
+  getUserByDeptId: (deptId?: string, searchValue?: string) => axiosInstance.get(`agreement/getUserByDeptId?deptId=${deptId}&searchValue=${searchValue}`),
   //协议授权机构查询
   agreementdeptTree: (id: string, deptName: string) => axiosInstance.get(`agreement/deptTree?id=${id}&deptName=${deptName}`),
   //启用禁用
@@ -25,6 +25,8 @@ const agreementApi = (axiosInstance: ApiInstance) => ({
   agreementDelete: (ids: any) => axiosInstance.delete(`/agreement/agreementDelete?ids=${ids}`),
   //获取保险公司数结构
   findTree: (data: any) => axiosInstance.post('esmInsCompany/findTree', data),
+  //复制协议
+  agreementCopy: (data: any) => axiosInstance.post('/agreement/agreementCopy', data),
   /**
     * @param 承保规则
     */
@@ -57,11 +59,54 @@ const agreementApi = (axiosInstance: ApiInstance) => ({
   //协议费用批量删除
   AgreementFeedeleteByIds: (data: any) => axiosInstance.post('ptlAgreementCost/deleteByIds', data),
   //协议费用批量启用/禁用
-  AgreementFeeEnableByIds: (isEnabled:boolean,ids:any) => axiosInstance.post('ptlAgreementCost/enableDisableByIds?isEnabled='+isEnabled, ids),
+  AgreementFeeEnableByIds: (isEnabled: boolean, ids: any) => axiosInstance.post('ptlAgreementCost/enableDisableByIds?isEnabled=' + isEnabled, ids),
   //协议费用管理详情查询
   AgreementFeeById: (id: any) => axiosInstance.get(`ptlAgreementCost/queryById?id=${id}`),
   //协议上传文件
   agreementEditFile: (data: any) => axiosInstance.post('agreement/agreementEditFile', data),
 
+
+
+  /**
+   * 外部协议
+   */
+  //外部协议添加
+  contactAdd: (data: any) => axiosInstance.post('/agreement/contactAdd', data),
+  //外部协议修改
+  contactEdit: (data: any) => axiosInstance.post('/agreement/contactEdit', data),
+  //费用列表崔查询
+  costExternalList: (data: any) => axiosInstance.post('/ptlAgreementCostExternal/costExternalList', data),
+  //补录协议费用新增
+  ptlAgreementCostExternalsave: (data: any) => axiosInstance.post('/ptlAgreementCostExternal/save', data),
+  //补录协议费用修改
+  ptlAgreementCostExternalupdate: (data: any) => axiosInstance.post('ptlAgreementCostExternal/updateList', data),
+  //查询协议下对接人所有费用
+  selectByAgreementIdAll: (data: any) => axiosInstance.post('ptlAgreementCostExternal/selectByAgreementIdAll', data),
+  //删除对接人
+  deleteByPtlAgreementIdAndMobile: (data: any) => axiosInstance.post('ptlAgreementCostExternal/deleteByPtlAgreementIdAndMobile', data),
+  //费用管理分页列表
+  CostExternalFeePageList: (data: any) => axiosInstance.post('ptlAgreementCostExternal/pageList', data),
+  //单个费用修改
+  FeeupdateById: (data: any) => axiosInstance.post('/ptlAgreementCostExternal/updateById', data),
+  //单个费用查询
+  FeegetById: (id: any) => axiosInstance.get('/ptlAgreementCostExternal/getById?id=' + id),
+  //协议费用管理批量禁用/启用
+  enableDisableByIds: (isEnabled: boolean, ids: any) => axiosInstance.post('ptlAgreementCostExternal/enableDisableByIds?isEnabled=' + isEnabled, ids),
+  //批量删除
+  deleteById: (data: any) => axiosInstance.post('ptlAgreementCostExternal/deleteById', data),
+  //批量修改审核方式
+  approvalMethodAll: (auditMethod: string, ids: any) => axiosInstance.post('ptlAgreementCostExternal/approvalMethodAll?auditMethod=' + auditMethod, ids),
+
+
+  //费用审核
+  // 协议费用管理审核成功
+  auditSuccess: (data: any) => axiosInstance.post('/ptlAgreementCost/auditSuccess', data),
+  // 协议费用管理审核失败
+  auditFailed: (data:any) => axiosInstance.post(`/ptlAgreementCost/auditFailed`,data),
+  // 补录协议费用管理审核成功
+  ExternalauditSuccess: (data: any) => axiosInstance.post('/ptlAgreementCostExternal/auditSuccess', data),
+  // 补录协议费用管理审核失败
+  ExternalauditFailed: (data: any) => axiosInstance.post('/ptlAgreementCostExternal/auditFailed', data),
+
 })
 export default agreementApi

+ 5 - 6
src/api/modules/role.ts

@@ -5,26 +5,25 @@ interface roleData {
   system: string,
   permsId: number[],
   perms: string[],
-  [key: string]: any
 }
 const roleApi = (axiosInstance: ApiInstance) => ({
   // 新增角色
-  roleAdd: (data: roleData) => axiosInstance.post('userRole/roleAdd', data, {}),
+  roleAdd: (data: any) => axiosInstance.post('userRole/roleAdd', data, {}),
 
   //角色列表
   roleList:(data: any) => axiosInstance.post('userRole/roleList', data, {}),
 
   //查询角色信息
-  roleInfo:(params: roleData) => axiosInstance.get('userRole/roleGet', {params}),
+  roleInfo:(params: any) => axiosInstance.get('userRole/roleGet', {params}),
 
   //编辑角色信息
-  roleUpdate:(data: roleData) => axiosInstance.post('userRole/roleUpdate', data,{}),
+  roleUpdate:(data: any) => axiosInstance.post('userRole/roleUpdate', data,{}),
 
   //角色删除检测
-  roleDeleteValid:(data: { id: string }) => axiosInstance.post('userRole/roleDeleteValid', data,{}),
+  roleDeleteValid:(data: any) => axiosInstance.post('userRole/roleDeleteValid', data),
 
   //角色删除检测
-  roleDelete:(data: { id: string }) => axiosInstance.post('userRole/roleDelete', data,{}),
+  roleDelete:(data: any) => axiosInstance.post('userRole/roleDelete', data,{}),
 
   //配置路由
   updateConfig:(data: any) => axiosInstance.post('system/updateConfig', data,{})

+ 6 - 7
src/components/LoginForm/index.vue

@@ -2,7 +2,6 @@
 import type { FormInstance, FormRules } from "element-plus";
 import useUserStore from "@/store/modules/user";
 import { ref, useTemplateRef, onMounted,onUnmounted } from "vue";
-import { systemRoutes } from "@/router/routes";
 
 defineOptions({
   name: "LoginForm",
@@ -39,7 +38,7 @@ const form = ref({
   userName: props.userName ?? localStorage.login_account ?? "",
   passWord: "",
   captcha: "",
-  system: "",
+  system: "KK123",
   captchaId: 0,
   systemCode: "",
 });
@@ -100,7 +99,7 @@ function handleLogin() {
           loading.value = false;
           refreshCaptcha();
         });
-      
+
     }
   });
 }
@@ -153,7 +152,7 @@ function handleLogin() {
     :model="form"
     :rules="rules"
     class="min-h-500px w-full flex-col-stretch-center"
-    style="padding: 81px 75px"
+    style="padding: 81px 75px;"
     size="large"
   >
     <!-- <div class="mb-6">
@@ -210,7 +209,7 @@ function handleLogin() {
           </ElInput>
         </ElFormItem>
 
-        <ElFormItem prop="captcha" style="margin-bottom: 0">
+        <ElFormItem prop="captcha" style="margin-bottom: 0;">
           <ElCol :md="14" :sm="14" :xs="14">
             <ElInput
               v-model="form.captcha"
@@ -225,7 +224,7 @@ function handleLogin() {
           </ElCol>
           <ElCol :md="10" :sm="10" :xs="10" flex>
             <img
-              style="width: 100%; height: 32px; margin-left: 20px"
+              style="width: 100%; height: 32px; margin-left: 20px;"
               class="pointer"
               :src="captchaSrc"
               @click="refreshCaptcha"
@@ -248,7 +247,7 @@ function handleLogin() {
         :loading="loading"
         type="primary"
         @keydown.enter="handleEnter"
-        style="width: 100%"
+        style="width: 100%;"
         @click.prevent="handleLogin"
       >
         登录

+ 24 - 6
src/components/complexTable/index.vue

@@ -7,7 +7,8 @@
       <el-table ref="multipleTableRef"
         :header-cell-style="{ 'background-color': '#F7F7F9', 'border-bottom': '1px solid #EEF1F6', 'font-size': '15px', 'color': '#333', 'padding': '10px 0' }"
         :data="props.tableData" :height="tableHeight" :max-height="maxHeight" table-layout="fixed" style="width: 100%;"
-        @selection-change="selectionChange" @select-all="selectAllChange">
+        @selection-change="selectionChange" @select-all="selectAllChange" :highlight-current-row="highlightCurrentRow"
+        @current-change="currentChange" v-loading="loading">
         <!-- 空内容自定义 -->
         <template #empty>
           <div class="flex f-c a-c ">
@@ -72,7 +73,7 @@
                 v-if="typeof getDisplayText(scope.row, column) === 'string' && getDisplayText(scope.row, column).includes('\n')"
                 class="flex f-c ">
                 <span v-for="(line, index) in getDisplayText(scope.row, column).split('\n')" :key="index">{{ line
-                  }}</span>
+                }}</span>
               </div>
               <span v-else>
                 {{ getDisplayText(scope.row, column) }}
@@ -80,7 +81,7 @@
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="操作" fixed="right" :width="props.columnwidth" align="center">
+        <el-table-column label="操作" fixed="right" :width="props.columnwidth" v-if="props.showOperation" align="center">
           <template #default="scope">
             <div class="flex a-c j-c">
               <slot name="operation" :operationData="scope.row"></slot>
@@ -104,11 +105,14 @@ import type { TableInstance } from "element-plus";
 interface TableRow {
   [key: string]: any;
 }
-const emit = defineEmits(['getList', 'selectAllChange', 'selectionChange']);
-const props = defineProps<{
+const emit = defineEmits(['getList', 'selectAllChange', 'selectionChange', 'currentChange']);
+interface Props{
   tableData: Array<TableRow>;
   columnwidth: number,//操作栏宽度
   secondaryTable?: boolean,//是否展示二级表格
+  highlightCurrentRow?: boolean,//是否可点击
+  showOperation?: boolean,//操作显示/隐藏
+  loading?:boolean,
   columns: {
     prop: string;
     label: string;
@@ -140,17 +144,27 @@ const props = defineProps<{
   tableheight?: (number | string),
   maxHeight?: (number | string),
   uniqueIdName?: string,
-}>();
+};
 interface Row {
   [key: string]: any; // 假设Row是一个具有任意属性的对象
 }
 interface RouterLink {
   name: string;
 }
+const props = withDefaults(defineProps<Props>(), {
+  showOperation: true, // 默认值为 true
+});
+const loading=ref(false)
 const tableHeight = ref(props.tableheight); // 初始化表格高度
 const newSelectionList = ref<string[]>([]);
 const multipleTableRef = ref<TableInstance>();
 const TableData = ref<TableRow[]>();
+watch(props, () => {
+  if(props.loading!=undefined){
+    loading.value=props.loading;
+
+  }
+})
 onMounted(() => {
   let counter = 1;
   TableData.value = props.tableData.map((row) => ({
@@ -192,6 +206,10 @@ const selectAllChange = (value: any[]) => {
   emit('selectAllChange', newSelectionList.value)
 
 }
+//行点击事件
+const currentChange = (currentRow: any, _oldCurrentRow: any) => {
+  emit('currentChange', currentRow)
+}
 const selectionChange = (value: any[]) => {
   newSelectionList.value = [];
   if (value.length > 0) {

+ 22 - 20
src/components/ruleConditionContainer/index.vue

@@ -8,7 +8,7 @@
         </el-col>
         <el-col :span="3">
           <el-select v-model="item.operator" placeholder="运算符" style="width: 100px; margin: 0 10px;"
-            :disabled="item.attrType !== 'inputNumber' && item.attrType !== 'datetime' && item.attrType !== 'inputTag'">
+            :disabled="item.attrType !== 'inputNumber' && item.attrType !== 'datetime' && item.attrType !== 'inputTag' || disabled">
             <template v-if="item.attrType == 'inputTag'">
               <el-option label="包含" value="1"></el-option>
               <el-option label="不包含" value="2"></el-option>
@@ -20,14 +20,14 @@
           </el-select>
         </el-col>
         <el-col :span="15">
-          <template v-if="item.attrType == 'radio'">
-            <el-select v-model="item.min" placeholder="选择值" clearable filterable>
+          <template v-if="item.attrType == 'radio'" >
+            <el-select v-model="item.min" placeholder="选择值" clearable filterable :disabled="disabled">
               <el-option v-for="dictLabalitem in item.dictLabal" :key="dictLabalitem.id" :label="dictLabalitem.name"
                 :value="dictLabalitem.code" />
             </el-select>
           </template>
-          <template v-if="item.attrType == 'checkbox'">
-            <el-select v-model="item.minArray" placeholder="选择值" clearable filterable multiple
+          <template v-if="item.attrType == 'checkbox'" >
+            <el-select v-model="item.minArray" placeholder="选择值" clearable filterable multiple :disabled="disabled"
               @change="change($event, index)">
               <el-option v-for="dictLabalitem in item.dictLabal" :key="dictLabalitem.id" :label="dictLabalitem.name"
                 :value="dictLabalitem.name" />
@@ -37,52 +37,53 @@
             <el-row class="flex a-c">
               <template v-if="item.operator == '1' || item.operator == null">
                 <el-col :span="11">
-                  <el-input-number v-model="item.min" style="width: 100%;"></el-input-number>
+                  <el-input-number v-model="item.min" :disabled="disabled" style="width: 100%;"></el-input-number>
                 </el-col>
                 <el-col :span="2">
                   <div class="flex a-c j-c " style="font-size: 14px;color: #333;">至</div>
                 </el-col>
                 <el-col :span="11">
-                  <el-input-number v-model="item.max" style="width: 100%;"></el-input-number>
+                  <el-input-number v-model="item.max" :disabled="disabled" style="width: 100%;"></el-input-number>
                 </el-col>
               </template>
               <template v-if="item.operator == '2'">
                 <el-col :span="24">
-                  <el-input-number v-model="item.min" style="width: 100%;"></el-input-number>
+                  <el-input-number v-model="item.min" :disabled="disabled" style="width: 100%;"></el-input-number>
                 </el-col>
               </template>
               <template v-if="item.operator == '3'">
                 <el-col :span="24">
-                  <el-input-number v-model="item.min" style="width: 100%;"></el-input-number>
+                  <el-input-number v-model="item.min" :disabled="disabled" style="width: 100%;"></el-input-number>
                 </el-col>
               </template>
               <template v-if="item.operator == '4'">
                 <el-col :span="24">
-                  <el-input-number v-model="item.max" style="width: 100%;"></el-input-number>
+                  <el-input-number v-model="item.max" :disabled="disabled" style="width: 100%;"></el-input-number>
                 </el-col>
               </template>
               <template v-if="item.operator == '5'">
                 <el-col :span="24">
-                  <el-input-number v-model="item.max" style="width: 100%;"></el-input-number>
+                  <el-input-number v-model="item.max" :disabled="disabled" style="width: 100%;"></el-input-number>
                 </el-col>
               </template>
             </el-row>
           </template>
           <template v-if="item.attrType == 'select'">
-            <el-select v-model="item.minArray" placeholder="选择值" clearable filterable multiple
+            <el-select v-model="item.minArray" placeholder="选择值" clearable filterable multiple :disabled="disabled"
               @change="change($event, index)">
               <el-option v-for="dictLabalitem in item.dictLabal" :key="dictLabalitem.id" :label="dictLabalitem.name"
                 :value="item.attrName == '车辆类型' ? dictLabalitem.code : dictLabalitem.name" />
             </el-select>
           </template>
           <template v-if="item.attrType == 'inputTag'">
-            <el-input-tag v-model="item.minArray" @change="change($event, index)" placeholder="输入内容后按回车键隔开" />
+            <el-input-tag v-model="item.minArray" :disabled="disabled" @change="change($event, index)"
+              placeholder="输入内容后按回车键隔开" />
           </template>
           <template v-if="item.attrType == 'datetime'">
             <el-row class="flex a-c">
               <template v-if="item.operator == '1' || item.operator == null">
                 <el-col :span="11">
-                  <el-date-picker v-model="item.min" type="datetime" format="YYYY-MM-DD HH:mm:ss"
+                  <el-date-picker v-model="item.min" :disabled="disabled" type="datetime" format="YYYY-MM-DD HH:mm:ss"
                     value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 100%;">
                   </el-date-picker>
                 </el-col>
@@ -90,30 +91,30 @@
                   <div class="flex a-c j-c " style="font-size: 14px;color: #333;">至</div>
                 </el-col>
                 <el-col :span="11">
-                  <el-date-picker v-model="item.max" type="datetime" format="YYYY-MM-DD HH:mm:ss"
+                  <el-date-picker v-model="item.max" :disabled="disabled" type="datetime" format="YYYY-MM-DD HH:mm:ss"
                     value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 100%;">
                   </el-date-picker>
                 </el-col>
               </template>
               <template v-if="item.operator == '2'">
                 <el-col :span="24">
-                  <el-date-picker v-model="item.min" type="datetime" format="YYYY-MM-DD HH:mm:ss"
+                  <el-date-picker v-model="item.min" :disabled="disabled" type="datetime" format="YYYY-MM-DD HH:mm:ss"
                     value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 100%;">
                   </el-date-picker>
                 </el-col>
               </template>
               <template v-if="item.operator == '3'">
-                <el-col :span="24"> <el-date-picker v-model="item.min" type="datetime" format="YYYY-MM-DD HH:mm:ss"
+                <el-col :span="24"> <el-date-picker v-model="item.min" :disabled="disabled" type="datetime" format="YYYY-MM-DD HH:mm:ss"
                     value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 100%;">
                   </el-date-picker></el-col>
               </template>
               <template v-if="item.operator == '4'">
-                <el-col :span="24"><el-date-picker v-model="item.max" type="datetime" format="YYYY-MM-DD HH:mm:ss"
+                <el-col :span="24"><el-date-picker v-model="item.max" :disabled="disabled" type="datetime" format="YYYY-MM-DD HH:mm:ss"
                     value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 100%;">
                   </el-date-picker></el-col>
               </template>
               <template v-if="item.operator == '5'">
-                <el-col :span="24"> <el-date-picker v-model="item.max" type="datetime" format="YYYY-MM-DD HH:mm:ss"
+                <el-col :span="24"> <el-date-picker v-model="item.max" :disabled="disabled" type="datetime" format="YYYY-MM-DD HH:mm:ss"
                     value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 100%;">
                   </el-date-picker></el-col>
 
@@ -123,7 +124,7 @@
           </template>
         </el-col>
         <el-col :span="1">
-          <el-icon color="#666" size="18" style="margin-left: 10px;" @click="attrDel(index)">
+          <el-icon v-if="!disabled" color="#666" size="18" style="margin-left: 10px;" @click="attrDel(index)">
             <Delete />
           </el-icon>
         </el-col>
@@ -137,6 +138,7 @@
 import { defineProps, defineEmits } from "vue";
 const props = defineProps<{
   rulesAttrList: any[],//list集合
+  disabled?: boolean,
 }>();
 const emits = defineEmits(["Del", 'save', 'selectChange']);
 //右侧删除图标

+ 11 - 1
src/router/modules/externalAgreement.ts

@@ -26,10 +26,20 @@ const routes: RouteRecordRaw = {
           meta: {
             title: '协议添加',
             menu:false,
-            activeMenu: '/personnel/member',
+            activeMenu: '/externalAgreement/agreement/agreementIndex',
           },
         },
 
+        {
+          path: 'agreementDetails',
+          name: 'ExternalAgreementDetails',
+          component: () => import('@/views/externalAgreement/agreement/agreementDetails.vue'),
+          meta: {
+            title: '协议详情',
+            menu:false,
+            activeMenu: '/externalAgreement/agreement/agreementIndex',
+          },
+        },
       ]
     },
     {

+ 10 - 10
src/router/modules/quoteConfig.ts

@@ -39,16 +39,16 @@ const routes: RouteRecordRaw = {
             activeMenu: '/quoteConfig/agreement/agreementIndex',
           },
         },
-        // {
-        //   path: 'agreementDetails',
-        //   name: 'AgreementDetails',
-        //   component: () => import('@/views/quoteConfig/agreement/agreementDetails.vue'),
-        //   meta: {
-        //     title: '协议详情',
-        //     menu:false,
-        //     activeMenu: '/quoteConfig/agreement/agreementIndex',
-        //   },
-        // },
+        {
+          path: 'agreementDetails',
+          name: 'AgreementDetails',
+          component: () => import('@/views/quoteConfig/agreement/agreementDetails.vue'),
+          meta: {
+            title: '协议详情',
+            menu:false,
+            activeMenu: '/quoteConfig/agreement/agreementIndex',
+          },
+        },
       ]
     },
 

+ 22 - 6
src/router/modules/representative.ts

@@ -27,10 +27,26 @@ const routes: RouteRecordRaw = {
           meta: {
             title: '成员详情',
             menu:false
-          }, 
+          },
         },
       ]
-      
+
+    },
+    {
+      path: 'quoteApproval',
+      name: 'QuoteApproval',
+      component: () => import('@/views/representative/quoteApproval.vue'),
+      meta: {
+        title: '报价费用审核',
+      },
+    },
+    {
+      path: 'externalCostApproval',
+      name: 'ExternalCostApproval',
+      component: () => import('@/views/representative/externalCostApproval.vue'),
+      meta: {
+        title: '外部费用审核',
+      },
     },
     {
       path: 'salesman',
@@ -48,13 +64,13 @@ const routes: RouteRecordRaw = {
           meta: {
             title: '业务员详情',
             menu:false
-          }, 
+          },
         },
       ]
-      
+
     },
-    
-    
+
+
   ],
 }
 

+ 429 - 0
src/views/externalAgreement/agreement/agreementAdd.vue

@@ -0,0 +1,429 @@
+<template>
+  <div>
+    <PageMain style="padding: 20px;margin-bottom: 100px;">
+      <ElRow :gutter="60">
+        <ElCol :md="24" :lg="24" style="padding-bottom: 10px;font-size: 14px;">
+          <span class="strong">协议信息</span>
+        </ElCol>
+        <el-form :model="agreementFrom" label-width="120px" :rules="agreementFromRules" label-position="top"
+          ref="agreementFromRef" style="max-width: 100%;" class="flex a-c f-wrap" :size="fromSize">
+          <ElCol :md="24" :lg="6">
+            <el-form-item label="协议名称" prop="agreementTitle">
+              <el-input v-model="agreementFrom.agreementTitle" placeholder="输入协议名称" maxlength="50"
+                show-word-limit></el-input>
+            </el-form-item>
+          </ElCol>
+          <ElCol :md="24" :lg="6">
+            <el-form-item label="协议简称" prop="agreementAbbreviation">
+              <el-input v-model="agreementFrom.agreementAbbreviation" placeholder="输入简称" maxlength="50"
+                show-word-limit />
+            </el-form-item>
+          </ElCol>
+          <ElCol :md="24" :lg="6">
+            <el-form-item label="协议生效时间" prop="startDate">
+              <el-date-picker v-model="agreementFrom.startDate" style="width: 100%;" type="datetime"
+                placeholder="选择生效时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
+                time-format="HH:mm:ss" @change="handleStartDateChange" />
+            </el-form-item>
+          </ElCol>
+          <ElCol :md="24" :lg="6">
+            <el-form-item label="协议失效时间" prop="endDate">
+              <el-date-picker v-model="agreementFrom.endDate" style="width: 100%;" type="datetime" placeholder="选择失效时间"
+                format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss"
+                :disabled-date="disabledEndDate" />
+            </el-form-item>
+          </ElCol>
+          <ElCol :md="24" :lg="6">
+            <el-form-item label="是否含增值税结算" prop="withTax">
+              <el-radio-group v-model="agreementFrom.withTax">
+                <el-radio-button :label="item.label" :value="item.value" v-for="(item, index) in getDict('with_tax')"
+                  :key="index" />
+              </el-radio-group>
+            </el-form-item>
+          </ElCol>
+          <ElCol :md="24" :lg="6">
+            <el-form-item label="结算周期" prop="moneyTime">
+              <span style="margin: 0  20px;font-size: 18px;">T</span>
+              <el-input-number v-model="agreementFrom.moneyTime" :min="1" :max="999" />
+            </el-form-item>
+          </ElCol>
+          <ElCol :md="24" :lg="12"></ElCol>
+          <ElCol :md="24" :lg="12">
+            <el-form-item label="协议描述" prop="agreementName">
+              <el-input v-model="agreementFrom.agreementName" placeholder="请输入" type="textarea" maxlength="500"
+                show-word-limit />
+            </el-form-item>
+          </ElCol>
+          <ElCol :md="24" :lg="24" style="padding-bottom: 10px;font-size: 14px;">
+            <ElDivider></ElDivider>
+            <span class="strong">其他信息</span>
+          </ElCol>
+          <ElCol :md="24" :lg="6">
+            <el-form-item label="协议归属" prop="deptId">
+              <el-cascader v-model="agreementFrom.deptId" style="width: 100%;" filterable clearable
+                :options="deptOptions" :props="parentIdprops" :show-all-levels="false" @change="deptIdChange" />
+            </el-form-item>
+          </ElCol>
+          <ElCol :md="24" :lg="6">
+            <el-form-item label="保险公司" prop="companyId">
+              <el-cascader v-model="agreementFrom.companyId" style="width: 100%;" filterable clearable
+                :options="companyOptions" :props="companyIdprops" :show-all-levels="false" @change="companyIdChange" />
+            </el-form-item>
+          </ElCol>
+          <ElCol :md="24" :lg="6">
+            <el-form-item label="协议类型" prop="agreementType">
+              <el-select v-model="agreementFrom.agreementType" placeholder="选择协议类型">
+                <el-option :label="item.label" :value="item.value" v-for="(item, index) in getDict('agreement_type')"
+                  :key="index" />
+              </el-select>
+            </el-form-item>
+          </ElCol>
+          <ElCol :md="24" :lg="6">
+            <el-form-item label="管理人" prop="custodianId">
+              <el-input v-model="managerName" @click="managerModalVisible = true">{{ agreementFrom.custodianId
+              }}</el-input>
+            </el-form-item>
+          </ElCol>
+        </el-form>
+      </ElRow>
+
+    </PageMain>
+    <FixedActionBar>
+      <ElButton type="primary" @click="submitForm(agreementFromRef)">
+        保存
+      </ElButton>
+      <ElButton @click="router.back()">
+        取消
+      </ElButton>
+    </FixedActionBar>
+    <!-- 选择管理人 -->
+    <managerModal :managerModal="managerModalVisible" :deptOptions="deptOptions" :managerlist="managerlist"
+      @save="managerModalsave" @NodeClick="managerModalNodeClick" @query="managerModalQuery" @cancel="managerModalVisible = false" />
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive } from 'vue'
+import { FormRules, FormInstance, ComponentSize, ElMessage } from 'element-plus';
+import { loadDicts, getDict } from '@/utils/composables/dictService';//字典组件
+import { useRoute, useRouter } from 'vue-router';
+import managerModal from "./components/managerModal.vue";
+import api from '@/api';
+const parentIdprops = {
+  expandTrigger: 'hover' as const,
+  value: 'id',
+  label: 'name',
+  checkStrictly: true,
+}
+const companyIdprops = {
+  expandTrigger: 'hover' as const,
+  value: 'id',
+  label: 'nameSimple',
+  checkStrictly: true,
+}
+interface AgreementForm {
+  id?: string; // 协议 ID
+  agreementTitle: string; // 协议名称
+  agreementAbbreviation: string; // 协议简称
+  startDate: string; // 生效时间,通常为 ISO 格式的日期字符串
+  endDate: string; // 失效时间,通常为 ISO 格式的日期字符串
+  withTax: string; // 是否含增值税结算
+  moneyTime: any; // 结算周期
+  agreementName: string; // 协议描述
+  deptId: string; // 协议归属
+  companyId: string; // 保险公司 ID
+  agreementType: string; // 协议类型
+  custodianId: string; // 管理人 ID
+
+}
+const route = useRoute();
+const router = useRouter();
+const id = ref(route.query.id as string);//id参数
+const deptOptions = ref([])//机构数据
+const companyOptions = ref()//保险公司数据
+const agreementFromRef = ref<FormInstance>()
+const fromSize = ref<ComponentSize>('large')
+const agreementFrom: AgreementForm = reactive({
+  id: "",
+  agreementTitle: "",//协议名称
+  agreementAbbreviation: "",//协议简称
+  startDate: "",//生效时间
+  endDate: "",//失效时间
+  withTax: "",//是否含增值税结算
+  moneyTime: 0,//结算周期
+  agreementName: "",//协议描述
+  deptId: "",//协议归属
+  companyId: "",//保险公司id
+  agreementType: "",//协议类型
+  custodianId: "",//管理人id
+
+})
+const validatepassword = (_rule: any, value: any, callback: any) => {
+  // 定义正则表达式,例如:只允许字母、数字,长度在4到10个字符之间
+  const codeRegex = /^(?:(?:\+|00)86)?1\d{10}$/;
+  // 判断是否为空
+  if (!value) {
+    return callback(new Error('请输入手机号'));
+  }
+
+  // 验证是否符合正则表达式
+  if (!codeRegex.test(value)) {
+    return callback(new Error('请输入正确的手机号'));
+  }
+  // 验证通过
+  callback();
+};
+
+const agreementFromRules = ref<FormRules>({
+  agreementTitle: [
+    { required: true, trigger: 'blur', message: '请输入协议名称' },
+  ],
+  agreementAbbreviation: [
+    { required: true, trigger: 'blur', message: '请输入协议简称' },
+  ],
+  startDate: [
+    { required: true, trigger: 'change', message: '选择生效时间' },
+  ],
+  endDate: [
+    { required: true, trigger: 'change', message: '选择失效时间' },
+  ],
+  withTax: [
+    { required: true, trigger: 'change', message: '请选择是否含增值税结算' },
+  ],
+  moneyTime: [
+    { required: true, trigger: 'blur', message: '请输入结算周期' },
+  ],
+  agreementName: [
+    { required: true, trigger: 'blur', message: '请输入协议描述' },
+  ],
+  deptId: [
+    { required: true, trigger: 'change', message: '请选择协议归属' },
+  ],
+  companyId: [
+    { required: true, trigger: 'change', message: '请选择保险公司' },
+  ],
+  agreementType: [
+    { required: true, trigger: 'blur', message: '请选择协议类型' },
+  ],
+  custodianId: [
+    { required: true, trigger: 'blur', message: '请选择管理人' },
+  ],
+  dockingPerson: [
+    { required: true, trigger: 'blur', message: '请输入对接人' },
+  ],
+  dockingPhone: [
+    { required: true, trigger: 'blur', message: '请输入对接人手机号' },
+    { validator: validatepassword, trigger: 'blur' }
+  ],
+  attributionId: [
+    { required: true, trigger: 'change', message: '请选择出单账号' },
+  ],
+
+});
+onBeforeMount(async () => {
+  await loadDicts(['agreement_type', 'with_tax']);//获取多个字典
+  getDeptTree();//归属机构
+  company();//获取保险公司列表
+  if (id.value) {
+    agreementFrom.id = id.value;
+    detailsInfo();//详情
+  }
+
+});
+//协议详情
+const detailsInfo = () => {
+  api.agreementApi.agreementGet(id.value).then((res: any) => {
+    if (res.code == '200') {
+      // 更新 agreementFrom 的属性
+      Object.keys(agreementFrom).forEach((key) => {
+        if (res.data.agreement.hasOwnProperty(key)) {
+          // 使用类型断言,确保类型匹配
+          agreementFrom[key as keyof AgreementForm] = res.data.agreement[key] as AgreementForm[keyof AgreementForm];
+        }
+      });
+    } else {
+    }
+  });
+}
+const companyIdChange = (value: any) => {
+  if (value) {
+    agreementFrom.companyId = value[value.length - 1]
+  }
+}
+const deptIdChange = (value: any) => {
+  if (value) {
+    agreementFrom.deptId = value[value.length - 1]
+  }
+}
+// 禁用失效时间选择
+const disabledEndDate = (date: any) => {
+  const startDate = new Date(agreementFrom.startDate);
+  return startDate && date < startDate; // 禁用小于生效时间的日期
+};
+
+// 处理生效时间变化
+const handleStartDateChange = (value: any) => {
+  // 如果生效时间改变,检查失效时间是否需要更新
+  if (agreementFrom.endDate && new Date(agreementFrom.endDate) < new Date(value)) {
+    agreementFrom.endDate = ''; // 清空失效时间
+  }
+};
+
+//嫌憎编辑提交事件
+const submitForm = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  await formEl.validate((valid) => {
+    if (valid) {
+      if (id.value) {
+        api.agreementApi.contactEdit({ ...agreementFrom }).then((res: any) => {
+          if (res.code == '200') {
+            ElMessage({
+              type: 'success',
+              message: res.msg,
+              plain: true,
+            })
+            router.back()
+          } else {
+          }
+        });
+      } else {
+        api.agreementApi.contactAdd({ ...agreementFrom }).then((res: any) => {
+          if (res.code == '200') {
+            ElMessage({
+              type: 'success',
+              message: res.msg,
+              plain: true,
+            })
+            router.back()
+          } else {
+          }
+        });
+      }
+    } else {
+
+    }
+  })
+}
+const getDeptTree = () => {
+  api.institutionApi.institutionList({}).then((res: any) => {
+    if (res.code == '200') {
+      deptOptions.value = res.data;
+      agreementFrom.deptId = res.data[0].id;
+    } else {
+    }
+  });
+}
+const company = () => {
+  api.agreementApi.findTree({ name: "" }).then((res: any) => {
+    if (res.code == '200') {
+      companyOptions.value = res.data;
+    } else {
+      ElMessage({
+        type: 'error',
+        message: res.msg,
+        plain: true,
+      })
+    }
+  });
+}
+//选择管理人
+interface managerlist {
+  id: string,
+  name: string,
+  deptName: string,
+}
+const managerModalVisible = ref(false)
+const managerlist = ref<managerlist[]>([]);//机构向下人员列表
+const managerName = ref();//管理员姓名  回显使用
+//选中机构获取人员
+const managerModalNodeClick = (id: string) => {
+  console.log(id)
+  api.agreementApi.getUserByDeptId(id,'').then((res: any) => {
+    if (res.code == '200') {
+      managerlist.value = res.data;
+    }
+  });
+}
+const managerModalQuery=(searchValue:string)=>{
+  api.agreementApi.getUserByDeptId('',searchValue).then((res: any) => {
+    if (res.code == '200') {
+      managerlist.value = res.data;
+    }
+  });
+}
+//选择管理人保存事件
+const managerModalsave = (id: string, name: string, deptName: string) => {
+  agreementFrom.custodianId = id;
+  managerName.value = name + ' - ' + deptName;
+  managerModalVisible.value = false;
+
+}
+
+</script>
+<style lang="scss" scoped>
+.disabled :deep(.el-upload--picture-card) {
+  display: none;
+}
+
+.agreementNotice {
+  width: max-content;
+  padding: 18px 24px;
+  border: 1px solid #eee;
+  border-radius: 4px;
+
+  &:hover {
+    background-color: #fafafa;
+  }
+
+  img {
+    width: 40px;
+    height: 40px;
+    margin-right: 20px;
+  }
+
+  span:first-child {
+    margin-bottom: 2px;
+    font-size: 14px;
+    color: #333;
+  }
+
+  span:last-child {
+    font-size: 14px;
+    color: #666;
+  }
+
+  .fileBtn {
+    margin-left: 40px;
+
+    .btn-icon {
+      margin: 0 10px;
+      font-size: 20px;
+      color: #999;
+      cursor: pointer;
+
+      &:hover {
+        color: #00a0f4;
+      }
+    }
+  }
+}
+
+.image-view {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 9999;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 100%;
+  background: rgb(0 0 0 / 60%);
+
+  img {
+    width: 800px;
+    height: 800px;
+    border-radius: 5px;
+  }
+}
+</style>

+ 727 - 0
src/views/externalAgreement/agreement/agreementDetails.vue

@@ -0,0 +1,727 @@
+<!-- 模板区域 -->
+<template>
+  <div>
+    <PageMain>
+      <div class="headers">
+        <div class="flex f-c a-start">
+          <div class="flex j-s a-c" style="width: 100%;">
+            <span class="title">{{ agreementInfo.agreementTitle }}</span>
+            <div>
+              <el-button type="default" @click="agreementAuth">协议授权</el-button>
+              <el-button type="default" plain @click="agreementEdit">编辑</el-button>
+              <el-dropdown trigger="click" @command="dropdownCommand" style="margin-left: 10px;">
+                <el-button plain>
+                  更多 <el-icon class="el-icon--right">
+                    <CaretBottom />
+                  </el-icon></el-button>
+                <template #dropdown>
+                  <el-dropdown-menu>
+                    <el-dropdown-item command="启用" v-if="agreementInfo.isEnable == '1'">启用</el-dropdown-item>
+                    <el-dropdown-item command="禁用" v-else>禁用</el-dropdown-item>
+                    <el-dropdown-item command="删除">删除</el-dropdown-item>
+                    <el-dropdown-item command="分配管理人">复制协议</el-dropdown-item>
+                  </el-dropdown-menu>
+                </template>
+              </el-dropdown>
+            </div>
+          </div>
+          <div style="margin-top: 10px;" class="flex">
+            <el-tag type="primary" style="margin-right: 20px;">{{
+              getDict('is_enable').find(val => val.value == agreementInfo.isEnable)?.label}}</el-tag>
+            <el-tag type="success">{{getDict('valid_status').find(val => val.value == agreementInfo.validStatus)?.label
+              }}</el-tag>
+          </div>
+        </div>
+        <el-descriptions :column="3" style="margin-top: 10px;">
+          <el-descriptions-item label="协议号:">{{ agreementInfo.agreementCode }}</el-descriptions-item>
+          <el-descriptions-item label="协议名称:">{{ agreementInfo.agreementTitle }}</el-descriptions-item>
+          <el-descriptions-item label="归属机构:">{{ agreementInfo.deptName }}</el-descriptions-item>
+          <el-descriptions-item label="授权机构:">{{ authDeptlength }}</el-descriptions-item>
+          <el-descriptions-item label="添加人:">
+            {{ agreementInfo.createBy }}
+          </el-descriptions-item>
+          <el-descriptions-item label="添加时间:">
+            {{ agreementInfo.createTime }}
+          </el-descriptions-item>
+        </el-descriptions>
+      </div>
+    </PageMain>
+    <PageMain class="agreement ">
+      <el-tabs v-model="activeName" class="demo-tabs">
+        <el-tab-pane label="协议信息" name="agreementInfo">
+          <el-descriptions title="基本信息" class="m-top-20" :column="3">
+            <el-descriptions-item label="协议名称:">{{ agreementInfo.agreementTitle
+            }}</el-descriptions-item>
+            <el-descriptions-item label="协议简称:">{{ agreementInfo.agreementAbbreviation
+            }}</el-descriptions-item>
+            <el-descriptions-item label="协议生效时间:">{{ agreementInfo.startDate }}</el-descriptions-item>
+            <el-descriptions-item label="协议失效时间:">{{ agreementInfo.endDate }}</el-descriptions-item>
+            <el-descriptions-item label="是否含增值税结算:">
+              {{ agreementInfo.withTax }}
+            </el-descriptions-item>
+            <el-descriptions-item label="结算周期:">T{{ agreementInfo.moneyTime }} </el-descriptions-item>
+            <el-descriptions-item label="协议描述:">{{ agreementInfo.agreementName }}</el-descriptions-item>
+          </el-descriptions>
+          <el-descriptions title="其他信息" class="m-top-20" :column="3">
+            <el-descriptions-item label="协议归属:">{{ agreementInfo.deptName }} </el-descriptions-item>
+            <el-descriptions-item label="保险公司:"> {{ agreementInfo.companyId }}</el-descriptions-item>
+            <el-descriptions-item label="协议类型:">{{ agreementInfo.agreementType }} </el-descriptions-item>
+            <el-descriptions-item label="管理人:"> {{ agreementInfo.custodianId }}</el-descriptions-item>
+            <el-descriptions-item label="对接人:"> {{ agreementInfo.dockingPerson }} </el-descriptions-item>
+            <el-descriptions-item label="对接人手机号:"> {{ agreementInfo.dockingPhone }} </el-descriptions-item>
+          </el-descriptions>
+        </el-tab-pane>
+        <el-tab-pane label="费用管理" name="costManagement">
+          <span class="strong m-right-20">对接人</span>
+          <el-button type="primary" @click="addUnderwritingRule" plain>
+            添加对接人
+            <template #icon>
+              <el-icon>
+                <Plus />
+              </el-icon>
+            </template>
+          </el-button>
+          <div class="flex f-c  RuleContainer" v-if="contactPersonList">
+            <div class="list-item" v-for="(item, index) in contactPersonList" :key="index">
+              <div class="header-title flex f-c ">
+                <div class="flex a-c j-s">
+                  <div class="flex a-c">
+                    <img src="../../../assets/images/fee.png" alt="">
+                    <span class="strong m-left-10">{{ item.contactPerson
+                    }}</span>
+                    <span class="strong m-left-10">{{ item.contactMobile }}</span>
+                  </div>
+                  <div class="flex">
+                    <el-button link type="primary" :icon="Delete"
+                      @click="contactPersonDel(item.contactMobile)">删除</el-button>
+                    <el-button link type="primary" :icon="Edit" @click="contactPersonEdit(item)">编辑</el-button>
+                    <el-button v-if="!item.contactPersonShow" link type="default"
+                      @click="item.contactPersonShow = !item.contactPersonShow">展开<el-icon class="m-left-10">
+                        <ArrowDownBold />
+                      </el-icon> </el-button>
+                    <el-button v-else link type="default"
+                      @click="item.contactPersonShow = !item.contactPersonShow">收起<el-icon class="m-left-10">
+                        <ArrowUpBold />
+                      </el-icon></el-button>
+                  </div>
+                </div>
+              </div>
+              <div class="header-content" v-if="item.contactPersonShow">
+                <ComplexTable :tableData="item.costExternalListVo" :columns="columns" :maxHeight="400"
+                  :showIndex="false" :columnwidth="200" :showSelect="false">
+                  <template v-slot:operation="scope">
+                    <el-button type="primary" link @click="itemEdit(scope.operationData.id)"> 编辑
+                    </el-button>
+                    <el-button type="primary" link @click="itemDel(scope.operationData.id)"> 删除
+                    </el-button>
+                  </template>
+                </ComplexTable>
+              </div>
+            </div>
+          </div>
+          <Empty v-else />
+        </el-tab-pane>
+      </el-tabs>
+    </PageMain>
+    <!-- 协议授权弹窗 -->
+    <auth-Drawer :Drawer="agreementAuthDrawer" @cancel="agreementAuthDrawer = false" @save="DrawerSave"
+      @query="Drawerquery" :deptlist="deptauthList" :checkedKeys="checkedKeys" :checkedIds="checkedIds"></auth-Drawer>
+    <!-- 规则费用抽屉组件 -->
+    <contactPersonFeeDialog v-show="addcontactPersonShow" :ruleFeeVisible="addcontactPersonShow"
+      :title='contactPersontitle' :agreementInfo="agreementInfo"  @save="contactPersonSave"
+      :contactPersonEditInfo="contactPersonEditInfo" addMethod="details" @cancel="addcontactPersonShow = false"  />
+    <!-- 规则费用编辑组件 -->
+    <contactPersonFeeDialogEdit :ruleFeeVisible="ruleFeeEditVisible" :headerTitle="ruleFeeHeaderTitle"
+      :agreementInfo="agreementInfo"  :costitemEditInfo="costitemEditInfo" @save="ruleFeeEditSave"
+      @cancel="ruleFeeEditVisible = false" />
+  </div>
+</template>
+<!-- 行为区域 -->
+<script lang='ts' setup>
+import api from '@/api';
+import { CaretBottom } from '@element-plus/icons-vue'
+import { ElMessage, ElMessageBox, } from 'element-plus'
+import { ref, reactive } from 'vue'
+import { useRoute, useRouter } from 'vue-router';
+import { loadDicts, getDict } from '@/utils/composables/dictService';//字典组件
+import authDrawer from "./components/agreementAuth.vue";
+import contactPersonFeeDialog from "./components/contactPersonFeeDialog.vue";
+import contactPersonFeeDialogEdit from "./components/contactPersonFeeDialogEdit.vue";
+import { Delete, Edit } from '@element-plus/icons-vue'
+interface Agreement {
+  [key: string]: string | number; // 协议名称
+}
+const agreementInfo = ref<Agreement>({}); // 初始值为 null
+const route = useRoute();
+const router = useRouter();
+const id = ref(route.query.id as string);//id参数
+const activeName = ref('costManagement')//默认标签页
+const authDeptlength = ref<number>(0);
+onBeforeMount(async () => {
+  await loadDicts(['agreement_type', 'valid_status', 'is_enable', 'with_tax', 'audit_status', 'insurance_type']);//获取多个字典
+
+  if (id.value) {
+    detailsInfo();//协议信息
+    costExternalList();//对接人列表
+  }
+})
+//协议详情
+const detailsInfo = () => {
+  api.agreementApi.agreementGet(id.value).then((res: any) => {
+    if (res.code == '200') {
+      agreementInfo.value = res.data.agreement;
+
+      authDeptlength.value = res.data.dept.length;
+      imageUrl.value = res.data.agreement.fileUrl;
+    } else {
+    }
+  });
+}
+
+//编辑跳转
+const agreementEdit = () => {
+  router.push({
+    name: 'ExternalagreementAdd',
+    query: {
+      id: id.value
+    }
+  })
+}
+//协议授权
+//检索事件
+const imageUrl = ref('');//协议文件
+const agreementAuthDrawer = ref(false)//授权弹窗
+const deptauthList = ref([]);//授权机构列表
+const checkedKeys = ref<string[]>([])//授权机构回显数据
+const checkedIds = ref<string[]>([])//授权机构回显id
+const Drawerquery = (name: any) => {
+  agreementAuth(name)
+}
+//授权保存
+const DrawerSave = (list: any) => {
+  api.agreementApi.authSave({ deptIds: list, id: id.value }).then((res: any) => {
+    if (res.code == '200') {
+      ElMessage({
+        type: 'success',
+        message: res.msg,
+        plain: true,
+      })
+      agreementAuthDrawer.value = false;
+    } else {
+    }
+  });
+}
+//协议授权机构获取
+const agreementAuth = (deptName: any) => {
+  let name = typeof deptName === 'string' ? deptName : '';
+  api.agreementApi.agreementdeptTree(id.value, name).then((res: any) => {
+    if (res.code == '200') {
+      agreementAuthDrawer.value = true;
+      deptauthList.value = res.data;
+      checkedKeys.value = getUncheckedIds(res.data);
+      checkedIds.value = getUncheckedIds(res.data);
+    } else {
+    }
+  });
+}
+// 递归回显数据
+function getUncheckedIds(data: any[]): string[] {
+  let ids: string[] = [];
+
+  data.forEach((item) => {
+    if (item.isCheck === 1) {
+      ids.push(item.id); // 如果 isCheck 为 0,添加 id
+    }
+    if (item.children && item.children.length > 0) {
+      // 如果有子项,递归调用
+      ids = ids.concat(getUncheckedIds(item.children));
+    }
+  });
+
+  return ids;
+}
+
+//更多操作集合
+const dropdownCommand = (e: any) => {
+  switch (e) {
+    case '启用':
+      api.agreementApi.sysUpAndDown({ ids: [id.value], opType: '0' }).then((res: any) => {
+        if (res.code == '200') {
+          ElMessage({
+            type: 'success',
+            message: res.msg,
+            plain: true,
+          })
+          router.push({
+            name: 'reload',
+          })
+        } else {
+        }
+      });
+      break;
+    case '禁用':
+      ElMessageBox.confirm(
+        '确定要禁用该协议吗,禁用后,该协议不在支持报价出单,并且已核保待缴费,待支付的订单,都将失效,请确认是否禁用?',
+        '禁用协议',
+        {
+          confirmButtonText: '确定禁用',
+          type: 'error',
+          center: true,
+          confirmButtonClass: 'el-button--danger',
+        }
+      )
+        .then(() => {
+          api.agreementApi.sysUpAndDown({ ids: [id.value], opType: '1' }).then((res: any) => {
+            if (res.code == '200') {
+              ElMessage({
+                type: 'success',
+                message: res.msg,
+                plain: true,
+              })
+              router.push({
+                name: 'reload',
+              })
+            }
+          });
+        })
+
+      break;
+    case '删除':
+      ElMessageBox.confirm(
+        '确定要删除该协议吗,删除后,该协议不在支持报价出单,并且已核保待缴费,待支付的订单,都将失效,请确认是否删除?',
+        '删除协议',
+        {
+          confirmButtonText: '确定删除',
+          type: 'error',
+          center: true,
+          confirmButtonClass: 'el-button--danger',
+        }
+      )
+        .then(() => {
+          api.agreementApi.agreementDelete({ ids: [id.value] }).then((res: any) => {
+            if (res.code == '200') {
+              ElMessage({
+                type: 'success',
+                message: res.msg,
+                plain: true,
+              })
+              router.back()
+            }
+          });
+        })
+      break;
+    case '复制协议':
+      break;
+    default:
+      break;
+  }
+
+}
+
+//  添加承保规则
+const addcontactPersonShow = ref(false);//添加对接人
+const contactPersonList = ref();//协议下对接人费用
+const contactPersontitle = ref();//弹窗title
+const addUnderwritingRule = () => {//添加对接人
+  addcontactPersonShow.value = true;
+  contactPersontitle.value = '添加';
+}
+
+//对接人列表
+const costExternalList = () => {
+  api.agreementApi.costExternalList({ ptlAgreementId: id.value }).then((res: any) => {
+    if (res.code == '200') {
+      res.data.map((val: any) => {
+        val.contactPersonShow = false;
+        return val;
+      })
+      contactPersonList.value = res.data;
+    } else {
+    }
+  });
+}
+//修改对接人所有费用
+interface contactPersonEditInfo{
+  ptlAgreementId: string,
+  contactPerson: string,
+  contactMobile: string,
+  ptlAgreementCostExternalAddList: any[],
+}
+const contactPersonEditInfo = reactive<contactPersonEditInfo>({
+  ptlAgreementId: "",//协议id
+  contactPerson: "",//对接人
+  contactMobile: "",//手机号
+  ptlAgreementCostExternalAddList: [],//费用集合
+})
+const contactPersonEdit = (item: any) => {
+  api.agreementApi.selectByAgreementIdAll({ ptlAgreementId: id.value, contactPerson: item.contactPerson, contactMobile: item.contactMobile }).then((res: any) => {
+    if (res.code == '200') {
+      const dict = getDict('insurance_type');//获取险种字典
+      const difference = getObjectArrayDifference(dict, res.data, "label", 'productName');//获取编辑数据和字典数组差集
+      const differenceArray:any = dataCompletion(difference);//差集对象赋值
+      contactPersonEditInfo.ptlAgreementId = id.value;
+      contactPersonEditInfo.contactPerson = item.contactPerson;
+      contactPersonEditInfo.contactMobile = item.contactMobile;
+      contactPersonEditInfo.ptlAgreementCostExternalAddList =[...res.data,...differenceArray];
+      contactPersontitle.value = '编辑';
+      addcontactPersonShow.value = true;
+    } else {
+    }
+  });
+}
+//匹配编辑和新增数组差集
+const getObjectArrayDifference = (arr1: any, arr2: any, key: string, key1: string) => {
+  console.log(arr1, arr2)
+  return arr1.filter((item1: any) =>
+    !arr2.some((item2: any) => item2[key1] === item1[key])
+  );
+}
+/**
+ * @param dataCompletion 编辑数据补全
+ * @param list 差集数组
+ */
+const dataCompletion = (list: any) => {
+  let array = list.map((val: any) => {
+    const filteredList: any = filterCostTypeList(val.label);//根据险种匹配列表
+    let list = JSON.parse(JSON.stringify(filteredList)); // 深拷贝
+    return {
+      productName: val.label,
+      productId: val.value,
+      effectiveTime: "",//生效时间
+      failureTime: "",//失效时间
+      auditMethod: "",//审核方式
+      isInquiry: "0",//是否线询
+      costDescribe: "",//费用描述
+      costExternalTypeAdds: list,
+    }
+  })
+  return array;
+}
+
+// 过滤方法
+const filterCostTypeList = (name: string) => {
+  const ptlAgreementCostTypeList = [
+    {
+      costType: "交强险",
+      inlet: 0,
+      export: 0,
+      totalCost: 0,
+      other: 0,
+      level1: 0,
+      level5: 0,
+    },
+    {
+      costType: "商业险",
+      inlet: 0,
+      export: 0,
+      totalCost: 0,
+      other: 0,
+      level1: 0,
+      level5: 0,
+    },
+    {
+      costType: "驾意险",
+      inlet: 0,
+      export: 0,
+      totalCost: 0,
+      other: 0,
+      level1: 0,
+      level5: 0,
+    }
+  ];
+  return ptlAgreementCostTypeList.filter(item => {
+    if (name === "单交" && item.costType === "商业险") {
+      return false; // 当 name 为 "单交" 且 costType 为 "商业险" 时,返回 false,不包含该项
+    }
+    if (name === "单三" && item.costType === "商业险") {
+      return false; // 当 name 为 "单交" 且 costType 为 "商业险" 时,返回 false,不包含该项
+    }
+    if (name === "单商" && item.costType === "交强险") {
+      return false; // 当 name 为 "商业" 且 costType 为 "交强险" 时,返回 false,不包含该项
+    }
+    return true; // 其他情况返回 true,保留该项
+  });
+};
+//删除规则
+const contactPersonDel = (contactMobile: string) => {
+  ElMessageBox.confirm(
+    '确定要删除该对接人吗,删除后,该对接人的费用也将同步删除,请确认是否删除?',
+    '删除对接人',
+    {
+      confirmButtonText: '确定删除',
+      type: 'error',
+      center: true,
+      confirmButtonClass: 'el-button--danger',
+    }
+  )
+    .then(() => {
+      api.agreementApi.deleteByPtlAgreementIdAndMobile({ ptlAgreementId: id.value, contactMobile: contactMobile }).then((res: any) => {
+        if (res.code == '200') {
+          costExternalList();
+          ElMessage({
+            type: 'success',
+            message: res.msg,
+            plain: true,
+          })
+        }
+      });
+    })
+}
+//添加费用
+const ruleFeeEditVisible = ref(false);//编辑弹窗
+const ruleFeeHeaderTitle = ref();//编辑弹窗title
+const costitemEditInfo = ref();
+const columns = [
+  { prop: "productName", label: "险种", width: '200' },
+  {
+    prop: "isInquiry", label: "是否现询", width: '200', formatter: (row: any) => {
+      if (row.isInquiry == '0') {
+        return "是"
+      } else {
+        return "否"
+      }
+    }
+  },
+  {
+    prop: "costExternalTypeAdds", label: "交强险费用", width: '300', formatter: (row: any) => {
+      let info = row.costExternalTypeAdds.find((val: any) => val.costType == '交强险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n一级:${info.level1.toFixed(2)}% 五级:${info.level5.toFixed(2)}%`
+      }else {
+        return '-'
+      }
+    }
+  },
+  {
+    prop: "costExternalTypeAdds", label: "商业险费用", width: '300', formatter: (row: any) => {
+      let info = row.costExternalTypeAdds.find((val: any) => val.costType == '商业险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n一级:${info.level1.toFixed(2)}% 五级:${info.level5.toFixed(2)}%`
+      }else {
+        return '-'
+      }
+    }
+  },
+  {
+    prop: "costExternalTypeAdds", label: "驾意险费用", width: '300', formatter: (row: any) => {
+      let info = row.costExternalTypeAdds.find((val: any) => val.costType == '驾意险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n一级:${info.level1.toFixed(2)}% 五级:${info.level5.toFixed(2)}%`
+      }else {
+        return '-'
+      }
+    }
+  },
+
+  {
+    prop: "effectiveTime", label: "有效期", width: '200',
+    formatter: (row: any) => {
+      return `起${row.effectiveTime}\n止${row.failureTime}`
+    }
+  },
+  {
+    prop: "isEnabled", label: "费用状态", width: '200', component: "Tag",
+    formatter: (row: any) => {
+      let name = getDict('is_enable').find(val => val.value == row.isEnabled).label
+      if (name) {
+        return { type: 'danger', text: name };
+      } else {
+        return { type: 'primary', text: name };
+      }
+    }
+  },
+  {
+    prop: "effective", label: "有效状态", width: '200',
+    component: "Tag",
+    formatter: (row: any) => {
+      if (row.effective) {
+        return { type: 'danger', text: '有效' };
+      } else {
+        return { type: 'danger', text: '无效' };
+      }
+    }
+  },
+];
+
+//费用提交
+const contactPersonSave = (data: object) => {
+  if (contactPersontitle.value == '编辑') {
+    api.agreementApi.ptlAgreementCostExternalupdate(data).then((res: any) => {
+      if (res.code == '200') {
+        addcontactPersonShow.value = false;
+        costExternalList();
+      } else {
+      }
+    });
+  } else {
+    api.agreementApi.ptlAgreementCostExternalsave(data).then((res: any) => {
+      if (res.code == '200') {
+        addcontactPersonShow.value = false;
+        costExternalList();
+      } else {
+      }
+    });
+  }
+
+}
+//费用编辑
+const ruleFeeEditSave = (data: object) => {
+  api.agreementApi.FeeupdateById(data).then((res: any) => {
+    if (res.code == '200') {
+      ElMessage({
+        type: 'success',
+        message: res.msg,
+        plain: true,
+      })
+      ruleFeeEditVisible.value=false;
+      costExternalList();
+    } else {
+    }
+  });
+}
+//编辑删除费用
+const itemEdit = (id: string) => {
+  api.agreementApi.FeegetById(id).then((res: any) => {
+    if (res.code == '200') {
+      ruleFeeHeaderTitle.value = res.data.productName;
+      costitemEditInfo.value = res.data;
+      ruleFeeEditVisible.value = true;
+    } else {
+    }
+  });
+}
+
+//删除费用
+const itemDel = (id: string) => {
+  ElMessageBox.confirm(
+    '确定要删除该费用,请确认是否删除?',
+    '删除费用',
+    {
+      confirmButtonText: '确定删除',
+      type: 'error',
+      center: true,
+      confirmButtonClass: 'el-button--danger',
+    }
+  )
+    .then(() => {
+      api.agreementApi.deleteById([id]).then((res: any) => {
+        if (res.code == '200') {
+          costExternalList();
+          ElMessage({
+            type: 'success',
+            message: res.msg,
+            plain: true,
+          })
+        } else {
+        }
+      });
+    })
+}
+</script>
+<!-- 样式区域 -->
+<style lang='scss' scoped>
+:deep(.demo-tabs .el-tabs__item) {
+  height: 60px;
+  font-size: 20px;
+  font-weight: bold !important;
+}
+
+:deep(.ruleFee .el-tabs__item) {
+  height: 40px;
+  font-size: 14px;
+  font-weight: 500 !important;
+}
+
+:deep(.agreement .p-5) {
+  padding-top: 0;
+}
+
+:deep(.el-descriptions__cell) {
+  width: 33.33%;
+}
+
+:deep(.my-label) {
+  font-weight: bold !important;
+}
+
+.headers {
+  .title {
+    font-size: 20px;
+    font-weight: bold;
+    color: #333;
+  }
+}
+
+.RuleContainer {
+  margin-top: 20px;
+
+  .list-item {
+    padding: 18px 16px;
+    margin-bottom: 20px;
+    border: 1px solid #e5e5e5;
+    border-radius: 10px;
+
+    .empty {
+      font-size: 14px;
+      color: #666;
+      text-align: center;
+    }
+  }
+}
+
+.agreementNotice {
+  width: max-content;
+  padding: 18px 24px;
+  border: 1px solid #eee;
+  border-radius: 4px;
+
+  &:hover {
+    background-color: #fafafa;
+  }
+
+  img {
+    width: 40px;
+    height: 40px;
+    margin-right: 20px;
+  }
+
+  span:first-child {
+    margin-bottom: 2px;
+    font-size: 14px;
+    color: #333;
+  }
+
+  span:last-child {
+    font-size: 14px;
+    color: #666;
+  }
+
+  .fileBtn {
+    margin-left: 40px;
+
+    .btn-icon {
+      margin: 0 10px;
+      font-size: 20px;
+      color: #999;
+      cursor: pointer;
+
+      &:hover {
+        color: #00a0f4;
+      }
+    }
+  }
+}
+
+.title {
+  display: flex;
+
+  &::before {
+    display: inline-block;
+    width: 4px;
+    height: 18px;
+    margin-right: 20px;
+    content: "";
+    background-color: #0083ff;
+  }
+}
+</style>

+ 473 - 11
src/views/externalAgreement/agreement/agreementIndex.vue

@@ -1,17 +1,479 @@
-<!-- 模板区域 -->
 <template>
-<div>
-<PageMain>
-</PageMain>
-</div>
+  <div>
+    <PageMain class="vh100">
+      <SearchForm :fields="fields" :formInline="formInline" :onSearch="agreementQuery" :onReset="resetForm" />
+      <ComplexTable :tableData="tableData" :columns="columns" :showIndex="false" :columnwidth="200" :showSelect="true"
+        :pageInfo="pageInfo" @getList="getList" @selectionChange="selectionChange">
+        <template v-slot:table-title-btn>
+          <RouterLink :to="{ name: 'ExternalagreementAdd' }">
+            <el-button type="primary">
+              添加协议
+              <template #icon>
+                <el-icon>
+                  <Plus />
+                </el-icon>
+              </template>
+            </el-button>
+          </RouterLink>
+          <el-dropdown placement="bottom-start">
+            <el-button > 批量管理<el-icon>
+                <arrow-down />
+              </el-icon>
+            </el-button>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item :disabled="!sysUpAndDownList.length" @click="batchDel">删除</el-dropdown-item>
+                <el-dropdown-item :disabled="!sysUpAndDownList.length" @click="batchdisable">禁用</el-dropdown-item>
+                <el-dropdown-item :disabled="!sysUpAndDownList.length" @click="batchenable">启用</el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+        </template>
+        <template v-slot:operation="scope">
+          <el-button type="primary" link @click="agreemenUpdate(scope.operationData)"> 详情
+          </el-button>
+          <el-dropdown placement="bottom-start" trigger="click">
+            <span class="el-dropdown-link">
+              更 多
+            </span>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item @click="enable(scope.operationData.id)">启用</el-dropdown-item>
+                <el-dropdown-item @click="disable(scope.operationData.id)">禁用</el-dropdown-item>
+                <el-dropdown-item @click="del(scope.operationData.id)">删除</el-dropdown-item>
+                <el-dropdown-item @click="agreemenCopy(scope.operationData.id)">复制协议</el-dropdown-item>
+                <el-dropdown-item @click="batchAuthorization(scope.operationData.id)">协议授权</el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+        </template>
+        <template v-slot:search="scope">
+          {{ scope.slotData.label }}
+        </template>
+      </ComplexTable>
+    </PageMain>
+    <auth-Drawer :Drawer="agreementAuthDrawer" @cancel=" agreementAuthDrawer = false" @save="DrawerSave"
+      @query="Drawerquery" :deptlist="deptauthList" :checkedKeys="checkedKeys" :checkedIds="checkedIds"></auth-Drawer>
+  </div>
 </template>
 
-<!-- 行为区域 -->
-<script lang='ts' setup>
-import { ref,reactive } from 'vue'
-import api from '@/api'
+<script lang="ts" setup>
+import { ref, reactive } from 'vue'
+import { RouterLink, useRouter } from "vue-router";
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { loadDicts, getDict } from '@/utils/composables/dictService';//字典组件
+import authDrawer from "./components/agreementAuth.vue";
+import api from '@/api';
+interface PageInfo {
+  pageNum: number;
+  pageSize: number;
+  sizes: number[];
+  total: number;
+}
+onBeforeMount(async () => {
+  await loadDicts(['agreement_type', 'valid_status', 'is_enable', 'with_tax']);//获取多个字典
+  findpage();//列表数据
+  getDeptTree();
+  agreement_type.value = getDict('agreement_type');//协议类型
+  valid_status.value = getDict('valid_status');//生效状态
+  is_enable.value = getDict('is_enable');//协议状态
+  with_tax.value = getDict('with_tax')//是否含税
+});
+
+const parentIdprops = {
+  expandTrigger: 'hover' as const,
+  value: 'id',
+  label: 'name',
+  checkStrictly: true,
+}
+const tableData = ref([
+]);
+const sysUpAndDownList = ref<string[]>([])//选中id
+const provinceoptions = ref<string[]>([])//省市区回显数据
+const deptOptions = ref()//机构数据
+const agreement_type = ref();
+const valid_status = ref();
+const is_enable = ref();
+const with_tax = ref();
+const router = useRouter();
+const pageInfo = ref({
+  pageNum: 1,
+  pageSize: 20,
+  sizes: [10, 20, 30, 40, 50],
+  total: 100,
+});
+const formInline = reactive({
+  searchValue: '',//协议信息
+  deptId: "",//归属
+  companyId: '',//保险公司id
+  agreementType: '',//协议类型
+  validStatus: "",//有效状态
+  isEnable: "",//协议状态
+  withTax: "",
+  dockingPerson: "",
+  attributionName: "",
+  takeStartDate: "",
+  takeEndDate: "",
+  loseStartDate: "",
+  loseEndDate: "",
+  isExternal:'1',
+  value1:[],
+  value2:[],
+})
+
+//表格字段数据
+const fields = ref([
+  { label: "协议信息", model: "searchValue", type: "input", placeholder: "输入代码,名称,简称查找" },
+  {
+    label: "协议归属", model: "deptId", type: "cascader", options: deptOptions, props: parentIdprops, onChange: (value: any) => {
+      formInline.deptId = value[value.length - 1];
+    }
+  },
+  {
+    label: "保险公司", model: "companyId", type: "select", placeholder: "选择保险公司",
+  },
+  {
+    label: "协议类型", model: "agreementType", type: "select", placeholder: "选择保险公司", options: agreement_type,
+  },
+  {
+    label: "生效状态", model: "validStatus", type: "select", placeholder: "选择生效状态", options: valid_status,
+  },
+  {
+    label: "协议状态", model: "isEnable", type: "select", placeholder: "选择协议状态", options: is_enable,
+  },
+  {
+    label: "是否含税结算", model: "withTax", type: "select", placeholder: "请选择", options: with_tax,
+  },
+  {
+    label: "生效时间", model: "value1", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
+    onChange: (value: any) => {
+      formInline.takeStartDate = value[0];
+      formInline.takeEndDate = value[1];
+    }
+  },
+  {
+    label: "失效时间", model: "value2", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
+    onChange: (value: any) => {
+      formInline.loseStartDate = value[0];
+      formInline.loseEndDate = value[1];
+    }
+  },
+]);
+
+//数据查询
+function findpage() {
+  api.agreementApi.agreementList({ pages: pageInfo.value.pageNum, size: pageInfo.value.pageSize, ...formInline }).then((res: any) => {
+    if (res.code == '200') {
+      tableData.value = res.data.records;
+      pageInfo.value.pageNum = res.data.current;
+      pageInfo.value.pageSize = res.data.size;
+      pageInfo.value.total = res.data.total;
+    } else {
+    }
+  });
+}
+const columns = [
+  { prop: "agreementCode", label: "协议编号", width: '200', },
+  {
+    prop: "agreementTitle", label: "协议名称", width: '200',
+  },
+  { prop: "agreementAbbreviation", label: "协议简称", width: '120', },
+  {
+    prop: "deptName", label: "归属", width: '120',
+  },
+  {
+    prop: "agreementType", label: "协议类型", width: '200', formatter: (row: any) => {
+      let name = getDict('agreement_type').find(val => val.value == row.agreementType).label
+      return name
+    }
+  },
+  {
+    prop: "isEnable", label: "协议状态", width: '100',
+    component: "Tag",
+    formatter: (row: any) => {
+      let name = getDict('is_enable').find(val => val.value == row.isEnable).label
+      if (name) {
+        return { type: 'primary', text: name };
+      } else {
+        return { type: 'primary', text: name };
+      }
+    }
+
+  },
+  {
+    prop: "validStatus", label: "生效状态", width: '120', component: "Tag",
+    formatter: (row: any) => {
+      let name = getDict('valid_status').find(val => val.value == row.validStatus).label
+      if (name) {
+        return { type: 'danger', text: name };
+      } else {
+        return { type: 'danger', text: name };
+      }
+    }
+  },
+  {
+    prop: "withTax", label: "是否含税结算", width: '180',
+    formatter: (row: any) => {
+      let name = getDict('with_tax').find(val => val.value == row.withTax).label
+      return name
+    }
+  },
+  {
+    prop: "moneyTime", label: "结算周期", width: '120',
+    formatter: (row: any) => {
+      return 'T' + row.moneyTime
+    }
+  },
+  { prop: "company", label: "保险公司", width: '200' },
+  { prop: "custodianId", label: "管理人", width: '200' },
+  { prop: "startDate", label: "生效时间", width: '200' },
+  { prop: "endDate", label: "失效时间", width: '200' },
+  { prop: "createTime", label: "添加时间", width: '200' },
+  { prop: "createBy", label: "添加人", width: '200' },
+];
+//分页事件
+function getList(item: PageInfo) {
+  pageInfo.value.pageNum = item.pageNum;
+  pageInfo.value.pageSize = item.pageSize;
+  findpage();
+
+};
+//机构授权
+const agreementAuthDrawer = ref(false)//授权弹窗
+const deptauthList = ref([]);//授权机构列表
+const checkedKeys = ref<string[]>([])//授权机构回显数据
+const checkedIds = ref<string[]>([])//授权机构回显id
+//授权机构检索
+const Drawerquery = (name: any) => {
+  agreementAuth(name)
+}
+//授权保存
+const DrawerSave = (list: any) => {
+  api.agreementApi.authSave({ deptIds: list, id: agreementId.value }).then((res: any) => {
+    if (res.code == '200') {
+      ElMessage({
+        type: 'success',
+        message: res.msg,
+        plain: true,
+      })
+      agreementAuthDrawer.value = false;
+    } else {
+    }
+  });
+}
+//协议授权
+const agreementAuth = (deptName: any) => {
+  let name = typeof deptName === 'string' ? deptName : '';
+  api.agreementApi.agreementdeptTree(agreementId.value, name).then((res: any) => {
+    if (res.code == '200') {
+      agreementAuthDrawer.value = true;
+      deptauthList.value = res.data;
+      checkedKeys.value = getUncheckedIds(res.data);
+      checkedIds.value = getUncheckedIds(res.data);
+    } else {
+    }
+  });
+}
+// 定义递归函数
+function getUncheckedIds(data: any[]): string[] {
+  let ids: string[] = [];
+
+  data.forEach((item) => {
+    if (item.isCheck === 1) {
+      ids.push(item.id); // 如果 isCheck 为 0,添加 id
+    }
+    if (item.children && item.children.length > 0) {
+      // 如果有子项,递归调用
+      ids = ids.concat(getUncheckedIds(item.children));
+    }
+  });
+
+  return ids;
+}
+
+function agreemenUpdate(item: any) {
+  router.push({
+    name: 'ExternalAgreementDetails',
+    query: {
+      id: item.id
+    }
+  })
+}
+
+//多选事件
+const selectionChange = (val: any) => {
+  sysUpAndDownList.value = val;
+}
+//协议授权
+const agreementId = ref()
+const batchAuthorization = (value: string) => {
+  agreementId.value = value;
+  api.agreementApi.agreementdeptTree(value, '').then((res: any) => {
+    if (res.code == '200') {
+      agreementAuthDrawer.value = true;
+      deptauthList.value = res.data;
+      checkedKeys.value = getUncheckedIds(res.data);
+      checkedIds.value = getUncheckedIds(res.data);
+    } else {
+    }
+  });
+
+}
+//复制协议
+const agreemenCopy = (id:string) => {
+  router.push({
+    name: 'AgreementCopy',
+    query: {
+      id: id
+    }
+  })
+}
+//禁用
+const disable = (value: string) => {
+  ElMessageBox.confirm(
+    '确定要禁用该协议吗,禁用后,该协议不在支持报价出单,并且已核保待缴费,待支付的订单,都将失效,请确认是否禁用?',
+    '禁用协议',
+    {
+      confirmButtonText: '确定禁用',
+      type: 'error',
+      center: true,
+      confirmButtonClass: 'el-button--danger',
+    }
+  )
+    .then(() => {
+      sysUpAndDown('1', [value]);
+    })
+}
+//启用
+const enable = (value: string) => {
+  sysUpAndDown('0', [value]);
+}
+const del = (value: string) => {
+  ElMessageBox.confirm(
+    '确定要删除该协议吗,删除后,该协议不在支持报价出单,并且已核保待缴费,待支付的订单,都将失效,请确认是否删除?',
+    '删除协议',
+    {
+      confirmButtonText: '确定删除',
+      type: 'error',
+      center: true,
+      confirmButtonClass: 'el-button--danger',
+    }
+  )
+    .then(() => {
+      api.agreementApi.agreementDelete([value]).then((res: any) => {
+        if (res.code == '200') {
+          ElMessage({
+            type: 'success',
+            message: res.msg,
+            plain: true,
+          })
+          router.push({
+            name: 'reload',
+          })
+        }
+      });
+    })
+}
+//批量删除
+const batchDel = () => {
+  ElMessageBox.confirm(
+    '确定要删除该协议吗,删除后,该协议不在支持报价出单,并且已核保待缴费,待支付的订单,都将失效,请确认是否删除?',
+    '删除协议',
+    {
+      confirmButtonText: '确定删除',
+      type: 'error',
+      center: true,
+      confirmButtonClass: 'el-button--danger',
+    }
+  )
+    .then(() => {
+      api.agreementApi.agreementDelete(sysUpAndDownList.value).then((res: any) => {
+        if (res.code == '200') {
+          ElMessage({
+            type: 'success',
+            message: res.msg,
+            plain: true,
+          })
+          router.push({
+            name: 'reload',
+          })
+        }
+      });
+    })
+
+}
+//批量禁用
+const batchdisable = () => {
+  ElMessageBox.confirm(
+    '确定要禁用该协议吗,禁用后,该协议不在支持报价出单,并且已核保待缴费,待支付的订单,都将失效,请确认是否禁用?',
+    '禁用协议',
+    {
+      confirmButtonText: '确定禁用',
+      type: 'error',
+      center: true,
+      confirmButtonClass: 'el-button--danger',
+    }
+  )
+    .then(async () => {
+      await sysUpAndDown('1', undefined);
+    })
+    .catch(() => {
+    })
+
+
+}
+//批量启用
+const batchenable = async () => {
+  await sysUpAndDown('0', undefined);
+}
+const agreementQuery = () => {
+  findpage();
+}
+const sysUpAndDown = async (type: string, list?: string[]) => {
+  await api.agreementApi.sysUpAndDown({ ids: list ? list : sysUpAndDownList.value, opType: type }).then((res: any) => {
+    if (res.code == '200') {
+      findpage();
+      ElMessage({
+        type: 'success',
+        message: res.msg,
+        plain: true,
+      })
+    }
+  });
+}
+const resetForm = () => {
+  formInline.searchValue = '';
+  provinceoptions.value = [];
+  findpage();
+}
+const getDeptTree = () => {
+  api.institutionApi.institutionList({}).then((res: any) => {
+    if (res.code == '200') {
+      deptOptions.value = res.data;
+    } else {
+    }
+  });
+}
 </script>
-<!-- 样式区域 -->
-<style lang='scss' scoped>
 
+<style lang="scss" scoped>
+.demo-form-inline .el-input {
+  --el-input-width: 220px;
+}
+
+.demo-form-inline .el-select {
+  --el-select-width: 220px;
+}
+
+:deep(.el-dropdown-link) {
+  display: flex;
+  align-items: center;
+  margin-left: 15px;
+  color: var(--el-color-primary);
+  cursor: pointer;
+}
+
+.el-inputs {
+  width: 100% !important;
+}
 </style>

+ 83 - 0
src/views/externalAgreement/agreement/components/agreementAuth.vue

@@ -0,0 +1,83 @@
+<!-- 模板区域 -->
+<template>
+  <div>
+    <el-drawer v-model="props.Drawer" :direction="direction" @open="DrawerOpen" :close-on-click-modal="false">
+      <template #header>
+        <h4>参与机构</h4>
+      </template>
+      <template #default>
+        <div class="flex f-c">
+          <div>
+            <el-input v-model="deptName" class="m-right-20" style="width: 240px;" placeholder="输入名称"
+              :prefix-icon="Search" />
+            <el-button @click="query">查询</el-button>
+          </div>
+          <el-checkbox v-model="checkedALL" label="全选" size="large" />
+          <el-tree :data="props.deptlist" show-checkbox node-key="id" ref="treeRef" :props="defaultProps"
+            :default-expand-all="true" @check="handleCheck" :default-checked-keys="props.checkedKeys"
+            :check-strictly="true" />
+        </div>
+      </template>
+      <template #footer>
+        <div>
+          <el-button @click="cancel">取消</el-button>
+          <el-button type="primary" @click="save">保存</el-button>
+        </div>
+      </template>
+    </el-drawer>
+  </div>
+</template>
+
+<!-- 行为区域 -->
+<script lang="ts" setup>
+import { defineProps, defineEmits } from "vue";
+import { DrawerProps } from 'element-plus';
+import { Search } from '@element-plus/icons-vue'
+const props = defineProps<{
+  Drawer: boolean,
+  deptlist: string[]
+  checkedKeys: string[]
+  checkedIds: string[]
+}>();
+const emits = defineEmits(["cancel", 'save', 'DrawerOpen', 'query']);
+const defaultProps = {
+  children: 'children',
+  label: 'name',
+}
+const direction = ref<DrawerProps['direction']>('rtl')
+const deptName = ref('');
+
+
+const checkedALL = ref(false)
+const ids = ref()//id集合
+const DrawerOpen = () => {
+
+}
+watch(props, () => {
+  if (props.Drawer) {
+    ids.value = props.checkedIds;
+  }
+
+})
+const cancel = () => {
+  emits('cancel')
+}
+const save = () => {
+    emits('save', ids.value)
+}
+const query = () => {
+  emits('query', deptName.value)
+
+}
+const handleCheck = (
+  _checkedNodes: any[],
+  checkedInfo: {
+    checkedKeys: any[];
+    checkedNodes: any[];
+    halfCheckedKeys: any[];
+    halfCheckedNodes: any[];
+  }
+) => {
+  ids.value = checkedInfo.checkedKeys;
+};
+</script>

+ 485 - 0
src/views/externalAgreement/agreement/components/contactPersonFeeDialog.vue

@@ -0,0 +1,485 @@
+<!-- 模板区域 -->
+<template>
+  <div>
+    <el-drawer v-model="props.ruleFeeVisible" :direction="direction" :close-on-click-modal="false" size="50%"
+      @open="draweropen" @close="close">
+      <template #header>
+        <h4>{{ props.title }}费用</h4>
+      </template>
+      <template #default>
+        <ElRow :gutter="20" class="m-top-20">
+          <el-form :model="ruleFeeinfo" label-width="120px" ref="formRef" style="width: 100%;" :rules="feerules"
+            class="flex a-c f-wrap" :size="fromSize">
+            <ElCol :md="24" :lg="18">
+              <el-form-item label="协议" :prop="addMethod == 'list' ? 'ptlAgreementId' : ''">
+                <el-select v-if="addMethod == 'list'" v-model="ruleFeeinfo.ptlAgreementId" placeholder="选择协议"
+                  :disabled="props.title != '添加'">
+                  <el-option v-for="item in agreementselect" :key="item.id" :label="item.agreementTitle"
+                    :value="item.id" />
+                </el-select>
+                <el-select v-else v-model="agreementActiveId" placeholder="选择协议" :disabled="props.title != '添加'">
+                  <el-option v-for="item in agreementselect" :key="item.id" :label="item.agreementTitle"
+                    :value="item.id" />
+                </el-select>
+              </el-form-item>
+            </ElCol>
+            <ElCol :md="24" :lg="18">
+              <el-form-item label="快速配置"
+                v-if="agreementActiveId || ruleFeeinfo.ptlAgreementId || props.agreementInfo?.id">
+                <el-select v-model="contactPersonListid" placeholder="选择对接人" @visible-change="contactvisiblechange"
+                  :disabled="props.title != '添加'" @change="contactPersonChange">
+                  <el-option v-for="item in contactPersonList" :key="item.contactMobile" :label="item.contactPerson"
+                    :value="item.contactMobile" />
+                </el-select>
+                <span style="font-size: 12px;color: #aaa;">选择已存在的对接人,直接复制该对接人的费用信息;也可在下方输入框手动配置</span>
+              </el-form-item>
+            </ElCol>
+            <ElCol :md="24" :lg="12">
+              <el-form-item label="对接人姓名" prop="contactPerson">
+                <el-input v-model="ruleFeeinfo.contactPerson" placeholder="请输入对接人姓名" maxlength="50" show-word-limit />
+              </el-form-item>
+            </ElCol>
+            <ElCol :md="24" :lg="12">
+              <el-form-item label="对接人手机号" prop="contactMobile">
+                <el-input v-model="ruleFeeinfo.contactMobile" placeholder="请输入手机号" maxlength="11" show-word-limit />
+              </el-form-item>
+            </ElCol>
+          </el-form>
+        </ElRow>
+        <div style="padding-left: 40px;">
+          <el-tabs v-model="activeName" type="card" @tab-click="hledclick" style="position: relative;"
+            class="ruleFeetabs">
+            <el-tab-pane v-for="(item, index) in ruleFeeinfo.ptlAgreementCostExternalAddList" :key="index"
+              :label="item.productName" :name="item.productName">
+              <ElRow :gutter="20" class="m-top-20">
+                <el-form :model="item" label-width="80px" ref="feeFormRef" style="width: 100%;" :rules="feerules"
+                  class="flex a-c f-wrap" :size="fromSize">
+                  <ElCol :md="24" :lg="12">
+                    <el-form-item label="生效时间" prop="effectiveTime">
+                      <el-date-picker v-model="item.effectiveTime" style="width: 100%;" type="datetime"
+                        placeholder="选择生效时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
+                        time-format="HH:mm:ss" @change="handleStartDateChange($event, index)" />
+                    </el-form-item>
+                  </ElCol>
+                  <ElCol :md="24" :lg="12">
+                    <el-form-item label="失效时间" prop="failureTime">
+                      <el-date-picker v-model="item.failureTime" style="width: 100%;" type="datetime"
+                        placeholder="选择失效时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
+                        time-format="HH:mm:ss" :disabled-date="(date: any) => disabledEndDate(date, index)" />
+                    </el-form-item>
+                  </ElCol>
+                  <ElCol :md="24" :lg="12">
+                    <el-form-item label="审核方式" prop="auditMethod">
+                      <el-select v-model="item.auditMethod" placeholder="选择审核方式">
+                        <el-option label="自动审核" value="0" />
+                        <el-option label="手动审核" value="1" />
+                      </el-select>
+                    </el-form-item>
+                  </ElCol>
+                  <ElCol :md="24" :lg="12">
+                    <el-form-item label="是否现询" prop="isInquiry">
+                      <el-radio-group v-model="item.isInquiry">
+                        <el-radio value="0" size="large">是</el-radio>
+                        <el-radio value="1" size="large">否</el-radio>
+                      </el-radio-group>
+                    </el-form-item>
+                  </ElCol>
+                  <ElCol :md="24" :lg="24">
+                    <el-form-item label="费用描述" prop="costDescribe">
+                      <el-input v-model="item.costDescribe" maxlength="500" placeholder="请输入费用描述" show-word-limit
+                        type="textarea" />
+                    </el-form-item>
+                  </ElCol>
+                </el-form>
+              </ElRow>
+
+              <el-table :data="item.costExternalTypeAdds" style="width: 100%;" border
+                :header-cell-style="{ 'background-color': '#F7F7F9', 'border-bottom': '1px solid #EEF1F6', 'font-size': '15px', 'color': '#333', 'padding': '10px 0' }">
+                <template #empty>
+                  <div class="flex f-c a-c ">
+                    <img src="../../assets/images/empty.png" alt="">
+                    <span style="font-size: 14px;color: #909399;">暂无数据</span>
+                  </div>
+                </template>
+                <el-table-column prop="costType" label="类型"></el-table-column>
+                <el-table-column prop="inlet" label="入口比例" width="180" align="center">
+                  <template #default="scope">
+                    <el-input-number v-model="scope.row.inlet" :precision="2" controls-position="right"
+                      style="width: 100%;" :min="0" :max="100">
+                      <template #suffix>%</template>
+                    </el-input-number>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="export" label="出口比例" width="180" align="center">
+                  <template #default="scope">
+                    <el-input-number v-model="scope.row.export" :precision="2" controls-position="right"
+                      style="width: 100%;" :min="0" :max="100">
+                      <template #suffix>%</template>
+                    </el-input-number>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="totalCost" label="总费用比例" width="180" align="center">
+                  <template #default="scope">
+                    <el-input-number v-model="scope.row.totalCost" :precision="2" controls-position="right"
+                      style="width: 100%;" :min="0" :max="100">
+                      <template #suffix>%</template>
+                    </el-input-number>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="other" label="其他费用比例" width="180" align="center">
+                  <template #default="scope">
+                    <el-input-number v-model="scope.row.other" :precision="2" controls-position="right"
+                      style="width: 100%;" :min="0" :max="100">
+                      <template #suffix>%</template>
+                    </el-input-number>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="level1" label="1级比例" width="180" align="center">
+                  <template #default="scope">
+                    <el-input-number v-model="scope.row.level1" :precision="2" controls-position="right"
+                      style="width: 100%;" :min="0" :max="100">
+                      <template #suffix>%</template>
+                    </el-input-number>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="level5" label="5级比例" width="180" align="center">
+                  <template #default="scope">
+                    <el-input-number v-model="scope.row.level5" :precision="2" controls-position="right"
+                      style="width: 100%;" :min="0" :max="100">
+                      <template #suffix>%</template>
+                    </el-input-number>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </el-tab-pane>
+          </el-tabs>
+        </div>
+      </template>
+      <template #footer>
+        <div class="flex a-c j-c">
+          <el-button @click="cancel">取消</el-button>
+          <el-button type="primary" @click="save(feeFormRef)">提交审核</el-button>
+        </div>
+      </template>
+    </el-drawer>
+  </div>
+</template>
+
+<!-- 行为区域 -->
+<script lang='ts' setup>
+import { ref, } from 'vue'
+import { DrawerProps, ComponentSize, FormInstance, FormRules, ElMessage } from 'element-plus';
+import { loadDicts, getDict } from '@/utils/composables/dictService';//字典组件
+import { defineProps, defineEmits } from "vue";
+import api from '@/api';
+const direction = ref<DrawerProps['direction']>('rtl')
+const fromSize = ref<ComponentSize>('default')
+const activeName = ref('单交')
+const props = defineProps<{
+  ruleFeeVisible: boolean,
+  agreementInfo?: any,
+  addMethod: string,
+  contactPersonEditInfo?: any,
+  title?: string,
+}>();
+interface ruleFeeinfo {
+  ptlAgreementId: string,
+  contactPerson: string,
+  contactMobile: string,
+  ptlAgreementCostExternalAddList: any[],
+}
+
+const emits = defineEmits(["cancel", 'save']);
+const ruleFeeinfo = reactive<ruleFeeinfo>({
+  ptlAgreementId: "",//协议id
+  contactPerson: "",//对接人
+  contactMobile: "",//手机号
+  ptlAgreementCostExternalAddList: [],//费用集合
+});//规则费用集合
+const insuranceTypeIndex = ref(0);//险种区域下标
+const agreementActiveId = ref();//选中协议id
+const agreementselect = ref();
+const feeFormRef = ref<FormInstance>()
+const formRef = ref<FormInstance>();
+const feerules = ref<FormRules>({
+  ptlAgreementId: [
+    { required: true, trigger: 'change', message: '请选择' },
+  ],
+  contactPerson: [
+    { required: true, trigger: 'blur', message: '请输入对接人姓名' },
+  ],
+  contactMobile: [
+    { required: true, trigger: 'blur', message: '请输入手机号' },
+  ],
+  effectiveTime: [
+    { required: true, trigger: 'change', message: '请选择生效时间' },
+  ],
+  failureTime: [
+    { required: true, trigger: 'change', message: '请选择失效时间' },
+  ],
+  auditMethod: [
+    { required: true, trigger: 'change', message: '请选择审核方式' },
+  ],
+  isInquiry: [
+    { required: true, trigger: 'change', message: '请选择是否线询' },
+  ],
+})
+watch(props, () => {
+  if (props.contactPersonEditInfo && props.contactPersonEditInfo.contactPerson) {
+    Object.assign(ruleFeeinfo, props.contactPersonEditInfo);
+    activeName.value = ruleFeeinfo.ptlAgreementCostExternalAddList[0].productName;
+  }
+})
+onMounted(async () => {
+  await loadDicts(['insurance_type'])
+  const dict = getDict('insurance_type');
+  agreementList();
+  ruleFeeinfo.ptlAgreementCostExternalAddList = dict.map((val: any) => {
+    const filteredList: any = filterCostTypeList(val.label);//根据险种匹配列表
+    let list = JSON.parse(JSON.stringify(filteredList)); // 深拷贝
+    return {
+      productName: val.label,
+      productId: val.value,
+      effectiveTime: "",//生效时间
+      failureTime: "",//失效时间
+      auditMethod: "0",//审核方式
+      isInquiry: "0",//是否线询
+      costDescribe: "",//费用描述
+      costExternalTypeAdds: list,
+    }
+  })
+})
+// 协议列表
+const agreementList = () => {
+  api.agreementApi.agreementList({ pages: 1, size: 100, isExternal: '1' }).then((res: any) => {
+    if (res.code == '200') {
+      agreementselect.value = res.data.records;
+    } else {
+    }
+  });
+}
+//对接人列表
+const contactPersonList = ref();
+const contactPersonListid = ref();
+//对接人下拉列表
+const costExternalList = () => {
+  api.agreementApi.costExternalList({ ptlAgreementId: agreementActiveId.value ? agreementActiveId.value : props.agreementInfo?.id }).then((res: any) => {
+    if (res.code == '200') {
+      contactPersonList.value = res.data;
+    } else {
+    }
+  });
+}
+//选择对接人
+const contactPersonChange = (value: string) => {
+  let info = contactPersonList.value.find((val: any) => val.contactMobile == value);
+  ruleFeeinfo.ptlAgreementCostExternalAddList = info.costExternalListVo;
+  activeName.value = ruleFeeinfo.ptlAgreementCostExternalAddList[0].productName;
+
+}
+//下拉框出现事件
+const contactvisiblechange = (visible: boolean) => {
+  if (visible) {
+    costExternalList();
+  }
+}
+// 禁用失效时间选择
+const disabledEndDate = (date: any, index: number) => {
+  let start = ruleFeeinfo.ptlAgreementCostExternalAddList[index]?.effectiveTime;
+  const startDate = new Date(start);
+  return startDate && date < startDate; // 禁用小于生效时间的日期
+};
+
+// 处理生效时间变化
+/**
+ * @param index  险种下标
+ * @param Costindex 费用下标
+ */
+const handleStartDateChange = (value: any, index: number,) => {
+  let endDate = ruleFeeinfo.ptlAgreementCostExternalAddList[index]?.failureTime;
+  // 如果生效时间改变,检查失效时间是否需要更新
+  if (endDate && new Date(endDate) < new Date(value)) {
+    ruleFeeinfo.ptlAgreementCostExternalAddList[index].failureTime = ''; // 清空失效时间
+  }
+};
+const cancel = () => {
+  emits("cancel")
+}
+const close=()=>{
+  emits("cancel")
+}
+const validateContactPerson = () => {
+  if (formRef.value) {
+    formRef.value.validateField(['contactPerson', 'contactMobile', 'ptlAgreementId'], (valid) => {
+      if (valid) {
+        console.log('对接人验证通过');
+      } else {
+        ElMessage({
+          type: 'error',
+          message: '对接人信息必填',
+          plain: true,
+        });
+      }
+    });
+  }
+};
+const save = async (formEl: FormInstance | undefined | any) => {
+  validateContactPerson();
+  if (!formEl) return
+  const validationPromises = ruleFeeinfo.ptlAgreementCostExternalAddList.map((formRef: any, index: any) => {
+    // 轮询验证所有表单校验
+    return new Promise((resolve, reject) => {
+      if (formRef) {
+        formEl[index].validate((valid: boolean) => {
+          if (valid) {
+
+            resolve(true);
+          } else {
+            reject(index);
+          }
+        });
+      } else {
+        reject(index);
+      }
+    });
+  });
+
+  try {
+    await Promise.all(validationPromises);
+    // 所有表单验证通过后执行提交逻辑
+    if (props.addMethod == 'details') {
+      ruleFeeinfo.ptlAgreementId = agreementActiveId.value ? agreementActiveId.value : props.agreementInfo.id;
+    }
+    emits("save", ruleFeeinfo)
+  } catch (error) {
+    const invalidIndex: any = error; // 获取未通过校验的表单索引
+    const invalidForm = ruleFeeinfo.ptlAgreementCostExternalAddList[invalidIndex]; // 获取未通过校验的表单对象
+    activeName.value = invalidForm.productName;
+    ElMessage({
+      type: 'error',
+      message: `${ruleFeeinfo.ptlAgreementCostExternalAddList[invalidIndex].productName}费用未填写完整`,
+      plain: true,
+    });
+  }
+};
+// 过滤方法
+const ptlAgreementCostTypeList = [
+  {
+    costType: "交强险",
+    inlet: 0,
+    export: 0,
+    totalCost: 0,
+    other: 0,
+    level1: 0,
+    level5: 0,
+  },
+  {
+    costType: "商业险",
+    inlet: 0,
+    export: 0,
+    totalCost: 0,
+    other: 0,
+    level1: 0,
+    level5: 0,
+  },
+  {
+    costType: "驾意险",
+    inlet: 0,
+    export: 0,
+    totalCost: 0,
+    other: 0,
+    level1: 0,
+    level5: 0,
+  }
+];
+
+const filterCostTypeList = (name: string) => {
+  return ptlAgreementCostTypeList.filter(item => {
+    if (name === "单交" && item.costType === "商业险") {
+      return false; // 当 name 为 "单交" 且 costType 为 "商业险" 时,返回 false,不包含该项
+    }
+    if (name === "单三" && item.costType === "商业险") {
+      return false; // 当 name 为 "单交" 且 costType 为 "商业险" 时,返回 false,不包含该项
+    }
+    if (name === "单商" && item.costType === "交强险") {
+      return false; // 当 name 为 "商业" 且 costType 为 "交强险" 时,返回 false,不包含该项
+    }
+    return true; // 其他情况返回 true,保留该项
+  });
+};
+const hledclick = (pane: any) => {
+  insuranceTypeIndex.value = pane.index;
+  activeName.value = pane.props.name;
+}
+const draweropen = () => {
+  if(formRef.value){
+    formRef.value.resetFields();
+  }
+  contactPersonListid.value='';
+  ruleFeeinfo.ptlAgreementId = "";
+  ruleFeeinfo.contactPerson = "";
+  ruleFeeinfo.contactMobile = "";
+  ruleFeeinfo.ptlAgreementCostExternalAddList.map((val: any) => {
+    val.effectiveTime = "";
+    val.failureTime = "";
+    val.costDescribe = "";
+    val.costExternalTypeAdds.map((item: any) => {
+      for (let key in item) {
+        if(item[key]!='costType'){
+          item[key] = 0;
+        }
+      }
+      return item
+    })
+    return val;
+  })
+}
+</script>
+<!-- 样式区域 -->
+<style lang='scss' scoped>
+:deep(.el-drawer__header) {
+  padding-top: 0;
+  margin-bottom: 0;
+  border-bottom: 1px solid #f2f2f2;
+}
+
+.agreement {
+  width: 100%;
+  padding: 15px;
+  font-size: 14px;
+  color: #333;
+  border-radius: 4px;
+
+  p {
+    margin: 0;
+    margin-top: 10px;
+  }
+}
+
+.feeItem {
+  width: 100%;
+  border: 1px solid #e5e5e5;
+  border-radius: 8px;
+
+  .header {
+    padding: 12px 14px;
+
+    .title {
+      display: flex;
+
+      &::before {
+        display: inline-block;
+        width: 4px;
+        height: 18px;
+        margin-right: 20px;
+        content: "";
+        background-color: #0083ff;
+      }
+    }
+  }
+}
+
+:deep(.ruleFeetabs>.el-tabs__content) {
+  position: static;
+}
+</style>

+ 317 - 0
src/views/externalAgreement/agreement/components/contactPersonFeeDialogEdit.vue

@@ -0,0 +1,317 @@
+<!-- 模板区域 -->
+<template>
+  <div>
+    <el-drawer v-model="props.ruleFeeVisible" :direction="direction" :close-on-click-modal="false" size="50%"
+      @close="close">
+      <template #header>
+        <h4>{{ props.headerTitle }}费用编辑</h4>
+      </template>
+      <template #default>
+        <div class="rejectionReason flex a-start" v-if="costitemEditInfo.reviewDescription">
+          <el-icon color="red" class="m-right-20"><CircleClose /></el-icon>
+          <div class="flex f-c">
+            <span class="strong" style="color: #333;">审核不通过</span>
+            <span >审核原因:{{costitemEditInfo. reviewDescription }}</span>
+            <div class="flex a-c ">
+              <span class="m-right-20">审核人:{{ costitemEditInfo.auditPerson }}</span>
+              <span >审核时间:{{costitemEditInfo.auditTime }}</span>
+            </div>
+          </div>
+        </div>
+        <ElRow :gutter="20" class="m-top-20">
+          <el-form :model="contactPersonEditInfo" label-width="120px" ref="contactPersonFormRef" :disabled="disabledShow" style="width: 100%;"
+            :rules="feerules" class="flex a-c f-wrap" :size="fromSize">
+            <ElCol :md="24" :lg="12">
+              <el-form-item label="对接人姓名" prop="contactPerson">
+                <el-input v-model="contactPersonEditInfo.contactPerson"  placeholder="请输入对接人姓名" />
+              </el-form-item>
+            </ElCol>
+            <ElCol :md="24" :lg="12">
+              <el-form-item label="对接人手机号" prop="contactMobile">
+                <el-input v-model="contactPersonEditInfo.contactMobile" placeholder="请输入手机号" />
+              </el-form-item>
+            </ElCol>
+            <ElCol :md="24" :lg="12">
+              <el-form-item label="生效时间" prop="effectiveTime">
+                <el-date-picker v-model="contactPersonEditInfo.effectiveTime" style="width: 100%;" type="datetime"
+                  placeholder="选择生效时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
+                  time-format="HH:mm:ss" @change="handleStartDateChange($event)" />
+              </el-form-item>
+            </ElCol>
+            <ElCol :md="24" :lg="12">
+              <el-form-item label="失效时间" prop="failureTime">
+                <el-date-picker v-model="contactPersonEditInfo.failureTime" style="width: 100%;" type="datetime"
+                  placeholder="选择失效时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
+                  time-format="HH:mm:ss" :disabled-date="(date: any) => disabledEndDate(date)" />
+              </el-form-item>
+            </ElCol>
+            <ElCol :md="24" :lg="12">
+              <el-form-item label="审核方式" prop="auditMethod">
+                <el-select v-model="contactPersonEditInfo.auditMethod" placeholder="选择审核方式">
+                  <el-option label="自动审核" value="0" />
+                  <el-option label="手动审核" value="1" />
+                </el-select>
+              </el-form-item>
+            </ElCol>
+            <ElCol :md="24" :lg="12">
+              <el-form-item label="是否现询" prop="isInquiry">
+                <el-radio-group v-model="contactPersonEditInfo.isInquiry">
+                  <el-radio value="0" size="large">是</el-radio>
+                  <el-radio value="1" size="large">否</el-radio>
+                </el-radio-group>
+              </el-form-item>
+            </ElCol>
+            <ElCol :md="24" :lg="24">
+              <el-form-item label="费用描述" prop="costDescribe">
+                <el-input v-model="contactPersonEditInfo.costDescribe" maxlength="500" placeholder="请输入费用描述"
+                  show-word-limit type="textarea" />
+              </el-form-item>
+            </ElCol>
+          </el-form>
+        </ElRow>
+
+        <el-table :data="contactPersonEditInfo.costExternalTypeAdds" style="width: 100%;" border
+          :header-cell-style="{ 'background-color': '#F7F7F9', 'border-bottom': '1px solid #EEF1F6', 'font-size': '15px', 'color': '#333', 'padding': '10px 0' }">
+          <template #empty>
+            <div class="flex f-c a-c ">
+              <img src="../../assets/images/empty.png" alt="">
+              <span style="font-size: 14px;color: #909399;">暂无数据</span>
+            </div>
+          </template>
+          <el-table-column prop="costType" label="类型"></el-table-column>
+          <el-table-column prop="inlet" label="入口比例" width="180" align="center">
+            <template #default="scope">
+              <el-input-number v-model="scope.row.inlet" :disabled="disabledShow" :precision="2" controls-position="right" style="width: 100%;"
+                :min="0" :max="100">
+                <template #suffix>%</template>
+              </el-input-number>
+            </template>
+          </el-table-column>
+          <el-table-column prop="export" label="出口比例" width="180" align="center">
+            <template #default="scope">
+              <el-input-number v-model="scope.row.export" :disabled="disabledShow" :precision="2" controls-position="right" style="width: 100%;"
+                :min="0" :max="100">
+                <template #suffix>%</template>
+              </el-input-number>
+            </template>
+          </el-table-column>
+          <el-table-column prop="totalCost" label="总费用比例" width="180" align="center">
+            <template #default="scope">
+              <el-input-number v-model="scope.row.totalCost" :disabled="disabledShow" :precision="2" controls-position="right"
+                style="width: 100%;" :min="0" :max="100">
+                <template #suffix>%</template>
+              </el-input-number>
+            </template>
+          </el-table-column>
+          <el-table-column prop="other" label="其他费用比例" width="180" align="center">
+            <template #default="scope">
+              <el-input-number v-model="scope.row.other" :disabled="disabledShow" :precision="2" controls-position="right" style="width: 100%;"
+                :min="0" :max="100">
+                <template #suffix>%</template>
+              </el-input-number>
+            </template>
+          </el-table-column>
+          <el-table-column prop="level1" label="1级比例" width="180" align="center">
+            <template #default="scope">
+              <el-input-number v-model="scope.row.level1" :disabled="disabledShow" :precision="2" controls-position="right" style="width: 100%;"
+                :min="0" :max="100">
+                <template #suffix>%</template>
+              </el-input-number>
+            </template>
+          </el-table-column>
+          <el-table-column prop="level5" label="5级比例" width="180" align="center">
+            <template #default="scope">
+              <el-input-number v-model="scope.row.level5" :disabled="disabledShow" :precision="2" controls-position="right" style="width: 100%;"
+                :min="0" :max="100">
+                <template #suffix>%</template>
+              </el-input-number>
+            </template>
+          </el-table-column>
+        </el-table>
+      </template>
+      <template #footer>
+        <div class="flex a-c j-c" v-if="!disabledShow">
+          <el-button @click="cancel">取消</el-button>
+          <el-button type="primary" @click="save(contactPersonFormRef)">提交审核</el-button>
+        </div>
+        <div class="flex f-c " v-if="!costitemEditInfo?.reviewDescription">
+          <el-checkbox v-model="automatic" label="审核后,自动跳支审核下一条费用" size="large" />
+          <div class="flex a-c">
+            <el-button @click="rejectOperation">审核驳回</el-button>
+            <el-button type="primary" @click="auditOperation">审核通过</el-button>
+          </div>
+        </div>
+      </template>
+    </el-drawer>
+  </div>
+</template>
+
+<!-- 行为区域 -->
+<script lang='ts' setup>
+import { ref, } from 'vue'
+import { DrawerProps, ComponentSize, FormInstance, FormRules, ElMessage,ElMessageBox } from 'element-plus';
+import { defineProps, defineEmits } from "vue";
+const direction = ref<DrawerProps['direction']>('rtl')
+const fromSize = ref<ComponentSize>('default')
+const props = defineProps<{
+  ruleFeeVisible: boolean,
+  headerTitle?: string,
+  costitemEditInfo?: any,
+  operationType?: string,//操作类型
+
+}>();
+const emits = defineEmits(["cancel", 'save', 'auditOperation', 'rejectOperation']);
+watch(props, () => {
+  contactPersonEditInfo.value = props.costitemEditInfo;
+  //审核和驳回操作不可编辑
+  if (props.operationType == 'audit' || props.operationType == 'rejected') {
+    disabledShow.value = true;
+  } else {
+    disabledShow.value = false;
+
+  }
+})
+const disabledShow = ref(false);
+const automatic = ref(false);//是否连续审核
+const contactPersonEditInfo = ref();//规则费用集合
+const contactPersonFormRef = ref<FormInstance>()
+const feerules = ref<FormRules>({
+  contactPerson: [
+    { required: true, trigger: 'blur', message: '请输入对接人姓名' },
+  ],
+  contactMobile: [
+    { required: true, trigger: 'blur', message: '请输入手机号' },
+  ],
+  effectiveTime: [
+    { required: true, trigger: 'change', message: '请选择生效时间' },
+  ],
+  failureTime: [
+    { required: true, trigger: 'change', message: '请选择失效时间' },
+  ],
+  auditMethod: [
+    { required: true, trigger: 'change', message: '请选择审核方式' },
+  ],
+  isInquiry: [
+    { required: true, trigger: 'change', message: '请选择是否线询' },
+  ],
+})
+// 禁用失效时间选择
+const disabledEndDate = (date: any) => {
+  let start = contactPersonEditInfo.value.effectiveTime;
+  const startDate = new Date(start);
+  return startDate && date < startDate; // 禁用小于生效时间的日期
+};
+
+// 处理生效时间变化
+/**
+ * @param index  险种下标
+ * @param Costindex 费用下标
+ */
+const handleStartDateChange = (value: any) => {
+  let endDate = contactPersonEditInfo.value.failureTime;
+  // 如果生效时间改变,检查失效时间是否需要更新
+  if (endDate && new Date(endDate) < new Date(value)) {
+    contactPersonEditInfo.value.failureTime = ''; // 清空失效时间
+  }
+};
+const cancel = () => {
+  emits("cancel")
+}
+const close = () => {
+  emits("cancel")
+}
+const save = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  await formEl.validate((valid) => {
+    if (valid) {
+      emits('save', contactPersonEditInfo.value)
+    } else {
+      ElMessage({
+        type: 'error',
+        message: '信息不完整',
+        plain: true,
+      })
+    }
+  })
+}
+//审核驳回操作
+const rejectOperation = () => {
+  //驳回弹窗
+  ElMessageBox.prompt('', '审核不通过', {
+    confirmButtonText: '确定',
+    type: 'warning',
+    center: true,
+    inputType: "textarea",
+    inputPlaceholder: "请输入不通过原因",
+    inputPattern: /^[\u4e00-\u9fa5,。!?、;:“”‘’《》【】()——]+$/,
+    inputErrorMessage: '请输入中文',
+  })
+    .then(({ value }) => {
+      emits("rejectOperation",automatic.value,contactPersonEditInfo.value.id,value)
+    })
+}
+//审核通过操作
+const auditOperation = () => {
+  emits("auditOperation", automatic.value,contactPersonEditInfo.value.id)
+}
+</script>
+<!-- 样式区域 -->
+<style lang='scss' scoped>
+:deep(.el-drawer__header) {
+  padding-top: 0;
+  margin-bottom: 0;
+  border-bottom: 1px solid #f2f2f2;
+}
+
+.agreement {
+  width: 100%;
+  padding: 15px;
+  font-size: 14px;
+  color: #333;
+  border-radius: 4px;
+
+  p {
+    margin: 0;
+    margin-top: 10px;
+  }
+}
+
+.feeItem {
+  width: 100%;
+  border: 1px solid #e5e5e5;
+  border-radius: 8px;
+
+  .header {
+    padding: 12px 14px;
+
+    .title {
+      display: flex;
+
+      &::before {
+        display: inline-block;
+        width: 4px;
+        height: 18px;
+        margin-right: 20px;
+        content: "";
+        background-color: #0083ff;
+      }
+    }
+  }
+}
+
+.rejectionReason {
+  padding: 15px;
+  background: #fff1f0;
+  border: 1px solid #ffa39e;
+  border-radius: 5px;
+
+  span {
+    margin-bottom: 10px;
+    color: #666;
+  }
+}
+
+:deep(.ruleFeetabs>.el-tabs__content) {
+  position: static;
+}
+</style>

+ 110 - 0
src/views/externalAgreement/agreement/components/managerModal.vue

@@ -0,0 +1,110 @@
+<!-- 模板区域 -->
+<template>
+  <div>
+    <el-dialog v-model="props.managerModal" title="选择管理人" width="40%"  @close="cancel">
+      <div class="flex a-c">
+        <el-input v-model="searchValue" style="width: 240px;margin-right: 10px;" clearable placeholder="输入姓名,手机号,工号查找" />
+        <el-button type="primary" @click='searchValueclick'>查询</el-button>
+      </div>
+      <div class="deptlist flex ">
+        <div class="area" style="border-right: 1px solid #dcdfe6;" v-show="!searchValueShow">
+          <el-tree style="max-width: 600px;" :data="props.deptOptions" :props="parentIdprops" :highlight-current="true"
+            @node-click="handleNodeClick" />
+        </div>
+        <div class="area">
+          <el-radio-group v-model="userId">
+            <div class="flex f-c">
+              <el-radio :value="item.id" v-for="(item,index) in managerlist" @change="radioChange" :key="index" class="m-btn-20">
+                <div>{{ item.name }}</div>
+                <div>{{ item.id }}</div>
+              </el-radio>
+            </div>
+          </el-radio-group>
+        </div>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="cancel">取消</el-button>
+          <el-button type="primary" @click="save">
+            确定
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<!-- 行为区域 -->
+<script lang='ts' setup>
+import api from '@/api';
+import { ref, reactive } from 'vue'
+import { defineProps, defineEmits } from "vue";
+
+interface Tree {
+  id: string
+  children?: Tree[]
+}
+interface managerlist{
+  id:string,
+  name:string,
+  deptName:string,
+}
+const props = defineProps<{
+  managerModal: boolean,
+  deptOptions: string[]
+  managerlist: managerlist[],
+}>();
+const parentIdprops = {
+  expandTrigger: 'hover' as const,
+  value: 'id',
+  label: 'name',
+  checkStrictly: true,
+}
+const emits = defineEmits(["cancel", 'save', 'DrawerOpen', 'query', 'NodeClick','radioChange']);
+const userId = ref()
+const username = ref()
+const deptName=ref();
+const searchValue=ref();
+const searchValueShow=ref(false);
+watch(searchValue,()=>{
+  if(!searchValue.value){
+  searchValueShow.value=false;
+  }
+})
+const handleNodeClick = (data: Tree) => {
+  emits('NodeClick', data.id)
+}
+const cancel = () => {
+  emits('cancel')
+}
+const save = () => {
+  emits('save',userId.value,username.value,deptName.value)
+}
+
+const searchValueclick=()=>{
+  searchValueShow.value=true;
+  emits('query',searchValue.value)
+}
+const radioChange=(value:any)=>{
+  let name=props.managerlist.find(val=>val.id==value)?.name;
+  let deptname=props.managerlist.find(val=>val.id==value)?.deptName;
+  username.value=name;
+  deptName.value=deptname;
+}
+</script>
+<!-- 样式区域 -->
+<style lang='scss' scoped>
+.deptlist {
+  height: 400px;
+  margin-top: 20px;
+  border: 1px solid #dcdfe6;
+  border-radius: 5px;
+
+  .area {
+    flex: 1;
+    height: 100%;
+    padding: 10px;
+    overflow: auto;
+  }
+}
+</style>

+ 522 - 0
src/views/externalAgreement/costManagement.vue

@@ -0,0 +1,522 @@
+<template>
+  <div>
+    <PageMain class="vh100">
+      <SearchForm :fields="fields" :formInline="formInline" :onSearch="agreementQuery" :onReset="resetForm" />
+      <ComplexTable :tableData="tableData" :columns="columns" :showIndex="false" :columnwidth="200" :showSelect="true"
+        :pageInfo="pageInfo" @getList="getList" @selectionChange="selectionChange">
+        <template v-slot:table-title-btn>
+          <el-button type="primary" @click="agreementSelection">
+            添加费用
+            <template #icon>
+              <el-icon>
+                <Plus />
+              </el-icon>
+            </template>
+          </el-button>
+          <el-dropdown placement="bottom-start">
+            <el-button> 批量管理<el-icon>
+                <arrow-down />
+              </el-icon>
+            </el-button>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item :disabled="!sysUpAndDownList.length" @click="batchDel">删除</el-dropdown-item>
+                <el-dropdown-item :disabled="!sysUpAndDownList.length" @click="batchdisable">禁用</el-dropdown-item>
+                <el-dropdown-item :disabled="!sysUpAndDownList.length" @click="batchenable">启用</el-dropdown-item>
+                <el-dropdown-item :disabled="!sysUpAndDownList.length" @click="batchUpdate">批量编辑</el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+        </template>
+        <template v-slot:operation="scope">
+          <el-button type="primary" link @click="agreemenUpdate(scope.operationData.id)"> 编辑
+          </el-button>
+          <el-dropdown placement="bottom-start" trigger="click">
+            <span class="el-dropdown-link">
+              更 多
+            </span>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item @click="enable(scope.operationData.id)">启用</el-dropdown-item>
+                <el-dropdown-item @click="disable(scope.operationData.id)">禁用</el-dropdown-item>
+                <el-dropdown-item @click="del(scope.operationData.id)">删除</el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+        </template>
+      </ComplexTable>
+    </PageMain>
+    <el-dialog v-model="auditMethodVisible" title="选择协议" width="30%">
+
+      <ElRow :gutter="20" class="m-top-20">
+        <el-form :model="Editinfo" ref="FormRef" style="width: 100%;" :rules="rules" class="flex a-c f-wrap"
+          :size="fromSize">
+          <ElCol :md="24" :lg="24">
+            <el-form-item label="审核方式" prop="auditMethod">
+              <el-select v-model="Editinfo.auditMethod" placeholder="选择审核方式">
+                <el-option label="自动审核" value="0" />
+                <el-option label="手动审核" value="1" />
+              </el-select>
+            </el-form-item>
+          </ElCol>
+        </el-form>
+      </ElRow>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="auditMethodVisible = false">取消</el-button>
+          <el-button type="primary" @click="agreementSelectionConfirm(FormRef)">
+            确定
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <!-- 费用添加组件 -->
+    <contactPersonFeeDialog v-show="addcontactPersonShow" :ruleFeeVisible="addcontactPersonShow"
+      :title='contactPersontitle'   @save="contactPersonSave"
+       addMethod="list" @cancel="addcontactPersonShow = false"  />
+      <!-- 费用编辑组件 -->
+      <contactPersonFeeDialogEdit :ruleFeeVisible="ruleFeeEditVisible" :headerTitle="ruleFeeHeaderTitle"
+       :costitemEditInfo="costitemEditInfo" @save="ruleFeeEditSave"
+      @cancel="ruleFeeEditVisible = false" />
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive } from 'vue'
+import { useRoute, useRouter } from 'vue-router';
+import { ElMessage, ElMessageBox, FormRules, FormInstance, ComponentSize } from 'element-plus'
+import { loadDicts, getDict } from '@/utils/composables/dictService';//字典组件
+import contactPersonFeeDialogEdit from "./agreement/components/contactPersonFeeDialogEdit.vue";
+import contactPersonFeeDialog from "./agreement/components/contactPersonFeeDialog.vue";
+
+const FormRef = ref<FormInstance>()
+const fromSize = ref<ComponentSize>('large')//表单大小
+import api from '@/api';
+interface PageInfo {
+  pageNum: number;
+  pageSize: number;
+  sizes: number[];
+  total: number;
+}
+onBeforeMount(async () => {
+  await loadDicts(['valid_status', 'is_enable', 'audit_status', 'insurance_type']);//获取多个字典
+  if (id.value) {
+    formInline.agreement = id.value;
+  }
+  findpage();//列表数据
+  valid_status.value = getDict('valid_status');//生效状态
+  is_enable.value = getDict('is_enable');//协议状态
+  insurance_type.value = getDict('insurance_type')
+  audit_status.value = getDict('audit_status')
+
+});
+const tableData = ref([]);
+const sysUpAndDownList = ref<string[]>([])//选中id
+const insurance_type = ref();
+const valid_status = ref();
+const audit_status = ref();
+const is_enable = ref();
+const route = useRoute();
+const router = useRouter();
+const id = ref(route.query.id as string);//id参数
+const pageInfo = ref({
+  pageNum: 1,
+  pageSize: 20,
+  sizes: [10, 20, 30, 40, 50],
+  total: 100,
+});
+const formInline = reactive({
+  agreement: '',//协议信息
+  productId: "",//归属
+  rulesName: '',//保险公司id
+  costRules: '',//协议类型
+  agreementStatus: "",//有效状态
+  auditStatus: "",//协议状态
+  validState: "",
+  effectiveTime: [],
+  failureTime: [],
+})
+const rules = ref<FormRules>({
+  auditMethod: [
+    { required: true, trigger: 'blur', message: '请选择审核方式' },
+  ],
+
+})
+//表格字段数据
+const fields = ref([
+  { label: "所属协议", model: "agreement", type: "input", placeholder: "输入代码,名称,简称查找" },
+  {
+    label: "险种", model: "productId", type: "select", options: insurance_type,
+  },
+  {
+    label: "承保规则", model: "rulesName", type: "input", placeholder: "输入业务规则查找",
+  },
+  {
+    label: "费用规则", model: "costRules", type: "input", placeholder: "输入费用规则关键字查找",
+  },
+
+  {
+    label: "费用状态", model: "agreementStatus", type: "select", placeholder: "选择状态", options: is_enable,
+  },
+  {
+    label: "审核状态", model: "auditStatus", type: "select", placeholder: "选择状态", options: audit_status,
+  },
+  {
+    label: "有效状态", model: "validState", type: "select", placeholder: "请选择状态", options: valid_status,
+  },
+  {
+    label: "生效时间", model: "effectiveTime", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
+    onChange: (value: any) => {
+      console.log(value)
+      formInline.effectiveTime = value;
+    }
+  },
+  {
+    label: "失效时间", model: "failureTime", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
+    onChange: (value: any) => {
+      formInline.failureTime = value;
+    }
+  },
+]);
+
+//费用数据查询
+function findpage() {
+  api.agreementApi.CostExternalFeePageList({ pages: pageInfo.value.pageNum, size: pageInfo.value.pageSize, ...formInline }).then((res: any) => {
+    if (res.code == '200') {
+      tableData.value = res.data.records;
+      pageInfo.value.pageNum = res.data.current;
+      pageInfo.value.pageSize = res.data.size;
+      pageInfo.value.total = res.data.total;
+    } else {
+    }
+  });
+}
+
+const columns = [
+  {
+    prop: "agreementAbbreviation", label: "协议信息", width: '300',
+    formatter: (row: any) => {
+      return `${row.agreementCode}\n${row.agreementAbbreviation}`
+    }
+  },
+  { prop: "productName", label: "险种", width: '120', },
+  {
+    prop: "contactPerson", label: "对接人", width: '200', formatter: (row: any) => {
+      return `${row.contactPerson} ${row.contactMobile}`
+    }
+  },
+  {
+    prop: "isInquiry", label: "是否现询", width: '120', formatter: (row: any) => {
+      if (row.isInquiry == '0') {
+        return '是'
+      } else {
+        return "否"
+      }
+    }
+  },
+  {
+    prop: "auditMethod", label: "审核方式", width: '120', formatter: (row: any) => {
+      if (row.auditMethod == '0') {
+        return '自动审核'
+      } else {
+        return "手动审核"
+      }
+    }
+  },
+  {
+    prop: "isEnabled", label: "费用状态", width: '100', component: "Tag",
+    formatter: (row: any) => {
+      let name = getDict('is_enable').find(val => val.value == row.isEnabled).label
+      if (name) {
+        return { type: 'primary', text: name };
+      }
+    }
+  },
+  {
+    prop: "auditStatus", label: "审核状态", width: '120', component: "Tag",
+    formatter: (row: any) => {
+      let name = getDict('audit_status').find(val => val.value == row.auditStatus).label
+      if (name) {
+        return { type: 'warning', text: name };
+      }
+    }
+  },
+  { prop: "effectiveTime", label: "生效时间", width: '200' },
+  { prop: "failureTime", label: "失效时间", width: '200' },
+  {
+    prop: "costExternalTypeAdds", label: "交强险费用", width: '300', formatter: (row: any) => {
+      let info = row.costExternalTypeAdds.find((val: any) => val.costType == '交强险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n一级:${info.level1?.toFixed(2)}% 五级:${info.level5?.toFixed(2)}%`
+      } else {
+        return '-'
+      }
+    }
+  },
+  {
+    prop: "costExternalTypeAdds", label: "商业险费用", width: '300', formatter: (row: any) => {
+      let info = row.costExternalTypeAdds.find((val: any) => val.costType == '商业险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n一级:${info.level1?.toFixed(2)}% 五级:${info.level5?.toFixed(2)}%`
+      } else {
+        return '-'
+      }
+    }
+  },
+  {
+    prop: "costExternalTypeAdds", label: "驾意险费用", width: '300', formatter: (row: any) => {
+      let info = row.costExternalTypeAdds.find((val: any) => val.costType == '驾意险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n一级:${info.level1?.toFixed(2)}% 五级:${info.level5?.toFixed(2)}%`
+      } else {
+        return '-'
+      }
+    }
+  },
+];
+//分页事件
+function getList(item: PageInfo) {
+  pageInfo.value.pageNum = item.pageNum;
+  pageInfo.value.pageSize = item.pageSize;
+  findpage();
+
+};
+// 费用添加
+
+const addcontactPersonShow = ref(false);//添加对接人
+const contactPersontitle = ref();//弹窗title
+const agreementSelection = () => {//添加对接人
+  addcontactPersonShow.value = true;
+  contactPersontitle.value = '添加';
+}
+
+//费用提交
+const contactPersonSave = (data: object) => {
+  console.log(data);
+    api.agreementApi.ptlAgreementCostExternalsave(data).then((res: any) => {
+      if (res.code == '200') {
+        addcontactPersonShow.value = false;
+        findpage();
+      } else {
+      }
+    });
+}
+// 费用编辑
+const ruleFeeEditVisible=ref(false);
+const ruleFeeHeaderTitle = ref();//编辑弹窗title
+const costitemEditInfo = ref();
+const agreemenUpdate = async (id: any) => {
+  api.agreementApi.FeegetById(id).then((res: any) => {
+    if (res.code == '200') {
+      ruleFeeHeaderTitle.value = res.data.productName;
+      costitemEditInfo.value = res.data;
+      ruleFeeEditVisible.value = true;
+    } else {
+    }
+  });
+}
+//费用编辑
+const ruleFeeEditSave = (data: object) => {
+  api.agreementApi.FeeupdateById(data).then((res: any) => {
+    if (res.code == '200') {
+      ElMessage({
+        type: 'success',
+        message: res.msg,
+        plain: true,
+      })
+      ruleFeeEditVisible.value=false;
+      findpage();
+    } else {
+    }
+  });
+}
+//多选事件
+const selectionChange = (val: any) => {
+  sysUpAndDownList.value = val;
+}
+//禁用
+const disable = (value: string) => {
+  ElMessageBox.confirm(
+    '确定要禁用该协议吗,禁用后,该协议不在支持报价出单,并且已核保待缴费,待支付的订单,都将失效,请确认是否禁用?',
+    '禁用协议',
+    {
+      confirmButtonText: '确定禁用',
+      type: 'error',
+      center: true,
+      confirmButtonClass: 'el-button--danger',
+    }
+  )
+    .then(() => {
+      sysUpAndDown(false, [value]);
+    })
+}
+//启用
+const enable = (value: string) => {
+  sysUpAndDown(true, [value]);
+}
+const del = (value: string) => {
+  ElMessageBox.confirm(
+    '确定要删除该费用吗,删除后,该费用不在支持新的补录订单?',
+    '删除费用',
+    {
+      confirmButtonText: '确定删除',
+      type: 'error',
+      center: true,
+      confirmButtonClass: 'el-button--danger',
+    }
+  )
+    .then(() => {
+      api.agreementApi.deleteById([value]).then((res: any) => {
+        if (res.code == '200') {
+          ElMessage({
+            type: 'success',
+            message: res.msg,
+            plain: true,
+          })
+          router.push({
+            name: 'reload',
+          })
+        }
+      });
+    })
+}
+//批量删除
+const batchDel = () => {
+  ElMessageBox.confirm(
+    '确定要删除该费用吗,删除后,该费用不在支持新的补录订单?',
+    '删除费用',
+    {
+      confirmButtonText: '确定删除',
+      type: 'error',
+      center: true,
+      confirmButtonClass: 'el-button--danger',
+    }
+  )
+    .then(() => {
+      api.agreementApi.deleteById(sysUpAndDownList.value).then((res: any) => {
+        if (res.code == '200') {
+          ElMessage({
+            type: 'success',
+            message: res.msg,
+            plain: true,
+          })
+          router.push({
+            name: 'reload',
+          })
+        }
+      });
+    })
+
+}
+//批量禁用
+const batchdisable = () => {
+  ElMessageBox.confirm(
+    '确定要禁用该费用吗,禁用后,该费用不在支持新的补录订单,请确认是否禁用?',
+    '禁用费用',
+    {
+      confirmButtonText: '确定禁用',
+      type: 'error',
+      center: true,
+      confirmButtonClass: 'el-button--danger',
+    }
+  )
+    .then(async () => {
+      await sysUpAndDown(false, undefined);
+    })
+    .catch(() => {
+    })
+
+
+}
+//批量启用
+const batchenable = async () => {
+  await sysUpAndDown(true, undefined);
+}
+const agreementQuery = () => {
+  findpage();
+}
+const sysUpAndDown = async (type: boolean, list?: string[]) => {
+  await api.agreementApi.enableDisableByIds(type, list ? list : sysUpAndDownList.value).then((res: any) => {
+    if (res.code == '200') {
+      findpage();
+      ElMessage({
+        type: 'success',
+        message: res.msg,
+        plain: true,
+      })
+    }
+  });
+}
+// 批量编辑
+const batchUpdate = () => {
+  auditMethodVisible.value = true;
+
+}
+const resetForm = () => {
+  formInline.agreement = '';//协议信息
+  formInline.productId = "";//归属
+  formInline.rulesName = '';//保险公司id
+  formInline.costRules = '';//协议类型
+  formInline.agreementStatus = "";//有效状态
+  formInline.auditStatus = "";//协议状态
+  formInline.validState = "";
+  formInline.effectiveTime = [];
+  formInline.failureTime = [];
+  findpage();
+}
+//批量修改弹窗
+const auditMethodVisible = ref(false);
+
+const agreementSelectionConfirm = async (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  await formEl.validate((valid) => {
+    if (valid) {
+      api.agreementApi.approvalMethodAll(Editinfo.auditMethod, sysUpAndDownList.value).then((res: any) => {
+        if (res.code == '200') {
+          ElMessage({
+            type: 'success',
+            message: res.msg,
+            plain: true,
+          })
+          auditMethodVisible.value=false;
+          findpage();
+        } else {
+        }
+      });
+    } else {
+      ElMessage({
+        type: 'error',
+        message: '信息不完整',
+        plain: true,
+      })
+    }
+  })
+}
+// 批量编辑
+const Editinfo = reactive({
+  auditMethod: "",
+});
+</script>
+
+<style lang="scss" scoped>
+.demo-form-inline .el-input {
+  --el-input-width: 220px;
+}
+
+.demo-form-inline .el-select {
+  --el-select-width: 220px;
+}
+
+:deep(.el-dropdown-link) {
+  display: flex;
+  align-items: center;
+  margin-left: 15px;
+  color: var(--el-color-primary);
+  cursor: pointer;
+}
+
+.el-inputs {
+  width: 100% !important;
+}
+</style>

+ 1 - 2
src/views/personnel/roleManagement.vue

@@ -399,7 +399,7 @@ function deleteRole() {
     .roleDeleteValid({
       id: roleId.value,
     })
-    .then((res) => {
+    .then((res:any) => {
       console.log(res);
       if (res.code == 200) {
         ElMessageBox({
@@ -429,7 +429,6 @@ const dataMarkChange = () => {
   deptIds.value = [];
   disabledTree(deptTreeData.value, roleInfo.deptId);
   roleInfo.deptIds = deptIds.value;
-  console.log(123, roleInfo.deptIds)
   if (deptIds.value.length == 0) {
     deptTree.value!.setCheckedKeys([], false);
   } else {

+ 25 - 8
src/views/quoteConfig/agreement/agreementAdd.vue

@@ -97,7 +97,8 @@
           </ElCol>
           <ElCol :md="24" :lg="6">
             <el-form-item label="出单账号" prop="attributionId">
-              <el-input v-model="agreementFrom.attributionId" placeholder="请选择" />
+              <el-input v-model="attributionName" placeholder="请选择" type="textarea"
+                @click="orderAccountVisible = true" />
             </el-form-item>
           </ElCol>
           <ElCol :md="24" :lg="12">
@@ -152,8 +153,12 @@
         取消
       </ElButton>
     </FixedActionBar>
+    <!-- 选择管理人 -->
     <managerModal :managerModal="managerModalVisible" :deptOptions="deptOptions" :managerlist="managerlist"
-      @save="managerModalsave" @NodeClick="managerModalNodeClick" @query="managerModalQuery" @cancel="managerModalVisible = false" />
+      @save="managerModalsave" @NodeClick="managerModalNodeClick" @query="managerModalQuery"
+      @cancel="managerModalVisible = false" />
+    <!-- 选择出单账号 -->
+    <orderAccount :orderAccount="orderAccountVisible" @cancel="orderAccountVisible = false" @save="orderAccountSave" />
   </div>
 </template>
 
@@ -164,6 +169,7 @@ import { loadDicts, getDict } from '@/utils/composables/dictService';//字典组
 import { Fileonload, formatFileSize, processFileName } from '@/utils/composables/fileProcessing';//文件处理工具
 import { useRoute, useRouter } from 'vue-router';
 import managerModal from "./components/managerModal.vue";
+import orderAccount from "./components/orderAccount.vue";
 import api from '@/api';
 const parentIdprops = {
   expandTrigger: 'hover' as const,
@@ -413,6 +419,7 @@ const company = () => {
 //选择管理人
 interface managerlist {
   id: string,
+  userId:string,
   name: string,
   deptName: string,
 }
@@ -421,28 +428,38 @@ const managerlist = ref<managerlist[]>([]);//机构向下人员列表
 const managerName = ref();//管理员姓名  回显使用
 //选中机构获取人员
 const managerModalNodeClick = (id: string) => {
-  console.log(id)
-  api.agreementApi.getUserByDeptId(id,'').then((res: any) => {
+  api.agreementApi.getUserByDeptId(id, '').then((res: any) => {
     if (res.code == '200') {
       managerlist.value = res.data;
     }
   });
 }
-const managerModalQuery=(searchValue:string)=>{
-  api.agreementApi.getUserByDeptId('',searchValue).then((res: any) => {
+const managerModalQuery = (searchValue: string) => {
+  api.agreementApi.getUserByDeptId('', searchValue).then((res: any) => {
     if (res.code == '200') {
       managerlist.value = res.data;
     }
   });
 }
-//保存事件
+//选择管理人保存事件
 const managerModalsave = (id: string, name: string, deptName: string) => {
   agreementFrom.custodianId = id;
   managerName.value = name + ' - ' + deptName;
   managerModalVisible.value = false;
 
 }
-
+//选择出单账号
+const orderAccountVisible = ref(false);
+const attributionName = ref();
+const attributionUserAbbr = ref();
+//保存事件
+const orderAccountSave = (id: string, name: string, userAbbr: string) => {
+  console.log(id, name, userAbbr)
+  agreementFrom.attributionId = id;
+  attributionName.value = `用户名:${name}\n简称:${userAbbr}`;
+  attributionUserAbbr.value = userAbbr;
+  orderAccountVisible.value = false;
+}
 </script>
 <style lang="scss" scoped>
 .disabled :deep(.el-upload--picture-card) {

+ 236 - 0
src/views/quoteConfig/agreement/agreementCopy.vue

@@ -0,0 +1,236 @@
+<!-- 模板区域 -->
+<template>
+  <div>
+    <PageMain>
+      <div class="headers">
+        <span class="strong">天勤恒邦吕梁协议 - 非晋M - 0136</span>
+        <el-descriptions :column="2" style="margin-top: 10px;">
+          <el-descriptions-item label="协议号:">{{ agreementInfo.agreementCode }}</el-descriptions-item>
+          <el-descriptions-item label="协议名称:">{{ agreementInfo.agreementTitle }}</el-descriptions-item>
+          <el-descriptions-item label="归属机构:">{{ agreementInfo.deptName }}</el-descriptions-item>
+          <el-descriptions-item label="授权机构:">{{ authDeptlength }}</el-descriptions-item>
+          <el-descriptions-item label="添加人:">
+            {{ agreementInfo.createBy }}
+          </el-descriptions-item>
+          <el-descriptions-item label="添加时间:">
+            {{ agreementInfo.createTime }}
+          </el-descriptions-item>
+        </el-descriptions>
+      </div>
+      <div class="content m-top-20 flex a-c">
+        <span>出单费用{{ feeData.length }}条</span>
+        <div class="grayBlock m-right-10 m-left-20 flex a-c j-s">
+          <span class="m-right-20" style="line-height: 14px;">有效状态</span>
+          <el-dropdown trigger="click" @command="validStateCommand">
+            <el-button link style="font-size: 14px;color: #333;"> {{ valid_statusName ? valid_statusName : '全部'
+            }}<el-icon>
+                <arrow-down />
+              </el-icon>
+            </el-button>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item :command="item.label" v-for="(item, index) in getDict('valid_status')" :key="index">{{
+                  item.label }}</el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+        </div>
+        <div class="grayBlock m-right-10 m-left-20 flex a-c j-s">
+          <span class="m-right-20" style="line-height: 14px;">费用状态</span>
+          <el-dropdown placement="bottom-start" @command="agreementStatusCommand">
+            <el-button link style="font-size: 14px;color: #333;">{{ is_enableName ? is_enableName : '全部' }}<el-icon>
+                <arrow-down />
+              </el-icon>
+            </el-button>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item :command="item.label" v-for="(item, index) in is_enable" :key="index">{{ item.label
+                }}</el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+        </div>
+      </div>
+      <ComplexTable :tableData="feeData" :columns="columns" :showIndex="false" :columnwidth="200" :showOperation="false"
+        :showSelect="true" uniqueIdName="costId" @selectionChange="selectionChange">
+      </ComplexTable>
+
+    </PageMain>
+    <FixedActionBar>
+      <ElButton @click="router.back()">
+        取消
+      </ElButton>
+      <ElButton type="primary" @click="agreementcopy" :disabled="!sysUpAndDownList.length">
+        复制协议
+      </ElButton>
+    </FixedActionBar>
+  </div>
+</template>
+
+<!-- 行为区域 -->
+<script lang='ts' setup>
+import { ref, reactive } from 'vue'
+import api from '@/api'
+import { useRoute, useRouter } from 'vue-router';
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { loadDicts, getDict } from '@/utils/composables/dictService';//字典组件
+const route = useRoute();
+const router = useRouter();
+const id = ref(route.query.id as string);//id参数
+interface Agreement {
+  [key: string]: string | number; // 协议名称
+}
+const agreementInfo = ref<Agreement>({}); // 初始值为 null
+const authDeptlength = ref<number>(0);
+const feeData = ref([]);//费用数据
+const valid_status = ref();
+const valid_statusName = ref();
+const is_enable = ref();
+const is_enableName = ref();
+const sysUpAndDownList = ref<string[]>([])//选中id
+const formInline = reactive({
+  validState: '',//协议信息
+  agreementStatus: "",//归属
+})
+const columns = [
+
+  {
+    prop: "costRules", label: "规则明细", width: '500',
+  },
+  {
+    prop: "productName", label: "保险产品", width: '120',
+  },
+  {
+    prop: "isEnabled", label: "费用状态", width: '100', component: "Tag",
+    formatter: (row: any) => {
+      let name = getDict('is_enable').find(val => val.value == row.isEnabled).label
+      if (name) {
+        return { type: 'primary', text: name };
+      }
+    }
+  },
+  {
+    prop: "approved", label: "有效状态", width: '120', component: "Tag", formatter: (row: any) => {
+      if (row.isValid == '0') {
+        return { type: 'primary', text: '生效中' }
+      } else {
+        return { type: 'danger', text: '已失效' }
+
+      }
+
+    }
+  },
+  { prop: "effectiveTime", label: "生效时间", width: '200' },
+  { prop: "failureTime", label: "失效时间", width: '200' },
+  {
+    prop: "ruleConditions", label: "交强费用", width: '300', formatter: (row: any) => {
+      let info = row.ruleConditions.find((val: any) => val.costType == '交强险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n加投:${info.addThrow.toFixed(2)}% 手续费:${info.commission.toFixed(2)}%`
+      } else {
+        return '-';
+      }
+    }
+  },
+  {
+    prop: "ruleConditions", label: "商业费用", width: '300', formatter: (row: any) => {
+      let info = row.ruleConditions.find((val: any) => val.costType == '商业险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n加投:${info.addThrow.toFixed(2)}% 手续费:${info.commission.toFixed(2)}%`
+      } else {
+        return '-';
+      }
+    }
+  },
+  {
+    prop: "ruleConditions", label: "驾意险费用", width: '300', formatter: (row: any) => {
+      let info = row.ruleConditions.find((val: any) => val.costType == '驾意险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n加投:${info.addThrow.toFixed(2)}% 手续费:${info.commission.toFixed(2)}%`
+      } else {
+        return '-';
+      }
+    }
+  },
+];
+onBeforeMount(async () => {
+  await loadDicts(['valid_status', 'is_enable']);//获取多个字典
+  if (id.value) {
+    detailsInfo();//协议信息
+    findpage();
+    valid_status.value = getDict('valid_status')
+    is_enable.value = getDict('is_enable')
+  }
+})
+//协议详情
+const detailsInfo = () => {
+  api.agreementApi.agreementGet(id.value).then((res: any) => {
+    if (res.code == '200') {
+      res.data.agreement.fileName = processFileName(res.data.agreement.fileName)
+      res.data.agreement.fileSize = formatFileSize(res.data.agreement.fileSize);
+      agreementInfo.value = res.data.agreement;
+      authDeptlength.value = res.data.dept.length;
+    } else {
+    }
+  });
+}
+//费用数据查询
+function findpage() {
+  api.agreementApi.queryByFeePage({ pages: 1, size: 100, ...formInline }).then((res: any) => {
+    if (res.code == '200') {
+      feeData.value = res.data.records;
+    } else {
+    }
+  });
+}
+//费用复制
+const agreementcopy = () => {
+  api.agreementApi.agreementCopy({id:id.value,costIds:sysUpAndDownList.value}).then((res: any) => {
+    if (res.code == '200') {
+      ElMessage({
+        type: 'success',
+        message: res.msg,
+        plain: true,
+      })
+      router.back()
+    } else {
+    }
+  });
+}
+//多选事件
+const selectionChange = (val: any) => {
+  console.log(val)
+  sysUpAndDownList.value = val;
+}
+const validStateCommand = (e: any) => {
+  let info = valid_status.value.find((val: any) => val.label == e);
+  valid_statusName.value = info.label;
+  formInline.validState = info.value;
+  findpage();
+
+}
+const agreementStatusCommand = (e: any) => {
+  let info = is_enable.value.find((val: any) => val.label == e);
+  is_enableName.value = info.label;
+  formInline.agreementStatus = info.value;
+  findpage();
+}
+</script>
+<!-- 样式区域 -->
+<style lang='scss' scoped>
+.headers {
+  border-bottom: 1px solid #f2f2f2;
+}
+
+.grayBlock {
+  padding: 8px 10px;
+  font-size: 14px;
+  color: #666;
+  background: #f2f2f2;
+  border-radius: 4px;
+}
+
+:deep(.el-descriptions__cell) {
+  width: 33.33%;
+}
+</style>

+ 29 - 18
src/views/quoteConfig/agreement/agreementIndex.vue

@@ -16,7 +16,7 @@
             </el-button>
           </RouterLink>
           <el-dropdown placement="bottom-start">
-            <el-button> 批量管理<el-icon>
+            <el-button > 批量管理<el-icon>
                 <arrow-down />
               </el-icon>
             </el-button>
@@ -41,9 +41,9 @@
                 <el-dropdown-item @click="enable(scope.operationData.id)">启用</el-dropdown-item>
                 <el-dropdown-item @click="disable(scope.operationData.id)">禁用</el-dropdown-item>
                 <el-dropdown-item @click="del(scope.operationData.id)">删除</el-dropdown-item>
-                <el-dropdown-item @click="agreemenCopy">复制协议</el-dropdown-item>
+                <el-dropdown-item @click="agreemenCopy(scope.operationData.id)">复制协议</el-dropdown-item>
                 <el-dropdown-item @click="batchAuthorization(scope.operationData.id)">协议授权</el-dropdown-item>
-                <el-dropdown-item @click="agreemenUpdate(scope.operationData)">费用管理</el-dropdown-item>
+                <el-dropdown-item @click="cost(scope.operationData.id)">费用管理</el-dropdown-item>
               </el-dropdown-menu>
             </template>
           </el-dropdown>
@@ -91,7 +91,6 @@ const parentIdprops = {
 }
 const tableData = ref([
 ]);
-
 const sysUpAndDownList = ref<string[]>([])//选中id
 const provinceoptions = ref<string[]>([])//省市区回显数据
 const deptOptions = ref()//机构数据
@@ -120,6 +119,9 @@ const formInline = reactive({
   takeEndDate: "",
   loseStartDate: "",
   loseEndDate: "",
+  isExternal:'0',
+  value1:[],
+  value2:[],
 })
 
 //表格字段数据
@@ -152,14 +154,15 @@ const fields = ref([
     label: "出单账号", model: "attributionName", type: "input", placeholder: "选择出单账号"
   },
   {
-    label: "生效时间", model: "takeStartDate", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
+    label: "生效时间", model: "value1", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
     onChange: (value: any) => {
+      console.log(value)
       formInline.takeStartDate = value[0];
       formInline.takeEndDate = value[1];
     }
   },
   {
-    label: "失效时间", model: "loseStartDate", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
+    label: "失效时间", model: "value2", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
     onChange: (value: any) => {
       formInline.loseStartDate = value[0];
       formInline.loseEndDate = value[1];
@@ -231,7 +234,11 @@ const columns = [
       return 'T' + row.moneyTime
     }
   },
-  { prop: "attributionId", label: "出单账号", width: '120', },
+  { prop: "username", label: "出单账号", width: '220',
+  formatter: (row: any) => {
+      return `用户名:${row.username}\n简称:${row.userAbbr}`
+    }
+  },
   { prop: "company", label: "保险公司", width: '200' },
   { prop: "dockingPerson", label: "对接人", width: '200' },
   { prop: "custodianId", label: "管理人", width: '200' },
@@ -309,6 +316,14 @@ function agreemenUpdate(item: any) {
     }
   })
 }
+const cost=(id:string)=>{
+  router.push({
+    name: 'CostManagement',
+    query: {
+      id: id
+    }
+  })
+}
 //多选事件
 const selectionChange = (val: any) => {
   sysUpAndDownList.value = val;
@@ -329,8 +344,13 @@ const batchAuthorization = (value: string) => {
 
 }
 //复制协议
-const agreemenCopy = () => {
-
+const agreemenCopy = (id:string) => {
+  router.push({
+    name: 'AgreementCopy',
+    query: {
+      id: id
+    }
+  })
 }
 //禁用
 const disable = (value: string) => {
@@ -445,15 +465,6 @@ const sysUpAndDown = async (type: string, list?: string[]) => {
     }
   });
 }
-//添加子机构
-const subOrganizationAdd = (code: string) => {
-  router.push({
-    name: 'OrganizationDeptAdd',
-    query: {
-      code: code
-    }
-  })
-}
 const resetForm = () => {
   formInline.searchValue = '';
   provinceoptions.value = [];

+ 5 - 4
src/views/quoteConfig/agreement/components/managerModal.vue

@@ -14,9 +14,9 @@
         <div class="area">
           <el-radio-group v-model="userId">
             <div class="flex f-c">
-              <el-radio :value="item.id" v-for="(item,index) in managerlist" @change="radioChange" :key="index" class="m-btn-20">
+              <el-radio :value="item.userId" v-for="(item,index) in managerlist" @change="radioChange" :key="index" class="m-btn-20">
                 <div>{{ item.name }}</div>
-                <div>{{ item.id }}</div>
+                <div>{{ item.userId }}</div>
               </el-radio>
             </div>
           </el-radio-group>
@@ -46,6 +46,7 @@ interface Tree {
 }
 interface managerlist{
   id:string,
+  userId:string,
   name:string,
   deptName:string,
 }
@@ -86,8 +87,8 @@ const searchValueclick=()=>{
   emits('query',searchValue.value)
 }
 const radioChange=(value:any)=>{
-  let name=props.managerlist.find(val=>val.id==value)?.name;
-  let deptname=props.managerlist.find(val=>val.id==value)?.deptName;
+  let name=props.managerlist.find(val=>val.userId==value)?.name;
+  let deptname=props.managerlist.find(val=>val.userId==value)?.deptName;
   username.value=name;
   deptName.value=deptname;
 }

+ 134 - 0
src/views/quoteConfig/agreement/components/orderAccount.vue

@@ -0,0 +1,134 @@
+<!-- 模板区域 -->
+<template>
+  <div>
+    <el-dialog v-model="props.orderAccount" title="选择出单账号" width="50%" @close="close">
+      <div class="flex a-c j-s ">
+        <div class="flex a-c">
+          <el-input v-model="searchValue" style="width: 240px;margin-right: 10px;" clearable
+            placeholder="输入姓名,手机号,工号查找" />
+          <el-button type="primary">查询</el-button>
+        </div>
+        <div>
+          <el-button type="default" @click="addAccount">添加账号
+            <template #icon>
+              <el-icon>
+                <Plus />
+              </el-icon>
+            </template>
+          </el-button>
+          <el-button type="default" @click="refresh">刷新</el-button>
+        </div>
+      </div>
+      <ComplexTable :tableData="tableData" :columns="columns" :showIndex="false" :columnwidth="200" :showSelect="false"
+        :showOperation="false" :pageInfo="pageInfo" :maxHeight="400" @getList="getList" :highlightCurrentRow="true"
+        :loading="loding" @currentChange="currentChange">
+      </ComplexTable>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="cancel">取消</el-button>
+          <el-button type="primary" @click="save" :disabled="!activeInfo">
+            确定
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<!-- 行为区域 -->
+<script lang='ts' setup>
+import { ref,  } from 'vue'
+import api from '@/api'
+import {  useRouter } from "vue-router";
+import { defineProps, defineEmits } from "vue";
+interface PageInfo {
+  pageNum: number;
+  pageSize: number;
+  sizes: number[];
+  total: number;
+}
+const pageInfo = ref({
+  pageNum: 1,
+  pageSize: 20,
+  sizes: [10, 20, 30, 40, 50],
+  total: 100,
+});
+const router = useRouter();
+const props = defineProps<{
+  orderAccount: boolean,
+}>();
+const emits = defineEmits(["cancel", 'save']);
+const searchValue = ref();
+const activeInfo = ref();//选中对象
+const tableData = ref([
+]);
+const loding = ref(false);
+const columns = [
+  {
+    prop: "username", label: "账号信息", align: 'left', formatter: (row: any) => {
+      return `用户名:${row.username}\n简称:${row.userAbbr}`
+    }
+  },
+  {
+    prop: "insCompanyName", label: "保险公司",
+  },
+  { prop: "url", label: "系统", },
+  { prop: "deptName", label: "归属", },
+];
+//分页事件
+function getList(item: PageInfo) {
+  pageInfo.value.pageNum = item.pageNum;
+  pageInfo.value.pageSize = item.pageSize;
+  findpage();
+
+};
+onMounted(() => {
+  findpage();
+})
+//数据查询
+function findpage() {
+  api.insuranceApi.getAgreementAttributionList({ pages: pageInfo.value.pageNum, size: pageInfo.value.pageSize, username: searchValue.value }).then((res: any) => {
+    if (res.code == '200') {
+      tableData.value = res.data.records;
+      pageInfo.value.pageNum = res.data.current;
+      pageInfo.value.pageSize = res.data.size;
+      pageInfo.value.total = res.data.total;
+    } else {
+    }
+  });
+}
+const currentChange = (info: object) => {
+  console.log(info)
+  activeInfo.value = info;
+}
+const cancel = () => {
+  emits("cancel")
+}
+const close = () => {
+  emits('cancel')
+}
+const save = () => {
+  emits('save', activeInfo.value.id, activeInfo.value.username, activeInfo.value.userAbbr)
+}
+//打开新标签页
+const addAccount = () => {
+  const url = router.resolve({
+    name: 'InsuranceAccountAdd',
+  }).href; // 获取目标路由的完整 URL
+  window.open(url, '_blank'); // 在新标签页中打开
+
+}
+const refresh = () => {
+  loding.value = true;
+  api.insuranceApi.getAgreementAttributionList({ pages: 1, size: 20, username: searchValue.value }).then((res: any) => {
+    if (res.code == '200') {
+      tableData.value = res.data.records;
+      pageInfo.value.pageNum = res.data.current;
+      pageInfo.value.pageSize = res.data.size;
+      pageInfo.value.total = res.data.total;
+      loding.value = false;
+
+    }
+  });
+}
+</script>

+ 4 - 4
src/views/quoteConfig/agreement/components/ruleFeeDialog.vue

@@ -1,7 +1,7 @@
 <!-- 模板区域 -->
 <template>
   <div>
-    <el-drawer v-model="props.ruleFeeVisible" :direction="direction" :close-on-click-modal="false" size="57%">
+    <el-drawer v-model="props.ruleFeeVisible" :direction="direction" :close-on-click-modal="false" size="57%" @close="close">
       <template #header>
         <h4>添加费用</h4>
       </template>
@@ -259,9 +259,9 @@ const ruleConditionSave = (list: string[]) => {//获取规则条件选中集合
 const cancel = () => {
   emits("cancel")
 }
-
-
-
+const close=()=>{
+  emits("cancel")
+}
 const save = async (formEl: FormInstance | undefined | any) => {
   if (!formEl) return
   const validationPromises = ruleFeeinfo.value[insuranceTypeIndex.value].ptlAgreementCostAddList.map((formRef: any, index: any) => {

+ 89 - 24
src/views/quoteConfig/agreement/components/ruleFeeDialogEdit.vue

@@ -1,11 +1,22 @@
 <!-- 模板区域 -->
 <template>
   <div>
-    <el-drawer v-model="props.ruleFeeVisible" :direction="direction" :close-on-click-modal="false" size="57%">
+    <el-drawer v-model="props.ruleFeeVisible" :direction="direction" :close-on-click-modal="false" size="57%" @close="close">
       <template #header>
         <h4>{{ props.headerTitle }}费用编辑</h4>
       </template>
       <template #default>
+        <div class="rejectionReason flex a-start" v-if="costitemEditInfo.reviewDescription">
+          <el-icon color="red" class="m-right-20"><CircleClose /></el-icon>
+          <div class="flex f-c">
+            <span class="strong" style="color: #333;">审核不通过</span>
+            <span >审核原因:{{costitemEditInfo. reviewDescription }}</span>
+            <div class="flex a-c ">
+              <span class="m-right-20">审核人:{{ costitemEditInfo.auditPerson }}</span>
+              <span >审核时间:{{costitemEditInfo.auditTime }}</span>
+            </div>
+          </div>
+        </div>
         <div class="agreement ">
           <ElRow :gutter="20">
             <ElCol :md="10"><span><span style="color: #666;">协议号:</span> {{ props.agreementInfo.agreementCode }}</span>
@@ -18,7 +29,7 @@
           </ElRow>
           <ElRow :gutter="20" class="m-top-20">
             <el-form :model="costitemEditInfo" label-width="80px" ref="productFormRef" style="width: 100%;"
-              class="flex a-c f-wrap" :size="fromSize">
+              :disabled="disabledShow" class="flex a-c f-wrap" :size="fromSize">
               <ElCol :md="24" :lg="12">
                 <el-form-item label="生效时间" prop="effectiveTime">
                   <el-date-picker v-model="costitemEditInfo.effectiveTime" style="width: 100%;" type="datetime"
@@ -55,7 +66,7 @@
               <span class="strong m-right-20">规则条件</span>
             </ElCol>
             <ElCol :md="24" :lg="22">
-              <el-button type="primary" plain @click="ruleConditionVisible = true">
+              <el-button type="primary" :disabled="disabledShow" plain @click="ruleConditionVisible = true">
                 添加条件
                 <template #icon>
                   <el-icon>
@@ -64,7 +75,7 @@
                 </template>
               </el-button>
               <rule-Condition-Container :rulesAttrList="costitemEditInfo.ruleConditions" @Del="rulesAttrDel"
-                @selectChange="rulesAttrselectChange" />
+                @selectChange="rulesAttrselectChange" :disabled="disabledShow" />
             </ElCol>
           </div>
           <el-table :data="costitemEditInfo.ptlAgreementCostTypeList" class="m-top-20" style="width: 100%;" border
@@ -78,32 +89,32 @@
             <el-table-column prop="costType" label="类型"></el-table-column>
             <el-table-column prop="inlet" label="入口比例" width="180" align="center">
               <template #default="scope">
-                <el-input-number v-model="scope.row.inlet" :precision="2" controls-position="right" style="width: 100%;"
-                  :min="0" :max="100">
+                <el-input-number v-model="scope.row.inlet" :disabled="disabledShow" :precision="2"
+                  controls-position="right" style="width: 100%;" :min="0" :max="100">
                   <template #suffix>%</template>
                 </el-input-number>
               </template>
             </el-table-column>
             <el-table-column prop="export" label="出口比例" width="180" align="center">
               <template #default="scope">
-                <el-input-number v-model="scope.row.export" :precision="2" controls-position="right"
-                  style="width: 100%;" :min="0" :max="100">
+                <el-input-number v-model="scope.row.export" :disabled="disabledShow" :precision="2"
+                  controls-position="right" style="width: 100%;" :min="0" :max="100">
                   <template #suffix>%</template>
                 </el-input-number>
               </template>
             </el-table-column>
             <el-table-column prop="commission" label="手续费比例" width="180" align="center">
               <template #default="scope">
-                <el-input-number v-model="scope.row.commission" :precision="2" controls-position="right"
-                  style="width: 100%;" :min="0" :max="100">
+                <el-input-number v-model="scope.row.commission" :disabled="disabledShow" :precision="2"
+                  controls-position="right" style="width: 100%;" :min="0" :max="100">
                   <template #suffix>%</template>
                 </el-input-number>
               </template>
             </el-table-column>
             <el-table-column prop="addThrow" label="加投比例" width="180" align="center">
               <template #default="scope">
-                <el-input-number v-model="scope.row.addThrow" :precision="2" controls-position="right"
-                  style="width: 100%;" :min="0" :max="100">
+                <el-input-number v-model="scope.row.addThrow" :disabled="disabledShow" :precision="2"
+                  controls-position="right" style="width: 100%;" :min="0" :max="100">
                   <template #suffix>%</template>
                 </el-input-number>
               </template>
@@ -113,23 +124,30 @@
 
       </template>
       <template #footer>
-        <div class="flex a-c j-c">
+        <div class="flex a-c j-c" v-if="!disabledShow">
           <el-button @click="cancel">取消</el-button>
           <el-button type="primary" @click="save">提交审核</el-button>
         </div>
+        <div class="flex f-c " v-if="!costitemEditInfo?.reviewDescription">
+          <el-checkbox v-model="automatic" label="审核后,自动跳支审核下一条费用" size="large" />
+          <div class="flex a-c">
+            <el-button @click="rejectOperation">审核驳回</el-button>
+            <el-button type="primary" @click="auditOperation">审核通过</el-button>
+          </div>
+        </div>
       </template>
     </el-drawer>
     <!-- 规则条件弹窗 -->
     <RuleCondition :ruleConditionVisible="ruleConditionVisible" @cancel="ruleConditionVisible = false"
-      @save="ruleConditionSave"  :attrIdList="ruleConditions" />
+      @save="ruleConditionSave" :attrIdList="ruleConditions" />
 
   </div>
 </template>
 
 <!-- 行为区域 -->
 <script lang='ts' setup>
-import { ref,  } from 'vue'
-import { DrawerProps, ComponentSize,  } from 'element-plus';
+import { ref, } from 'vue'
+import { DrawerProps, ComponentSize, ElMessageBox } from 'element-plus';
 import { loadDicts } from '@/utils/composables/dictService';//字典组件
 import { defineProps, defineEmits } from "vue";
 const direction = ref<DrawerProps['direction']>('rtl')
@@ -137,22 +155,32 @@ const fromSize = ref<ComponentSize>('default')
 
 const props = defineProps<{
   ruleFeeVisible: boolean,
-  agreementInfo: any,
-  RulesInfo: any,
-  costitemEditInfo: any,
-  headerTitle?: string,
+  agreementInfo: any,//协议信息
+  RulesInfo: any,//费用信息
+  costitemEditInfo: any,//编辑回显数据
+  headerTitle?: string,//抽屉name
+  operationType?: string,//操作类型
 }>();
-const emits = defineEmits(["cancel", 'save']);
-const ruleConditions=ref();
+const emits = defineEmits(["cancel", 'save', 'auditOperation', 'rejectOperation']);
+const ruleConditions = ref();
 const ruleConditionVisible = ref(false);//规则条件弹窗
 const costitemEditInfo = ref();//编辑费用数据
+const disabledShow = ref(false);//是否可编辑
+const automatic = ref(false);//是否连续审核
 onMounted(async () => {
   await loadDicts(['insurance_type'])
 })
 watch(props, () => {
   if (props.costitemEditInfo) {
     costitemEditInfo.value = props.costitemEditInfo;
-    ruleConditions.value=props.costitemEditInfo.ruleConditions;
+    ruleConditions.value = props.costitemEditInfo.ruleConditions;
+  }
+  //审核和驳回操作不可编辑
+  if (props.operationType == 'audit' || props.operationType == 'rejected') {
+    disabledShow.value = true;
+  } else {
+    disabledShow.value = false;
+
   }
 })
 
@@ -197,12 +225,37 @@ const ruleConditionSave = (list: string[]) => {//获取规则条件选中集合
 const cancel = () => {
   emits("cancel")
 }
+const close=()=>{
+  emits("cancel")
+}
 const save = () => {
   console.log(costitemEditInfo.value)
   // return;
-  emits("save",costitemEditInfo.value)
+  emits("save", costitemEditInfo.value)
 }
 
+
+
+//审核驳回操作
+const rejectOperation = () => {
+  //驳回弹窗
+  ElMessageBox.prompt('', '审核不通过', {
+    confirmButtonText: '确定',
+    type: 'warning',
+    center: true,
+    inputType: "textarea",
+    inputPlaceholder: "请输入不通过原因",
+    inputPattern: /^[\u4e00-\u9fa5,。!?、;:“”‘’《》【】()——]+$/,
+    inputErrorMessage: '请输入中文',
+  })
+    .then(({ value }) => {
+      emits("rejectOperation",automatic.value,costitemEditInfo.value.id,value)
+    })
+}
+//审核通过操作
+const auditOperation = () => {
+  emits("auditOperation", automatic.value,costitemEditInfo.value.id)
+}
 </script>
 <!-- 样式区域 -->
 <style lang='scss' scoped>
@@ -250,6 +303,18 @@ const save = () => {
   }
 }
 
+.rejectionReason {
+  padding: 15px;
+  background: #fff1f0;
+  border: 1px solid #ffa39e;
+  border-radius: 5px;
+
+  span {
+    margin-bottom: 10px;
+    color: #666;
+  }
+}
+
 :deep(.ruleFeetabs>.el-tabs__content) {
   position: static;
 }

+ 34 - 28
src/views/quoteConfig/costManagement.vue

@@ -96,7 +96,7 @@
 
 <script lang="ts" setup>
 import { ref, reactive } from 'vue'
-import {  useRouter } from "vue-router";
+import { useRoute, useRouter } from 'vue-router';
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { loadDicts, getDict } from '@/utils/composables/dictService';//字典组件
 import ruleFeeDialog from "./agreement/components/ruleFeeDialog.vue";
@@ -109,14 +109,18 @@ interface PageInfo {
   total: number;
 }
 onBeforeMount(async () => {
-  await loadDicts([ 'valid_status', 'is_enable', 'audit_status','insurance_type']);//获取多个字典
+  await loadDicts(['valid_status', 'is_enable', 'audit_status', 'insurance_type']);//获取多个字典
+  if(id.value){
+    formInline.agreement=id.value;
+  }
   findpage();//列表数据
   getDeptTree();
   agreement();
   valid_status.value = getDict('valid_status');//生效状态
   is_enable.value = getDict('is_enable');//协议状态
-  insurance_type.value=getDict('insurance_type')
-  audit_status.value=getDict('audit_status')
+  insurance_type.value = getDict('insurance_type')
+  audit_status.value = getDict('audit_status')
+
 });
 const tableData = ref([
 ]);
@@ -124,11 +128,13 @@ const agreementQueryName = ref();//选择协议查询
 const agreementList = ref();//协议列表
 const sysUpAndDownList = ref<string[]>([])//选中id
 const deptOptions = ref()//机构数据
-const insurance_type=ref();
+const insurance_type = ref();
 const valid_status = ref();
-const audit_status=ref();
+const audit_status = ref();
 const is_enable = ref();
+const route = useRoute();
 const router = useRouter();
+const id = ref(route.query.id as string);//id参数
 const pageInfo = ref({
   pageNum: 1,
   pageSize: 20,
@@ -136,19 +142,15 @@ const pageInfo = ref({
   total: 100,
 });
 const formInline = reactive({
-  searchValue: '',//协议信息
-  deptId: "",//归属
-  companyId: '',//保险公司id
-  agreementType: '',//协议类型
-  validStatus: "",//有效状态
-  isEnable: "",//协议状态
-  withTax: "",
-  dockingPerson: "",
-  attributionName: "",
-  takeStartDate: "",
-  takeEndDate: "",
-  loseStartDate: "",
-  loseEndDate: "",
+  agreement: '',//协议信息
+  productId: "",//归属
+  rulesName: '',//保险公司id
+  costRules: '',//协议类型
+  agreementStatus: "",//有效状态
+  auditStatus: "",//协议状态
+  validState: "",
+  effectiveTime: [],
+  failureTime: [],
 })
 
 //表格字段数据
@@ -177,15 +179,13 @@ const fields = ref([
     label: "生效时间", model: "effectiveTime", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
     onChange: (value: any) => {
       console.log(value)
-      formInline.takeStartDate = value[0];
-      formInline.takeEndDate = value[1];
+      formInline.effectiveTime = value;
     }
   },
   {
     label: "失效时间", model: "failureTime", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
     onChange: (value: any) => {
-      formInline.loseStartDate = value[0];
-      formInline.loseEndDate = value[1];
+      formInline.failureTime = value;
     }
   },
 ]);
@@ -223,7 +223,7 @@ const columns = [
   },
   { prop: "productName", label: "险种", width: '120', },
   {
-    prop: "costRules", label: "费用规则",width: '500',
+    prop: "costRules", label: "费用规则", width: '500',
   },
   {
     prop: "isEnabled", label: "费用状态", width: '100', component: "Tag",
@@ -307,7 +307,7 @@ const ruleFeeEditSave = (data: object) => {
         message: res.msg,
         plain: true,
       })
-      ruleFeeEditVisible.value=false;
+      ruleFeeEditVisible.value = false;
       findpage();
     } else {
     }
@@ -489,9 +489,15 @@ const sysUpAndDown = async (type: boolean, list?: string[]) => {
   });
 }
 const resetForm = () => {
-  for(let key in formInline){
-    formInline[key as keyof typeof formInline]='';
-  }
+  formInline.agreement = '';//协议信息
+  formInline.productId = "";//归属
+  formInline.rulesName = '';//保险公司id
+  formInline.costRules = '';//协议类型
+  formInline.agreementStatus = "";//有效状态
+  formInline.auditStatus = "";//协议状态
+  formInline.validState = "";
+  formInline.effectiveTime = [];
+  formInline.failureTime = [];
   findpage();
 }
 const getDeptTree = () => {

+ 396 - 0
src/views/representative/externalCostApproval.vue

@@ -0,0 +1,396 @@
+<template>
+  <div>
+    <PageMain class="vh100">
+      <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
+        <el-tab-pane :label="`待审核(${pendingReviewlength})`" name="pendingReview">
+        </el-tab-pane>
+        <el-tab-pane :label="`审核不通过(${reviewRejectedlength})`" name="reviewRejected">
+        </el-tab-pane>
+      </el-tabs>
+      <SearchForm :fields="fields" :formInline="formInline" :onSearch="agreementQuery" :onReset="resetForm" />
+      <ComplexTable :tableData="tableData" :columns="columns" :showIndex="false" :columnwidth="200" :showSelect="true"
+        :pageInfo="pageInfo" @getList="getList" @selectionChange="selectionChange">
+        <template v-slot:table-title-btn>
+          <el-dropdown placement="bottom-start">
+            <el-button> 批量管理<el-icon>
+                <arrow-down />
+              </el-icon>
+            </el-button>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item :disabled="!sysUpAndDownList.length" @click="batchaudit">批量审核</el-dropdown-item>
+                <el-dropdown-item :disabled="!sysUpAndDownList.length" @click="batchrejected">批量驳回</el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+        </template>
+        <template v-slot:operation="scope">
+          <el-button v-if="scope.operationData.auditStatus == '0'" type="primary"  link @click="agreemenUpdate(scope.operationData.id)"> 审核
+          </el-button>
+          <el-button v-if="scope.operationData.auditStatus == '2'" type="primary" link
+            @click="agreemenUpdate(scope.operationData.id)"> 详情
+          </el-button>
+        </template>
+      </ComplexTable>
+    </PageMain>
+    <!-- 费用编辑组件 -->
+    <contactPersonFeeDialogEdit :ruleFeeVisible="ruleFeeEditVisible" :headerTitle="ruleFeeHeaderTitle"
+      :costitemEditInfo="costitemEditInfo" @save="ruleFeeEditSave" @cancel="ruleFeeEditVisible = false"
+      operationType="audit" @rejectOperation="rejectOperation" @auditOperation="auditOperation" />
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive } from 'vue'
+import { useRoute } from 'vue-router';
+import { ElMessage, ElMessageBox  } from 'element-plus'
+import { loadDicts, getDict } from '@/utils/composables/dictService';//字典组件
+import contactPersonFeeDialogEdit from "../externalAgreement/agreement/components/contactPersonFeeDialogEdit.vue";
+
+import api from '@/api';
+interface PageInfo {
+  pageNum: number;
+  pageSize: number;
+  sizes: number[];
+  total: number;
+}
+onBeforeMount(async () => {
+  await loadDicts(['valid_status', 'is_enable', 'audit_status', 'insurance_type']);//获取多个字典
+  if (id.value) {
+    formInline.agreement = id.value;
+  }
+  findpage();//列表数据
+  valid_status.value = getDict('valid_status');//生效状态
+  is_enable.value = getDict('is_enable');//协议状态
+  insurance_type.value = getDict('insurance_type')
+  audit_status.value = getDict('audit_status')
+
+});
+const activeName = ref('pendingReview')
+const pendingReviewlength = ref(0);
+const reviewRejectedlength = ref(0);
+const tableData = ref([]);
+const sysUpAndDownList = ref<string[]>([])//选中id
+const insurance_type = ref();
+const valid_status = ref();
+const audit_status = ref();
+const is_enable = ref();
+const route = useRoute();
+const id = ref(route.query.id as string);//id参数
+const pageInfo = ref({
+  pageNum: 1,
+  pageSize: 20,
+  sizes: [10, 20, 30, 40, 50],
+  total: 100,
+});
+const formInline = reactive({
+  agreement: '',//协议信息
+  productId: "",//归属
+  rulesName: '',//保险公司id
+  costRules: '',//协议类型
+  agreementStatus: "",//有效状态
+  auditStatus: "0",//协议状态
+  validState: "",
+  effectiveTime: [],
+  failureTime: [],
+})
+//表格字段数据
+const fields = ref([
+  { label: "所属协议", model: "agreement", type: "input", placeholder: "输入代码,名称,简称查找" },
+  {
+    label: "险种", model: "productId", type: "select", options: insurance_type,
+  },
+  {
+    label: "承保规则", model: "rulesName", type: "input", placeholder: "输入业务规则查找",
+  },
+  {
+    label: "费用规则", model: "costRules", type: "input", placeholder: "输入费用规则关键字查找",
+  },
+
+  {
+    label: "费用状态", model: "agreementStatus", type: "select", placeholder: "选择状态", options: is_enable,
+  },
+  {
+    label: "有效状态", model: "validState", type: "select", placeholder: "请选择状态", options: valid_status,
+  },
+  {
+    label: "生效时间", model: "effectiveTime", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
+    onChange: (value: any) => {
+      console.log(value)
+      formInline.effectiveTime = value;
+    }
+  },
+  {
+    label: "失效时间", model: "failureTime", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
+    onChange: (value: any) => {
+      formInline.failureTime = value;
+    }
+  },
+]);
+
+//费用数据查询
+function findpage() {
+  api.agreementApi.CostExternalFeePageList({ pages: pageInfo.value.pageNum, size: pageInfo.value.pageSize, ...formInline }).then((res: any) => {
+    if (res.code == '200') {
+      tableData.value = res.data.records;
+      pageInfo.value.pageNum = res.data.current;
+      pageInfo.value.pageSize = res.data.size;
+      pageInfo.value.total = res.data.total;
+      if (res.data.records[0]?.auditStatus == '0') {
+        pendingReviewlength.value = res.data.total;
+      } else {
+        reviewRejectedlength.value = res.data.total;
+      }
+    } else {
+    }
+  });
+}
+
+const columns = [
+  {
+    prop: "agreementAbbreviation", label: "协议信息", width: '300',
+    formatter: (row: any) => {
+      return `${row.agreementCode}\n${row.agreementAbbreviation}`
+    }
+  },
+  { prop: "productName", label: "险种", width: '120', },
+  {
+    prop: "contactPerson", label: "对接人", width: '200', formatter: (row: any) => {
+      return `${row.contactPerson} ${row.contactMobile}`
+    }
+  },
+  {
+    prop: "isInquiry", label: "是否现询", width: '120', formatter: (row: any) => {
+      if (row.isInquiry == '0') {
+        return '是'
+      } else {
+        return "否"
+      }
+    }
+  },
+  {
+    prop: "auditMethod", label: "审核方式", width: '120', formatter: (row: any) => {
+      if (row.auditMethod == '0') {
+        return '自动审核'
+      } else {
+        return "手动审核"
+      }
+    }
+  },
+  {
+    prop: "isEnabled", label: "费用状态", width: '100', component: "Tag",
+    formatter: (row: any) => {
+      let name = getDict('is_enable').find(val => val.value == row.isEnabled).label
+      if (name) {
+        return { type: 'primary', text: name };
+      }
+    }
+  },
+  {
+    prop: "auditStatus", label: "审核状态", width: '120', component: "Tag",
+    formatter: (row: any) => {
+      let name = getDict('audit_status').find(val => val.value == row.auditStatus).label
+      if (name) {
+        return { type: 'warning', text: name };
+      }
+    }
+  },
+  { prop: "effectiveTime", label: "生效时间", width: '200' },
+  { prop: "failureTime", label: "失效时间", width: '200' },
+  {
+    prop: "costExternalTypeAdds", label: "交强险费用", width: '300', formatter: (row: any) => {
+      let info = row.costExternalTypeAdds.find((val: any) => val.costType == '交强险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n一级:${info.level1?.toFixed(2)}% 五级:${info.level5?.toFixed(2)}%`
+      } else {
+        return '-'
+      }
+    }
+  },
+  {
+    prop: "costExternalTypeAdds", label: "商业险费用", width: '300', formatter: (row: any) => {
+      let info = row.costExternalTypeAdds.find((val: any) => val.costType == '商业险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n一级:${info.level1?.toFixed(2)}% 五级:${info.level5?.toFixed(2)}%`
+      } else {
+        return '-'
+      }
+    }
+  },
+  {
+    prop: "costExternalTypeAdds", label: "驾意险费用", width: '300', formatter: (row: any) => {
+      let info = row.costExternalTypeAdds.find((val: any) => val.costType == '驾意险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n一级:${info.level1?.toFixed(2)}% 五级:${info.level5?.toFixed(2)}%`
+      } else {
+        return '-'
+      }
+    }
+  },
+];
+//分页事件
+function getList(item: PageInfo) {
+  pageInfo.value.pageNum = item.pageNum;
+  pageInfo.value.pageSize = item.pageSize;
+  findpage();
+
+};
+// 费用编辑
+const ruleFeeEditVisible = ref(false);
+const ruleFeeHeaderTitle = ref();//编辑弹窗title
+const costitemEditInfo = ref();
+const agreemenUpdate = async (id: any) => {
+  api.agreementApi.FeegetById(id).then((res: any) => {
+    if (res.code == '200') {
+      ruleFeeHeaderTitle.value = res.data.productName;
+      costitemEditInfo.value = res.data;
+      ruleFeeEditVisible.value = true;
+    } else {
+    }
+  });
+}
+//费用编辑
+const ruleFeeEditSave = (data: object) => {
+  api.agreementApi.FeeupdateById(data).then((res: any) => {
+    if (res.code == '200') {
+      ElMessage({
+        type: 'success',
+        message: res.msg,
+        plain: true,
+      })
+      ruleFeeEditVisible.value = false;
+      findpage();
+    } else {
+    }
+  });
+}
+//多选事件
+const selectionChange = (val: any) => {
+  sysUpAndDownList.value = val;
+}
+//批量删除
+const batchaudit = () => {
+  ElMessageBox.confirm(
+    '确定审核通过该费用吗?',
+    '审核通过',
+    {
+      confirmButtonText: '确定',
+      type: 'info',
+      center: true,
+      confirmButtonClass: 'el-button--primary',
+    }
+  )
+    .then(() => {
+      ExternalauditSuccess(sysUpAndDownList.value)
+    })
+
+}
+//批量驳回
+const batchrejected = () => {
+  ElMessageBox.prompt('', '审核不通过', {
+    confirmButtonText: '确定',
+    type: 'warning',
+    center: true,
+    inputType: "textarea",
+    inputPlaceholder: "请输入不通过原因",
+    inputPattern: /^[\u4e00-\u9fa5,。!?、;:“”‘’《》【】()——]+$/,
+    inputErrorMessage: '请输入中文',
+  })
+    .then(({ value }) => {
+      ExternalauditFailed(sysUpAndDownList.value, value)
+    })
+}
+//单一审核回调
+const auditOperation = (automatic: any, id: any) => {
+  ExternalauditSuccess([id], automatic)
+}
+//单一驳回回调
+const rejectOperation = (automatic: any, id: any, value: any) => {
+  ExternalauditFailed([id], value, automatic)
+}
+const agreementQuery = () => {
+  findpage();
+}
+const ExternalauditSuccess = async (list: string[], automatic?: boolean) => {
+  await api.agreementApi.ExternalauditSuccess({ ids: list, automatic: automatic }).then((res: any) => {
+    if (res.code == '200') {
+      findpage();
+      ElMessage({
+        type: 'success',
+        message: res.msg,
+        plain: true,
+      })
+      ruleFeeEditVisible.value = false;
+      if (res.data) {
+        let info: any = tableData.value.find((val: any) => val.id == res.data);
+        if (info) {
+          agreemenUpdate(info.id)
+        }
+      }
+    }
+  });
+}
+const ExternalauditFailed = async (list: string[], value: string, automatic?: boolean) => {
+  await api.agreementApi.ExternalauditFailed({ ids: list, reason: value, automatic: automatic }).then((res: any) => {
+    if (res.code == '200') {
+      findpage();
+      ElMessage({
+        type: 'success',
+        message: res.msg,
+        plain: true,
+      })
+      ruleFeeEditVisible.value = false;
+      if (res.data) {
+        let info: any = tableData.value.find((val: any) => val.id == res.data);
+        if (info) {
+          agreemenUpdate(info.id)
+        }
+      }
+    }
+  });
+}
+const resetForm = () => {
+  formInline.agreement = '';//协议信息
+  formInline.productId = "";//归属
+  formInline.rulesName = '';//保险公司id
+  formInline.costRules = '';//协议类型
+  formInline.agreementStatus = "";//有效状态
+  formInline.auditStatus = "";//协议状态
+  formInline.validState = "";
+  formInline.effectiveTime = [];
+  formInline.failureTime = [];
+  findpage();
+}
+// 批量编辑
+const handleClick = (pane: any) => {
+  if (pane.props.name == 'pendingReview') {
+    formInline.auditStatus = '0';
+    findpage()
+  } else {
+    formInline.auditStatus = '2';
+    findpage();
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.demo-form-inline .el-input {
+  --el-input-width: 220px;
+}
+
+.demo-form-inline .el-select {
+  --el-select-width: 220px;
+}
+
+:deep(.el-dropdown-link) {
+  display: flex;
+  align-items: center;
+  margin-left: 15px;
+  color: var(--el-color-primary);
+  cursor: pointer;
+}
+
+.el-inputs {
+  width: 100% !important;
+}
+</style>

+ 504 - 0
src/views/representative/quoteApproval.vue

@@ -0,0 +1,504 @@
+<template>
+  <div>
+    <PageMain class="vh100">
+      <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
+        <el-tab-pane :label="`待审核(${pendingReviewlength})`" name="pendingReview">
+        </el-tab-pane>
+        <el-tab-pane :label="`审核不通过(${reviewRejectedlength})`" name="reviewRejected">
+        </el-tab-pane>
+      </el-tabs>
+      <SearchForm :fields="fields" :formInline="formInline" :onSearch="agreementQuery" :onReset="resetForm" />
+      <ComplexTable :tableData="tableData" :columns="columns" :showIndex="false" :columnwidth="200" :showSelect="true"
+        :pageInfo="pageInfo" @getList="getList" @selectionChange="selectionChange" uniqueIdName="costId">
+        <template v-slot:table-title-btn>
+          <el-dropdown placement="bottom-start" v-if="activeName == 'pendingReview'">
+            <el-button> 批量审核<el-icon>
+                <arrow-down />
+              </el-icon>
+            </el-button>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item :disabled="!sysUpAndDownList.length" @click="batchaudit">批量审核</el-dropdown-item>
+                <el-dropdown-item :disabled="!sysUpAndDownList.length" @click="batchrejected">批量驳回</el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+        </template>
+        <template v-slot:operation="scope">
+          <el-button v-if="scope.operationData.approved == '0'" type="primary" link
+            @click="agreemenUpdate(scope.operationData)"> 审核
+          </el-button>
+          <el-button v-if="scope.operationData.approved == '2'" type="primary" link
+            @click="agreemenUpdate(scope.operationData)"> 详情
+          </el-button>
+        </template>
+      </ComplexTable>
+    </PageMain>
+
+    <!-- 规则费用编辑组件 -->
+    <ruleFeeDialogEdit :ruleFeeVisible="ruleFeeEditVisible" :headerTitle="ruleFeeHeaderTitle"
+      :agreementInfo="AgreementInfo" :RulesInfo="ruleInfo" :costitemEditInfo="costitemEditInfo" @save="ruleFeeEditSave"
+      @cancel="ruleFeeEditVisible = false" operationType="audit" @rejectOperation="rejectOperation" @auditOperation="auditOperation" />
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive } from 'vue'
+import { useRoute, } from 'vue-router';
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { loadDicts, getDict } from '@/utils/composables/dictService';//字典组件
+import ruleFeeDialogEdit from "../quoteConfig/agreement/components/ruleFeeDialogEdit.vue";
+import api from '@/api';
+interface PageInfo {
+  pageNum: number;
+  pageSize: number;
+  sizes: number[];
+  total: number;
+}
+onBeforeMount(async () => {
+  await loadDicts(['valid_status', 'is_enable', 'audit_status', 'insurance_type']);//获取多个字典
+  if (id.value) {
+    formInline.agreement = id.value;
+  }
+  findpage();//列表数据
+  getDeptTree();
+  agreement();
+  valid_status.value = getDict('valid_status');//生效状态
+  is_enable.value = getDict('is_enable');//协议状态
+  insurance_type.value = getDict('insurance_type')
+  audit_status.value = getDict('audit_status')
+
+});
+const tableData = ref([
+]);
+const activeName = ref('pendingReview')
+const agreementQueryName = ref();//选择协议查询
+const agreementList = ref();//协议列表
+const sysUpAndDownList = ref<string[]>([])//选中id
+const deptOptions = ref()//机构数据
+const insurance_type = ref();
+const valid_status = ref();
+const audit_status = ref();
+const is_enable = ref();
+const route = useRoute();
+const id = ref(route.query.id as string);//id参数
+const pendingReviewlength = ref(0);
+const reviewRejectedlength = ref(0);
+const pageInfo = ref({
+  pageNum: 1,
+  pageSize: 20,
+  sizes: [10, 20, 30, 40, 50],
+  total: 100,
+});
+const formInline = reactive({
+  agreement: '',//协议信息
+  productId: "",//归属
+  rulesName: '',//保险公司id
+  costRules: '',//协议类型
+  agreementStatus: "",//有效状态
+  auditStatus: "0",//审核状态
+  validState: "",
+  effectiveTime: [],
+  failureTime: [],
+})
+
+//表格字段数据
+const fields = ref([
+  { label: "所属协议", model: "agreement", type: "input", placeholder: "输入代码,名称,简称查找" },
+  {
+    label: "险种", model: "productId", type: "select", options: insurance_type,
+  },
+  {
+    label: "承保规则", model: "rulesName", type: "input", placeholder: "输入业务规则查找",
+  },
+  {
+    label: "费用规则", model: "costRules", type: "input", placeholder: "输入费用规则关键字查找",
+  },
+
+  {
+    label: "费用状态", model: "agreementStatus", type: "select", placeholder: "选择状态", options: is_enable,
+  },
+  {
+    label: "有效状态", model: "validState", type: "select", placeholder: "请选择状态", options: valid_status,
+  },
+  {
+    label: "生效时间", model: "effectiveTime", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
+    onChange: (value: any) => {
+      console.log(value)
+      formInline.effectiveTime = value;
+    }
+  },
+  {
+    label: "失效时间", model: "failureTime", type: "date", dateType: "datetimerange", startplaceholder: "开始时间", endplaceholder: "结束时间",
+    onChange: (value: any) => {
+      formInline.failureTime = value;
+    }
+  },
+]);
+
+//费用数据查询
+function findpage() {
+  api.agreementApi.queryByFeePage({ pages: pageInfo.value.pageNum, size: pageInfo.value.pageSize, ...formInline }).then((res: any) => {
+    if (res.code == '200') {
+      tableData.value = res.data.records;
+      pageInfo.value.pageNum = res.data.current;
+      pageInfo.value.pageSize = res.data.size;
+      pageInfo.value.total = res.data.total;
+      if (res.data.records[0].approved == '0') {
+        pendingReviewlength.value = res.data.total;
+      } else {
+        reviewRejectedlength.value = res.data.total;
+      }
+    } else {
+    }
+  });
+}
+//协议列表查询
+function agreement() {
+  api.agreementApi.agreementList({ pages: pageInfo.value.pageNum, size: pageInfo.value.pageSize, searchValue: agreementQueryName.value }).then((res: any) => {
+    if (res.code == '200') {
+      agreementList.value = res.data.records;
+    } else {
+    }
+  });
+}
+const columns = [
+  {
+    prop: "agreementAbbreviation", label: "协议信息", width: '300',
+    formatter: (row: any) => {
+      return `${row.agreementCode}\n${row.agreementAbbreviation}`
+    }
+  },
+  {
+    prop: "ruleDescription", label: "承保规则", width: '500',
+  },
+  { prop: "productName", label: "险种", width: '120', },
+  {
+    prop: "costRules", label: "费用规则", width: '500',
+  },
+  {
+    prop: "isEnabled", label: "费用状态", width: '100', component: "Tag",
+    formatter: (row: any) => {
+      let name = getDict('is_enable').find(val => val.value == row.isEnabled).label
+      if (name) {
+        return { type: 'primary', text: name };
+      }
+    }
+  },
+  {
+    prop: "approved", label: "审核状态", width: '120', component: "Tag",
+    formatter: (row: any) => {
+      let name = getDict('audit_status').find(val => val.value == row.approved).label
+      if (name) {
+        return { type: 'warning', text: name };
+      }
+    }
+  },
+  { prop: "effectiveTime", label: "生效时间", width: '200' },
+  { prop: "failureTime", label: "失效时间", width: '200' },
+  {
+    prop: "ruleConditions", label: "交强费用", width: '300', formatter: (row: any) => {
+      let info = row.ruleConditions.find((val: any) => val.costType == '交强险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n加投:${info.addThrow.toFixed(2)}% 手续费:${info.commission.toFixed(2)}%`
+      } else {
+        return '-';
+      }
+    }
+  },
+  {
+    prop: "ruleConditions", label: "商业费用", width: '300', formatter: (row: any) => {
+      let info = row.ruleConditions.find((val: any) => val.costType == '商业险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n加投:${info.addThrow.toFixed(2)}% 手续费:${info.commission.toFixed(2)}%`
+      } else {
+        return '-';
+      }
+    }
+  },
+  {
+    prop: "ruleConditions", label: "驾意险费用", width: '300', formatter: (row: any) => {
+      let info = row.ruleConditions.find((val: any) => val.costType == '驾意险');
+      if (info) {
+        return `入口:${info.inlet.toFixed(2)}% 出口:${info.export.toFixed(2)}%\n加投:${info.addThrow.toFixed(2)}% 手续费:${info.commission.toFixed(2)}%`
+      } else {
+        return '-';
+      }
+    }
+  },
+];
+//分页事件
+function getList(item: PageInfo) {
+  pageInfo.value.pageNum = item.pageNum;
+  pageInfo.value.pageSize = item.pageSize;
+  findpage();
+
+};
+// 审核
+const agreemenUpdate = async (item: any) => {
+  ruleFeeHeaderTitle.value = item.productName;
+  AgreementInfo.value = { agreementCode: item.agreementCode, agreementTitle: item.agreementAbbreviation };
+  ruleInfo.value = { ruleDescription: item.ruleDescription };
+  await regionLicenseRegion('0');//车牌地区
+  await regionLicenseNumber('14');//车牌号
+  await api.agreementApi.AgreementFeeById(item.costId).then((res: any) => {
+    if (res.code == '200') {
+      res.data.ruleConditions = processArray(res.data.ruleConditions);
+      costitemEditInfo.value = res.data;
+      ruleFeeEditVisible.value = true;
+    } else {
+    }
+  });
+}
+//详情
+const ruleFeeEditSave = (data: object) => {
+  console.log()
+  api.agreementApi.AgreementFeeupdate(data).then((res: any) => {
+    if (res.code == '200') {
+      ElMessage({
+        type: 'success',
+        message: res.msg,
+        plain: true,
+      })
+      ruleFeeEditVisible.value = false;
+      findpage();
+    } else {
+    }
+  });
+}
+//添加车牌和车牌地区
+const processArray = (array: any[]) => {
+  return array.map((val) => {
+    switch (val.attrType) {
+      case 'inputNumber':
+      case 'datetime':
+        if (!val.operator) {
+          val.operator = '1'; // 设置默认值
+        }
+        break;
+      default:
+        break;
+    }
+    if (val.attrCode == 'LicenseNo') {
+      val.dictLabal = licensePlateNumber.value;
+    }
+    if (val.attrCode == 'LicenseArea') {
+      val.dictLabal = licensePlateRegion.value;
+    }
+    return val;
+  });
+};
+const licensePlateRegion = ref();//车牌地区
+const licensePlateNumber = ref();//车牌号
+const regionLicenseRegion = (value: string) => {
+  api.agreementApi.getAreaLicense(value).then((res: any) => {
+    if (res.code == '200') {
+      let data: any = [];
+      res.data.map((val: any) => {
+        data.push({
+          code: val.areaNumber,
+          name: val.license,
+        })
+        return val;
+      })
+      licensePlateRegion.value = data;
+    } else {
+    }
+  });
+}
+const regionLicenseNumber = (value: string) => {
+  api.agreementApi.getAreaLicense(value).then((res: any) => {
+    if (res.code == '200') {
+      let data: any = [];
+      res.data.map((val: any) => {
+        data.push({
+          code: val.areaNumber,
+          name: val.license,
+        })
+        return val;
+      })
+      licensePlateNumber.value = data;
+    } else {
+    }
+  });
+}
+//多选事件
+const selectionChange = (val: any) => {
+  console.log(val)
+  sysUpAndDownList.value = val;
+}
+
+//批量审核
+const batchaudit = () => {
+  ElMessageBox.confirm(
+    '确定审核通过该费用吗?',
+    '审核通过',
+    {
+      confirmButtonText: '确定',
+      type: 'info',
+      center: true,
+      confirmButtonClass: 'el-button--primary',
+    }
+  )
+    .then(() => {
+      auditSuccess(sysUpAndDownList.value)
+    })
+}
+//批量驳回
+const batchrejected = () => {
+  ElMessageBox.prompt('', '审核不通过', {
+    confirmButtonText: '确定',
+    type: 'warning',
+    center: true,
+    inputType: "textarea",
+    inputPlaceholder: "请输入不通过原因",
+    inputPattern: /^[\u4e00-\u9fa5,。!?、;:“”‘’《》【】()——]+$/,
+    inputErrorMessage: '请输入中文',
+  })
+    .then(({ value }) => {
+      auditFailed(sysUpAndDownList.value, value)
+    })
+}
+//单一审核回调
+const auditOperation=(automatic:any,id:any)=>{
+  auditSuccess([id],automatic)
+}
+//单一驳回回调
+const rejectOperation=(automatic:any,id:any,value:any)=>{
+  auditFailed([id], value,automatic)
+}
+const agreementQuery = () => {
+  findpage();
+}
+//审核不通过
+const auditFailed = async (list: string[], value: string,automatic?:boolean) => {
+  await api.agreementApi.auditFailed({ids:list, reason:value,automatic:automatic}).then((res: any) => {
+    if (res.code == '200') {
+      findpage();
+      ElMessage({
+        type: 'success',
+        message: res.msg,
+        plain: true,
+      })
+      ruleFeeEditVisible.value=false;
+      if(res.data){
+        let info=tableData.value.find((val:any)=>val.costId==res.data);
+        agreemenUpdate(info)
+      }
+    }
+  });
+}
+// 审核通过
+const auditSuccess = async (list: string[],automatic?:boolean) => {
+  await api.agreementApi.auditSuccess({ ids: list,automatic:automatic}).then((res: any) => {
+    if (res.code == '200') {
+      findpage();
+      ElMessage({
+        type: 'success',
+        message: res.msg,
+        plain: true,
+      })
+      ruleFeeEditVisible.value=false;
+      if(res.data){
+        let info=tableData.value.find((val:any)=>val.costId==res.data);
+        agreemenUpdate(info)
+      }
+    }
+  });
+}
+const resetForm = () => {
+  formInline.agreement = '';//协议信息
+  formInline.productId = "";//归属
+  formInline.rulesName = '';//保险公司id
+  formInline.costRules = '';//协议类型
+  formInline.agreementStatus = "";//有效状态
+  formInline.auditStatus = "";//协议状态
+  formInline.validState = "";
+  formInline.effectiveTime = [];
+  formInline.failureTime = [];
+  findpage();
+}
+const getDeptTree = () => {
+  api.institutionApi.institutionList({}).then((res: any) => {
+    if (res.code == '200') {
+      deptOptions.value = res.data;
+    } else {
+    }
+  });
+}
+//选择协议弹窗
+const ruleFeeEditVisible = ref(false);//编辑弹窗
+const ruleFeeHeaderTitle = ref();//编辑弹窗title
+const costitemEditInfo = ref();//编辑对象
+const AgreementInfo = ref();//协议对象
+const ruleInfo = ref();//规则对象
+
+const handleClick = (pane: any) => {
+  if (pane.props.name == 'pendingReview') {
+    formInline.auditStatus = '0';
+    findpage()
+  } else {
+    formInline.auditStatus = '2';
+    findpage();
+  }
+}
+
+</script>
+
+<style lang="scss" scoped>
+.demo-form-inline .el-input {
+  --el-input-width: 220px;
+}
+
+.demo-form-inline .el-select {
+  --el-select-width: 220px;
+}
+
+:deep(.el-dropdown-link) {
+  display: flex;
+  align-items: center;
+  margin-left: 15px;
+  color: var(--el-color-primary);
+  cursor: pointer;
+}
+
+.el-inputs {
+  width: 100% !important;
+}
+
+.Selection {
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+
+  .agreement {
+    width: 40%;
+    padding: 15px;
+    border-right: 1px solid #dcdfe6;
+
+    .agreementItem {
+      padding: 10px;
+      border-radius: 5px;
+
+      &:hover {
+        background: #f2f2f2;
+      }
+    }
+  }
+
+  .active {
+    color: #1890ff;
+    background: #f2f2f2;
+  }
+
+  .rule {
+    width: 60%;
+    padding: 15px;
+
+    .white-space {
+      display: inline-block;
+      margin-bottom: 10px;
+      white-space: normal;
+    }
+  }
+}
+</style>