소스 검색

fix: 新增风险规则

liqh 5 달 전
부모
커밋
df85bae952
28개의 변경된 파일4052개의 추가작업 그리고 4개의 파일을 삭제
  1. 50 0
      src/api/business-rules/rules-api.js
  2. 9 4
      src/api/market-manage/index.js
  3. 191 0
      src/views/business-rules/risk-rules/components/rules-list/index.vue
  4. 8 0
      src/views/business-rules/risk-rules/components/rules-mitt.js
  5. 241 0
      src/views/business-rules/risk-rules/components/task-rules-tree/index copy.vue
  6. 106 0
      src/views/business-rules/risk-rules/components/task-rules-tree/index.vue
  7. 54 0
      src/views/business-rules/risk-rules/index.vue
  8. 343 0
      src/views/business-rules/risk-rules/modules/create-rules.vue
  9. 366 0
      src/views/market-manage/external-manage/customer-manage/customer-create/index.vue
  10. 170 0
      src/views/market-manage/external-manage/customer-manage/customer-list/index.vue
  11. 99 0
      src/views/market-manage/external-manage/customer-manage/single-customer/components/clue-info.vue
  12. 91 0
      src/views/market-manage/external-manage/customer-manage/single-customer/components/contract-info.vue
  13. 58 0
      src/views/market-manage/external-manage/customer-manage/single-customer/components/customer-info.vue
  14. 146 0
      src/views/market-manage/external-manage/customer-manage/single-customer/components/decision-chain.vue
  15. 85 0
      src/views/market-manage/external-manage/customer-manage/single-customer/components/edit-info.vue
  16. 103 0
      src/views/market-manage/external-manage/customer-manage/single-customer/components/file-info.vue
  17. 105 0
      src/views/market-manage/external-manage/customer-manage/single-customer/components/follow-up.vue
  18. 114 0
      src/views/market-manage/external-manage/customer-manage/single-customer/components/project-info.vue
  19. 85 0
      src/views/market-manage/external-manage/customer-manage/single-customer/components/repayment-info.vue
  20. 84 0
      src/views/market-manage/external-manage/customer-manage/single-customer/components/view-info.vue
  21. 174 0
      src/views/market-manage/external-manage/customer-manage/single-customer/index.vue
  22. 140 0
      src/views/market-manage/external-manage/customer-manage/single-customer/modules/add-decision.vue
  23. 100 0
      src/views/market-manage/external-manage/customer-manage/single-customer/modules/add-followup.vue
  24. 153 0
      src/views/market-manage/external-manage/customer-manage/single-customer/modules/get-projectnum.vue
  25. 197 0
      src/views/market-manage/internal-manage/serviceProvider-manage/audit-list/index.vue
  26. 197 0
      src/views/market-manage/internal-manage/serviceProvider-manage/certified-list/index.vue
  27. 386 0
      src/views/market-manage/internal-manage/serviceProvider-manage/create-service/index.vue
  28. 197 0
      src/views/market-manage/internal-manage/serviceProvider-manage/unqualified-list/index.vue

+ 50 - 0
src/api/business-rules/rules-api.js

@@ -0,0 +1,50 @@
+/*
+ *  员工
+ *
+ * @Author:    DCCloud
+ * @Date:      2022-09-03 21:59:15
+ */
+
+import { getRequest, postEncryptRequest, postRequest } from '/src/lib/axios';
+
+export const rulesApi = {
+  /**
+   * 查询所有员工 @author Gnawzs
+   */
+  queryAll: () => {
+    return getRequest('/employee/queryAll');
+  },
+  /**
+   * 删除员工
+   */
+  deleteEmployee: (employeeId) => {
+    return getRequest(`/employee/delete/${employeeId}`);
+  },
+
+  /**
+   * 规则查询
+   */
+  queryRulesList: (params) => {
+    return getRequest(`/supports/risk/selectRisk?key=${params}`);
+  },
+
+  /**
+   * 规则数结构查询
+   */
+  queryRulesTree: () => {
+    return getRequest('/supports/risk/selectAllCategory');
+  },
+  /**
+   * 提交规则表单数据
+   */
+  submitRulesForm: (params) => {
+    return postRequest('/supports/risk/add', params);
+  },
+
+  /**
+   * 查询单条规则详情
+   */
+  getRulesInfoList: (params) => {
+    return getRequest(`/supports/risk/selectRiskOne/${params}`);
+  },
+};

+ 9 - 4
src/api/market-manage/index.js

