Bläddra i källkod

保险公司功能开发

caiyuqin 11 månader sedan
förälder
incheckning
8b65f365af

+ 4 - 1
src/api/index.ts

@@ -30,6 +30,7 @@ import additionalApi from '@/api/modules/additional.ts'
 import logApi from '@/api/modules/log.ts'
 
 import insurancePolicyApi from '@/api/modules/insurancePolicy.ts'
+import manageApi from '@/api/modules/consoleManage.ts'
 
 const axiosInstance:ApiInstance = axios.create({
   baseURL: (import.meta.env.DEV && import.meta.env.VITE_OPEN_PROXY === 'true') ? '/proxy/' : import.meta.env.VITE_APP_API_BASEURL,
@@ -128,6 +129,8 @@ const api = {
   projectApi: projectApi(axiosInstance),
   additionalApi: additionalApi(axiosInstance),
   logApi: logApi(axiosInstance),
-  insurancePolicyApi: insurancePolicyApi(axiosInstance)
+  insurancePolicyApi: insurancePolicyApi(axiosInstance),
+  manageApi: manageApi(axiosInstance),
+  
 }
 export default api

+ 14 - 0
src/api/modules/consoleManage.ts

@@ -0,0 +1,14 @@
+import { ApiInstance } from '../type'
+
+
+const manageApi = (axiosInstance: ApiInstance) => ({
+    getSearchConfigurationList: (params: any) => axiosInstance.get('/console/searchConfiguration/getSearchConfigurationList', {params}),//查询统一筛选条件列表
+    getSearchDefaultList: (params: any) => axiosInstance.get('/console/searchConfiguration/getSearchDefaultList', {params}),//查询页面默认筛选条件列表
+    getCompanyListByCompanyId: (params: any) => axiosInstance.get('/console/searchConfiguration/getPartnerCompanyListByCompanyId',{params}),//通过保险公司id查询合作公司的三级列表
+    getTaskMessageNoReadCount: (params: any) => axiosInstance.get('/console/task/getTaskMessageNoReadCount',{params}),//1.查看用户的未读导出任务消息
+    getPageTaskList: (params: any) => axiosInstance.post('/console/task/getPageTaskList',params),//用户的导出任务分页列表
+    updateReadStatus: (params: any) => axiosInstance.get('/console/task/updateReadStatus',{params}),//更新导出未读任务为已读
+
+  })
+
+export default manageApi

+ 9 - 0
src/api/types/agreementTypes.ts

@@ -212,3 +212,12 @@ export type agreementDeleteRequest = {
   [property: string]: any;
 }
 
+/**
+ * 分页
+ */
+export type PageInfo= {
+  pageNum: number;
+  pageSize: number;
+  sizes: number[];
+  total: number;
+}

+ 6 - 0
src/api/types/page.ts

@@ -0,0 +1,6 @@
+export interface PageInfo {
+  pageNum: number;
+  pageSize: number;
+  sizes: number[];
+  total: number;
+}

BIN
src/assets/images/download.png


BIN
src/assets/images/message.png


+ 162 - 0
src/layouts/components/Topbar/Toolbar/downLoad/downLoadList.vue

@@ -0,0 +1,162 @@
+<script setup lang="ts">
+import useSettingsStore from "@/store/modules/settings";
+import doIcon from "@/assets/images/download.png";
+import api from "@/api";
+defineOptions({
+  name: "message",
+});
+const emits = defineEmits(["close"]);
+const props = defineProps({
+  show: {
+    type: Boolean,
+    default: false,
+  },
+});
+
+onMounted(() => {
+  initDefaultList();
+});
+
+const arrColor = ["#FF4545", "#666666", "#0083FF"]; //任务状态 0.失败 1 进行中  2. 完成
+const startsList = [
+  {
+    color: "#FF4545",
+    text: "下载失败",
+  },
+  {
+    color: "#666666",
+    text: "下载中...",
+  },
+  {
+    color: "#0083FF",
+    text: "下载资料",
+  },
+];
+
+const finished = ref(false);
+const params = ref({
+  pages: 1,
+  size: 10,
+  uploadUserId: JSON.parse(localStorage.getItem("userInfo")).username,
+});
+const taskList = ref([]);
+const initDefaultList = async () => {
+  const { data } = await api.manageApi.getPageTaskList(params.value);
+  const dataList = data.records;
+  dataList.forEach((item) => {
+    taskList.value.push(item);
+  });
+  params.value.pages++;
+  if (dataList.length < params.value.size) {
+    // 数据全部加载完成
+    finished.value = true;
+  }
+};
+
+const load = () => {
+  if (!finished.value) {
+    params.value.pages++;
+    initDefaultList();
+  }
+};
+
+const handleClose = () => {
+  emits("close");
+};
+// 暴露给父组件的方法
+defineExpose({
+  initDefaultList,
+});
+</script>
+
+<template>
+  <div class='drawer-box'>
+    <el-drawer v-model="props.show" direction="rtl" :before-close="handleClose">
+      <template #header>
+        <div class='header-title'>任务中心</div>
+      </template>
+      <div class='content'>
+        <div class='content-tip'>
+          <el-icon>
+            <warning color="#FAA21E" />
+          </el-icon>
+          <div class='tit'>系统仅保留7天内的记录</div>
+        </div>
+
+        <div v-infinite-scroll="load" :infinite-scroll-immediate='false'>
+          <div class='list' v-for="(item,index) in taskList" :key="index">
+            <div>
+              <div>{{item.taskName}}</div>
+              <div class='time'>导出时间:{{item.uploadDate}}</div>
+            </div>
+            <div class='flex items'>
+              <el-icon v-if='item.taskStatus==2'>
+                <download color='#0083FF' />
+              </el-icon>
+              <el-icon v-if='item.taskStatus==0'>
+                <download color='#FF4545' />
+              </el-icon>
+              <ElImage v-if='item.taskStatus==1' :src="doIcon" :style="`width:16px;height:16px;`" fit="fill" />
+              <div class='text' :style='{color:startsList[item.taskStatus].color}'> {{startsList[item.taskStatus].text}}
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </el-drawer>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.drawer-box {
+  .header-title {
+    color: #333;
+    font-weight: 500;
+    font-size: 20px;
+    padding-bottom: 18px;
+  }
+  :deep(.el-drawer__header) {
+    border-bottom: 1px solid #e5e5e5;
+    margin-bottom: 0;
+  }
+
+  .content {
+    color: #333333;
+    font-size: 14px;
+    .content-tip {
+      background: #fffaef;
+      border-radius: 6px 6px 6px 6px;
+      border: 1px solid #faa21e;
+      padding: 16px 24px;
+      display: flex;
+      align-items: center;
+      margin-bottom: 24px;
+    }
+    .tit {
+      color: #333333;
+      font-size: 16px;
+      margin-left: 16px;
+    }
+  }
+  .list {
+    padding: 16px 24px;
+    box-sizing: border-box;
+    border-radius: 6px 6px 6px 6px;
+    border: 1px solid #eeeeee;
+    margin-bottom: 20px;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    .items {
+      align-items: center;
+    }
+    .text {
+      margin-left: 5px;
+    }
+    .time {
+      color: #666666;
+      margin-top: 8px;
+    }
+  }
+}
+</style>

+ 87 - 0
src/layouts/components/Topbar/Toolbar/downLoad/index.vue

@@ -0,0 +1,87 @@
+<script setup lang="ts">
+import useSettingsStore from "@/store/modules/settings";
+import message from "@/assets/images/message.png";
+import DownLoadList from "./downLoadList.vue";
+import api from "@/api";
+import useUserStore from "@/store/modules/message";
+
+const userStore = useUserStore();
+defineOptions({
+  name: "message",
+});
+
+onMounted(() => {
+  initDefaultList();
+});
+
+//查询数据
+const number = ref();
+const phone = JSON.parse(localStorage.getItem("userInfo")).username;
+const initDefaultList = async () => {
+  const { data } = await api.manageApi.getTaskMessageNoReadCount({
+    userId: phone,
+  });
+  number.value = data;
+};
+
+const settingsStore = useSettingsStore();
+const show = ref(false);
+const download = async () => {
+  const { data } = await api.manageApi.updateReadStatus({
+    userId: phone,
+  });
+  show.value = true;
+};
+
+const downLoadRef = ref();
+const isVisible=ref(false)
+watch(
+  () => userStore.count,
+  () => {
+    isVisible.value=true
+    show.value = true;
+    downLoadRef.value?.initDefaultList();
+  }
+);
+</script>
+
+<template>
+  <span v-if="settingsStore.mode === 'pc'" id="navbarTarget" class="flex-center cursor-pointer px-2 py-1 download-box" @click="download">
+    <ElImage :src="message" :style="`width:15px;height:15px;`" fit="fill" />
+    <div v-if='number' class='message-icon'></div>
+  </span>
+  <DownLoadList :show='show' @close='show=false' ref='downLoadRef'></DownLoadList>
+</template>
+
+<style scoped lang="scss">
+.download-box {
+  position: relative;
+  .message-icon {
+    position: absolute;
+    right: 5px;
+    top: 2px;
+    width: 6px;
+    height: 6px;
+    border-radius: 50%;
+    background: #f5222d;
+  }
+
+  /* 过渡动画样式 */
+  .slide-up-enter-from,
+  .slide-up-leave-to {
+    opacity: 0;
+    transform: translateY(100vh); /* 从视口底部开始 */
+  }
+
+  .slide-up-enter-active,
+  .slide-up-leave-active {
+    transition: all 0.8s cubic-bezier(0.25, 0.8, 0.25, 1); /* 平滑的动画曲线 */
+  }
+
+  .slide-up-enter-to,
+  .slide-up-leave-from {
+    opacity: 1;
+    transform: translateY(0); /* 移动到最终位置 */
+  }
+}
+</style>

+ 2 - 0
src/layouts/components/Topbar/Toolbar/rightSide.vue

@@ -4,6 +4,7 @@ import useUserStore from '@/store/modules/user'
 import eventBus from '@/utils/eventBus'
 import ColorScheme from './ColorScheme/index.vue'
 import Fullscreen from './Fullscreen/index.vue'
+import DownLoad from './downLoad/index.vue'
 import NavSearch from './NavSearch/index.vue'
 import PageReload from './PageReload/index.vue'
 import {useRouter} from "vue-router"
@@ -27,6 +28,7 @@ watch(() => userStore.avatar, () => {
 <template>
   <div class="flex items-center">
     <!-- <NavSearch v-if="settingsStore.settings.toolbar.navSearch" /> -->
+    <DownLoad v-if="settingsStore.settings.toolbar.fullscreen" />
     <Fullscreen v-if="settingsStore.settings.toolbar.fullscreen" />
     <PageReload v-if="settingsStore.settings.toolbar.pageReload" />
     <ColorScheme v-if="settingsStore.settings.toolbar.colorScheme" />

+ 9 - 0
src/store/modules/message.ts

@@ -0,0 +1,9 @@
+
+
+const useTabbarStore = defineStore('message',()=>{
+    return{
+      count:0
+    }
+})
+
+export default useTabbarStore

+ 198 - 98
src/views/consoleManage/businessDataManage/companyDataManage/companyDataManageDetail.vue

@@ -1,117 +1,217 @@
 <template>
-  <div class="logDetail">
-    <el-descriptions :column="2">
-      <template #title>
-        <div class="title">
-          <div class="icon">
-            <el-icon><List /></el-icon>
-          </div>
-          <p>{{ detailData?.operationContent }} 保险公司</p>
-        </div>
-      </template>
-      <el-descriptions-item label="操作功能:" label-align="right" align="left" label-width="100">{{ detailData?.moduleName }}</el-descriptions-item>
-      <el-descriptions-item label="操作类型:" label-align="right" align="left" label-width="100">{{ detailData?.operatorName }}</el-descriptions-item>
-      <el-descriptions-item label="操作人:" label-align="right" align="left" label-width="100">{{ detailData?.createBy }}</el-descriptions-item>
-      <el-descriptions-item label="操作时间:" label-align="right" align="left" label-width="100">{{ detailData?.createTime }}</el-descriptions-item>
-    </el-descriptions>
-    <el-row :gutter="20" class="content">
-      <el-col :span="11">
-        <p>变更前</p>
-        <div class="list">
-          <el-row class="list-item" :gutter="20" v-for="item in detailData?.compareResultList" :key="item">
-            <el-col :span="6">{{ item.name }}</el-col>
-            <el-col :span="18" style="color: #606266">{{ item.fieldContent }}</el-col>
-          </el-row>
-        </div>
-      </el-col>
-      <el-divider direction="vertical" style="height: 100%"></el-divider>
-      <el-col :span="11">
-        <p>变更后</p>
-        <div class="list">
-          <el-row class="list-item" :gutter="20" v-for="item in detailData?.compareResultList" :key="item">
-            <el-col :span="6">{{ item.name }}</el-col>
-            <el-col :span="18" style="color: #606266">{{ item.newFieldContent }}</el-col>
-          </el-row>
-        </div>
-      </el-col>
-    </el-row>
+  <div class="log">
+    <div class='btn-box'>
+      <el-button type="primary" plain class='query-btn'
+        @click='dialogShow'>{{selectedKeys.length?`已选${selectedKeys.length}项`:'筛选条件'}}</el-button>
+      <div class='query-btn'>
+        <DowButton @endAnim='downloadFile'></DowButton>
+      </div>
+    </div>
+    <QueryForm :option="listOption" @query='query' @delSelect='delSelect' ref='queryFormRef'></QueryForm>
+
+    <!-- 表格 -->
+    <ComplexTable :tableData="tableData" :showSelect='false' :columns="listOption.columns" :showIndex="false"
+      :columnwidth="120" :pageInfo="pageInfo" @getList="getList" :showOperation="false">
+    </ComplexTable>
+
+    <FilterDialog :show='isShow' @close='isShow=false' @sure='filterSure' ref='filterDialogRef' @selectedKeys='selected'
+      routerKey='companyDataManageDetail'>
+    </FilterDialog>
   </div>
 </template>
 
 <script setup lang="ts">
-import api from '@/api'
-import { useRoute, useRouter } from 'vue-router'
+import { useRouter } from "vue-router";
+import api from "@/api";
 import { ElMessage } from "element-plus";
+import QueryForm from "../../components/queryForm.vue";
+import FilterDialog from "../../components/filterDialog.vue";
+import DowButton from "../../components/button.vue";
+import useUserStore from "@/store/modules/message";
+import PageInfo from "@/api/types/agreementTypes";
+
+const router = useRouter();
+const userStore = useUserStore();
+const isShow = ref(false);
+
+const pageInfo = ref({
+  pageNum: 1,
+  pageSize: 20,
+  sizes: [10, 20, 30, 40, 50],
+  total: 0,
+});
+const listOption = reactive({
+  rowKey: "companyId",
+  //查询
+  queryFormFields: [],
+  // 表格列
+  columns: [
+    {
+      prop: "date",
+      label: "保险公司",
+      width: "200",
+    },
+    {
+      prop: "name",
+      label: "合作保险公司",
+      width: "300",
+    },
+    {
+      prop: "address",
+      label: "订单",
+      width: "120",
+    },
+    {
+      prop: "tag",
+      label: "车牌号",
+      width: "180",
+    },
+    {
+      prop: "tag",
+      label: "订单类型",
+      width: "180",
+    },
+    {
+      prop: "tag",
+      label: "险种",
+      width: "180",
+    },
+    {
+      prop: "tag",
+      label: "保费",
+      width: "180",
+      align: "right",
+      sortable: "default",
+    },
+    {
+      prop: "tag",
+      label: "录单时间",
+      width: "180",
+    },
+    {
+      prop: "tag",
+      label: "签单时间",
+      width: "180",
+    },
+  ],
+});
+const tableData = ref([
+  {
+    date: "2016-05-02",
+    name: "1222",
+    address: "123.25",
+    tag: "3222",
+  },
+  {
+    date: "2016-05-02",
+    name: "3222",
+    address: "422.352",
+    tag: "2225",
+  },
+]);
+const selectedKeys = ref([]);
+const selected = function (val) {
+  selectedKeys.value = val;
+};
+
+//查询
+const query = (item) => {
+  console.log(item);
+};
+
+//查询数据
+const phone = JSON.parse(localStorage.getItem("userInfo")).username;
+
+//获取默认选择数据
+const defaultList = ref();
+const pageHiddenList = ref([]); //页面不显示的数据
+const initDefaultList = async () => {
+  const { data } = await api.manageApi.getSearchDefaultList({
+    routerKey: "companyDataManageDetail",
+    userId: phone,
+  });
+  listOption.queryFormFields = data.filter((e) => e.showFlag);
+
+  pageHiddenList.value = data.filter((e) => !e.showFlag);
+  defaultList.value = data.map((e) => e.id);
+  selectedKeys.value = defaultList.value;
+  queryFormRef.value?.initDefaultSaveForm();
+};
+
+//删除
+const filterDialogRef = ref();
+const delSelect = (id) => {
+  listOption.queryFormFields = listOption.queryFormFields.filter(
+    (item) => item.id != id
+  );
+  filterDialogRef.value.initList(
+    [...listOption.queryFormFields, ...pageHiddenList.value],
+    defaultList.value
+  );
+};
+
+//打开dialogShow
+const dialogShow = function () {
+  isShow.value = true;
+  filterDialogRef.value.initList(
+    [...listOption.queryFormFields, ...pageHiddenList.value],
+    defaultList.value
+  );
+};
 
-const myRoute = useRoute()
-const myRouter = useRouter()
-
-let detailData = ref(undefined)
-
-const initDetail = () => {
-  api.logApi.selectById(myRoute.query.id).then((res: any) => {
-    if(res.code == 200) {
-      detailData.value = res.data
-    } else {
-      ElMessage({
-        message: res.msg,
-        type: 'warning'
-      })
-    }
-  })
+//确定
+const queryFormRef = ref();
+const filterSure = (item, index) => {
+  isShow.value = false;
+  const secondGroupIds = item.list.map((item) => item.id);
+  const oldList = listOption.queryFormFields.filter((item) =>
+    secondGroupIds.includes(item.id)
+  );
+  const firstGroupIds = listOption.queryFormFields.map((item) => item.id);
+  let newList = item.list.filter((item) => !firstGroupIds.includes(item.id));
+
+  //过滤掉默认不显示的数据
+  const hiddenList = new Set(pageHiddenList.value.map((item) => item.id));
+  const filterList = newList.filter((item) => !hiddenList.has(item.id));
+
+  listOption.queryFormFields = [...oldList, ...filterList];
+  queryFormRef.value?.initDefaultSaveForm();
+  selectedKeys.value = item.list.filter((item) => item.id);
+};
+
+const isVisible = ref(false);
+const downloadFile = () => {
+  isVisible.value = true;
+  userStore.count++;
+};
+
+//分页事件
+function getList(item: PageInfo) {
+  pageInfo.value.pageNum = item.pageNum;
+  pageInfo.value.pageSize = item.pageSize;
 }
 
 onMounted(() => {
-  initDetail()
-})
-
+  initDefaultList();
+});
 </script>
 
 <style scoped lang="scss">
-.logDetail{
-  padding: 24px;
-  background: #FFFFFF;
+.log {
   width: 100%;
   height: calc(100vh - 120px);
-  .title{
-    display: flex;
-    align-items: center;
-    justify-content: flex-start;
-    .icon{
-      width: 30px;
-      height: 30px;
-      border-radius: 50%;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      background: #1A85FA;
-      color: #FFFFFF;
-      font-size: 20px;
-      margin-right: 10px;
-    }
-  }
-  .content{
-    height: calc(100% - 120px);
-    overflow: hidden;
-    p{
-      text-align: center;
-      background: #F0F0F0;
-      margin: 0;
-      padding: 16px 0;
-    }
-    .list{
-      height: calc(100% - 80px);
-      overflow-y: auto;
-      overflow-x: hidden;
-      .list-item{
-        margin: 14px 0;
-        padding: 0 20px;
-        display: flex;
-      }
-    }
+  background: #ffffff;
+  padding: 24px;
+  overflow-y: auto;
+  .query-btn {
+    margin-left: 20px;
   }
-  :deep(.el-descriptions) {
-    width: 50%;
+  .btn-box {
+    padding-bottom: 15px;
+    margin-bottom: 24px;
+    border-bottom: 1px solid #eeeeee;
+    display: flex;
+    justify-content: flex-end;
   }
 }
 </style>

+ 210 - 140
src/views/consoleManage/businessDataManage/companyDataManage/index.vue

@@ -1,169 +1,239 @@
 <template>
   <div class="log">
-    <el-form label-width="100" label-position="left" :model="form">
-      <el-row :gutter="20">
-        <el-col :span="8">
-          <el-form-item label="操作人">
-            <el-input v-model="form.operator" placeholder="请输入操作人姓名查找"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="操作时间">
-            <el-date-picker
-              v-model="form.operatingTime"
-              type="daterange"
-              range-separator="至"
-              start-placeholder="开始时间"
-              end-placeholder="结束时间"
-              format="YYYY-MM-DD"
-              value-format="YYYY-MM-DD"
-              @change="timeChange"
-            />
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="操作功能">
-            <el-select v-model="form.function" placeholder="请选择">
-              <el-option label="工能1" value="1" key="1"></el-option>
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="操作内容">
-            <el-input v-model="form.content" placeholder="请输入"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :span="16" style="display: flex; align-items: center; justify-content: flex-end">
-          <el-button type="primary" @click="search">查询</el-button>
-          <el-button plain type="primary" @click="reset">重置</el-button>
-        </el-col>
-      </el-row>
-    </el-form>
-    <el-table
-      :data="tableData"
-      height="600"
-      style="margin-top: 24px"
-    >
-      <el-table-column label="操作人" prop="createBy" width="200"></el-table-column  >
-      <el-table-column label="操作时间" prop="createTime" width="240"></el-table-column>
-      <el-table-column label="操作功能" prop="moduleName"></el-table-column>
-      <el-table-column label="操作内容" prop="operationContent"></el-table-column>
-      <el-table-column label="类型" prop="operatorName" width="150"></el-table-column>
-      <el-table-column label="操作" width="150">
-        <template #default="scope">
-          <el-button link type="primary" @click="detail(scope.row)">查看详情</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    <div class="pagination">
-      <el-pagination
-        v-model:current-page="pages"
-        v-model:page-size="size"
-        :page-sizes="[10, 20, 30, 40]"
-        layout="total, sizes, prev, pager, next, jumper"
-        :total="total"
-        @size-change="handleSizeChange"
-        @current-change="handleCurrentChange"
-      ></el-pagination>
+    <div class='btn-box'>
+      <el-button type="primary" plain class='query-btn'
+        @click='dialogShow'>{{selectedKeys.length?`已选${selectedKeys.length}项`:'筛选条件'}}</el-button>
+      <div class='query-btn'>
+        <DowButton @endAnim='downloadFile'></DowButton>
+      </div>
     </div>
+    <QueryForm :option="listOption" @query='query' @delSelect='delSelect' ref='queryFormRef'></QueryForm>
+
+    <!-- 表格 -->
+    <ComplexTable :tableData="tableData" :showSelect='false' :columns="listOption.columns" :showIndex="false"
+      :columnwidth="120" :pageInfo="pageInfo" @getList="getList">
+      <template v-slot:operation="scope">
+        <el-button type="primary" link @click='agreementEdit(scope.operationData.id)'>明细</el-button>
+      </template>
+    </ComplexTable>
+
+    <FilterDialog :show='isShow' @close='isShow=false' @sure='filterSure' ref='filterDialogRef' @selectedKeys='selected'
+      routerKey='companyDataManage'>
+    </FilterDialog>
   </div>
 </template>
 
 <script setup lang="ts">
-import { useRouter } from 'vue-router'
-import api from '@/api'
-import {ElMessage} from "element-plus";
+import { useRouter } from "vue-router";
+import api from "@/api";
+import { ElMessage } from "element-plus";
+import QueryForm from "../../components/queryForm.vue";
+import FilterDialog from "../../components/filterDialog.vue";
+import DowButton from "../../components/button.vue";
+import useUserStore from "@/store/modules/message";
+import PageInfo from "@/api/types/agreementTypes";
 
-const myRouter = useRouter()
+const router = useRouter();
+const userStore = useUserStore();
+const isShow = ref(false);
 
-let activeName = ref('first')
-const handleClick = () => {
+const pageInfo = ref({
+  pageNum: 1,
+  pageSize: 20,
+  sizes: [10, 20, 30, 40, 50],
+  total: 0,
+});
+const listOption = reactive({
+  rowKey: "companyId",
+  //查询
+  queryFormFields: [],
+  // 表格列
+  columns: [
+    {
+      prop: "date",
+      label: "保险公司",
+      width: "200",
+    },
+    {
+      prop: "name",
+      label: "合作保险公司",
+      width: "300",
+    },
+    {
+      prop: "address",
+      label: "订单",
+      width: "120",
+      align: "right",
+      sortable: "default",
+    },
+    {
+      prop: "tag",
+      label: "保费",
+      width: "180",
+      align: "right",
+      sortable: "default",
+    },
+    {
+      prop: "tag",
+      label: "单交保费",
+      width: "180",
+      align: "right",
+      sortable: "default",
+    },
+    {
+      prop: "tag",
+      label: "单商保费",
+      width: "180",
+      align: "right",
+      sortable: "default",
+    },
+    {
+      prop: "tag",
+      label: "单三保费",
+      width: "180",
+      align: "right",
+      sortable: "default",
+    },
+    {
+      prop: "tag",
+      label: "交三保费",
+      width: "180",
+      align: "right",
+      sortable: "default",
+    },
+    {
+      prop: "tag",
+      label: "交商保费",
+      width: "180",
+      align: "right",
+      sortable: "default",
+    },
+  ],
+});
+const tableData = ref([
+  {
+    date: "2016-05-02",
+    name: "1222",
+    address: "123.25",
+    tag: "3222",
+  },
+  {
+    date: "2016-05-02",
+    name: "3222",
+    address: "422.352",
+    tag: "2225",
+  },
+]);
+const selectedKeys = ref([]);
+const selected = function (val) {
+  selectedKeys.value = val;
+};
 
-}
+//查询
+const query = (item) => {
+  console.log(item);
+};
 
-let form = ref({})
-const tableProps = ref({
-  value: "id",
-  label: "name",
-  children: "children",
-  checkStrictly: true,
-});
-let option = ref([])
-const timeChange = (val) => {
+//查询数据
+const phone = JSON.parse(localStorage.getItem("userInfo")).username;
 
-}
-// 搜索
-const search = () => {
-  pages.value = 1
-  size.value = 10
-  initData()
-}
-const reset = () => {
-  form.value = {}
-  pages.value = 1
-  size.value = 10
-  initData()
-}
+//获取默认选择数据
+const defaultList = ref();
+const pageHiddenList = ref([]); //页面不显示的数据
+const initDefaultList = async () => {
+  const { data } = await api.manageApi.getSearchDefaultList({
+    routerKey: "companyDataManage",
+    userId: phone,
+  });
+  listOption.queryFormFields = data.filter((e) => e.showFlag);
 
-// 列表
-let tableData = ref([])
-const detail = (row) => {
-  myRouter.push({
-    path: '/consoleManage/businessDataManage/companyDataManage/companyDataManageDetail',
-    query: {
-      id: row.id
-    }
-  })
-}
+  pageHiddenList.value = data.filter((e) => !e.showFlag);
+  defaultList.value = data.map((e) => e.id);
+  selectedKeys.value = defaultList.value;
+  queryFormRef.value?.initDefaultSaveForm();
+};
 
-// 分页
-let pages = ref(1)
-let size = ref(10)
-let total = ref(0)
-const handleSizeChange = (size) => {
-  size.value = size
-  initData()
-}
-const handleCurrentChange = (page) => {
-  pages.value = page
-  initData()
-}
+//删除
+const filterDialogRef = ref();
+const delSelect = (id) => {
+  listOption.queryFormFields = listOption.queryFormFields.filter(
+    (item) => item.id != id
+  );
+  filterDialogRef.value.initList(
+    [...listOption.queryFormFields, ...pageHiddenList.value],
+    defaultList.value
+  );
+};
+
+//打开dialogShow
+const dialogShow = function () {
+  isShow.value = true;
+  filterDialogRef.value.initList(
+    [...listOption.queryFormFields, ...pageHiddenList.value],
+    defaultList.value
+  );
+};
+
+//确定
+const queryFormRef = ref();
+const filterSure = (item, index) => {
+  isShow.value = false;
+  const secondGroupIds = item.list.map((item) => item.id);
+  const oldList = listOption.queryFormFields.filter((item) =>
+    secondGroupIds.includes(item.id)
+  );
+  const firstGroupIds = listOption.queryFormFields.map((item) => item.id);
+  let newList = item.list.filter((item) => !firstGroupIds.includes(item.id));
+
+  //过滤掉默认不显示的数据
+  const hiddenList = new Set(pageHiddenList.value.map((item) => item.id));
+  const filterList = newList.filter((item) => !hiddenList.has(item.id));
+
+  listOption.queryFormFields = [...oldList, ...filterList];
+  queryFormRef.value?.initDefaultSaveForm();
+  selectedKeys.value = item.list.filter((item) => item.id);
+};
 
-const initData = () => {
-  api.logApi.list({
-    pages: pages.value,
-    size: size.value,
-    ...form.value
-  }).then((res: any) => {
-    if(res.code === 200) {
-      tableData.value = res.data.records
-      total.value = res.data.total
-    } else {
-      ElMessage({
-        message: res.msg,
-        type: 'warning'
-      })
-    }
-  })
+const isVisible = ref(false);
+const downloadFile = () => {
+  isVisible.value = true;
+  userStore.count++;
+};
+
+//分页事件
+function getList(item: PageInfo) {
+  pageInfo.value.pageNum = item.pageNum;
+  pageInfo.value.pageSize = item.pageSize;
 }
 
+const agreementEdit = (id) => {
+  router.push({
+    name: "companyDataManageDetail",
+    query: {
+      id: id,
+    },
+  });
+};
 onMounted(() => {
-  initData()
-})
-
+  initDefaultList();
+});
 </script>
 
 <style scoped lang="scss">
-.log{
+.log {
   width: 100%;
   height: calc(100vh - 120px);
-  background: #FFFFFF;
+  background: #ffffff;
   padding: 24px;
   overflow-y: auto;
-  .pagination{
-    margin-top: 24px;
+  .query-btn {
+    margin-left: 20px;
+  }
+  .btn-box {
+    padding-bottom: 15px;
+    margin-bottom: 24px;
+    border-bottom: 1px solid #eeeeee;
     display: flex;
-    align-items: center;
     justify-content: flex-end;
   }
 }

+ 84 - 0
src/views/consoleManage/components/button.vue

@@ -0,0 +1,84 @@
+<template>
+  <!-- 导出按钮 -->
+  <div class='relative'>
+    <div ref='exportButton'>
+      <el-button type="primary" plain class='query-btn' @click='handleExport' :disabled="isExporting">导出</el-button>
+    </div>
+    <div ref="animationElement" class="absolute z-9999 transition-all duration-8000 ease-in-out opacity-0 "
+      style="pointer-events: none;">
+      <el-icon :size='22'>
+        <download color='#0083FF' />
+      </el-icon>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import message from "@/assets/images/message.png";
+const emits = defineEmits(["endAnim"]);
+
+const exportButton = ref(null);
+const animationElement = ref(null);
+const isExporting = ref(false);
+const iconSize = 30;
+const animationBaseStyles = computed(() => ({
+  transition: 'none',
+}));
+
+// 处理导出动画
+const handleExport = () => {
+  if (isExporting.value) return;
+  isExporting.value = true;
+  const animEl = animationElement.value;
+  const btnEl = exportButton.value;
+  resetAnimationElement(animEl);
+
+  animEl.style.position = 'fixed';
+  const btnRect = btnEl.getBoundingClientRect();
+  const initialLeft = btnRect.left + (btnRect.width / 2) - (iconSize / 2);
+  const initialTop = btnRect.top + (btnRect.height / 2) - (iconSize / 2);
+  animEl.style.left = `${initialLeft}px`;
+  animEl.style.top = `${initialTop}px`;
+  animEl.offsetHeight;
+
+  setTimeout(() => {
+    animEl.style.transition = 'opacity 0.3s ease-out';
+    animEl.style.opacity = '1';
+  }, 50);
+
+  setTimeout(() => {
+    const targetRect = document.getElementById('navbarTarget').getBoundingClientRect();
+    const targetLeft = targetRect.left + (targetRect.width / 2) - (iconSize / 2) + 6;
+    const targetTop = targetRect.top + (targetRect.height / 2) - (iconSize / 2) + 6;
+    animEl.style.transition = 'all 1.5s cubic-bezier(0.2, 0.85, 0.4, 0.95)';
+    animEl.style.left = `${targetLeft}px`;
+    animEl.style.top = `${targetTop}px`;
+    animEl.style.transform = 'scale(0.9)';
+  }, 350);
+
+  // 动画结束后处理
+  setTimeout(() => {
+    animEl.style.transition = 'all 0.3s ease';
+    animEl.style.transform = 'scale(1) translateY(-5px)';
+    setTimeout(() => {
+      animEl.style.transition = 'opacity 0.3s ease-out';
+      animEl.style.opacity = '0';
+      isExporting.value = false;
+      emits("endAnim",);
+    }, 300);
+  }, 2000);
+};
+// 重置动画
+const resetAnimationElement = (el) => {
+  el.style.position = 'absolute';
+  el.style.transition = 'none';
+  el.style.opacity = '0';
+  el.style.transform = 'scale(1)';
+  el.style.left = '0px';
+  el.style.top = '0px';
+};
+</script>
+
+<style scoped>
+</style>

+ 376 - 0
src/views/consoleManage/components/filterDialog.vue

@@ -0,0 +1,376 @@
+<template>
+  <div class="filter-dialog" v-if='props.show'>
+    <el-dialog v-model="props.show" title="选择筛选条件" @close='handleCancel'>
+      <div class='dialog-box'>
+        <el-row :gutter="10" class='dialog-cont'>
+          <el-col :span="12" class='divider'>
+            <el-input v-model="searchName" placeholder="搜索" class='search-input'></el-input>
+            <div class="insuranceLeft">
+              <el-tree ref="treeRef" :data="treeList" :props="defaultProps" show-checkbox node-key="id"
+                @check="handleCheckChange" :check-strictly="false" :default-expand-all="true"
+                :default-checked-keys="selectedKeys" :filter-node-method="handleSearchName"></el-tree>
+            </div>
+          </el-col>
+          <el-divider direction="vertical" class='divider'></el-divider>
+          <el-col :span="11" class='divider'>
+            <div class='dialog-r-title'>
+              <span>已选: {{ selectedList.length }} 项筛选条件</span>
+              <el-button link type="primary" @click="clear">清空</el-button>
+            </div>
+            <div class="selectedList">
+              <div class='dialog-r-list' v-for="(JYX, index) in selectedList" :key="JYX.id">
+                <span>{{ JYX.label }}</span>
+                <el-icon class='del-icon' v-if='!JYX.defaultFlag && !JYX.selectFlag' @click="handleDel(JYX, index)">
+                  <Close />
+                </el-icon>
+              </div>
+            </div>
+          </el-col>
+        </el-row>
+        <div class="footer">
+          <el-button plain @click="handleCancel">取消</el-button>
+          <el-button type="primary" @click="handleConfirm">确定</el-button>
+        </div>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+const props = defineProps({
+  show: {
+    type: Boolean,
+    default: false,
+  },
+  routerKey: {
+    type: String,
+    default: "",
+  },
+});
+
+const shows = ref(true);
+
+// 查找
+import api from "@/api";
+import { ElMessage } from "element-plus";
+import type { ElTree } from "element-plus";
+
+const treeRef = ref<InstanceType<typeof ElTree>>();
+const emits = defineEmits(["close", "selectedKeys", "sure"]);
+let searchName = ref("");
+watch(searchName, (val) => {
+  treeRef.value!.filter(val);
+});
+
+const handleSearchName = (value: string, data: any) => {
+  if (!value) return true;
+  return data.label.includes(value);
+};
+
+// 默认勾选的数据
+let selectedKeys = ref([]);
+
+// 数据源
+let treeList = ref([
+  // {
+  //   label: "时间",
+  //   id: 1,
+  //   inputType: "date-picker",
+  //   key: "date2",
+  //   defaultValue: "",
+  // },
+  // {
+  //   label: "签单时间",
+  //   id: 2,
+  //   inputType: "date-picker",
+  //   key: "date2",
+  //   defaultValue: "",
+  // },
+  // {
+  //   label: "录单时间",
+  //   id: 3,
+  //   inputType: "date-picker",
+  //   key: "date3",
+  //   defaultValue: "",
+  // },
+  // {
+  //   label: "保险公司",
+  //   id: 4,
+  //   inputType: "select-single",
+  //   key: "test4",
+  //   listOption: [],
+  //   defaultValue: [],
+  //   selectValue: "", //用逗号分开存储的值
+  // },
+  // {
+  //   label: "合作保险公司",
+  //   id: 5,
+  //   inputType: "select-multiple",
+  //   key: "test5",
+  //   listOption: [],
+  //   defaultValue: [],
+  //   selectValue: "", //用逗号分开存储的值
+  // },
+  // {
+  //   label: "业务员类型",
+  //   id: 6,
+  //   inputType: "select-multiple",
+  //   key: "test6",
+  //   listOption: [],
+  //   defaultValue: [],
+  //   selectValue: "", //用逗号分开存储的值
+  // },
+  // {
+  //   label: "协议类型",
+  //   id: 7,
+  //   inputType: "select-multiple",
+  //   key: "test7",
+  //   listOption: [],
+  //   defaultValue: [],
+  //   selectValue: "", //用逗号分开存储的值
+  // },
+  // {
+  //   label: "出单机构",
+  //   id: 8,
+  //   inputType: "date-tree",
+  //   key: "test8",
+  //   listOption: [],
+  //   defaultValue: [],
+  //   defaultProps: {
+  //     children: "children",
+  //     label: "label",
+  //   },
+  //   selectValue: "", //用逗号分开存储的值
+  // },
+  // {
+  //   label: "订单状态",
+  //   id: 9,
+  //   inputType: "select-single",
+  //   key: "test9",
+  //   listOption: [],
+  //   defaultValue: [],
+  //   selectValue: "", //用逗号分开存储的值
+  // },
+  // {
+  //   label: "订单类型",
+  //   id: 10,
+  //   inputType: "select-multiple",
+  //   key: "test10",
+  //   listOption: [],
+  //   defaultValue: [],
+  //   selectValue: "", //用逗号分开存储的值
+  // },
+]);
+const defaultProps = {
+  children: "children",
+  label: "label",
+  disabled: function (data) {
+    return data.defaultFlag || data.selectFlag || !data.showFlag;
+  },
+};
+const handleCheckChange = (data, row) => {
+  if (row.checkedNodes.length > 0) {
+    let list1 = row.checkedNodes.filter((a) => a.parentId == "0");
+    let list2 = row.checkedNodes.filter((a) => a.parentId != "0");
+    if (list1.length > 0) {
+      let list3 = list1.filter((a) => list2.some((b) => b.parentId == a.id));
+      selectedList.value = row.checkedNodes.filter(
+        (a) => !list3.some((b) => b.id == a.id)
+      );
+    } else {
+      selectedList.value = list2;
+    }
+    selectedList.value.forEach((item) => {
+      item.drivingIntentionId = item.id;
+    });
+  }
+};
+
+// 选择驾意险
+let selectedList = ref([]);
+const handleType = (item, index) => {
+  item.checked = !item.checked;
+  selectedList.value = [];
+  treeList.value.forEach((sub) => {
+    if (sub.checked) {
+      selectedList.value.push(sub);
+    }
+  });
+};
+
+// 删除
+const handleDel = (item, index) => {
+  selectedList.value.splice(index, 1);
+  selectedKeys.value = selectedList.value.map((a) => a.drivingIntentionId);
+  treeRef.value!.setCheckedKeys(selectedKeys.value, true);
+};
+
+// 编辑
+let editIndex = ref(0);
+const initEditData = (data, index, id) => {
+  editIndex.value = index;
+  api.projectApi
+    .treeList({
+      company: id ? id : "1738811735599380291",
+    })
+    .then((res) => {
+      if (res.code == 200) {
+        if (res.data && res.data.length > 0) {
+          res.data.forEach((item) => {
+            item.checked = false;
+            item.drivingIntentionId = item.id;
+          });
+        }
+        treeList.value = res.data;
+        if (data && data.length > 0) {
+          selectedList.value = JSON.parse(JSON.stringify(data));
+          selectedKeys.value = selectedList.value.map(
+            (a) => a.drivingIntentionId
+          );
+        }
+      } else {
+        ElMessage({
+          message: res.msg,
+          type: "warning",
+        });
+      }
+    });
+};
+
+// 取消
+const handleCancel = () => {
+  emits("close");
+};
+// 保存
+const handleConfirm = () => {
+  emits("sure", {
+    list: selectedList.value,
+    index: editIndex.value,
+  });
+};
+//赋默认值
+const defaultSelectedId = ref();
+const initDefaultSelect = function (list) {
+  if (list && list.length) {
+    let ids = getMultiLabels(list, treeList.value);
+    selectedKeys.value = ids;
+    emits("selectedKeys", selectedKeys.value);
+  }
+};
+//数据过滤
+const getMultiLabels = (selectedValues, foodList) => {
+  return selectedValues.map((targetValue) => {
+    const matchedItem = foodList.find(
+      (item) => item.label == targetValue.label
+    );
+    return matchedItem ? matchedItem.id : "";
+  });
+};
+// 清空
+const clear = () => {
+  selectedList.value = selectedList.value.filter((item) =>
+    defaultSelectedId.value.includes(item.id)
+  );
+  treeRef.value!.setCheckedKeys(defaultSelectedId.value, true);
+};
+//获取全部选择数据
+const phone = JSON.parse(localStorage.getItem("userInfo")).username;
+const initList = async (list, defaultList) => {
+  defaultSelectedId.value = defaultList;
+  if (treeList.value.length) {
+    initDefaultSelect(list);
+    selectedList.value = list || [];
+  } else {
+    const { data } = await api.manageApi.getSearchConfigurationList({
+      routerKey: props.routerKey,
+      userId: phone,
+    });
+     treeList.value = data;
+    initDefaultSelect(list);
+    selectedList.value = list || [];
+  }
+};
+
+defineExpose({
+  initEditData,
+  initList,
+});
+</script>
+
+<style scoped lang="scss">
+.filter-dialog {
+  .dialog-box {
+    height: 430px;
+    .dialog-cont {
+      height: calc(100% - 30px);
+      border: 1px solid #ccc;
+      margin: 5px;
+      border-radius: 5px;
+      padding: 5px;
+      overflow: hidden;
+    }
+    .dialog-r-title {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin: 8px 0;
+    }
+    .dialog-r-list {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin: 10px;
+    }
+    .divider {
+      height: 100%;
+    }
+    .search-input {
+      margin-bottom: 10px;
+    }
+    .del-icon {
+      cursor: pointer;
+    }
+    :deep(.el-tree-node) {
+      margin-bottom: 8px;
+    }
+  }
+}
+.insuranceLeft,
+.selectedList {
+  height: calc(100% - 42px);
+  overflow-y: auto;
+}
+.insuranceLeft {
+  width: 100%;
+  .insuranceItem {
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+    margin: 10px 0;
+    span {
+      margin-left: 10px;
+    }
+    .checkIcon {
+      width: 14px;
+      height: 14px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      border: 1px solid #ccc;
+      border-radius: 2px;
+      font-size: 10px;
+      color: #fff;
+    }
+    .active {
+      color: #fff;
+      background: #3994fb;
+      border-color: #3994fb;
+    }
+  }
+}
+.footer {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+</style>

+ 397 - 0
src/views/consoleManage/components/queryForm.vue

@@ -0,0 +1,397 @@
+
+<template>
+  <div class="form-filter">
+    <el-form label-position="left" :model="queryForm" class='form-content'>
+      <template v-for="(option, index) in option.queryFormFields" :key="index">
+        <!-- input -->
+        <el-form-item :label="option.label" class='form-input r-24 border position-box'
+          v-if="option.inputType == 'input'" @mouseenter="option.isShowDelIcon = true"
+          @mouseleave="option.isShowDelIcon = false">
+          <el-input class="input-deep input-w" v-model="queryForm.data[option.key]" :placeholder="`请输入${option.label}`"
+            clearable>
+          </el-input>
+          <template v-if='!option.defaultFlag'>
+            <view class='icon-del' @click='del(option)' v-show='option.isShowDelIcon'>
+              <el-icon>
+                <CircleCloseFilled color='#ccc' :size='30' />
+              </el-icon>
+            </view>
+          </template>
+        </el-form-item>
+
+        <!-- select -->
+        <el-form-item :label="option.label" class='form-select-single  r-24 border position-box'
+          v-if="option.inputType == 'select-single' || option.selectType=='1'" @mouseenter="option.isShowDelIcon = true"
+          @mouseleave="option.isShowDelIcon = false">
+          <el-select class='min-w ' v-model="queryForm.data[option.key]" placeholder=""
+            @change='singleChange($event,option)' clearable>
+            <el-option v-for="item in option.listOption" :key="item.value" :label="item.label" :value="item.value">
+            </el-option>
+          </el-select>
+          <template v-if='!option.defaultFlag'>
+            <view class='icon-del' @click='del(option)' v-show='option.isShowDelIcon'>
+              <el-icon>
+                <CircleCloseFilled color='#ccc' :size='30' />
+              </el-icon>
+            </view>
+          </template>
+        </el-form-item>
+
+        <!-- select 多选-->
+        <el-form-item :label="option.label" class='form-select-multiple  r-24 border position-box'
+          v-if="option.inputType == 'select-multiple' || option.selectType=='2'"
+          @mouseenter="option.isShowDelIcon = true" @mouseleave="option.isShowDelIcon = false">
+          <el-select class='min-w' multiple v-model="queryForm.data[option.key]" value-key="value" placeholder=""
+            @change='moreChange($event,option,option.listOption)' clearable>
+            <el-option v-for="item in option.listOption" :key="item.value" :label="item.label" :value="item.value">
+            </el-option>
+            <template #tag>
+              <view v-show='option.selectValue'>
+                <text v-if='option.listOption'>{{option.selectValue}}</text>
+                <text class='text-color' v-else>请选择</text>
+              </view>
+            </template>
+          </el-select>
+          <template v-if='!option.defaultFlag'>
+            <view class='icon-del' @click='del(option)' v-show='option.isShowDelIcon'>
+              <el-icon>
+                <CircleCloseFilled color='#ccc' :size='30' />
+              </el-icon>
+            </view>
+          </template>
+        </el-form-item>
+
+        <!-- 日期 -->
+        <el-form-item :label="option.label" class='form-date-picker  r-24 border position-box'
+          v-if="option.inputType == 'date-picker'" @mouseenter="option.isShowDelIcon = true"
+          @mouseleave="option.isShowDelIcon = false">
+          <el-date-picker v-model="queryForm.data[option.key]" type="daterange" unlink-panels start-placeholder="开始日期"
+            end-placeholder="结束日期" :shortcuts="shortcuts" value-format="YYYY-MM-DD">
+            <template #range-separator>
+              <view>⇀</view>
+            </template>
+          </el-date-picker>
+          <template v-if='!option.defaultFlag'>
+            <view class='icon-del' @click='del(option)' v-show='option.isShowDelIcon'>
+              <el-icon>
+                <CircleCloseFilled color='#ccc' :size='30' />
+              </el-icon>
+            </view>
+          </template>
+        </el-form-item>
+
+        <!-- 年份 -->
+        <el-form-item :label="option.label" class='form-date-picker  r-24 border position-box'
+          v-if="option.inputType == 'date-year'" @mouseenter="option.isShowDelIcon = true"
+          @mouseleave="option.isShowDelIcon = false">
+          <el-date-picker v-model="queryForm.data[option.key]" type="year" placeholder="选择年份" value-format="YYYY">
+            <template #range-separator>
+              <view>⇀</view>
+            </template>
+          </el-date-picker>
+          <template v-if='!option.defaultFlag'>
+            <view class='icon-del' @click='del(option)' v-show='option.isShowDelIcon'>
+              <el-icon>
+                <CircleCloseFilled color='#ccc' :size='30' />
+              </el-icon>
+            </view>
+          </template>
+        </el-form-item>
+
+        <!-- tree  selectValue: [], //选中的Key存储的值   listOption原始数据 -->
+        <el-form-item :label="option.label" class='form-date-tree  r-24 border position-box'
+          v-if="option.inputType == 'date-tree'" @mouseenter="option.isShowDelIcon = true"
+          @mouseleave="option.isShowDelIcon = false">
+          <el-tree-select v-model="queryForm.data[option.key]" :data="option.listOption" :render-after-expand="false"
+            :props="defaultProps" node-key="id" show-checkbox multiple
+            @check="(data,checked)=>handleCheckChange(data,checked,option,queryForm.data[option.key])">
+            <template #tag>
+              <view v-show='option.selectValue'>{{option.selectValue}}</view>
+            </template>
+          </el-tree-select>
+          <template v-if='!option.defaultFlag'>
+            <view class='icon-del' @click='del(option)' v-show='option.isShowDelIcon'>
+              <el-icon>
+                <CircleCloseFilled color='#ccc' :size='30' />
+              </el-icon>
+            </view>
+          </template>
+        </el-form-item>
+
+        <!-- 级联选择 -->
+        <el-form-item :label="option.label" class='form-date-cascader  r-24 border position-box'
+          v-if="option.inputType == 'date-cascader'" @mouseenter="option.isShowDelIcon = true"
+          @mouseleave="option.isShowDelIcon = false">
+          <el-cascader v-model="queryForm.data[option.key]" :options="option.listOption" clearable
+            :props="optionProps" />
+          <template v-if='!option.defaultFlag'>
+            <view class='icon-del' @click='del(option)' v-show='option.isShowDelIcon'>
+              <el-icon>
+                <CircleCloseFilled color='#ccc' :size='30' />
+              </el-icon>
+            </view>
+          </template>
+        </el-form-item>
+
+      </template>
+      <el-button type="primary" @click='query'>查询</el-button>
+    </el-form>
+
+  </div>
+</template>
+
+<script setup lang="ts">
+import { useRouter } from "vue-router";
+import { timestampFormat } from "@/utils/dayjs";
+import api from "@/api";
+
+const emit = defineEmits(["query", "delSelect"]);
+
+const props = defineProps({
+  option: {
+    type: Object,
+    default: () => {
+      return {
+        labelWidth: {}, // label宽度,
+      };
+    },
+  },
+});
+
+const defaultProps = {
+  children: "children",
+  label: "name",
+};
+
+const optionProps = {
+  value: "areaCode",
+  label: "areaCname",
+  children: "child",
+};
+
+const showDelete = ref(false);
+let queryForm = reactive({ data: {} });
+const shortcuts = [
+  {
+    text: "今日",
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      start.setTime(start.getTime());
+      return [start, end];
+    },
+  },
+  {
+    text: "最近7天",
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+      return [start, end];
+    },
+  },
+  {
+    text: "本月",
+    value: () => {
+      const year = new Date().getFullYear();
+      const month = new Date().getMonth() + 1;
+      const date = new Date(year, month, 0).getDate();
+
+      const end = new Date(year, month - 1, date);
+      const start = new Date(year, new Date().getMonth(), 1);
+      return [start, end];
+    },
+  },
+  {
+    text: "本年",
+    value: () => {
+      const end = new Date(new Date().getFullYear(), 11, 31);
+      const start = new Date(new Date().getFullYear(), 0, 1);
+      return [start, end];
+    },
+  },
+];
+//获取默认值
+const propsOption = props.option;
+const initDefaultSaveForm = () => {
+  let defaultSaveForm = {};
+  propsOption.queryFormFields.forEach((item) => {
+    let key = item.key;
+    let val = item.defaultValue;
+    if (item.inputType == "date-picker" && !val) {
+      const start = new Date();
+      defaultSaveForm[key] = [
+        timestampFormat(start.getTime()),
+        timestampFormat(start.getTime()),
+      ];
+    } else if (item.inputType == "date-year") {
+      const start = new Date();
+      defaultSaveForm[key] = [timestampFormat(start.getTime(), "YYYY")];
+    } else {
+      let mul = item.inputType == "select-multiple";
+      let sin = item.inputType == "select-single";
+      if (mul || sin) {
+        defaultSaveForm[key] = item.listOption ? val : "";
+      } else {
+        defaultSaveForm[key] = val;
+      }
+      if (mul) {
+        defaultSaveForm[key] = [val];
+      }
+      if (sin && item.isFirst) {
+        singleChange(0, item);
+      }
+    }
+  });
+  queryForm.data = Object.assign({}, defaultSaveForm);
+  console.log(queryForm.data);
+};
+
+//多选中发生变化
+const moreChange = (selectedValues: CheckboxValueType, item, foodList) => {
+  const foodLabels = getMultiLabels(selectedValues, foodList, "value");
+  item.selectValue = foodLabels.join(",");
+};
+
+//tree  change
+const handleCheckChange = (data, row, option, ids) => {
+  const foodLabels = getMultiLabels(ids, row.checkedNodes, "id");
+  option.selectValue = foodLabels.join(",");
+};
+
+//数据过滤
+const getMultiLabels = (selectedValues, foodList, key) => {
+  return selectedValues.map((targetValue) => {
+    const matchedItem = foodList.find((item) => item[key] === targetValue);
+    return matchedItem ? matchedItem.label || matchedItem.name : "";
+  });
+};
+
+//单选查联动数据
+const singleChange = async (val, option) => {
+  if (option.isFirst) {
+    //查询合作的保险公司数据
+    const { data } = await api.manageApi.getCompanyListByCompanyId({
+      companyId: val,
+    });
+    queryForm.data.partnerCompanyIds = "";
+    propsOption.queryFormFields.forEach((e) => {
+      if (e.key == "partnerCompanyIds") {
+        e.selectValue = "";
+        e.listOption = data;
+        e.listOption.unshift({
+          value: "0",
+          label: "全部",
+        });
+      }
+    });
+  }
+};
+
+//查询
+const query = () => {
+  emit("query", queryForm.data);
+};
+
+//删除
+const del = (option) => {
+  queryForm.data[option.key] = "";
+  emit("delSelect", option.id);
+};
+
+// 暴露给父组件的方法
+defineExpose({
+  initDefaultSaveForm,
+});
+</script>
+
+<style scoped lang="scss">
+.form-content {
+  display: flex;
+  flex-wrap: wrap;
+  .r-24 {
+    margin-right: 24px;
+  }
+  .border {
+    border-radius: 2px 2px 2px 2px;
+    border: 1px solid #e5e5e5;
+  }
+  :deep(.el-form-item__label) {
+    padding-left: 12px;
+  }
+  .min-w {
+    min-width: 200px;
+  }
+  .input-w {
+    width: 200px;
+  }
+  .position-box {
+    position: relative;
+    .icon-del {
+      position: absolute;
+      right: -8px;
+      top: -14px;
+    }
+    :deep(.el-icon) {
+      font-size: 20px;
+    }
+  }
+  .text-color {
+    color: #a3a8b3;
+  }
+}
+// input
+.form-input {
+  .input-deep {
+    :deep(.el-input__wrapper) {
+      box-shadow: 0 0 0 0px var(--el-input-border-color, var(--el-border-color))
+        inset;
+      cursor: default;
+      .el-input__inner {
+        cursor: default !important;
+      }
+    }
+  }
+}
+//select
+.form-select-single,
+.form-select-multiple {
+  :deep(.el-select__wrapper) {
+    border: none; /* 去除边框 */
+    box-shadow: none;
+  }
+}
+
+//picker
+.form-date-picker {
+  :deep(.el-date-editor.el-input__wrapper) {
+    border: none; /* 去除边框 */
+    box-shadow: none;
+    padding-left: 0;
+    padding-right: 0;
+    width: 240px;
+  }
+  :deep(.el-input__wrapper) {
+    border: none; /* 去除边框 */
+    box-shadow: none;
+  }
+  :deep(.el-date-editor .el-range__icon) {
+    display: none;
+  }
+}
+
+//tree
+.form-date-tree {
+  :deep(.el-select__wrapper) {
+    box-shadow: none;
+    min-width: 240px;
+  }
+}
+//el-cascader
+.form-date-cascader {
+  :deep(.el-cascader .el-input__wrapper) {
+    box-shadow: 0 0 0 0px var(--el-input-border-color, var(--el-border-color))
+      inset;
+  }
+}
+</style>