Browse Source

fix: 客户管理逻辑修改

hanxiaohui 4 months ago
parent
commit
ec661b74c4

+ 104 - 0
src/views/customer-manage/customer-detail/components/LinkCompany/compoents/LinkList/CardInfo.vue

@@ -0,0 +1,104 @@
+<template>
+  <div class="card-info">
+    <div class="card-item" v-for="i in 10">
+      <div class="c-i-left">
+        <div class="cil-top">
+          <div class="c-i-t1">中国大唐集团有限公司</div>
+          <img src="/@/assets/images/page-detail-layout/customer/SS_user.png" alt="" />
+          <!--          <bs-dic-tag :dicts="[]" />-->
+          <a-tag color="blue">业主单位</a-tag>
+        </div>
+
+        <div class="cil-bottom">
+          <div class="cil-item-1">
+            <bs-ellipsis-text text="法人:韩晓辉" />
+          </div>
+          <div class="cil-i-s">|</div>
+          <div class="cil-item-2">
+            <bs-ellipsis-text text="社会信用代码:91360108322555535J" />
+          </div>
+          <div class="cil-i-s">|</div>
+          <div class="cil-item-3">
+            <bs-ellipsis-text text="地址:江西省南昌经济技术开发区下区12号地址小徐区230号" />
+          </div>
+        </div>
+      </div>
+      <div class="c-i-right">
+        <div class="cir-top">韩晓辉</div>
+        <div class="cir-bottom">2025-01-01</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import {BsDicTag, BsEllipsisText} from '/@/components/BsUi/index.js';
+</script>
+
+<style lang="scss" scoped>
+  .card-info {
+    width: 100%;
+    display: flex;
+    flex-direction: column;
+    gap:20px;
+    .card-item {
+      border: 1px solid #e4e7ed;
+      border-radius: 8px;
+      padding: 10px;
+      display: flex;
+      justify-content: space-between;
+      .c-i-left {
+        display: flex;
+        flex-direction: column;
+        flex: 1;
+        gap:8px;
+        .cil-top {
+          display: flex;
+          justify-content: flex-start;
+          gap: 4px;
+        }
+        .c-i-t1 {
+          color: 1f1f1f;
+          font-size: 16px;
+          font-weight: 600;
+        }
+
+        .cil-bottom {
+          width: 100%;
+          display: flex;
+          color: #535c74;
+          font-size: 14px;
+          font-weight: 500;
+          .cil-item-1 {
+            width: 100px;
+            display: flex;
+            align-items: flex-end;
+          }
+          .cil-item-2 {
+            width: 250px;
+            display: flex;
+            align-items: flex-end;
+          }
+          .cil-item-3 {
+            width: 100px;
+            display: flex;
+            align-items: flex-end;
+          }
+          .cil-i-s {
+            margin: 0 20px;
+          }
+        }
+      }
+      .c-i-right {
+        width: 90px;
+        display: flex;
+        flex-direction: column;
+        color: #535C74;
+        font-size: 14px;
+        align-items: flex-end;
+        gap:8px;
+        justify-content: flex-end
+      }
+    }
+  }
+</style>

+ 19 - 0
src/views/customer-manage/customer-detail/components/LinkCompany/compoents/LinkList/index.vue

@@ -0,0 +1,19 @@
+<template>
+  <bs-catalog title="关联公司列表">
+    <template #content>
+      <card-info></card-info>
+    </template>
+  </bs-catalog>
+</template>
+
+<script setup>
+  import { BsCatalog } from '/@/components/BsUi/index.js';
+  import CardInfo from './CardInfo.vue';
+</script>
+
+<style scoped lang="scss">
+  .org-struct-chart {
+    width: 100%;
+    height: 100%;
+  }
+</style>

+ 283 - 0
src/views/customer-manage/customer-detail/components/LinkCompany/compoents/OrgStructChart/index.vue