@@ -14,7 +14,7 @@ export const clientManageApi = {
   getXMHeaderList: (projectId) => {
     return getRequest(`/project/detail/show?projectId=${projectId}`);
   },
-  
+
   /**
    * 查询客户信息 @author wzs
    * @param {string} customerId 客户id
@@ -26,7 +26,7 @@ export const clientManageApi = {
 
   // 上传附件
   uploadDocument: (params) => {
-    return postRequest(`social/upload`,params);
+    return postRequest(`social/upload`, params);
   },
 
   // 释放公海
@@ -36,7 +36,7 @@ export const clientManageApi = {
 
   // 开标结果登记
   openBid: (params) => {
-    return postRequest(`/social/project/biding/result`,params);
+    return postRequest(`/social/project/biding/result`, params);
   },
 
   // 委托方管理列表头部卡片
@@ -51,11 +51,16 @@ export const clientManageApi = {
 
   // 项目列表
   interventionsList: (params) => {
-    return postRequest(`/project/list`,params);
+    return postRequest(`/project/list`, params);
   },
 
   // 查询投标阶段状态
   getBidStages: (projectId) => {
     return getRequest(`/social/project/bid/stages?projectId=${projectId}`);
   },
+
+  //新增服务商信息
+  createServiceInfo: (params) => {
+    return postRequest(`/project/list`, params);
+  },
 };

+ 191 - 0
src/views/business-rules/risk-rules/components/rules-list/index.vue

@@ -0,0 +1,191 @@
+<!--
+  *  风险树列表
+  *
+  * @Author:    DCCloud
+  * @Date:      2025-05-28 20:46:18
+-->
+<template>
+  <a-card class="employee-container">
+    <div class="header">
+      <a-typography-title :level="5">规则详情</a-typography-title>
+      <div class="query-operate">
+        <a-button @click="goDetailPage" class="smart-margin-left10">
+          <template #icon>
+          </template>
+          新增
+        </a-button>
+      </div>
+    </div>
+
+    <a-table
+      size="small"
+      :columns="columns"
+      :data-source="tableData"
+      :pagination="false"
+      :loading="tableLoading"
+      bordered
+    >
+      <template #bodyCell="{ record, column }">
+        <template v-if="column.dataIndex === 'operate'">
+          <div class="smart-table-operate">
+            <a-button v-privilege="'system:employee:update'" type="link" size="small" @click="goDetailPage(record)">编辑</a-button>
+          </div>
+        </template>
+      </template>
+    </a-table>
+  </a-card>
+</template>
+<script setup lang="ts">
+  import { onMounted } from 'vue';
+  import { useRouter } from 'vue-router';
+  import _ from 'lodash';
+  import { computed, createVNode, reactive, ref, watch } from 'vue';
+  import { rulesApi } from '/@/api/business-rules/rules-api';
+  import { smartSentry } from '/@/lib/smart-sentry';
+  import useDict from '/@/utils/dict-util';
+
+  onMounted(async () => {
+    // await initDict();
+    queryRules();
+  });
+
+  // ----------------------- 以下是字段定义 emits props ---------------------
+
+  const props = defineProps({
+    selectedRulesId: Number,
+    breadcrumb: Array,
+  });
+
+  // ----------------------- 表格/列表/ 搜索 ---------------------
+  //字段
+  const columns = ref([
+    {
+      title: '风险维度',
+      dataIndex: 'riskDimension',
+      align: 'center',
+      width: 85,
+    },
+    {
+      title: '风险指标',
+      dataIndex: 'riskMetrics',
+      align: 'center',
+      width: 110,
+    },
+    {
+      title: '指标定义',
+      dataIndex: 'definedMetrics',
+      align: 'center',
+      width: 100,
+    },
+    {
+      title: '条件运算符',
+      dataIndex: 'operator',
+      align: 'center',
+      width: 100,
+    },
+    {
+      title: '条件控制值',
+      dataIndex: 'conditionalValue',
+      align: 'center',
+      width: 100,
+      ellipsis: true,
+    },
+    {
+      title: '提醒方式',
+      dataIndex: 'remindWay',
+      align: 'center',
+      width: 100,
+    },
+    {
+      title: '提醒时间(每天)',
+      dataIndex: 'remindTime',
+      align: 'center',
+      width: 120,
+    },
+    {
+      title: '风险等级',
+      dataIndex: 'riskGrade',
+      align: 'center',
+      width: 100,
+      ellipsis: true,
+    },
+    {
+      title: '状态',
+      dataIndex: 'enable',
+      align: 'center',
+      width: 100,
+    },
+    {
+      title: '操作',
+      dataIndex: 'operate',
+      align: 'center',
+      fixed: 'right',
+      width: 140,
+    },
+  ]);
+  const tableData = ref();
+  const selectedRulesId = ref();
+  const tableLoading = ref(false);
+
+  // 查询
+  async function queryRules() {
+    tableLoading.value = true;
+    try {
+      selectedRulesId.value = props.selectedRulesId;
+      let res = await rulesApi.queryRulesList(selectedRulesId.value);
+      tableData.value = res.data;
+    } catch (error) {
+      smartSentry.captureError(error);
+    } finally {
+      tableLoading.value = false;
+    }
+  }
+
+  //检测数据变化
+  watch(
+    () => props.selectedRulesId,
+    () => {
+      if (props.selectedRulesId !== selectedRulesId.value) {
+        queryRules()
+      }
+    },
+    { immediate: true }
+  );
+
+  // ----------------------- 添加、修改、禁用、重置密码、页面跳转 ------------------------------------
+  const router = useRouter();
+  function goDetailPage(record) {
+    console.log('record', record);
+    router.push({
+      path: '/business-rules/create-rules',
+      query: {
+        id: record.id,
+      },
+    });
+  }
+</script>
+<style scoped lang="less">
+  .employee-container {
+    height: 100%;
+  }
+
+  .header {
+    display: flex;
+    align-items: center;
+  }
+
+  .query-operate {
+    margin-left: auto;
+    display: flex;
+    align-items: center;
+    margin-bottom: 20px;
+  }
+
+  .btn-group {
+    margin: 10px 0;
+
+    .btn {
+      margin-right: 8px;
+    }
+  }
+</style>

+ 8 - 0
src/views/business-rules/risk-rules/components/rules-mitt.js

@@ -0,0 +1,8 @@
+/*
+ * 部门event bus
+ *
+ * @Author:    DCCloud
+ * @Date:      2022-07-12 23:32:48
+ */
+import mitt from 'mitt';
+export default mitt();

+ 241 - 0
src/views/business-rules/risk-rules/components/task-rules-tree/index copy.vue

@@ -0,0 +1,241 @@
+<!--
+  * 部门树形结构
+  *
+  * @Author:    DCCloud
+  * @Date:      2022-08-08 20:46:18
+-->
+<template>
+  <a-card class="tree-container">
+    <a-row class="smart-margin-bottom10">
+      <a-input v-model:value.trim="keywords" placeholder="请输入部门名称" />
+    </a-row>
+    <a-tree v-if="!_.isEmpty(departmentTreeData)" v-model:selectedKeys="selectedKeys" v-model:checkedKeys="checkedKeys"
+      class="tree" :treeData="departmentTreeData"
+      :fieldNames="{ title: 'name', key: 'departmentId', value: 'departmentId' }" style="width: 100%; overflow-x: auto"
+      :style="[!height ? '' : { height: `${height}px`, overflowY: 'auto' }]" :checkable="props.checkable"
+      :checkStrictly="props.checkStrictly" :selectable="!props.checkable" :defaultExpandAll="true"
+      @select="treeSelectChange">
+      <template #title="item">
+        <div>{{ item.name }}</div>
+      </template>
+    </a-tree>
+    <div class="no-data" v-else>暂无结果</div>
+  </a-card>
+</template>
+<script setup>
+import { onMounted, onUnmounted, ref, watch } from 'vue';
+import _ from 'lodash';
+import { departmentApi } from '/src/api/system/department-api';
+import rulesEmitter from '../rules-mitt';
+import { smartSentry } from '/src/lib/smart-sentry';
+
+const DEPARTMENT_PARENT_ID = 0;
+
+// ----------------------- 组件参数 ---------------------
+
+const props = defineProps({
+  // 是否可以选中
+  checkable: {
+    type: Boolean,
+    default: false,
+  },
+  // 父子节点选中状态不再关联
+  checkStrictly: {
+    type: Boolean,
+    default: false,
+  },
+  // 树高度 超出出滚动条
+  height: Number,
+  // 显示菜单
+  showMenu: {
+    type: Boolean,
+    default: false,
+  },
+});
+
+// ----------------------- 部门树的展示 ---------------------
+const topDepartmentId = ref();
+// 所有部门列表
+const departmentList = ref([]);
+// 部门树形数据
+const departmentTreeData = ref([]);
+// 存放部门id和部门,用于查找
+const idInfoMap = ref(new Map());
+
+onMounted(() => {
+  queryDepartmentTree();
+});
+
+// 刷新
+async function refresh() {
+  await queryDepartmentTree();
+  if (currentSelectedDepartmentId.value) {
+    selectTree(currentSelectedDepartmentId.value);
+  }
+}
+
+// 查询部门列表并构建 部门树
+async function queryDepartmentTree() {
+  let res = await departmentApi.queryAllDepartment();
+  console.log("34343",res);
+  
+  let data = res.data;
+  departmentList.value = data;
+  departmentTreeData.value = buildDepartmentTree(data, DEPARTMENT_PARENT_ID);
+  console.log("departmentTreeData.value",departmentTreeData.value);
+  
+
+  data.forEach((e) => {
+    idInfoMap.value.set(e.departmentId, e);
+  });
+
+  // 默认显示 最顶级ID为列表中返回的第一条数据的ID
+  if (!_.isEmpty(departmentTreeData.value) && departmentTreeData.value.length > 0) {
+    topDepartmentId.value = departmentTreeData.value[0].departmentId;
+  }
+
+  selectTree(departmentTreeData.value[0].departmentId);
+}
+
+// 构建部门树
+function buildDepartmentTree(data, parentId) {
+  let children = data.filter((e) => e.parentId === parentId) || [];
+  children.forEach((e) => {
+    e.children = buildDepartmentTree(data, e.departmentId);
+  });
+  updateDepartmentPreIdAndNextId(children);
+  return children;
+}
+
+// 更新树的前置id和后置id
+function updateDepartmentPreIdAndNextId(data) {
+  for (let index = 0; index < data.length; index++) {
+    if (index === 0) {
+      data[index].nextId = data.length > 1 ? data[1].departmentId : undefined;
+      continue;
+    }
+
+    if (index === data.length - 1) {
+      data[index].preId = data[index - 1].departmentId;
+      data[index].nextId = undefined;
+      continue;
+    }
+
+    data[index].preId = data[index - 1].departmentId;
+    data[index].nextId = data[index + 1].departmentId;
+  }
+}
+
+// ----------------------- 树的选中 ---------------------
+const selectedKeys = ref([]);
+const checkedKeys = ref([]);
+const breadcrumb = ref([]);
+const currentSelectedDepartmentId = ref();
+const selectedDepartmentChildren = ref([]);
+
+rulesEmitter.on('selectTree', selectTree);
+
+function selectTree(id) {
+  selectedKeys.value = [id];
+  treeSelectChange(selectedKeys.value);
+}
+
+function treeSelectChange(idList) {
+  console.log("treeSelectChange",idList);
+  
+  if (_.isEmpty(idList)) {
+    breadcrumb.value = [];
+    selectedDepartmentChildren.value = [];
+    return;
+  }
+  let id = idList[0];
+  selectedDepartmentChildren.value = departmentList.value.filter((e) => e.parentId == id);
+  let filterDepartmentList = [];
+  recursionFilterDepartment(filterDepartmentList, id, true);
+  breadcrumb.value = filterDepartmentList.map((e) => e.name);
+}
+
+// -----------------------  筛选 ---------------------
+const keywords = ref('');
+watch(
+  () => keywords.value,
+  () => {
+    onSearch();
+  }
+);
+
+// 筛选
+function onSearch() {
+  if (!keywords.value) {
+    departmentTreeData.value = buildDepartmentTree(departmentList.value, DEPARTMENT_PARENT_ID);
+    return;
+  }
+  let originData = departmentList.value.concat();
+  if (!originData) {
+    return;
+  }
+  // 筛选出名称符合的部门
+  let filterDepartment = originData.filter((e) => e.name.indexOf(keywords.value) > -1);
+  let filterDepartmentList = [];
+  // 循环筛选出的部门 构建部门树
+  filterDepartment.forEach((e) => {
+    recursionFilterDepartment(filterDepartmentList, e.departmentId, false);
+  });
+
+  departmentTreeData.value = buildDepartmentTree(filterDepartmentList, DEPARTMENT_PARENT_ID);
+}
+
+// 根据ID递归筛选部门
+function recursionFilterDepartment(resList, id, unshift) {
+  let info = idInfoMap.value.get(id);
+  if (!info || resList.some((e) => e.departmentId == id)) {
+    return;
+  }
+  if (unshift) {
+    resList.unshift(info);
+  } else {
+    resList.push(info);
+  }
+  if (info.parentId && info.parentId != 0) {
+    recursionFilterDepartment(resList, info.parentId, unshift);
+  }
+}
+
+onUnmounted(() => {
+  rulesEmitter.all.clear();
+});
+
+// ----------------------- 以下是暴露的方法内容 ----------------------------
+defineExpose({
+  queryDepartmentTree,
+  selectedDepartmentChildren,
+  breadcrumb,
+  selectedKeys,
+  checkedKeys,
+  keywords,
+});
+</script>
+<style scoped lang="less">
+.tree-container {
+  height: 100%;
+
+  .tree {
+    height: 618px;
+    margin-top: 10px;
+    overflow-x: hidden;
+  }
+
+  .sort-flag-row {
+    margin-top: 10px;
+    margin-bottom: 10px;
+  }
+
+  .sort-span {
+    margin-left: 5px;
+  }
+
+  .no-data {
+    margin: 10px;
+  }
+}
+</style>

+ 106 - 0
src/views/business-rules/risk-rules/components/task-rules-tree/index.vue

@@ -0,0 +1,106 @@
+<!--
+  * 部门树形结构
+  *
+  * @Author:    DCCloud
+  * @Date:      2022-08-08 20:46:18
+-->
+<template>
+  <a-card class="tree-container">
+    <a-row class="smart-margin-bottom10">
+      <a-input v-model:value.trim="keywords" placeholder="请输入部门名称" />
+    </a-row>
+    <a-tree
+      v-model:selectedKeys="selectedKeys"
+      v-model:checkedKeys="checkedKeys"
+      class="tree"
+      :treeData="departmentList"
+      :fieldNames="{}"
+      style="width: 100%; overflow-x: auto"
+      :style="[!height ? '' : { height: `${height}px`, overflowY: 'auto' }]"
+      @select="treeSelectChange"
+    >
+    </a-tree>
+  </a-card>
+</template>
+<script setup>
+  import { onMounted, onUnmounted, ref, watch } from 'vue';
+  import _ from 'lodash';
+  import { rulesApi } from '/@/api/business-rules/rules-api';
+
+  // ----------------------- 组件参数 ---------------------
+
+  const props = defineProps({
+    // 是否可以选中
+    checkable: {
+      type: Boolean,
+      default: false,
+    },
+    // 父子节点选中状态不再关联
+    checkStrictly: {
+      type: Boolean,
+      default: false,
+    },
+    // 树高度 超出出滚动条
+    height: Number,
+    // 显示菜单
+    showMenu: {
+      type: Boolean,
+      default: false,
+    },
+  });
+  // ----------------------- 部门树的展示 ---------------------
+  // 所有部门列表
+  const departmentList = ref([]);
+
+  onMounted(() => {
+    queryDepartmentTree();
+  });
+
+  // 查询部门列表并构建 部门树
+  async function queryDepartmentTree() {
+    let res = await rulesApi.queryRulesTree();
+    let data = res.data;
+    departmentList.value = data;
+  }
+
+  // ----------------------- 树的选中 ---------------------
+  const selectedKeys = ref([]);
+  const checkedKeys = ref([]);
+
+  function treeSelectChange(idList) {
+    selectedKeys.value = idList;
+  }
+
+  onUnmounted(() => {
+  });
+
+  // ----------------------- 以下是暴露的方法内容 ----------------------------
+  defineExpose({
+    queryDepartmentTree,
+    selectedKeys,
+  });
+</script>
+<style scoped lang="less">
+  .tree-container {
+    height: 100%;
+
+    .tree {
+      height: 618px;
+      margin-top: 10px;
+      overflow-x: hidden;
+    }
+
+    .sort-flag-row {
+      margin-top: 10px;
+      margin-bottom: 10px;
+    }
+
+    .sort-span {
+      margin-left: 5px;
+    }
+
+    .no-data {
+      margin: 10px;
+    }
+  }
+</style>

+ 54 - 0
src/views/business-rules/risk-rules/index.vue

@@ -0,0 +1,54 @@
+<!--
+  * 组织架构
+  *
+  * @Author:    DCCloud
+  * @Date:      2022-08-08 20:46:18
+-->
+<template>
+  <div class="height100">
+    <a-row :gutter="24" class="height100">
+      <a-col :span="5">
+        <DepartmentTree ref="departmentTree" />
+      </a-col>
+
+      <a-col :span="19" class="height100">
+        <div class="employee-box height100">
+          <EmployeeList style="flex-grow: 2.5" class="employee" :selectedRulesId="selectedRulesId" />
+        </div>
+      </a-col>
+    </a-row>
+  </div>
+</template>
+<script setup>
+import _ from 'lodash';
+import { computed, ref } from 'vue';
+import DepartmentTree from './components/task-rules-tree/index.vue';
+import EmployeeList from './components/rules-list/index.vue';
+
+const departmentTree = ref();
+
+// 当前选中的目录id
+const selectedRulesId = computed(() => {
+  if (departmentTree.value) {
+    let selectedKeys = departmentTree.value.selectedKeys;
+    console.log("selectedDepartmentId", _.isEmpty(selectedKeys) ? null : selectedKeys[0]);
+    return _.isEmpty(selectedKeys) ? null : selectedKeys[0];
+  }
+  return null;
+});
+
+</script>
+<style scoped lang="less">
+.height100 {
+  height: 100%;
+}
+
+.employee-box {
+  display: flex;
+  flex-direction: column;
+
+  .employee {
+    flex-grow: 2;
+  }
+}
+</style>

+ 343 - 0
src/views/business-rules/risk-rules/modules/create-rules.vue

@@ -0,0 +1,343 @@
+<template>
+  <a-card>
+    <a-form class="smart-query-form" ref="stepFormRef" labelWrap :label-col="labelCol" :model="formModel" :rules="formRules">
+      <div class="approval-steps">
+        <div>
+          <div class="basic-title">
+            <div class="basic-title-left">
+              <div class="basic-title-line"></div>
+              <span class="basic-title-text">{{title}}</span>
+            </div>
+            <div class="basic-title-right">
+              <a-button type="primary" @click="submit">提交</a-button>
+            </div>
+          </div>
+          <div class="steps-content">
+            <a-row :gutter="24" class="smart-query-form-row">
+              <a-col :span="12">
+                <a-form-item label="风险维度" name="riskDimension" class="smart-query-form-item">
+                  <DictSelect key-code="BLINK_RISK_DIMENSION" v-model:value="formModel.riskDimension" placeholder="请选择风险维度" width="100%" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="12">
+                <a-form-item label="风险模板" name="riskModel" class="smart-query-form-item">
+                  <DictSelect key-code="BLINK_RISK_MODEL" v-model:value="formModel.riskModel" placeholder="请选择风险模板" width="100%" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="24" class="smart-query-form-row">
+              <a-col :span="12">
+                <a-form-item label="风险指标" name="riskMetrics" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.riskMetrics" placeholder="请输入风险指标" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="24" class="smart-query-form-row">
+              <a-col :span="24">
+                <a-form-item label="指标定义" name="definedMetrics" class="smart-query-form-item">
+                  <a-textarea v-model:value="formModel.definedMetrics" placeholder="请输入指标定义" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="24" class="smart-query-form-row">
+              <a-col :span="12">
+                <a-form-item label="条件运算符" name="operator" class="smart-query-form-item">
+                  <DictSelect key-code="BLINK_CONDITIONAL_OPERATORS" v-model:value="formModel.operator" placeholder="请选择条件运算符" width="100%" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="12">
+                <a-form-item label="条件控制值" name="conditionalValue" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.conditionalValue" placeholder="请输入条件控制值" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="24" class="smart-query-form-row">
+              <a-col :span="12">
+                <a-form-item label="提醒方式" name="remindWay" class="smart-query-form-item">
+                  <DictSelect key-code="BLINK_REMIND_WAY" v-model:value="formModel.remindWay" placeholder="请选择提醒方式" width="100%" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="12">
+                <a-form-item label="提醒时间" name="remindTime" class="smart-query-form-item">
+                  <a-time-picker v-model:value="formModel.remindTime" format="HH:mm" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="12">
+                <a-form-item label="风险等级" name="riskGrade" class="smart-query-form-item">
+                  <DictSelect key-code="BLINK_RISK_GRADE" v-model:value="formModel.riskGrade" placeholder="请选择风险等级" width="100%" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="12">
+                <a-form-item label="状态" name="enable" class="smart-query-form-item">
+                  <a-switch checked-children="开" un-checked-children="关" v-model:checked="formModel.enable" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="24" class="smart-query-form-row">
+              <a-col :span="12">
+                <a-form-item label="提醒人" name="remindPeople" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.remindPeople" placeholder="请输入提醒人" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="24" class="smart-query-form-row">
+              <a-col :span="24">
+                <a-form-item label="风险标题" name="riskTitle" class="smart-query-form-item">
+                  <a-textarea v-model:value="formModel.riskTitle" placeholder="请输入风险标题" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="24" class="smart-query-form-row">
+              <a-col :span="24">
+                <a-form-item label="风险描述" name="riskDescription" class="smart-query-form-item">
+                  <a-textarea v-model:value="formModel.riskDescription" placeholder="请输入风险描述" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="24" class="smart-query-form-row">
+              <a-col :span="12">
+                <a-form-item label="是否显示门户页面" name="portalPage" class="smart-query-form-item">
+                  <a-switch checked-children="开" un-checked-children="关" v-model:checked="formModel.portalPage" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="12">
+                <a-form-item label="显示门户页面" name="showPortalPage" class="smart-query-form-item">
+                  <DictSelect key-code="BLINK_PORTAL_PAGE" v-model:value="formModel.showPortalPage" placeholder="请选择显示门户页面" width="100%" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="24" class="smart-query-form-row">
+              <a-col :span="12">
+                <a-form-item label="统计数据" name="countData" class="smart-query-form-item">
+                  <DictSelect key-code="BLINK_COUNT_DATA" v-model:value="formModel.countData" placeholder="请选择统计数据" width="100%" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="12">
+                <a-form-item label="显示单位" name="unit" class="smart-query-form-item">
+                  <DictSelect key-code="BLINK_DISPLAY_UNIT" v-model:value="formModel.unit" placeholder="请选择显示单位" width="100%" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="24" class="smart-query-form-row">
+              <a-col :span="12">
+                <a-form-item label="统计字段" name="countField" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.countField" placeholder="请输入统计字段" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="24" class="smart-query-form-row">
+              <a-col :span="12">
+                <a-form-item label="是否发起任务" name="launchRiskTask" class="smart-query-form-item">
+                  <a-switch checked-children="开" un-checked-children="关" v-model:checked="formModel.launchRiskTask" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="12">
+                <a-form-item label="任务整改期限" name="term" class="smart-query-form-item">
+                  <a-input-number v-model:value="formModel.term" placeholder="请输入任务整改期限" style="width: 100%" :min="1" addon-after="天" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+          </div>
+        </div>
+      </div>
+    </a-form>
+  </a-card>
+</template>
+<script setup>
+  import { onMounted, reactive, ref } from 'vue';
+  import { useRouter } from 'vue-router';
+  import { message, Modal } from 'ant-design-vue';
+  import _ from 'lodash';
+  import dayjs from 'dayjs';
+  import DictSelect from '/@/components/support/dict-select/index.vue';
+  import { rulesApi } from '/@/api/business-rules/rules-api';
+
+  const stepFormRef = ref(null);
+  const router = useRouter();
+
+  // --------------------- 表单数据定义 ---------------------
+  const formModel = reactive({
+    riskDimension: undefined, //风险维度
+    riskModel: undefined, //风险模板
+    riskMetrics: undefined, //风险指标
+    definedMetrics: undefined, //指标定义
+    operator: undefined, //条件运算符
+    conditionalValue: undefined, //条件值
+    remindWay: undefined, //提醒方式
+    remindTime: undefined, //提醒时间
+    riskGrade: undefined, //风险等级
+    enable: false, //是否启用
+    remindPeople: undefined, //提醒人
+    riskTitle: undefined, //风险标题
+    riskDescription: undefined, //风险描述
+    portalPage: false, //是否显示门户页面
+    showPortalPage: undefined, //显示门户页面
+    countData: undefined, //统计数据
+    unit: undefined, //显示单位
+    countField: undefined, //统计字段
+    launchRiskTask: false, //是否发起风险任务
+    term: undefined, //任务整改期限[天]
+  });
+
+  const title = ref('新增规则');
+
+  // --------------------- 校验规则 ---------------------
+  const formRules = {
+    // deliveryName: [{ required: true, message: '请输入项目名称', trigger: 'change' }],
+  };
+
+  const labelCol = { style: { width: '128px' } };
+
+  // ----------------------- 步骤相关 ---------------------------
+
+  //路由
+  const query = router.currentRoute.value.query;
+  console.log('query', query);
+
+  onMounted(() => {
+    if (query.id) {
+      getRulesInfoList();
+      title.value = '编辑规则';
+    }
+  });
+
+  // 查询列表
+  function getRulesInfoList() {
+    rulesApi.getRulesInfoList(query.id).then(
+      (res) => {
+        if (res.data.id) {
+          updateFormData(res.data);
+        }
+      },
+      (err) => {
+        console.error(err);
+      }
+    );
+  }
+
+  // 更新表单数据
+  function updateFormData(data) {
+    if (data) {
+      // 过滤出 data 中与 formModel 相关的字段并赋值
+      const filteredData = Object.keys(data).reduce((acc, key) => {
+        if (formModel.hasOwnProperty(key) && key !== 'remindTime') {
+          // 排除 remindTime 字段
+          // 特殊处理 portalPage、enable 和 launchRiskTask,将其从字符串转换为布尔值
+          if (['portalPage', 'enable', 'launchRiskTask'].includes(key)) {
+            acc[key] = data[key] === 'true'; // 如果是 "true",转换为 true,否则为 false
+          } else {
+            acc[key] = data[key];
+          }
+        }
+        return acc;
+      }, {});
+      // 将过滤后的数据批量赋值给 formModel
+      Object.assign(formModel, filteredData);
+
+      if (data.remindTime) {
+        // 将字符串时间转换为 Day.js 对象
+        formModel.remindTime = dayjs(data.remindTime, 'HH:mm');
+        console.log(' formModel.remindTime', formModel.remindTime);
+      }
+    }
+  }
+
+  //-----------------------------提交\重置---------------------------------
+
+  const submit = () => {
+    console.log('formModel', formModel);
+    stepFormRef.value
+      .validateFields()
+      .then((values) => {
+        Modal.confirm({
+          title: '提示',
+          content: '确定要提交吗?',
+          okText: '确认',
+          onOk() {
+            postFormData();
+          },
+          cancelText: '取消',
+          onCancel() {},
+        });
+      })
+      .catch((error) => {
+        console.log('step1_error', error);
+      });
+  };
+  //提交表单数据
+  const postFormData = () => {
+    rulesApi.submitRulesForm(formModel).then((res) => {
+      message.success('提交成功');
+      reset();
+      router.push({ path: '/business-rules/risk-rules' });
+    });
+  };
+
+  //清空表单数据
+  const reset = () => {
+    Object.keys(formModel).forEach((key) => {
+      formModel[key] = undefined;
+    });
+  };
+</script>
+
+<style scoped lang="less">
+  .approval-steps {
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
+    // width: 1350px;
+    margin: 0 auto;
+
+    .basic-title {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      width: 100%;
+      height: 40px;
+      padding: 0 16px 4px 16px;
+      border-bottom: 2px solid #f6f6f6;
+      background: #ffffff;
+      border-top-left-radius: 8px;
+      border-top-right-radius: 8px;
+
+      .basic-title-left {
+        height: 100%;
+        display: flex;
+        align-items: center;
+
+        .basic-title-line {
+          width: 4px;
+          height: 20px;
+          border-radius: 4px;
+          background: #267ef8;
+          margin-right: 5px;
+        }
+
+        .basic-title-text {
+          font-size: 16px;
+          font-style: normal;
+          font-weight: 600;
+          line-height: 20px;
+        }
+      }
+
+      .basic-title-right {
+        display: flex;
+        gap: 10px;
+      }
+    }
+
+    .steps-content {
+      margin-top: 14px;
+    }
+
+    .steps-action {
+      display: flex;
+      justify-content: center;
+      margin-top: 18px;
+    }
+  }
+</style>

+ 366 - 0
src/views/market-manage/external-manage/customer-manage/customer-create/index.vue

@@ -0,0 +1,366 @@
+<template>
+  <a-card>
+    <a-form class="smart-query-form" ref="stepFormRef" labelWrap :label-col="labelCol" :model="formModel" :rules="formRules">
+      <div class="approval-steps">
+        <div>
+          <div class="basic-title">
+            <div class="basic-title-left">
+              <div class="basic-title-line"></div>
+              <span class="basic-title-text">基本信息</span>
+            </div>
+            <div class="basic-title-right">
+              <a-button type="primary" @click="reset">重置</a-button>
+              <a-button type="primary" @click="submit">提交</a-button>
+            </div>
+          </div>
+          <div class="steps-content">
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="8">
+                <a-form-item label="客户名称" name="customerName" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.customerName" placeholder="请输入客户名称" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="客户类型" name="customerType" class="smart-query-form-item">
+                  <DictSelect key-code="BLINK_CUSTOMER_TYPE" v-model:value="formModel.customerType" placeholder="请选择客户类型" width="100%" />
+                </a-form-item>
+              </a-col>
+             
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+               <a-col :span="8">
+                <a-form-item label="统一社会代码" name="socialCode" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.socialCode" placeholder="请输入统一社会代码" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="客户省市区" name="provinceCityDistrict" class="smart-query-form-item">
+                  <AreaCascader
+                    type="province_city_district"
+                    style="width: 100%"
+                    v-model:value="provinceCityDistrict"
+                    placeholder="请选择省市区"
+                    @change="changeArea"
+                  />
+                </a-form-item>
+              </a-col>
+              <a-col :span="16">
+                <a-form-item label="详细地址" name="address" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.address" placeholder="请输入详细地址" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="8">
+                <a-form-item label="注册时间" name="companyRegisterDate" class="smart-query-form-item">
+                  <a-date-picker v-model:value="formModel.companyRegisterDate" placeholder="创建日期" value-format="YYYY-MM-DD" style="width: 100%" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="注册资本" name="companyRegisterCapital" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.companyRegisterCapital" placeholder="请输入注册资本" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="客户对接人" name="customerManager" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.customerManager" placeholder="请选择客户对接人" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="8">
+                <a-form-item label="对接人电话" name="customerManagerMobile" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.customerManagerMobile" placeholder="请输入对接人电话" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="24">
+                <a-form-item label="公司简介" name="customerDescription" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.customerDescription" placeholder="请输入公司简介" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="24">
+                <a-form-item label="经营范围" name="customerNature" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.customerNature" placeholder="请输入经营范围" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="24">
+                <a-form-item label="备注" name="customerRemark" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.customerRemark" placeholder="请输入备注" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+          </div>
+        </div>
+        <div>
+          <div class="basic-title">
+            <div class="basic-title-left">
+              <div class="basic-title-line"></div>
+              <span class="basic-title-text">开票信息</span>
+            </div>
+            <div class="basic-title-right">
+              <!-- <a-button type="primary">提交</a-button> -->
+            </div>
+          </div>
+          <div class="steps-content">
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="8">
+                <a-form-item label="开票名称" name="invoiceTitle" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceTitle" placeholder="请输入开票名称" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="开票税号" name="invoiceCode" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceCode" placeholder="请输入开票税号" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="开票地址" name="invoiceAddress" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceAddress" placeholder="请输入开票地址" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="8">
+                <a-form-item label="电话" name="invoiceMobile" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceMobile" placeholder="请输入电话" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="开户银行" name="invoiceBankName" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceBankName" placeholder="请选择开户银行" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="账号" name="invoiceBankAccount" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceBankAccount" placeholder="请输入账号" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="8">
+                <a-form-item label="开票类型" name="invoiceType" class="smart-query-form-item">
+                  <DictSelect
+                    key-code="BLINK_CUSTOMER_INVOICE_TYPE"
+                    v-model:value="formModel.invoiceType"
+                    placeholder="请选择开票类型"
+                    width="100%"
+                  />
+                </a-form-item>
+              </a-col>
+            </a-row>
+          </div>
+        </div>
+        <div>
+          <div class="basic-title">
+            <div class="basic-title-left">
+              <div class="basic-title-line"></div>
+              <span class="basic-title-text">其他信息</span>
+            </div>
+            <div class="basic-title-right">
+              <!-- <a-button type="primary">提交</a-button> -->
+            </div>
+          </div>
+          <div class="steps-content">
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="24">
+                <a-form-item label="附件" name="attachment" class="smart-query-form-item">
+                  <Upload
+                    :defaultFileList="defaultFileList"
+                    :maxUploadSize="10"
+                    :folder="FILE_FOLDER_TYPE_ENUM.COMMON.value"
+                    buttonText="上传附件"
+                    listType="text"
+                    extraMsg="最多上传10个附件"
+                    @change="changeAttachment"
+                  />
+                </a-form-item>
+              </a-col>
+            </a-row>
+          </div>
+        </div>
+      </div>
+    </a-form>
+  </a-card>
+</template>
+<script setup>
+  import { onMounted, reactive, ref, useAttrs } from 'vue';
+  import { useRouter } from 'vue-router';
+  import { message, Modal } from 'ant-design-vue';
+  import _ from 'lodash';
+  // import { customerApi } from '/@/api/teamwork/customer/customer-api';
+  import AreaCascader from '/@/components/framework/area-cascader/index.vue';
+  import DictSelect from '/@/components/support/dict-select/index.vue';
+  import Upload from '/@/components/support/file-upload/index.vue';
+  import { FILE_FOLDER_TYPE_ENUM } from '/@/constants/support/file-const';
+
+  const stepFormRef = ref(null);
+  const router = useRouter();
+
+  // --------------------- 数据 ---------------------
+  const formModel = reactive({
+    customerCode: undefined, //客户编码
+    customerName: undefined, //客户名称
+    socialCode: undefined, //社会统一信用代码
+    partnerLevel: undefined, //客户级别
+    customerStatus: undefined, //客户状态
+    province: undefined, //省份
+    provinceName: undefined,
+    city: undefined, //城市
+    cityName: undefined,
+    area: undefined, //区或县
+    areaName: undefined,
+    address: undefined, //详细地址
+    customerType: undefined, //客户类型
+    customerManager: undefined, //客户对接人
+    customerManagerMobile: undefined, //客户对接人电话
+    companyRegisterCapital: undefined, //注册资本
+    companyRegisterDate: undefined, //注册时间
+    customerDescription: undefined, //公司简介
+    customerNature: undefined, //经营范围
+    customerRemark: undefined, //备注
+    invoiceTitle: undefined, //发票抬头
+    invoiceCode: undefined, //开票税号
+    invoiceAddress: undefined, //开票地址
+    invoiceMobile: undefined, //开票电话
+    invoiceBankName: undefined, //开户银行
+    invoiceBankAccount: undefined, //银行账户
+    invoiceType: undefined, //开票类型
+    attachment: undefined, //附件集合
+  });
+
+  // --------------------- 校验规则 ---------------------
+  const formRules = {
+    // customerName: [{ required: true, message: '请输入客户名称', trigger: 'change' }],
+  };
+
+  const labelCol = { style: { width: '110px' } };
+
+  // ----------------------- 上传附件 ----------------------------
+  // 已上传的附件列表
+  const defaultFileList = ref([]);
+  function changeAttachment(fileList) {
+    defaultFileList.value = fileList;
+    formModel.attachment = _.isEmpty(fileList) ? [] : fileList;
+  }
+
+  // ----------------------- 步骤相关 ---------------------------
+
+  const submit = () => {
+    console.log('formModel', formModel);
+    stepFormRef.value
+      .validateFields()
+      .then((values) => {
+        Modal.confirm({
+          title: '提示',
+          content: '确定要提交吗?',
+          okText: '确认',
+          onOk() {
+            postFormData();
+          },
+          cancelText: '取消',
+          onCancel() {},
+        });
+      })
+      .catch((error) => {
+        console.log('step1_error', error);
+      });
+  };
+
+  const postFormData = () => {
+    customerApi.CustomerAddition(formModel).then((res) => {
+      message.success('提交成功');
+      router.push({ path: '/teamwork/customer-manage/customer-list' });
+    });
+  };
+  //------------------------地区-------------------------------------
+
+  const provinceCityDistrict = ref([]);
+  function changeArea(value, selectedOptions) {
+    Object.assign(formModel, {
+      province: '',
+      provinceName: '',
+      city: '',
+      cityName: '',
+      area: '',
+      areaName: '',
+    });
+    if (!_.isEmpty(selectedOptions)) {
+      // 地区信息
+      formModel.province = provinceCityDistrict.value[0].value;
+      formModel.provinceName = provinceCityDistrict.value[0].label;
+
+      formModel.city = provinceCityDistrict.value[1].value;
+      formModel.cityName = provinceCityDistrict.value[1].label;
+      if (provinceCityDistrict.value[2]) {
+        formModel.area = provinceCityDistrict.value[2].value;
+        formModel.areaName = provinceCityDistrict.value[2].label;
+      }
+    }
+    console.log('provinceCityDistrict', provinceCityDistrict.value);
+  }
+</script>
+
+<style scoped lang="less">
+  .approval-steps {
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
+    // width: 1350px;
+    margin: 0 auto;
+
+    .basic-title {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      width: 100%;
+      height: 40px;
+      padding: 0 16px 4px 16px;
+      border-bottom: 2px solid #f6f6f6;
+      background: #ffffff;
+      border-top-left-radius: 8px;
+      border-top-right-radius: 8px;
+
+      .basic-title-left {
+        height: 100%;
+        display: flex;
+        align-items: center;
+
+        .basic-title-line {
+          width: 4px;
+          height: 20px;
+          border-radius: 4px;
+          background: #267ef8;
+          margin-right: 5px;
+        }
+
+        .basic-title-text {
+          font-size: 16px;
+          font-style: normal;
+          font-weight: 600;
+          line-height: 20px;
+        }
+      }
+
+      .basic-title-right {
+        display: flex;
+        gap: 10px;
+      }
+    }
+
+    .steps-content {
+      margin-top: 14px;
+    }
+
+    .steps-action {
+      display: flex;
+      justify-content: center;
+      margin-top: 18px;
+    }
+  }
+</style>

+ 170 - 0
src/views/market-manage/external-manage/customer-manage/customer-list/index.vue

@@ -0,0 +1,170 @@
+
+<template>
+  <a-card class="employee-container">
+    <a-table
+      size="small"
+      :columns="columns"
+      :data-source="tableData"
+      :pagination="false"
+      :loading="tableLoading"
+      :scroll="{ x: 1500 }"
+      row-key="employeeId"
+      bordered
+    >
+      <template #bodyCell="{ record, column }">
+        <template v-if="column.dataIndex === 'operate'">
+          <div class="smart-table-operate">
+            <a-button v-privilege="'system:employee:update'" type="link" size="small" @click="goDetailPage(record)">编辑</a-button>
+          </div>
+        </template>
+      </template>
+    </a-table>
+  </a-card>
+</template>
+<script setup lang="ts">
+    import { onMounted } from 'vue';
+    import { useRouter } from 'vue-router';
+    import _ from 'lodash';
+    import { computed, createVNode, reactive, ref, watch } from 'vue';
+    import { rulesApi } from '/@/api/business-rules/rules-api';
+    import { smartSentry } from '/@/lib/smart-sentry';
+
+    import useDict from '/@/utils/dict-util';
+    const initDict = async () => {
+      await useDict.init(['performance_method']);
+    };
+
+    onMounted(async () => {
+      await initDict();
+      queryRules();
+    });
+
+    // ----------------------- 以下是字段定义 emits props ---------------------
+
+    const props = defineProps({
+      selectedRulesId: Number,
+      breadcrumb: Array,
+    });
+
+    // ----------------------- 表格/列表/ 搜索 ---------------------
+    //字段
+    const columns = ref([
+      {
+        title: '风险维度',
+        dataIndex: 'riskDimension',
+        align: 'center',
+        width: 85,
+      },
+      {
+        title: '风险指标',
+        dataIndex: 'riskDimension',
+        align: 'center',
+        width: 70,
+      },
+      {
+        title: '指标定义',
+        dataIndex: 'riskDimension',
+        align: 'center',
+        width: 100,
+      },
+      {
+        title: '条件运算符',
+        dataIndex: 'phone',
+        align: 'center',
+        width: 100,
+      },
+      {
+        title: '条件控制值',
+        dataIndex: 'email',
+        align: 'center',
+        width: 100,
+        ellipsis: true,
+      },
+      {
+        title: '提醒方式',
+        dataIndex: 'administratorFlag',
+        align: 'center',
+        width: 60,
+      },
+      {
+        title: '提醒时间(每天)',
+        dataIndex: 'disabledFlag',
+        align: 'center',
+        width: 60,
+      },
+      {
+        title: '风险等级',
+        dataIndex: 'positionName',
+        align: 'center',
+        width: 100,
+        ellipsis: true,
+      },
+      {
+        title: '状态',
+        dataIndex: 'roleNameList',
+        align: 'center',
+        width: 100,
+      },
+      {
+        title: '操作',
+        dataIndex: 'operate',
+        align: 'center',
+        fixed: 'right',
+        width: 140,
+      },
+    ]);
+    const tableData = ref();
+
+    const tableLoading = ref(false);
+    // 查询
+    async function queryRules() {
+      tableLoading.value = true;
+      try {
+        let res = await rulesApi.queryRulesList();
+        tableData.value = res.data;
+      } catch (error) {
+        smartSentry.captureError(error);
+      } finally {
+        tableLoading.value = false;
+      }
+    }
+
+
+    // ----------------------- 添加、修改、禁用、重置密码 ------------------------------------
+
+    const router = useRouter();
+    function goDetailPage(record) {
+      console.log("record",record);
+      router.push({
+        path: '/business-rules/create-rules',
+        query: {
+          id: record.id,
+        },
+      });
+    }
+</script>
+<style scoped lang="less">
+  .employee-container {
+    height: 100%;
+  }
+
+  .header {
+    display: flex;
+    align-items: center;
+  }
+
+  .query-operate {
+    margin-left: auto;
+    display: flex;
+    align-items: center;
+    margin-bottom: 20px;
+  }
+
+  .btn-group {
+    margin: 10px 0;
+
+    .btn {
+      margin-right: 8px;
+    }
+  }
+</style>

+ 99 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/components/clue-info.vue

@@ -0,0 +1,99 @@
+<template>
+    <a-table size="small" :pagination="false" bordered :dataSource="dataSource" :columns="columns" />
+    <!-- 分页 -->
+    <div class="smart-query-table-page" v-if="dataSource.length">
+        <a-pagination showSizeChanger showQuickJumper show-less-items :pageSizeOptions="PAGE_SIZE_OPTIONS"
+            :defaultPageSize="pagination.pageSize" v-model:current="pagination.pageNum"
+            v-model:pageSize="pagination.pageSize" :total="total" @change="fetchTableData"
+            @showSizeChange="fetchTableData" :show-total="(total) => `共${total}条`" />
+    </div>
+</template>
+
+<script setup name="线索信息">
+import { formatMoney } from '/@/utils/str-util.js';
+import { ref, reactive } from 'vue';
+import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
+
+// 分页数据
+const pagination = reactive({
+    pageNum: 1,
+    pageSize: PAGE_SIZE,
+});
+
+// 数据总数
+const total = ref(0);
+
+const columns = reactive([
+    {
+        title: '序号',
+        dataIndex: '_index',
+        width: 50,
+    },
+    {
+        title: '线索编号',
+        dataIndex: 'clueNumber',
+    },
+    {
+        title: '线索名称',
+        dataIndex: 'clueName',
+    },
+    {
+        title: '线索类型',
+        dataIndex: 'clueType',
+    },
+    {
+        title: '决策关键人',
+        dataIndex: 'decisionMaker',
+    },
+    {
+        title: '电话',
+        dataIndex: 'phone',
+    },
+    {
+        title: '招标方式',
+        dataIndex: 'tenderMethod',
+    },
+    {
+        title: '预计开标时间',
+        dataIndex: 'expectedOpeningTime',
+    },
+    {
+        title: '预计合同金额',
+        dataIndex: 'expectedContractAmount',
+        customRender: ({ text }) => {
+            return formatMoney(text, 2);
+        }
+    },
+    {
+        title: '创建时间',
+        dataIndex: 'createTime',
+    },
+]);
+
+// 生成模拟数据
+function generateMockData(totalData = 10) {
+    const sourceData = columns;
+    const data = [];
+    for (let i = 0; i < totalData; i++) {
+        const item = {};
+        for (let j = 0; j < sourceData.length; j++) {
+            item[sourceData[j].dataIndex] = `row${i + 1},col${j + 1}`;
+        }
+        item._index = i + 1;
+
+        data.push(item);
+    }
+    total.value = data.length;
+    return data;
+}
+
+function fetchTableData() {
+    const data = generateMockData();
+    dataSource.value = data;
+    total.value = data.length;
+}
+
+const dataSource = reactive(generateMockData());
+</script>
+
+<style lang="less" scoped></style>

+ 91 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/components/contract-info.vue

@@ -0,0 +1,91 @@
+<template>
+  <CommonTable ref="commonTableRef" :tableOptions="tableConfig"> </CommonTable>
+</template>
+
+<script setup lang="jsx">
+import { ref } from 'vue';
+import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
+import useDict from '/@/utils/dict-util';
+await useDict.init(['province_city_district', 'BLINK_CUSTOMER_PARTNER_LEVEL', 'BLINK_CUSTOMER_TYPE']);
+
+// 定义 props
+const props = defineProps({
+  id: {
+    type: String,
+    default: () => ({}),
+  },
+});
+
+const commonTableRef = ref(null);
+const tableConfig = ref({
+  // 设置网络请求地址
+  url: '/supports/customer/contract/queryPage',
+  // 设置网络请求方式为GET
+  requestMethod: 'GET',
+  tableId: TABLE_ID_CONST.TEAMWORK.CUSTOMER_MANAGE.CONTRACT_LIST,
+  columns: [
+    {
+      title: '合同名称',
+      dataIndex: 'contractName',
+      align: 'center',
+    },
+    {
+      title: '合同ID',
+      dataIndex: 'contractCode',
+      align: 'center',
+    },
+    {
+      title: '税率',
+      dataIndex: 'rate',
+      align: 'center',
+    },
+    {
+      title: '合同金额(元)',
+      dataIndex: 'contractAmount',
+      align: 'center',
+    },
+    {
+      title: '补充协议金额(元)',
+      dataIndex: 'supplementaryAmount',
+      align: 'center',
+    },
+    {
+      title: '合同总金额(元)',
+      dataIndex: 'contractTotalAmount',
+      align: 'center',
+    },
+    {
+      title: '开票金额(元)',
+      dataIndex: 'invoiceAmount',
+      align: 'center',
+    },
+    {
+      title: '开票进度',
+      dataIndex: 'invoicePercent',
+      align: 'center',
+    },
+    {
+      title: '回款金额(元)',
+      dataIndex: 'paymentAmount',
+      align: 'center',
+    },
+    {
+      title: '回款进度',
+      dataIndex: 'paymentPercent',
+      align: 'center',
+    },
+  ],
+  tableAttrs: {},
+  showIndexColumn: true,
+  // 请求前传参
+  beforeFetch({ params }) {
+    return {
+      customerId: props.id,
+      ...params,
+    };
+  },
+  // afterFetch({ data }) {},
+});
+</script>
+
+<style lang="less" scoped></style>

+ 58 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/components/customer-info.vue

@@ -0,0 +1,58 @@
+<template>
+  <a-flex style="padding: 0 20px" vertical gap="large">
+    <a-descriptions v-for="desc in customerInfo" :key="desc.title" :title="desc.title" :column="4">
+      <a-descriptions-item v-for="item in desc.descItem" :key="item.id" :label="item.label" :span="item.span">
+        {{ item.value }}
+      </a-descriptions-item>
+    </a-descriptions>
+  </a-flex>
+</template>
+
+<script setup name="客户信息">
+import { ref, onMounted, watchEffect } from 'vue';
+
+const props = defineProps({
+  id: {
+    type: String,
+  },
+  descData: {
+    type: Object,
+  },
+});
+
+const customerInfo = ref([]);
+
+onMounted(() => {
+  updateCustomerInfo();
+});
+
+watchEffect(() => {
+  updateCustomerInfo();
+});
+
+function updateCustomerInfo() {
+  customerInfo.value = [
+    {
+      title: '基本信息',
+      descItem: [
+        { label: '客户编号', value: props.descData?.customerCode },
+        { label: '客户名称', value: props.descData?.customerName },
+      ],
+    },
+    {
+      title: '企业信息',
+      descItem: [
+        { label: '公司名称', value: props.descData?.customerName },
+        { label: '统一社会信用代码', value: props.descData?.socialCode },
+        { label: '电话', value: props.descData?.customerManagerMobile, span: 2 },
+        { label: '注册资本', value: props.descData?.companyRegisterCapital },
+        { label: '注册时间', value: props.descData?.companyRegisterDate },
+        { label: '注册地址', value: props.descData?.address, span: 2 },
+        { label: '企业简介', value: props.descData?.customerDescription },
+      ],
+    },
+  ];
+}
+</script>
+
+<style lang="less" scoped></style>

+ 146 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/components/decision-chain.vue

@@ -0,0 +1,146 @@
+<template>
+  <CommonTable ref="commonTableRef" :tableOptions="tableConfig"> </CommonTable>
+  <addDec ref="addDecRef" :visible="isModalVisible" @refresh="initPage"> </addDec>
+</template>
+
+<script setup lang="jsx">
+  import { ref } from 'vue';
+  import { useRouter } from 'vue-router';
+  import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
+  import useDict from '/@/utils/dict-util';
+  import { customerApi } from '/@/api/teamwork/customer/customer-api.js';
+  import addDec from '../modules/add-decision.vue';
+  import { SmartLoading } from '/@/components/framework/smart-loading';
+  import { smartSentry } from '/@/lib/smart-sentry';
+  import { message, Modal } from 'ant-design-vue';
+
+  await useDict.init(['province_city_district', 'BLINK_CUSTOMER_PARTNER_LEVEL', 'BLINK_CUSTOMER_TYPE']);
+
+  // 定义 props
+  const props = defineProps({
+    id: {
+      type: String,
+      default: () => ({}),
+    },
+  });
+  const commonTableRef = ref(null);
+  const addDecRef = ref();
+  const router = useRouter();
+
+  const tableConfig = ref({
+    // 设置网络请求地址
+    url: '/supports/customer/decision/list',
+
+    // 设置网络请求方式为GET
+    requestMethod: 'GET',
+    tableId: TABLE_ID_CONST.TEAMWORK.CUSTOMER_MANAGE.PAYMENT_LIST,
+    buttons: [
+      {
+        label: '新增',
+        iconName: 'PlusOutlined',
+        attrs: {
+          type: 'primary',
+          onClick: () => {
+            addDecRef.value.showModal({ customerId: props.id });
+          },
+        },
+      },
+    ],
+    columns: [
+      {
+        title: '决策人',
+        dataIndex: 'decisionName',
+        align: 'center',
+      },
+      {
+        title: '职务',
+        dataIndex: 'staffName',
+        align: 'center',
+      },
+      {
+        title: '职务权重',
+        dataIndex: 'staffWeight',
+        align: 'center',
+      },
+      {
+        title: '电话',
+        dataIndex: 'phoneNumber',
+        align: 'center',
+      },
+      {
+        title: '年龄',
+        dataIndex: 'decisionAge',
+        align: 'center',
+      },
+      {
+        title: '性别',
+        dataIndex: 'decisionSex',
+        align: 'center',
+      },
+      {
+        title: '操作',
+        dataIndex: 'action',
+        fixed: 'right',
+        align: 'center',
+        width: 110,
+        customRender: ({ text, record, index, column }) => {
+          return (
+            <div class='smart-table-operate'>
+              <a-button type='link' onClick={() => addDecRef.value.showModal({ ...record, customerId: props.id })}>
+                编辑
+              </a-button>
+              <a-button type='link' danger onClick={() => onDelete(record)}>
+                删除
+              </a-button>
+            </div>
+          );
+        },
+      },
+    ],
+    tableAttrs: {},
+    showIndexColumn: true,
+    // 请求前传参
+    beforeFetch({ params }) {
+      return {
+        customerId: props.id,
+        ...params,
+      };
+    },
+    // afterFetch({ data }) {},
+  });
+
+  function initPage() {
+    commonTableRef.value.reload();
+  }
+
+  //确认删除
+  function onDelete(data) {
+    Modal.confirm({
+      title: '提示',
+      content: '确定要删除吗?',
+      okText: '删除',
+      okType: 'danger',
+      onOk() {
+        requestDelete(data);
+      },
+      cancelText: '取消',
+      onCancel() {},
+    });
+  }
+
+  //请求删除
+  async function requestDelete(data) {
+    SmartLoading.show();
+    try {
+      await customerApi.DecisionDelete(data.id);
+      message.success('删除成功');
+      initPage();
+    } catch (e) {
+      smartSentry.captureError(e);
+    } finally {
+      SmartLoading.hide();
+    }
+  }
+</script>
+
+<style lang="less" scoped></style>

+ 85 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/components/edit-info.vue

@@ -0,0 +1,85 @@
+<template>
+  <CommonTable ref="commonTableRef" :tableOptions="tableConfig"> </CommonTable>
+</template>
+
+<script setup lang="jsx">
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
+import useDict from '/@/utils/dict-util';
+await useDict.init(['province_city_district', 'BLINK_CUSTOMER_PARTNER_LEVEL', 'BLINK_CUSTOMER_TYPE']);
+
+// 定义 props
+const props = defineProps({
+  id: {
+    type: String,
+    default: () => ({}),
+  },
+});
+
+const commonTableRef = ref(null);
+const router = useRouter();
+
+const tableConfig = ref({
+  // 设置网络请求地址
+  url: '/supports/customer/repayment/queryPage',
+
+  // 设置网络请求方式为GET
+  requestMethod: 'GET',
+  tableId: TABLE_ID_CONST.TEAMWORK.CUSTOMER_MANAGE.EDIT_LIST,
+  columns: [
+    {
+      title: '回款方',
+      dataIndex: 'repaymentUnitName',
+      align: 'center',
+    },
+    {
+      title: '回款日期',
+      dataIndex: 'repaymentDate',
+      align: 'center',
+    },
+    {
+      title: '关联合同',
+      dataIndex: 'relatedContract',
+      align: 'center',
+    },
+    {
+      title: '关联项目',
+      dataIndex: 'relatedDelivery',
+      align: 'center',
+    },
+    {
+      title: '回款金额(元)',
+      dataIndex: 'paymentAmount',
+      align: 'center',
+    },
+    {
+      title: '回款进度',
+      dataIndex: 'paymentPercent',
+      align: 'center',
+    },
+    {
+      title: '开票金额(元)',
+      align: 'center',
+    },
+    {
+      title: '开票进度',
+      dataIndex: 'invoicePercent',
+      align: 'center',
+    },
+  ],
+  tableAttrs: {},
+  showIndexColumn: true,
+  // 请求前传参
+  beforeFetch({ params }) {
+    return {
+      dataId: props.id,
+      type: '4',
+      ...params,
+    };
+  },
+  // afterFetch({ data }) {},
+});
+</script>
+
+<style lang="less" scoped></style>

+ 103 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/components/file-info.vue

@@ -0,0 +1,103 @@
+<template>
+  <CommonTable ref="commonTableRef" :tableOptions="tableConfig"> </CommonTable>
+</template>
+
+<script setup lang="jsx">
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
+import useDict from '/@/utils/dict-util';
+await useDict.init(['province_city_district', 'BLINK_CUSTOMER_PARTNER_LEVEL', 'BLINK_CUSTOMER_TYPE']);
+
+// 定义 props
+const props = defineProps({
+  id: {
+    type: String,
+    default: () => ({}),
+  },
+});
+
+const commonTableRef = ref(null);
+const router = useRouter();
+
+const tableConfig = ref({
+  // 设置网络请求地址
+  url: '/supports/customer/file/queryPage',
+
+  // 设置网络请求方式为GET
+  requestMethod: 'GET',
+
+  tableId: TABLE_ID_CONST.TEAMWORK.CUSTOMER_MANAGE.FILE_LIST,
+
+  buttons: [
+    {
+      label: '上传附件',
+      iconName: 'PlusOutlined',
+      attrs: {
+        type: 'primary',
+        onClick: () => {
+          router.push({
+            path: '',
+          });
+        },
+      },
+    },
+  ],
+  columns: [
+    {
+      title: '附件名称',
+      dataIndex: 'fileName',
+      align: 'center',
+    },
+    {
+      title: '附件大小',
+      dataIndex: 'fileSize',
+      align: 'center',
+    },
+    {
+      title: '上传人',
+      dataIndex: 'creatorName',
+      align: 'center',
+    },
+    {
+      title: '创建时间',
+      dataIndex: 'createTime',
+      align: 'center',
+    },
+    {
+      title: '操作',
+      dataIndex: 'action',
+      fixed: 'right',
+      align: 'center',
+      width: 160,
+      customRender: ({ text, record, index, column }) => {
+        return (
+          <div class='smart-table-operate'>
+            <a-button type='link' onClick={() => goDetailPage(record)}>
+              预览
+            </a-button>
+            <a-button type='link' onClick={() => goDetailPage(record)}>
+              下载
+            </a-button>
+            <a-button type='link' danger onClick={() => goDetailPage(record)}>
+              删除
+            </a-button>
+          </div>
+        );
+      },
+    },
+  ],
+  tableAttrs: {},
+  showIndexColumn: true,
+  // 请求前传参
+  beforeFetch({ params }) {
+    return {
+      customerId: props.id,
+      ...params,
+    };
+  },
+  // afterFetch({ data }) {},
+});
+</script>
+
+<style lang="less" scoped></style>

+ 105 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/components/follow-up.vue

@@ -0,0 +1,105 @@
+<template>
+  <div class="main">
+    <div class="top" @click="handleAddFollowup">
+      <a-textarea readonly placeholder="请填写跟进" :auto-size="{ minRows: 2, maxRows: 5 }" />
+    </div>
+    <div class="bottom" v-for="(item, index) in followInfo" :key="index">
+      <div class="bottom-left">
+        <span>{{ item.createTime }}</span>
+      </div>
+      <div class="bottom-center">
+        <span>头像</span>
+      </div>
+      <div class="bottom-right">
+        <div class="bottom-right-top">
+          <span>{{ item.createUserId }}</span>
+          <span>14:23:56</span>
+          <span>{{ item.contactType[0].valueName }}</span>
+        </div>
+        <div class="bottom-right-bottom">
+          <span>{{ item.content }}</span>
+        </div>
+      </div>
+    </div>
+  </div>
+  <addFol ref="addFolRef" :visible="isModalVisible" @ok="handleOk" @cancel="handleCancel" @refresh="initPage">
+  </addFol>
+</template>
+<script setup lang="jsx">
+import { onMounted, ref } from 'vue';
+import addFol from '../modules/add-followup.vue';
+import { customerApi } from '/@/api/teamwork/customer/customer-api.js';
+
+// 定义 props
+const props = defineProps({
+  id: {
+    type: String,
+    default: () => ({}),
+  },
+});
+
+const followInfo = ref([]);
+// {
+//   createTime: null,
+//   avatar: null,
+//   createUserId: null,
+//   contactType: null,
+//   content: null,
+// }
+onMounted(() => {
+  initPage();
+});
+
+const addFolRef = ref();
+
+function initPage() {
+  customerApi.FollowUpQuery(props.id).then((res) => {
+    followInfo.value = res.data
+    console.log('followInfo', followInfo);
+  });
+}
+function handleAddFollowup() {
+  addFolRef.value.showModal(props.id);
+}
+</script>
+
+<style lang="less" scoped>
+.main {
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+
+  .top {
+    cursor: pointer;
+    width: 100%;
+    height: 50px;
+    background-color: white;
+    border-radius: 8px;
+    display: flex;
+    align-items: center;
+  }
+
+  .bottom {
+    width: 100%;
+    display: flex;
+    align-items: center;
+    gap: 10px;
+
+    .bottom-center {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      width: 50px;
+      height: 50px;
+      background-color: white;
+      border-radius: 50%;
+    }
+
+    .bottom-right-top {
+      display: flex;
+      align-items: center;
+      gap: 10px;
+    }
+  }
+}
+</style>

+ 114 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/components/project-info.vue

@@ -0,0 +1,114 @@
+<template>
+  <CommonTable ref="commonTableRef" :tableOptions="tableConfig"> </CommonTable>
+  <getProjectNum ref="getProjectNumRef" :visible="isModalVisible"> </getProjectNum>
+</template>
+
+<script setup lang="jsx">
+  import { ref } from 'vue';
+  import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
+  import getProjectNum from '../modules/get-projectnum.vue';
+  import useDict from '/@/utils/dict-util';
+  await useDict.init(['province_city_district', 'BLINK_CUSTOMER_PARTNER_LEVEL', 'BLINK_CUSTOMER_TYPE']);
+
+  // 定义 props
+  const props = defineProps({
+    id: {
+      type: String,
+      default: () => ({}),
+    },
+  });
+
+  const commonTableRef = ref(null);
+  const getProjectNumRef = ref();
+
+  const tableConfig = ref({
+    // 设置网络请求地址
+    url: '/supports/customer/delivery/queryPage',
+
+    // 设置网络请求方式为GET
+    requestMethod: 'GET',
+    tableId: TABLE_ID_CONST.TEAMWORK.CUSTOMER_MANAGE.PROJECT_LIST,
+    columns: [
+      {
+        title: '项目名称',
+        dataIndex: 'deliveryName',
+        align: 'center',
+      },
+      {
+        title: '项目ID',
+        dataIndex: 'deliveryCode',
+        align: 'center',
+      },
+      {
+        title: '项目状态',
+        dataIndex: 'status',
+        align: 'center',
+      },
+      {
+        title: '任务数量',
+        dataIndex: 'taskCount',
+        align: 'center',
+        customRender: ({ text, record, index, column }) => {
+          return (
+            <div class='smart-table-operate'>
+              <a type='link' onClick={() => handlegetProjectNum(record)}>
+                {text}
+              </a>
+            </div>
+          );
+        },
+      },
+      {
+        title: '预计开始时间',
+        dataIndex: 'planStartDate',
+        align: 'center',
+      },
+      {
+        title: '预计结束时间',
+        dataIndex: 'planEndDate',
+        align: 'center',
+      },
+      {
+        title: '预计人天',
+        dataIndex: 'planDays',
+        align: 'center',
+      },
+      {
+        title: '实际人天',
+        dataIndex: 'actualDays',
+        align: 'center',
+      },
+      {
+        title: '交付经理',
+        dataIndex: 'deliveryManager',
+        align: 'center',
+      },
+    ],
+    tableAttrs: {},
+    showIndexColumn: true,
+    // 请求前传参
+    beforeFetch({ params }) {
+      return {
+        customerId: props.id,
+        ...params,
+      };
+    },
+    // afterFetch({ data }) {},
+  });
+
+  function goDetailPage(record) {
+    // console.log('111111', record);
+    // router.push({
+    //   path: '/teamwork/customer-manage/single-customer',
+    //   query: {
+    //     ...record,
+    //   },
+    // });
+  }
+
+  function handlegetProjectNum(record) {
+    getProjectNumRef.value.showModal({ ...record });
+  }
+</script>
+
+<style lang="less" scoped></style>

+ 85 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/components/repayment-info.vue

@@ -0,0 +1,85 @@
+<template>
+  <CommonTable ref="commonTableRef" :tableOptions="tableConfig"> </CommonTable>
+</template>
+
+<script setup lang="jsx">
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
+import useDict from '/@/utils/dict-util';
+await useDict.init(['province_city_district', 'BLINK_CUSTOMER_PARTNER_LEVEL', 'BLINK_CUSTOMER_TYPE']);
+
+// 定义 props
+const props = defineProps({
+  id: {
+    type: String,
+    default: () => ({}),
+  },
+});
+
+const commonTableRef = ref(null);
+const router = useRouter();
+
+const tableConfig = ref({
+  // 设置网络请求地址
+  url: '/supports/customer/repayment/queryPage',
+
+  // 设置网络请求方式为GET
+  requestMethod: 'GET',
+  tableId: TABLE_ID_CONST.TEAMWORK.CUSTOMER_MANAGE.PAYMENT_LIST,
+  columns: [
+    {
+      title: '回款方',
+      dataIndex: 'repaymentUnitName',
+      align: 'center',
+    },
+    {
+      title: '回款日期',
+      dataIndex: 'repaymentDate',
+      align: 'center',
+    },
+    {
+      title: '关联合同',
+      dataIndex: 'relatedContract',
+      align: 'center',
+    },
+    {
+      title: '关联项目',
+      dataIndex: 'relatedDelivery',
+      align: 'center',
+    },
+    {
+      title: '回款金额(元)',
+      dataIndex: 'paymentAmount',
+      align: 'center',
+    },
+    {
+      title: '回款进度',
+      dataIndex: 'paymentPercent',
+      align: 'center',
+    },
+    {
+      title: '开票金额(元)',
+      dataIndex: 'invoiceAmount',
+      align: 'center',
+    },
+    {
+      title: '开票进度',
+      dataIndex: 'invoicePercent',
+      align: 'center',
+    },
+  ],
+  tableAttrs: {},
+  showIndexColumn: true,
+  // 请求前传参
+  beforeFetch({ params }) {
+    return {
+      customerId: props.id,
+      ...params,
+    };
+  },
+  // afterFetch({ data }) {},
+});
+</script>
+
+<style lang="less" scoped></style>

+ 84 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/components/view-info.vue

@@ -0,0 +1,84 @@
+<template>
+  <CommonTable ref="commonTableRef" :tableOptions="tableConfig"> </CommonTable>
+</template>
+
+<script setup lang="jsx">
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
+import useDict from '/@/utils/dict-util';
+await useDict.init(['province_city_district', 'BLINK_CUSTOMER_PARTNER_LEVEL', 'BLINK_CUSTOMER_TYPE']);
+
+// 定义 props
+const props = defineProps({
+  id: {
+    type: String,
+    default: () => ({}),
+  },
+});
+
+const commonTableRef = ref(null);
+
+const tableConfig = ref({
+  // 设置网络请求地址
+  url: '/supports/view/record/queryPage',
+
+  // 设置网络请求方式为GET
+  requestMethod: 'GET',
+  tableId: TABLE_ID_CONST.TEAMWORK.CUSTOMER_MANAGE.VIEW_LIST,
+  columns: [
+    {
+      title: '回款方',
+      dataIndex: 'repaymentUnitName',
+      align: 'center',
+    },
+    {
+      title: '回款日期',
+      dataIndex: 'repaymentDate',
+      align: 'center',
+    },
+    {
+      title: '关联合同',
+      dataIndex: 'relatedContract',
+      align: 'center',
+    },
+    {
+      title: '关联项目',
+      dataIndex: 'relatedDelivery',
+      align: 'center',
+    },
+    {
+      title: '回款金额(元)',
+      dataIndex: 'paymentAmount',
+      align: 'center',
+    },
+    {
+      title: '回款进度',
+      dataIndex: 'paymentPercent',
+      align: 'center',
+    },
+    {
+      title: '开票金额(元)',
+      align: 'center',
+    },
+    {
+      title: '开票进度',
+      dataIndex: 'invoicePercent',
+      align: 'center',
+    },
+  ],
+  tableAttrs: {},
+  showIndexColumn: true,
+  // 请求前传参
+  beforeFetch({ params }) {
+    return {
+      dataId: props.id,
+      type: '4',
+      ...params,
+    };
+  },
+  // afterFetch({ data }) {},
+});
+</script>
+
+<style lang="less" scoped></style>

+ 174 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/index.vue

@@ -0,0 +1,174 @@
+<template>
+  <a-flex style="padding: 0 20px" vertical :gap="10">
+    <a-card :bordered="false">
+      <a-flex justify="space-between" align="center">
+        <a-flex align="center" gap="small">
+          <a-flex vertical gap="small">
+            <div class="header-info">
+              <div class="header-info-top">
+                <span>{{ singleCusValue?.customerName }}</span>
+                <a-tag color="#D4AF37" style="font-size: 10px;">{{ singleCusValue?.partnerLevel[0]?.valueName }}</a-tag>
+              </div>
+              <div class="header-info-bottom">
+                <div>客户类型:
+                  <span>{{ singleCusValue?.customerType[0]?.valueName }}</span>
+                </div>
+                <div>客户编码:
+                  <span>{{ singleCusValue?.customerCode }}</span>
+                </div>
+                <div>所在省市:
+                  <span>{{ `${singleCusValue?.provinceName}${singleCusValue?.cityName}` }}</span>
+                </div>
+              </div>
+            </div>
+          </a-flex>
+        </a-flex>
+        <!-- <a-space>
+          <a-button type="primary">编辑</a-button>
+        </a-space> -->
+      </a-flex>
+    </a-card>
+    <a-card :bordered="false">
+      <a-flex vertical gap="small">
+        <div class="context">
+          <div v-for="item in descList" :key="item.id" class="context-item">
+            <span>{{ item.label }}</span>
+            <span>{{ item.value }}</span>
+          </div>
+        </div>
+      </a-flex>
+    </a-card>
+    <a-card :tab-list="tabList" :active-tab-key="tabKey" @tabChange="onTabChange">
+      <component :is="tabList[tabKey]['component']" :id="query.id" :descData="singleCusValue"></component>
+    </a-card>
+  </a-flex>
+</template>
+
+<script setup>
+  import { ref, defineAsyncComponent, onMounted, watchEffect } from 'vue';
+  // import { customerApi } from '/@/api/teamwork/customer/customer-api';
+  import { useRouter } from 'vue-router';
+
+  const router = useRouter();
+  const query = router.currentRoute.value.query;
+  const singleCusValue = ref({
+    customerName: '',
+    partnerLevel: [],
+    customerType: [],
+  });
+
+  const descList = ref([
+    { id: '1', label: '合同数量', value: singleCusValue.contractQuantity },
+    { id: '2', label: '累计产值', value: singleCusValue.totalOutputValue },
+    { id: '3', label: '已开票', value: singleCusValue.invoiceAmount },
+    { id: '4', label: '未开票', value: singleCusValue.unlicensedAmount },
+  ]);
+
+  const tabKey = ref('0');
+  const tabList = [
+    {
+      key: '0',
+      tab: '客户信息',
+      component: defineAsyncComponent(() => import('./components/customer-info.vue')),
+    },
+    {
+      key: '1',
+      tab: '跟进记录',
+      component: defineAsyncComponent(() => import('./components/follow-up.vue')),
+    },
+    {
+      key: '2',
+      tab: '决策链条信息',
+      component: defineAsyncComponent(() => import('./components/decision-chain.vue')),
+    },
+    {
+      key: '3',
+      tab: '合同信息',
+      component: defineAsyncComponent(() => import('./components/contract-info.vue')),
+    },
+    {
+      key: '4',
+      tab: '项目信息',
+      component: defineAsyncComponent(() => import('./components/project-info.vue')),
+    },
+    {
+      key: '5',
+      tab: '回款信息',
+      component: defineAsyncComponent(() => import('./components/repayment-info.vue')),
+    },
+    {
+      key: '6',
+      tab: '文件资料',
+      component: defineAsyncComponent(() => import('./components/file-info.vue')),
+    },
+  ];
+
+  onMounted(() => {
+    getSingleCustomerList();
+  });
+
+  // 查询列表
+  function getSingleCustomerList() {
+    customerApi.getCustomerList(query.id).then(
+      (res) => {
+        singleCusValue.value = res.data;
+        console.log('singleCusValue', singleCusValue.value);
+      },
+      (err) => {
+        console.error(err);
+      }
+    );
+  }
+
+  const onTabChange = (value) => {
+    tabKey.value = value;
+  };
+</script>
+
+<style lang="less" scoped>
+  .header-info {
+    .header-info-top {
+      display: flex;
+      align-items: center;
+      gap: 20px;
+      margin-bottom: 10px;
+
+      span {
+        font-size: 20px;
+        font-weight: 600;
+      }
+    }
+
+    .header-info-bottom {
+      display: flex;
+      align-items: center;
+      gap: 80px;
+
+      span {
+        font-size: 15px;
+        font-weight: 600;
+        color: rgb(0, 0, 0);
+      }
+    }
+  }
+
+  .context {
+    display: flex;
+    align-items: center;
+    gap: 100px;
+    margin-left: 20px;
+
+    .context-item {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      gap: 10px;
+    }
+
+    span:nth-child(1) {
+      font-size: 15px;
+      font-weight: 600;
+      color: rgb(1, 1, 1);
+    }
+  }
+</style>

+ 140 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/modules/add-decision.vue

@@ -0,0 +1,140 @@
+<!--
+  * 部门表单 弹窗
+  *
+  * @Author:    BoundLink
+  * @Date:      2022-08-08 20:46:18
+-->
+<template>
+  <a-modal v-model:open="visible" title="新增决策人" @ok="handleOk" @cancel="closeModal" destroyOnClose>
+    <a-form ref="formRef" :model="formState" layout="vertical" :rules="fromRules">
+      <a-form-item label="决策人" name="decisionName">
+        <a-input v-model:value.trim="formState.decisionName" placeholder="请输入决策人姓名" />
+      </a-form-item>
+      <a-form-item label="职务" name="staffName">
+        <a-input v-model:value.trim="formState.staffName" placeholder="请输入职务" />
+      </a-form-item>
+      <a-form-item style="width: 100%" label="职务权重" name="staffWeight">
+        <a-input-number style="width: 100%" v-model:value.trim="formState.staffWeight" placeholder="请输入职务权重" />
+      </a-form-item>
+      <a-form-item label="电话" name="phoneNumber">
+        <a-input v-model:value.trim="formState.phoneNumber" placeholder="请输入电话" />
+      </a-form-item>
+      <a-form-item label="年龄" name="decisionAge">
+        <a-input-number style="width: 100%" v-model:value.trim="formState.decisionAge" placeholder="请输入年龄" />
+      </a-form-item>
+      <a-form-item label="性别" name="decisionSex">
+        <a-input v-model:value.trim="formState.decisionSex" placeholder="请输入性别" />
+      </a-form-item>
+    </a-form>
+  </a-modal>
+</template>
+<script setup>
+  import { reactive, ref } from 'vue';
+  import { customerApi } from '/@/api/teamwork/customer/customer-api.js';
+  import { smartSentry } from '/@/lib/smart-sentry';
+  import { SmartLoading } from '/@/components/framework/smart-loading';
+
+  // ----------------------- 对外暴漏 ---------------------
+  defineExpose({
+    showModal,
+  });
+
+  // ----------------------- modal 的显示与隐藏 ---------------------
+  const emits = defineEmits(['refresh']);
+
+  const visible = ref(false);
+
+  function showModal(params) {
+    visible.value = true;
+    updateFormData(params);
+  }
+
+  function closeModal() {
+    visible.value = false;
+    resetFormData();
+  }
+
+  // ----------------------- form 表单操作 ---------------------
+  const formRef = ref();
+
+  const defaultPlatformAccountForm = {
+    customerId: undefined,
+    id: undefined,
+    decisionName: undefined, //决策人姓名
+    staffName: undefined, //职务
+    staffWeight: undefined, //职务权重
+    phoneNumber: undefined, //电话
+    decisionAge: undefined, //年龄
+    decisionSex: undefined, //性别
+  };
+
+  let formState = reactive({
+    ...defaultPlatformAccountForm,
+  });
+
+  // 表单校验规则
+  const fromRules = {
+    decisionName: [{ required: true, message: '决策人姓名不能为空' }],
+    staffName: [{ required: true, message: '职务不能为空' }],
+    staffWeight: [{ required: true, message: '职务权重不能为空' }],
+    phoneNumber: [{ required: true, message: '电话不能为空' }],
+    decisionAge: [{ required: true, message: '年龄不能为空' }],
+    decisionSex: [{ required: true, message: '性别不能为空' }],
+  };
+
+  // 更新表单数据
+  function updateFormData(data) {
+    console.log('-=-=-=-=', data);
+
+    Object.assign(formState, defaultPlatformAccountForm);
+    if (data) {
+      Object.assign(formState, data);
+    }
+    visible.value = true;
+  }
+
+  // 重置表单数据
+  function resetFormData() {
+    Object.assign(formState, defaultPlatformAccountForm);
+  }
+
+  async function handleOk() {
+    try {
+      await formRef.value.validate();
+      if (formState.id) {
+        updateDecision();
+      } else {
+        addDecision();
+      }
+    } catch (error) {}
+  }
+
+  // ----------------------- form 表单  ajax 操作 ---------------------
+  // 添加 ajax请求
+  async function addDecision() {
+    SmartLoading.show();
+    try {
+      await customerApi.DecisionAddition(formState);
+      emits('refresh');
+      closeModal();
+    } catch (error) {
+      smartSentry.captureError(error);
+    } finally {
+      SmartLoading.hide();
+    }
+  }
+
+  // 编辑 ajax请求
+  async function updateDecision() {
+    SmartLoading.show();
+    try {
+      await customerApi.DecisionUpdate(formState);
+      emits('refresh');
+      closeModal();
+    } catch (error) {
+      smartSentry.captureError(error);
+    } finally {
+      SmartLoading.hide();
+    }
+  }
+</script>

+ 100 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/modules/add-followup.vue

@@ -0,0 +1,100 @@
+<!--
+  * 跟进方式 弹窗
+  *
+  * @Author:    BoundLink
+  * @Date:      2022-08-08 20:46:18
+-->
+<template>
+  <a-modal v-model:open="visible" title="新增跟进记录" @ok="handleOk" @cancel="closeModal" destroyOnClose>
+    <a-form ref="formRef" :model="formState" layout="vertical" :rules="formRules">
+      <a-form-item label="跟进内容" name="content">
+        <a-input v-model:value="formState.content" placeholder="请输入跟进内容" />
+      </a-form-item>
+      <a-form-item label="跟进方式" name="contactType" placeholder="请选择跟进方式">
+        <DictSelect key-code="BLINK_CUSTOMER_FOLLOW_TYPE" v-model:value="formState.contactType" width="100%" />
+      </a-form-item>
+    </a-form>
+  </a-modal>
+</template>
+<script setup>
+import message from 'ant-design-vue/lib/message';
+import { reactive, ref } from 'vue';
+import { customerApi } from '/@/api/teamwork/customer/customer-api.js';
+import { smartSentry } from '/@/lib/smart-sentry';
+import DictSelect from '/@/components/common/dict-select/index.vue';
+import { SmartLoading } from '/@/components/framework/smart-loading';
+
+// ----------------------- 对外暴漏 ---------------------
+defineExpose({
+  showModal,
+});
+
+// ----------------------- modal 的显示与隐藏 ---------------------
+const emits = defineEmits(['refresh']);
+
+const visible = ref(false);
+const customerId = ref(null);
+
+function showModal(id) {
+  visible.value = true;
+  customerId.value = id;
+  // updateFormData(data);
+}
+
+function closeModal() {
+  visible.value = false;
+  resetFormData();
+}
+
+// ----------------------- form 表单操作 ---------------------
+const formRef = ref();
+
+const defaultPlatformAccountForm = {
+  customerId: customerId, //客户id
+  content: undefined, //跟进内容
+  contactType: undefined, //跟进方式
+};
+
+let formState = reactive({
+  ...defaultPlatformAccountForm,
+});
+
+// 表单校验规则
+const formRules = {
+  content: [
+    { required: true, message: '跟进内容不能为空' },
+  ],
+  contactType: [
+    { required: true, message: '跟进方式不能为空' },
+  ],
+};
+
+// 重置表单数据
+function resetFormData() {
+  Object.assign(formState, defaultPlatformAccountForm);
+}
+
+async function handleOk() {
+  try {
+    await formRef.value.validate();
+    addFollowup();
+  } catch (error) {
+  }
+}
+
+// ----------------------- form 表单  ajax 操作 ---------------------
+// 添加 ajax请求
+async function addFollowup() {
+  SmartLoading.show();
+  try {
+    await customerApi.FollowUpAdd(formState);
+    closeModal();
+    message.success('提交成功');
+    emits('refresh');
+  } catch (error) {
+    smartSentry.captureError(error);
+  } finally {
+    SmartLoading.hide();
+  }
+}
+</script>

+ 153 - 0
src/views/market-manage/external-manage/customer-manage/single-customer/modules/get-projectnum.vue

@@ -0,0 +1,153 @@
+<!--
+  * 跟进方式 弹窗
+  *
+  * @Author:    BoundLink
+  * @Date:      2022-08-08 20:46:18
+-->
+<template>
+  <a-modal v-model:open="visible" @ok="closeModal" destroyOnClose style="width: 90%; height: 90%">
+    <div class="title">
+      <div class="top-title">
+        <span>{{ recordData.deliveryName }}</span>
+        <a-tag>{{ recordData.status }}</a-tag>
+      </div>
+
+      <div class="bottom-title">
+        <span>项目ID:{{ recordData.deliveryCode }}</span>
+        <span>任务数:{{ recordData.taskCount }}</span>
+        <span>预计开始:{{ recordData.planStartDate }}</span>
+        <span>预计结束:{{ recordData.planEndDate }}</span>
+        <span>预计人天:{{ recordData.planDays }}</span>
+        <span>实际人天:{{ recordData.actualDays }}</span>
+        <span>交付经理:{{ recordData.deliveryManager }}</span>
+      </div>
+    </div>
+    <a-form ref="formRef" :model="formState" layout="vertical">
+      <CommonTable ref="commonTableRef" :tableOptions="tableConfig"> </CommonTable>
+    </a-form>
+  </a-modal>
+</template>
+<script setup>
+  import { reactive, ref } from 'vue';
+  import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
+
+  // ----------------------- 对外暴漏 ---------------------
+  defineExpose({
+    showModal,
+  });
+
+  // ----------------------- modal 的显示与隐藏 ---------------------
+  const emits = defineEmits(['refresh']);
+
+  const visible = ref(false);
+  const commonTableRef = ref(null);
+  const recordData = reactive({});
+
+  function showModal(record) {
+    visible.value = true;
+    Object.assign(recordData, record);
+    console.log('recordDate', recordData);
+  }
+
+  // ----------------------- 表格配置 ---------------------
+
+  const tableConfig = ref({
+    // 设置网络请求地址
+    url: '/supports/customer/queryPage',
+
+    // 设置网络请求方式为GET
+    requestMethod: 'GET',
+    tableId: TABLE_ID_CONST.TEAMWORK.CUSTOMER_MANAGE.TASK_LIST,
+    columns: [
+      {
+        title: '任务名称',
+        dataIndex: 'socialCode',
+        align: 'center',
+      },
+      {
+        title: '任务ID',
+        dataIndex: 'provinceCityDistrict',
+        align: 'center',
+      },
+      {
+        title: '任务状态',
+        dataIndex: 'provinceCityDistrict',
+        align: 'center',
+      },
+      {
+        title: '预计开始',
+        dataIndex: 'provinceCityDistrict',
+        align: 'center',
+      },
+      {
+        title: '预计结束',
+        dataIndex: 'provinceCityDistrict',
+        align: 'center',
+      },
+      {
+        title: '预计人天',
+        dataIndex: 'provinceCityDistrict',
+        align: 'center',
+      },
+      {
+        title: '实际开始',
+        dataIndex: 'provinceCityDistrict',
+        align: 'center',
+      },
+      {
+        title: '实际结束',
+        dataIndex: 'provinceCityDistrict',
+        align: 'center',
+      },
+      {
+        title: '实际人天',
+        dataIndex: 'provinceCityDistrict',
+        align: 'center',
+      },
+      {
+        title: '前端开发',
+        dataIndex: 'provinceCityDistrict',
+        align: 'center',
+      },
+      {
+        title: '后端开发',
+        dataIndex: 'provinceCityDistrict',
+        align: 'center',
+      },
+    ],
+    tableAttrs: {},
+    showIndexColumn: true,
+    // 请求前传参
+    beforeFetch({ params }) {
+      return {
+        ...params,
+      };
+    },
+    // afterFetch({ data }) {},
+  });
+
+  function closeModal() {
+    visible.value = false;
+  }
+</script>
+<style lang="less" scoped>
+  .title {
+    display: flex;
+    flex-direction: column;
+    gap: 10px;
+    .top-title {
+      display: flex;
+      gap: 10px;
+      span {
+        font-size: 16px;
+      }
+    }
+    .bottom-title {
+      display: flex;
+      gap: 20px;
+      span {
+        font-size: 16px;
+      }
+    }
+  }
+</style>

+ 197 - 0
src/views/market-manage/internal-manage/serviceProvider-manage/audit-list/index.vue

@@ -0,0 +1,197 @@
+<template>
+  <div class="table-demo">
+    <bs-table v-bind="tableOptions">
+      <template #searchRight>
+        <a-space>
+          <a-button type="primary" @click="openEditDrawer">
+            <template #icon>
+              <PlusOutlined />
+            </template>
+            <span>新增</span>
+          </a-button>
+        </a-space>
+      </template>
+    </bs-table>
+
+    <add-or-edit-drawer ref="addOrEditDrawerRef" />
+  </div>
+</template>
+
+<script setup>
+  import BsTable, { useBsTable } from '/@/components/BsUi/Table/index.js';
+  import { onMounted, ref } from 'vue';
+  import { pick } from 'lodash';
+  import AddOrEditDrawer from '/@/views/table-demo/components/AddOrEditDrawer.vue';
+  import { clientManageApi } from '/@/api/market-manage/index.js';
+
+  const addOrEditDrawerRef = ref(null);
+
+  const {
+    tableOptions,
+    setTablePropsValue: setValue,
+    getTablePropsValue: getValue,
+  } = useBsTable({
+    tableOptions: {
+      gridOptions: {
+        loading: false,
+        columns: [
+          {
+            field: 'id',
+            title: '状态',
+          },
+          {
+            field: 'name',
+            title: '流水号',
+          },
+          {
+            field: 'name1',
+            title: '服务商名称',
+          },
+          {
+            field: 'name2',
+            title: '服务商ID',
+          },
+          {
+            field: 'name',
+            title: '服务商地址',
+          },
+          {
+            field: 'name',
+            title: '归属区域',
+          },
+          {
+            field: 'name',
+            title: '服务商类型',
+          },
+          {
+            field: 'name',
+            title: '注册来源',
+          },
+          {
+            field: 'name',
+            title: '注册时间',
+          },
+          {
+            field: 'name',
+            title: '归属营销经理',
+          },
+          {
+            field: 'action',
+            title: '操作',
+          },
+        ],
+      },
+      searchConfig: {
+        enabled: true,
+        fieldSpan: 4,
+        fields: [
+          {
+            field: 'name',
+            label: '',
+            component: 'a-input',
+            componentProps: {
+              placeholder: '请输入服务商名称',
+            },
+          },
+          {
+            field: 'name',
+            label: '',
+            component: 'a-select',
+            componentProps: {
+              placeholder: '请选择地址',
+            },
+          },
+          {
+            field: 'name',
+            label: '',
+            component: 'a-select',
+            componentProps: {
+              placeholder: '请选择服务商类型',
+            },
+          },
+        ],
+        onSearch() {
+          fetchTableData();
+        },
+        onReset() {
+          fetchTableData();
+        },
+      },
+      // pagerConfig: {
+      //   enabled: true,
+      //   pageSize: 10,
+      //   pageNum: 1,
+      //   total: 100,
+      //   onChange: () => {
+      //     fetchTableData();
+      //   },
+      // },
+      toolbarConfig: {
+        onRefresh() {
+          fetchTableData();
+        },
+      },
+    },
+  });
+
+  const getSearchParams = () => {
+    return getValue('searchConfig.data');
+  };
+  const getPageInfo = () => {
+    return pick(getValue('pagerConfig.pageInfo'), ['pageNum', 'pageSize']);
+  };
+
+  const fetchTableData = () => {
+    setValue('gridOptions.loading', true);
+
+    const params = {
+      ...getSearchParams(),
+      ...getPageInfo(),
+    };
+
+    //
+    // clientManageApi.interventionsList(params).then((res) => {
+    //   console.log('res', res);
+    //   setValue('gridOptions.data', res.data.list);
+    // });
+    
+    const TableDate = [
+      {
+        id: '1111111',
+        name: 'John Doe',
+        name1: '1212212',
+        name2: '1313131',
+      },
+      {
+        id: '22222',
+        name: 'John Doe',
+        name1: '1212212',
+        name2: '1313131',
+      },
+      {
+        id: '33333',
+        name: 'John sssssDoe',
+        name1: '12122sss12',
+        name2: '13sss13131',
+      },
+    ];
+    setTimeout(() => {
+      setValue('gridOptions.data', TableDate);
+      setValue('gridOptions.loading', false);
+    }, 1000);
+  };
+
+  onMounted(() => {
+    console.log('表格已加载');
+    fetchTableData();
+  });
+
+  const openEditDrawer = () => {
+    addOrEditDrawerRef.value.showDrawer();
+  };
+</script>
+
+<style scoped lang="scss">
+  .table-demo {
+  }
+</style>

+ 197 - 0
src/views/market-manage/internal-manage/serviceProvider-manage/certified-list/index.vue

@@ -0,0 +1,197 @@
+<template>
+  <div class="table-demo">
+    <bs-table v-bind="tableOptions">
+      <template #searchRight>
+        <a-space>
+          <a-button type="primary" @click="openEditDrawer">
+            <template #icon>
+              <PlusOutlined />
+            </template>
+            <span>新增</span>
+          </a-button>
+        </a-space>
+      </template>
+    </bs-table>
+
+    <add-or-edit-drawer ref="addOrEditDrawerRef" />
+  </div>
+</template>
+
+<script setup>
+  import BsTable, { useBsTable } from '/@/components/BsUi/Table/index.js';
+  import { onMounted, ref } from 'vue';
+  import { pick } from 'lodash';
+  import AddOrEditDrawer from '/@/views/table-demo/components/AddOrEditDrawer.vue';
+  import { clientManageApi } from '/@/api/market-manage/index.js';
+
+  const addOrEditDrawerRef = ref(null);
+
+  const {
+    tableOptions,
+    setTablePropsValue: setValue,
+    getTablePropsValue: getValue,
+  } = useBsTable({
+    tableOptions: {
+      gridOptions: {
+        loading: false,
+        columns: [
+          {
+            field: 'id',
+            title: '状态',
+          },
+          {
+            field: 'name',
+            title: '流水号',
+          },
+          {
+            field: 'name1',
+            title: '服务商名称',
+          },
+          {
+            field: 'name2',
+            title: '服务商ID',
+          },
+          {
+            field: 'name',
+            title: '服务商地址',
+          },
+          {
+            field: 'name',
+            title: '归属区域',
+          },
+          {
+            field: 'name',
+            title: '服务商类型',
+          },
+          {
+            field: 'name',
+            title: '注册来源',
+          },
+          {
+            field: 'name',
+            title: '注册时间',
+          },
+          {
+            field: 'name',
+            title: '归属营销经理',
+          },
+          {
+            field: 'action',
+            title: '操作',
+          },
+        ],
+      },
+      searchConfig: {
+        enabled: true,
+        fieldSpan: 4,
+        fields: [
+          {
+            field: 'name',
+            label: '',
+            component: 'a-input',
+            componentProps: {
+              placeholder: '请输入服务商名称',
+            },
+          },
+          {
+            field: 'name',
+            label: '',
+            component: 'a-select',
+            componentProps: {
+              placeholder: '请选择地址',
+            },
+          },
+          {
+            field: 'name',
+            label: '',
+            component: 'a-select',
+            componentProps: {
+              placeholder: '请选择服务商类型',
+            },
+          },
+        ],
+        onSearch() {
+          fetchTableData();
+        },
+        onReset() {
+          fetchTableData();
+        },
+      },
+      // pagerConfig: {
+      //   enabled: true,
+      //   pageSize: 10,
+      //   pageNum: 1,
+      //   total: 100,
+      //   onChange: () => {
+      //     fetchTableData();
+      //   },
+      // },
+      toolbarConfig: {
+        onRefresh() {
+          fetchTableData();
+        },
+      },
+    },
+  });
+
+  const getSearchParams = () => {
+    return getValue('searchConfig.data');
+  };
+  const getPageInfo = () => {
+    return pick(getValue('pagerConfig.pageInfo'), ['pageNum', 'pageSize']);
+  };
+
+  const fetchTableData = () => {
+    setValue('gridOptions.loading', true);
+
+    const params = {
+      ...getSearchParams(),
+      ...getPageInfo(),
+    };
+
+    //
+    // clientManageApi.interventionsList(params).then((res) => {
+    //   console.log('res', res);
+    //   setValue('gridOptions.data', res.data.list);
+    // });
+    
+    const TableDate = [
+      {
+        id: '1111111',
+        name: 'John Doe',
+        name1: '1212212',
+        name2: '1313131',
+      },
+      {
+        id: '22222',
+        name: 'John Doe',
+        name1: '1212212',
+        name2: '1313131',
+      },
+      {
+        id: '33333',
+        name: 'John sssssDoe',
+        name1: '12122sss12',
+        name2: '13sss13131',
+      },
+    ];
+    setTimeout(() => {
+      setValue('gridOptions.data', TableDate);
+      setValue('gridOptions.loading', false);
+    }, 1000);
+  };
+
+  onMounted(() => {
+    console.log('表格已加载');
+    fetchTableData();
+  });
+
+  const openEditDrawer = () => {
+    addOrEditDrawerRef.value.showDrawer();
+  };
+</script>
+
+<style scoped lang="scss">
+  .table-demo {
+  }
+</style>

+ 386 - 0
src/views/market-manage/internal-manage/serviceProvider-manage/create-service/index.vue

@@ -0,0 +1,386 @@
+<template>
+  <a-card>
+    <a-form class="smart-query-form" ref="stepFormRef" labelWrap :label-col="labelCol" :model="formModel" :rules="formRules">
+      <div class="approval-steps">
+        <div>
+          <div class="basic-title">
+            <div class="basic-title-left">
+              <div class="basic-title-line"></div>
+              <span class="basic-title-text">基本信息</span>
+            </div>
+            <div class="basic-title-right">
+              <a-button type="primary" @click="reset">重置</a-button>
+              <a-button type="primary" @click="submit">提交</a-button>
+            </div>
+          </div>
+          <div class="steps-content">
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="8">
+                <a-form-item label="操作人" name="customerName" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.customerName" placeholder="请输入操作人" disabled />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="操作部门" name="customerType" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.socialCode" placeholder="请输入操作部门" disabled />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="操作时间" name="customerType" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.socialCode" placeholder="请输入操作时间" disabled />
+                </a-form-item>
+              </a-col>
+            </a-row>
+          </div>
+        </div>
+        <div>
+          <div class="basic-title">
+            <div class="basic-title-left">
+              <div class="basic-title-line"></div>
+              <span class="basic-title-text">服务商信息</span>
+            </div>
+            <div class="basic-title-right">
+              <!-- <a-button type="primary">提交</a-button> -->
+            </div>
+          </div>
+          <div class="steps-content">
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="8">
+                <a-form-item label="类型" name="socialCode" class="smart-query-form-item">
+                  <DictSelect key-code="BLINK_CUSTOMER_TYPE" v-model:value="formModel.customerType" placeholder="请选择服务商类型" width="100%" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="16">
+                <a-form-item label="服务商名称" name="invoiceTitle" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceTitle" placeholder="请输入服务商名称" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="社会统一代码" name="invoiceCode" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceCode" placeholder="请输入社会统一代码" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="8">
+                <a-form-item label="省市区" name="invoiceAddress" class="smart-query-form-item">
+                  <AreaCascader
+                    type="province_city_district"
+                    style="width: 100%"
+                    v-model:value="provinceCityDistrict"
+                    placeholder="请选择省市区"
+                    @change="changeArea"
+                  />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="详细地址" name="invoiceMobile" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceMobile" placeholder="请输入详细地址" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="对接人" name="invoiceBankName" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceBankName" placeholder="请选择对接人" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="8">
+                <a-form-item label="注册时间" name="invoiceAddress" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceAddress" placeholder="请输入注册时间" />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="注册资本" name="invoiceMobile" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceMobile" placeholder="请输入注册资本" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="8">
+                <a-form-item label="对接人电话" name="invoiceAddress" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceAddress" placeholder="请输入对接人电话" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="24">
+                <a-form-item label="公司简介" name="invoiceAddress" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceAddress" placeholder="请输入公司简介" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="24">
+                <a-form-item label="经营范围" name="invoiceAddress" class="smart-query-form-item">
+                  <a-input v-model:value="formModel.invoiceAddress" placeholder="请输入经营范围" />
+                </a-form-item>
+              </a-col>
+            </a-row>
+            <a-row :gutter="16" class="smart-query-form-row" style="display: flex; align-items: center">
+              <a-col :span="8">
+                <a-form-item label="营业执照" name="attachment" class="smart-query-form-item">
+                  <Upload
+                    :defaultFileList="defaultFileListYY"
+                    :maxUploadSize="1"
+                    buttonText="上传营业执照"
+                    list-type="picture-card"
+                    @change="changeAttachmentYY"
+                  />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="身份证人像面" name="attachment" class="smart-query-form-item">
+                  <Upload
+                    :defaultFileList="defaultFileListFront"
+                    :maxUploadSize="1"
+                    buttonText="上传身份证人像面"
+                    list-type="picture-card"
+                    @change="changeAttachmentFront"
+                  />
+                </a-form-item>
+              </a-col>
+              <a-col :span="8">
+                <a-form-item label="身份证国徽面" name="attachment" class="smart-query-form-item">
+                  <Upload
+                    :defaultFileList="defaultFileListBack"
+                    :maxUploadSize="1"
+                    buttonText="上传身份证国徽面"
+                    list-type="picture-card"
+                    @change="changeAttachmentBack"
+                  />
+                </a-form-item>
+              </a-col>
+            </a-row>
+          </div>
+        </div>
+        <div>
+          <div class="basic-title">
+            <div class="basic-title-left">
+              <div class="basic-title-line"></div>
+              <span class="basic-title-text">其他信息</span>
+            </div>
+            <div class="basic-title-right">
+              <!-- <a-button type="primary">提交</a-button> -->
+            </div>
+          </div>
+          <div class="steps-content">
+            <a-row :gutter="16" class="smart-query-form-row">
+              <a-col :span="24">
+                <a-form-item label="附件" name="attachment" class="smart-query-form-item">
+                  <Upload
+                    :defaultFileList="defaultFileList"
+                    :maxUploadSize="10"
+                    :folder="FILE_FOLDER_TYPE_ENUM.COMMON.value"
+                    buttonText="上传附件"
+                    listType="text"
+                    extraMsg="最多上传10个附件"
+                    @change="changeAttachment"
+                  />
+                </a-form-item>
+              </a-col>
+            </a-row>
+          </div>
+        </div>
+      </div>
+    </a-form>
+  </a-card>
+</template>
+<script setup>
+  import { onMounted, reactive, ref, useAttrs } from 'vue';
+  import { useRouter } from 'vue-router';
+  import { message, Modal } from 'ant-design-vue';
+  import _ from 'lodash';
+  import { clientManageApi } from '/@/api/market-manage/index.js';
+  import AreaCascader from '/@/components/framework/area-cascader/index.vue';
+  import DictSelect from '/@/components/support/dict-select/index.vue';
+  import Upload from '/@/components/support/file-upload/index.vue';
+  import { FILE_FOLDER_TYPE_ENUM } from '/@/constants/support/file-const';
+
+  const stepFormRef = ref(null);
+  const router = useRouter();
+
+  // --------------------- 数据 ---------------------
+  const formModel = reactive({
+    customerCode: undefined, //客户编码
+    customerName: undefined, //客户名称
+    socialCode: undefined, //社会统一信用代码
+    partnerLevel: undefined, //客户级别
+    customerStatus: undefined, //客户状态
+    province: undefined, //省份
+    provinceName: undefined,
+    city: undefined, //城市
+    cityName: undefined,
+    area: undefined, //区或县
+    areaName: undefined,
+    address: undefined, //详细地址
+    customerType: undefined, //客户类型
+    customerManager: undefined, //客户对接人
+    customerManagerMobile: undefined, //客户对接人电话
+    companyRegisterCapital: undefined, //注册资本
+    companyRegisterDate: undefined, //注册时间
+    customerDescription: undefined, //公司简介
+    customerNature: undefined, //经营范围
+    customerRemark: undefined, //备注
+    invoiceTitle: undefined, //发票抬头
+    invoiceCode: undefined, //开票税号
+    invoiceAddress: undefined, //开票地址
+    invoiceMobile: undefined, //开票电话
+    invoiceBankName: undefined, //开户银行
+    invoiceBankAccount: undefined, //银行账户
+    invoiceType: undefined, //开票类型
+    attachment: undefined, //附件集合
+  });
+
+  // --------------------- 校验规则 ---------------------
+  const formRules = {
+    // customerName: [{ required: true, message: '请输入客户名称', trigger: 'change' }],
+  };
+
+  const labelCol = { style: { width: '110px', height: '42px' } };
+
+  // ----------------------- 上传附件 ----------------------------
+  // 通用的文件列表更新函数
+  function updateFileList(fileList, defaultFileListRef, formKey) {
+    defaultFileListRef.value = fileList;
+    formModel[formKey] = _.isEmpty(fileList) ? [] : fileList;
+  }
+
+  const defaultFileList = ref([]);
+  const defaultFileListYY = ref([]);
+  const defaultFileListFront = ref([]);
+  const defaultFileListBack = ref([]);
+  function changeAttachmentYY(fileList) {
+    updateFileList(fileList, defaultFileListYY, 'photo1');
+  }
+  function changeAttachmentFront(fileList) {
+    updateFileList(fileList, defaultFileListFront, 'photo2');
+  }
+  function changeAttachmentBack(fileList) {
+    updateFileList(fileList, defaultFileListBack, 'photo3');
+  }
+  function changeAttachment(fileList) {
+    updateFileList(fileList, defaultFileListYY, 'attachment');
+  }
+
+  // ----------------------- 步骤相关 ---------------------------
+
+  const submit = () => {
+    console.log('formModel', formModel);
+    stepFormRef.value
+      .validateFields()
+      .then((values) => {
+        Modal.confirm({
+          title: '提示',
+          content: '确定要提交吗?',
+          okText: '确认',
+          onOk() {
+            postFormData();
+          },
+          cancelText: '取消',
+          onCancel() {},
+        });
+      })
+      .catch((error) => {
+        console.log('step1_error', error);
+      });
+  };
+
+  const postFormData = () => {
+    clientManageApi.createServiceInfo(formModel).then((res) => {
+      message.success('提交成功');
+      router.push({ path: 'market-manage/internal-manage/serviceProvider-manage/service-list' });
+    });
+  };
+  //------------------------地区-------------------------------------
+
+  const provinceCityDistrict = ref([]);
+  function changeArea(value, selectedOptions) {
+    Object.assign(formModel, {
+      province: '',
+      provinceName: '',
+      city: '',
+      cityName: '',
+      area: '',
+      areaName: '',
+    });
+    if (!_.isEmpty(selectedOptions)) {
+      // 地区信息
+      formModel.province = provinceCityDistrict.value[0].value;
+      formModel.provinceName = provinceCityDistrict.value[0].label;
+
+      formModel.city = provinceCityDistrict.value[1].value;
+      formModel.cityName = provinceCityDistrict.value[1].label;
+      if (provinceCityDistrict.value[2]) {
+        formModel.area = provinceCityDistrict.value[2].value;
+        formModel.areaName = provinceCityDistrict.value[2].label;
+      }
+    }
+    console.log('provinceCityDistrict', provinceCityDistrict.value);
+  }
+</script>
+
+<style scoped lang="less">
+  ::v-deep .ant-row {
+    display: flex;
+    align-items: center;
+  }
+  .approval-steps {
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
+    // width: 1350px;
+    margin: 0 auto;
+
+    .basic-title {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      width: 100%;
+      height: 40px;
+      padding: 0 16px 4px 16px;
+      border-bottom: 2px solid #f6f6f6;
+      background: #ffffff;
+      border-top-left-radius: 8px;
+      border-top-right-radius: 8px;
+
+      .basic-title-left {
+        height: 100%;
+        display: flex;
+        align-items: center;
+
+        .basic-title-line {
+          width: 4px;
+          height: 20px;
+          border-radius: 4px;
+          background: #267ef8;
+          margin-right: 5px;
+        }
+
+        .basic-title-text {
+          font-size: 16px;
+          font-style: normal;
+          font-weight: 600;
+          line-height: 20px;
+        }
+      }
+
+      .basic-title-right {
+        display: flex;
+        gap: 10px;
+      }
+    }
+
+    .steps-content {
+      margin-top: 14px;
+    }
+
+    .steps-action {
+      display: flex;
+      justify-content: center;
+      margin-top: 18px;
+    }
+  }
+</style>

+ 197 - 0
src/views/market-manage/internal-manage/serviceProvider-manage/unqualified-list/index.vue

@@ -0,0 +1,197 @@
+<template>
+  <div class="table-demo">
+    <bs-table v-bind="tableOptions">
+      <template #searchRight>
+        <a-space>
+          <a-button type="primary" @click="openEditDrawer">
+            <template #icon>
+              <PlusOutlined />
+            </template>
+            <span>新增</span>
+          </a-button>
+        </a-space>
+      </template>
+    </bs-table>
+
+    <add-or-edit-drawer ref="addOrEditDrawerRef" />
+  </div>
+</template>
+
+<script setup>
+  import BsTable, { useBsTable } from '/@/components/BsUi/Table/index.js';
+  import { onMounted, ref } from 'vue';
+  import { pick } from 'lodash';
+  import AddOrEditDrawer from '/@/views/table-demo/components/AddOrEditDrawer.vue';
+  import { clientManageApi } from '/@/api/market-manage/index.js';
+
+  const addOrEditDrawerRef = ref(null);
+
+  const {
+    tableOptions,
+    setTablePropsValue: setValue,
+    getTablePropsValue: getValue,
+  } = useBsTable({
+    tableOptions: {
+      gridOptions: {
+        loading: false,
+        columns: [
+          {
+            field: 'id',
+            title: '状态',
+          },
+          {
+            field: 'name',
+            title: '流水号',
+          },
+          {
+            field: 'name1',
+            title: '服务商名称',
+          },
+          {
+            field: 'name2',
+            title: '服务商ID',
+          },
+          {
+            field: 'name',
+            title: '服务商地址',
+          },
+          {
+            field: 'name',
+            title: '归属区域',
+          },
+          {
+            field: 'name',
+            title: '服务商类型',
+          },
+          {
+            field: 'name',
+            title: '注册来源',
+          },
+          {
+            field: 'name',
+            title: '注册时间',
+          },
+          {
+            field: 'name',
+            title: '归属营销经理',
+          },
+          {
+            field: 'action',
+            title: '操作',
+          },
+        ],
+      },
+      searchConfig: {
+        enabled: true,
+        fieldSpan: 4,
+        fields: [
+          {
+            field: 'name',
+            label: '',
+            component: 'a-input',
+            componentProps: {
+              placeholder: '请输入服务商名称',
+            },
+          },
+          {
+            field: 'name',
+            label: '',
+            component: 'a-select',
+            componentProps: {
+              placeholder: '请选择地址',
+            },
+          },
+          {
+            field: 'name',
+            label: '',
+            component: 'a-select',
+            componentProps: {
+              placeholder: '请选择服务商类型',
+            },
+          },
+        ],
+        onSearch() {
+          fetchTableData();
+        },
+        onReset() {
+          fetchTableData();
+        },
+      },
+      // pagerConfig: {
+      //   enabled: true,
+      //   pageSize: 10,
+      //   pageNum: 1,
+      //   total: 100,
+      //   onChange: () => {
+      //     fetchTableData();
+      //   },
+      // },
+      toolbarConfig: {
+        onRefresh() {
+          fetchTableData();
+        },
+      },
+    },
+  });
+
+  const getSearchParams = () => {
+    return getValue('searchConfig.data');
+  };
+  const getPageInfo = () => {
+    return pick(getValue('pagerConfig.pageInfo'), ['pageNum', 'pageSize']);
+  };
+
+  const fetchTableData = () => {
+    setValue('gridOptions.loading', true);
+
+    const params = {
+      ...getSearchParams(),
+      ...getPageInfo(),
+    };
+
+    //
+    // clientManageApi.interventionsList(params).then((res) => {
+    //   console.log('res', res);
+    //   setValue('gridOptions.data', res.data.list);
+    // });
+    
+    const TableDate = [
+      {
+        id: '1111111',
+        name: 'John Doe',
+        name1: '1212212',
+        name2: '1313131',
+      },
+      {
+        id: '22222',
+        name: 'John Doe',
+        name1: '1212212',
+        name2: '1313131',
+      },
+      {
+        id: '33333',
+        name: 'John sssssDoe',
+        name1: '12122sss12',
+        name2: '13sss13131',
+      },
+    ];
+    setTimeout(() => {
+      setValue('gridOptions.data', TableDate);
+      setValue('gridOptions.loading', false);
+    }, 1000);
+  };
+
+  onMounted(() => {
+    console.log('表格已加载');
+    fetchTableData();
+  });
+
+  const openEditDrawer = () => {
+    addOrEditDrawerRef.value.showDrawer();
+  };
+</script>
+
+<style scoped lang="scss">
+  .table-demo {
+  }
+</style>