@dongkboy 1 год назад
Родитель
Сommit
b015ae21a2

+ 13 - 1
src/api/modules/agreement.ts

@@ -89,12 +89,24 @@ const agreementApi = (axiosInstance: ApiInstance) => ({
   //单个费用修改
   FeeupdateById: (data: any) => axiosInstance.post('/ptlAgreementCostExternal/updateById', data),
   //单个费用查询
-  FeegetById: (id: any) => axiosInstance.get('/ptlAgreementCostExternal/getById?id='+id),
+  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

+ 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"
       >
         登录

+ 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']);
 //右侧删除图标

+ 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
-          }, 
+          },
         },
       ]
-      
+
     },
-    
-    
+
+
   ],
 }
 

+ 4 - 1
src/views/externalAgreement/agreement/components/contactPersonFeeDialog.vue

@@ -2,7 +2,7 @@
 <template>
   <div>
     <el-drawer v-model="props.ruleFeeVisible" :direction="direction" :close-on-click-modal="false" size="50%"
-      @open="draweropen">
+      @open="draweropen" @close="close">
       <template #header>
         <h4>{{ props.title }}费用</h4>
       </template>
@@ -305,6 +305,9 @@ const handleStartDateChange = (value: any, index: number,) => {
 const cancel = () => {
   emits("cancel")
 }
+const close=()=>{
+  emits("cancel")
+}
 const validateContactPerson = () => {
   if (formRef.value) {
     formRef.value.validateField(['contactPerson', 'contactMobile', 'ptlAgreementId'], (valid) => {

+ 78 - 15
src/views/externalAgreement/agreement/components/contactPersonFeeDialogEdit.vue

@@ -1,18 +1,29 @@
 <!-- 模板区域 -->
 <template>
   <div>
-    <el-drawer v-model="props.ruleFeeVisible" :direction="direction" :close-on-click-modal="false" size="50%">
+    <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" style="width: 100%;"
+          <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-input v-model="contactPersonEditInfo.contactPerson"  placeholder="请输入对接人姓名" />
               </el-form-item>
             </ElCol>
             <ElCol :md="24" :lg="12">
@@ -70,7 +81,7 @@
           <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%;"
+              <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>
@@ -78,7 +89,7 @@
           </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%;"
+              <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>
@@ -86,7 +97,7 @@
           </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"
+              <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>
@@ -94,7 +105,7 @@
           </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%;"
+              <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>
@@ -102,7 +113,7 @@
           </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%;"
+              <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>
@@ -110,7 +121,7 @@
           </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%;"
+              <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>
@@ -119,10 +130,17 @@
         </el-table>
       </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(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>
@@ -131,7 +149,7 @@
 <!-- 行为区域 -->
 <script lang='ts' setup>
 import { ref, } from 'vue'
-import { DrawerProps, ComponentSize, FormInstance, FormRules, ElMessage } from 'element-plus';
+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')
@@ -139,12 +157,22 @@ const props = defineProps<{
   ruleFeeVisible: boolean,
   headerTitle?: string,
   costitemEditInfo?: any,
+  operationType?: string,//操作类型
+
 }>();
-const emits = defineEmits(["cancel", 'save']);
+const emits = defineEmits(["cancel", 'save', 'auditOperation', 'rejectOperation']);
 watch(props, () => {
   contactPersonEditInfo.value = props.costitemEditInfo;
-  console.log(contactPersonEditInfo.value)
+  //审核和驳回操作不可编辑
+  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>({
@@ -189,11 +217,14 @@ const handleStartDateChange = (value: any) => {
 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)
+      emits('save', contactPersonEditInfo.value)
     } else {
       ElMessage({
         type: 'error',
@@ -203,6 +234,26 @@ const save = async (formEl: FormInstance | undefined) => {
     }
   })
 }
+//审核驳回操作
+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>
@@ -248,6 +299,18 @@ const save = async (formEl: FormInstance | undefined) => {
   }
 }
 
+.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;
 }

+ 18 - 16
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="attributionName" placeholder="请选择" type="textarea" @click="orderAccountVisible = true" />
+              <el-input v-model="attributionName" placeholder="请选择" type="textarea"
+                @click="orderAccountVisible = true" />
             </el-form-item>
           </ElCol>
           <ElCol :md="24" :lg="12">
@@ -154,9 +155,10 @@
     </FixedActionBar>
     <!-- 选择管理人 -->
     <managerModal :managerModal="managerModalVisible" :deptOptions="deptOptions" :managerlist="managerlist"
-      @save="managerModalsave" @NodeClick="managerModalNodeClick" @query="managerModalQuery" @cancel="managerModalVisible = false" />
-      <!-- 选择出单账号 -->
-      <orderAccount :orderAccount="orderAccountVisible" @cancel="orderAccountVisible = false" @save="orderAccountSave" />
+      @save="managerModalsave" @NodeClick="managerModalNodeClick" @query="managerModalQuery"
+      @cancel="managerModalVisible = false" />
+    <!-- 选择出单账号 -->
+    <orderAccount :orderAccount="orderAccountVisible" @cancel="orderAccountVisible = false" @save="orderAccountSave" />
   </div>
 </template>
 
@@ -417,6 +419,7 @@ const company = () => {
 //选择管理人
 interface managerlist {
   id: string,
+  userId:string,
   name: string,
   deptName: string,
 }
@@ -425,15 +428,14 @@ 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;
     }
@@ -447,16 +449,16 @@ const managerModalsave = (id: string, name: string, deptName: string) => {
 
 }
 //选择出单账号
-const orderAccountVisible=ref(false);
-const attributionName=ref();
-const attributionUserAbbr=ref();
+const orderAccountVisible = ref(false);
+const attributionName = ref();
+const attributionUserAbbr = ref();
 //保存事件
-const orderAccountSave=( id: string, name: string, userAbbr:string)=>{
-  console.log(id,name,userAbbr)
+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;
+  attributionName.value = `用户名:${name}\n简称:${userAbbr}`;
+  attributionUserAbbr.value = userAbbr;
+  orderAccountVisible.value = false;
 }
 </script>
 <style lang="scss" scoped>

+ 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;
 }

+ 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;
 }

+ 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>