@@ -0,0 +1,283 @@
+<template>
+  <div ref="containerRef" class="org-chart-container" />
+</template>
+
+<script>
+import { ref, onMounted, onBeforeUnmount } from 'vue'
+import { Graph, Node, Point } from '@antv/x6'
+
+export default {
+  name: 'OrgChart',
+  setup() {
+    const containerRef = ref(null)
+    let graph = null
+
+    // 注册节点和边的类型
+    const registerChartElements = () => {
+      Graph.registerNode(
+          'org-node',
+          {
+            width: 180,
+            height: 60,
+            markup: [
+              {
+                tagName: 'rect',
+                selector: 'body',
+              },
+              {
+                tagName: 'image',
+                selector: 'avatar',
+              },
+              {
+                tagName: 'text',
+                selector: 'rank',
+              },
+              {
+                tagName: 'text',
+                selector: 'name',
+              },
+            ],
+            attrs: {
+              body: {
+                refWidth: '100%',
+                refHeight: '100%',
+                fill: '#5F95FF',
+                stroke: '#5F95FF',
+                strokeWidth: 1,
+                rx: 10,
+                ry: 10,
+                pointerEvents: 'visiblePainted',
+              },
+              avatar: {
+                width: 48,
+                height: 48,
+                refX: 8,
+                refY: 6,
+              },
+              rank: {
+                refX: 0.9,
+                refY: 0.2,
+                fill: '#fff',
+                fontFamily: 'Courier New',
+                fontSize: 14,
+                textAnchor: 'end',
+                textDecoration: 'underline',
+              },
+              name: {
+                refX: 0.9,
+                refY: 0.6,
+                fill: '#fff',
+                fontFamily: 'Courier New',
+                fontSize: 14,
+                fontWeight: '800',
+                textAnchor: 'end',
+              },
+            },
+          },
+          true
+      )
+
+      Graph.registerEdge(
+          'org-edge',
+          {
+            zIndex: -1,
+            attrs: {
+              line: {
+                fill: 'none',
+                strokeLinejoin: 'round',
+                strokeWidth: 2,
+                stroke: '#A2B1C3',
+                sourceMarker: null,
+                targetMarker: null,
+              },
+            },
+          },
+          true
+      )
+    }
+
+    // 创建节点
+    const createNode = (x, y, rank, name, image) => {
+      return graph.addNode({
+        x,
+        y,
+        shape: 'org-node',
+        attrs: {
+          avatar: {
+            opacity: 0.7,
+            // 'xlink:href': image,
+          },
+          rank: {
+            text: rank,
+            wordSpacing: '-5px',
+            letterSpacing: 0,
+          },
+          name: {
+            text: name,
+            fontSize: 13,
+            fontFamily: 'Arial',
+            letterSpacing: 0,
+          },
+        },
+        // 禁用节点拖动
+        movable: false,
+      })
+    }
+
+    // 创建连线
+    const createLink = (source, target, vertices) => {
+      return graph.addEdge({
+        vertices,
+        source: {
+          cell: source,
+        },
+        target: {
+          cell: target,
+        },
+        shape: 'org-edge',
+        // 禁用连线拖动
+        connector: {
+          name: 'normal',
+          args: {
+            style: {
+              pointerEvents: 'none',
+            },
+          },
+        },
+        // 禁用连线调整
+        router: {
+          name: 'manhattan',
+          args: {
+            padding: 10,
+          },
+        },
+        attrs: {
+          line: {
+            // 禁止选中连线
+            pointerEvents: 'none',
+          },
+        },
+      })
+    }
+
+    // 初始化图表
+    const initChart = () => {
+      if (!containerRef.value) return
+
+      // 创建图表实例
+      graph = new Graph({
+        container: containerRef.value,
+        connecting: {
+          anchor: 'orth',
+        },
+        // 禁用鼠标滚轮缩放
+        mousewheel: {
+          enabled: true,
+        },
+        // 禁用平移
+        panning: true,
+        // 禁用框选
+        selecting: {
+          enabled: false,
+        },
+        interacting: {
+          nodeMovable: false,
+          edgeMovable: false,
+        },
+      })
+
+      // 图表数据
+      const male =
+          'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*kUy8SrEDp6YAAAAAAAAAAAAAARQnAQ'
+      const female =
+          'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*f6hhT75YjkIAAAAAAAAAAAAAARQnAQ'
+
+      // 创建节点
+      const bart = createNode(300, 70, 'CEO', 'Bart Simpson', male)
+      const homer = createNode(90, 200, 'VP Marketing', 'Homer Simpson', male)
+      const marge = createNode(300, 200, 'VP Sales', 'Marge Simpson', female)
+      const lisa = createNode(500, 200, 'VP Production', 'Lisa Simpson', female)
+      const maggie = createNode(400, 350, 'Manager', 'Maggie Simpson', female)
+      const lenny = createNode(190, 350, 'Manager', 'Lenny Leonard', male)
+      const carl = createNode(190, 500, 'Manager', 'Carl Carlson', male)
+
+      // 创建连线
+      createLink(bart, marge, [
+        {
+          x: 385,
+          y: 180,
+        },
+      ])
+      createLink(bart, homer, [
+        {
+          x: 385,
+          y: 180,
+        },
+        {
+          x: 175,
+          y: 180,
+        },
+      ])
+      createLink(bart, lisa, [
+        {
+          x: 385,
+          y: 180,
+        },
+        {
+          x: 585,
+          y: 180,
+        },
+      ])
+      createLink(homer, lenny, [
+        {
+          x: 175,
+          y: 380,
+        },
+      ])
+      createLink(homer, carl, [
+        {
+          x: 175,
+          y: 530,
+        },
+      ])
+      createLink(marge, maggie, [
+        {
+          x: 385,
+          y: 380,
+        },
+      ])
+
+      // 调整视图以适应所有节点
+      graph.zoomToFit({ padding: 20, maxScale: 1 })
+    }
+
+    // 组件挂载后初始化图表
+    onMounted(() => {
+      registerChartElements()
+      initChart()
+    })
+
+    // 组件卸载前清理图表
+    onBeforeUnmount(() => {
+      if (graph) {
+        graph.dispose()
+        graph = null
+      }
+    })
+
+    return {
+      containerRef,
+    }
+  },
+}
+</script>
+
+<style scoped>
+.org-chart-container {
+  width: 100%;
+  height: 600px;
+  border: 1px solid #e5e7eb;
+  border-radius: 6px;
+  overflow: hidden;
+}
+</style>

+ 21 - 6
src/views/customer-manage/customer-detail/components/LinkCompany/index.vue

@@ -1,19 +1,34 @@
 <template>
   <div class="link-company">
-    <div class="link-flow"></div>
+    <div class="link-flow">
+      <bs-catalog title="关联公司架构">
+        <template #content>
+          <org-struct-chart />
+        </template>
+      </bs-catalog>
+    </div>
+    <div class="link-list">
+      <link-list />
+    </div>
   </div>
 </template>
-<script setup></script>
+<script setup>
+  import OrgStructChart from './compoents/OrgStructChart/index.vue';
+  import LinkList from './compoents/LinkList/index.vue';
+  import { BsCatalog } from '/@/components/BsUi/index.js';
+</script>
 
 <style scoped lang="scss">
   .link-company {
     width: 100%;
-    height: 100%;
     display: flex;
-    gap: 10px;
-
+    gap: 30px;
     .link-flow {
-
+      border-radius: 8px;
+      flex: 1;
+    }
+    .link-list {
+      width: 670px;
     }
   }
 </style>

+ 22 - 10
src/views/customer-manage/customer-detail/index.vue

@@ -2,18 +2,30 @@
   <div class="page-detail">
     <page-detail-layout :tabs="tabs" v-model:tab-active-key="tabActiveKey" :index-config="indexConfig" :title="customerDetailData?.customerName">
       <template #titleRight>
-        <img v-if="customerDetailData?.customerType === 'S'" src="/@/assets/images/page-detail-layout/customer/SS_user.png" alt="" />
-        <img v-if="customerDetailData?.customerType === 'A'" src="/@/assets/images/page-detail-layout/customer/AA_user.png" alt="" />
-        <img v-if="customerDetailData?.customerType === 'B'" src="/@/assets/images/page-detail-layout/customer/BB_user.png" alt="" />
-        <img v-if="customerDetailData?.customerType === 'C'" src="/@/assets/images/page-detail-layout/customer/CC_user.png" alt="" />
-       <bs-dic-tag :dicts="customerDetailData?.customerSource" />
+        <img v-if="customerDetailData?.customerGrade[0].valueCode === 'S'" src="/@/assets/images/page-detail-layout/customer/SS_user.png" alt="" />
+        <img v-if="customerDetailData?.customerGrade[0].valueCode === 'A'" src="/@/assets/images/page-detail-layout/customer/AA_user.png" alt="" />
+        <img v-if="customerDetailData?.customerGrade[0].valueCode === 'B'" src="/@/assets/images/page-detail-layout/customer/BB_user.png" alt="" />
+        <img v-if="customerDetailData?.customerGrade[0].valueCode === 'C'" src="/@/assets/images/page-detail-layout/customer/CC_user.png" alt="" />
+        <bs-dic-tag :dicts="customerDetailData?.customerSource" />
       </template>
 
       <template #toolBtn>
-        <a-button danger ghost type="primary" size="small">加入黑名单</a-button>
-        <a-button danger ghost type="primary" size="small">释放公海</a-button>
-        <a-button ghost type="primary" size="small">客户转移</a-button>
-        <a-button type="primary" size="small">信息编辑</a-button>
+        <a-button danger ghost type="primary" size="small">
+          <UserAddOutlined />
+          <span>加入黑名单</span>
+        </a-button>
+        <a-button danger ghost type="primary" size="small">
+          <UserDeleteOutlined />
+          <span>释放公海</span>
+        </a-button>
+        <a-button ghost type="primary" size="small">
+          <RightSquareOutlined />
+          <span> 客户转移 </span></a-button
+        >
+        <a-button type="primary" size="small">
+          <EditOutlined />
+          <span>信息编辑</span>
+        </a-button>
       </template>
 
       <template #titleBottom>
@@ -62,7 +74,7 @@
   import CooperativeProject from '/@/views/customer-manage/customer-detail/components/CooperativeProject/index.vue';
   import CustomerDecisionChain from '/@/views/customer-manage/customer-detail/components/CustomerDecisionChain/index.vue';
   import FollowUp from '/@/views/customer-manage/customer-detail/components/FollowUp/index.vue';
-  import { BsDicTag } from "/@/components/BsUi/index.js"
+  import { BsDicTag, BsIcon } from '/@/components/BsUi/index.js';
 
   import { fetchCustomerHeaderInfo, fetchCustomerDetail } from '/@/api/customer-manage/index.js';
 

+ 49 - 2
src/views/customer-manage/visit-recommendation/components/map-info/index.vue

@@ -3,12 +3,34 @@
     <bs-catalog title="拜访规划">
       <template #headerRight>
         <a-button type="primary">
-          <template #icon><PlusSquareOutlined /></template>
+          <template #icon>
+            <PlusSquareOutlined />
+          </template>
           <span>创建路线</span>
         </a-button>
       </template>
 
-      <template #content>11111111111</template>
+      <template #content>
+        <div class="mp-content">
+          <div class="mp-header">
+            <span class="mp-h-top">
+              共计5个城市 2025.06.18 ~ 2025.06.18 累计周期 12天
+            </span>
+
+            <div class="mp-h-bottom">
+              <span>上海 2025.06.05 | 3天</span>
+              <SwapRightOutlined />
+              <span>上海 2025.06.05 | 3天</span>
+              <SwapRightOutlined />
+              <span>上海 2025.06.05 | 3天</span>
+              <SwapRightOutlined />
+              <span>上海 2025.06.05 | 3天</span>
+              <SwapRightOutlined />
+              <span>上海 2025.06.05 | 3天</span>
+            </div>
+          </div>
+        </div>
+      </template>
     </bs-catalog>
   </div>
 </template>
@@ -21,5 +43,30 @@
     flex: 2;
     height: 100%;
     border-radius: 8px;
+    .mp-content {
+      border: 1px solid #f0f0f0;
+      border-radius: 2px;
+      padding: 20px;
+      .mp-header {
+        width: 100%;
+        height: 100%;
+        .mp-h-top {
+          padding: 5px 10px;
+          background: var(--vxe-ui-font-primary-color);
+          font-size: 16px;
+          font-weight: 600;
+          color: #fff;
+          border-radius: 8px;
+        }
+        .mp-h-bottom {
+          margin-top: 20px;
+          width: 100%;
+          display: flex;
+          flex-wrap: wrap;
+          gap: 20px;
+          font-weight: 600;
+        }
+      }
+    }
   }
 </style>

+ 3 - 1
src/views/customer-manage/visit-recommendation/components/table-data/index.vue

@@ -97,7 +97,9 @@
         data: [],
         columns: [
           {
-            type: 'seq',
+            type: 'checkbox',
+            width: '60px',
+            align: 'center',
           },
           {
             title: '客户名称',