ソースを参照

feature: 删除无用文件,添加交易记录,钱包余额,用户权限列表,币种管理页面

ljc 6 ヶ月 前
コミット
20d0429d61
67 ファイル変更3398 行追加6850 行削除
  1. 0 85
      src/components/AvatarCropper/index.vue
  2. 1 0
      src/components/BreadCrumb.vue
  3. 0 269
      src/components/DataScreen/Multiline/index.vue
  4. 0 117
      src/components/DataScreen/barEcharts/index.vue
  5. 0 111
      src/components/DataScreen/lineEcharts/index.vue
  6. 0 38
      src/components/DataScreen/migrationEcharts/data.js
  7. 0 332
      src/components/DataScreen/migrationEcharts/index.vue
  8. 0 3043
      src/components/DataScreen/migrationEcharts/map.js
  9. 0 183
      src/components/DataScreen/pie/index.vue
  10. 0 18
      src/components/PageWrapLayout/index.scss
  11. 0 13
      src/components/PageWrapLayout/index.vue
  12. 0 116
      src/components/RightClickMenu/index.vue
  13. 0 26
      src/components/SwitchDark/index.vue
  14. 0 163
      src/components/Theme/index.vue
  15. 0 8
      src/components/pipeline/index.vue
  16. 0 150
      src/components/pipeline/zb-pipeline-start.vue
  17. 0 30
      src/components/u-container-layout/index.vue
  18. 5 2
      src/config/index.ts
  19. 0 218
      src/layout/LayoutColumns/index.vue
  20. 0 34
      src/layout/LayoutHorizontal/HeaderHorizontal/index.scss
  21. 0 61
      src/layout/LayoutHorizontal/HeaderHorizontal/index.vue
  22. 0 24
      src/layout/LayoutHorizontal/index.vue
  23. 0 67
      src/layout/LayoutVertical/HeaderVertical/index.scss
  24. 0 38
      src/layout/LayoutVertical/HeaderVertical/index.vue
  25. 0 46
      src/layout/LayoutVertical/index.vue
  26. 0 19
      src/layout/components/Footer/index.vue
  27. 0 19
      src/layout/components/Header/ToolLeft.vue
  28. 0 23
      src/layout/components/Header/ToolRight.vue
  29. 0 100
      src/layout/components/Header/components/Avatar.vue
  30. 0 30
      src/layout/components/Header/components/CollapseIcon.vue
  31. 0 38
      src/layout/components/Header/components/Hamburger.vue
  32. 0 178
      src/layout/components/Header/components/HeaderSearch.vue
  33. 0 13
      src/layout/components/Header/components/Height.vue
  34. 0 89
      src/layout/components/Header/components/Language.vue
  35. 0 86
      src/layout/components/Header/components/PersonalDialog.vue
  36. 0 93
      src/layout/components/Header/components/Remind.vue
  37. 0 27
      src/layout/components/Header/components/ScreenFull.vue
  38. 0 44
      src/layout/components/Header/components/Setting.vue
  39. 0 50
      src/layout/components/Header/components/globalComSize.vue
  40. 0 39
      src/layout/components/Main/index.vue
  41. 0 22
      src/layout/components/Mobile/index.vue
  42. 0 57
      src/layout/components/Sidebar/components/Logo.vue
  43. 0 54
      src/layout/components/Sidebar/index.vue
  44. 0 49
      src/layout/components/SubMenu/Link.vue
  45. 0 33
      src/layout/components/SubMenu/MenuItem.vue
  46. 0 74
      src/layout/components/SubMenu/SubItem.vue
  47. 0 51
      src/layout/components/SubMenu/SubMenu.vue
  48. 0 67
      src/layout/components/TagsView/components/MoreButton.vue
  49. 0 162
      src/layout/components/TagsView/index.vue
  50. 0 85
      src/layout/index.vue
  51. 18 16
      src/routers/modules/uCard.ts
  52. 24 0
      src/service/ucard.ts
  53. 6 1
      src/styles/cwg_common.scss
  54. 22 0
      src/utils/getStatusColor.ts
  55. 28 0
      src/views/card/CardTransactions/const.ts
  56. 127 119
      src/views/card/CardTransactions/index.vue
  57. 24 0
      src/views/card/CardUserOrder/const.ts
  58. 394 0
      src/views/card/CardUserOrder/index.vue
  59. 12 0
      src/views/card/CardUserRights/const.ts
  60. 613 0
      src/views/card/CardUserRights/index.vue
  61. 3 5
      src/views/card/GlobalCurrency/index.vue
  62. 7 0
      src/views/card/VirtualCard/const.ts
  63. 46 13
      src/views/card/VirtualCard/index.vue
  64. 59 0
      src/views/components/PaymentTransfer/const.ts
  65. 312 0
      src/views/components/PaymentTransfer/index.scss
  66. 1696 0
      src/views/components/PaymentTransfer/index.vue
  67. 1 2
      tsconfig.json

+ 0 - 85
src/components/AvatarCropper/index.vue

@@ -1,85 +0,0 @@
-<template>
-  <vue-cropper
-    ref="cropper"
-    :img="avatarUrl"
-    :output-size="defaultOptions.outputSize"
-    :output-type="defaultOptions.outputType"
-    :info="defaultOptions.info"
-    :full="defaultOptions.full"
-    :fixed="defaultOptions.fixed"
-    :auto-crop-width="defaultOptions.autoCropWidth"
-    :auto-crop-height="defaultOptions.autoCropHeight"
-    :fixed-box="defaultOptions.fixedBox"
-    :auto-crop="defaultOptions.autoCrop"
-    :center-box="defaultOptions.centerBox"
-    @real-time="realTime"
-  />
-</template>
-
-<script lang="ts" setup>
-  import { defineExpose, reactive, ref } from 'vue'
-  import { VueCropper } from 'vue-cropper'
-  import 'vue-cropper/dist/index.css'
-
-  const emit = defineEmits(['change'])
-  let props = defineProps({
-    avatarUrl: {
-      type: String,
-    },
-    options: {
-      type: Object,
-      default: () => {},
-    },
-  })
-
-  let cropper = ref()
-
-  const defaultOptions = reactive({
-    outputSize: 0.8, // 裁剪生成图片的质量
-    outputType: 'png', // 生成图片的格式
-    info: true, // 裁剪框的大小信息
-    fixed: true, // 是否开启截图框宽高固定比例
-    autoCrop: true, // 是否默认生成截图框
-    anMoveBox: true, // 截图框能否拖动
-    original: false, // 上传图片按照原始比例渲染
-    autoCropWidth: 300, // 默认生成截图框宽度
-    autoCropHeight: 300, // 默认生成截图框高度
-    // 只有自动截图开启 宽度高度才生效
-    centerBox: false, // 截图框是否被限制在图片里面
-    high: true, // 是否按照dpr设备比例图片
-    fixedBox: false, // 固定截图框大小 不允许改变
-    full: false, // 是否输出原图比例的截图
-    ...props.options,
-  })
-
-  const getBase64 = () => {
-    return new Promise((resolve) => {
-      cropper.value.getCropData((data) => {
-        resolve(data)
-      })
-    })
-  }
-
-  const rotateLeft = () => {
-    cropper.value.rotateLeft()
-  }
-  const rotateRight = () => {
-    cropper.value.rotateRight()
-  }
-
-  const zoom = (percent) => {
-    cropper.value.changeScale(percent)
-  }
-
-  // 实时预览图片
-  const realTime = (data) => {
-    emit('change', data)
-  }
-
-  defineExpose({
-    getBase64,
-    rotateLeft,
-    rotateRight,
-    zoom,
-  })
-</script>

+ 1 - 0
src/components/BreadCrumb.vue

@@ -9,6 +9,7 @@
 <script lang="ts" setup>
   import { useRoute } from 'vue-router'
   import { computed } from 'vue'
+
   const route = useRoute()
   const breadCrumbs = computed(() => {
     return route.matched.filter((item) => {

+ 0 - 269
src/components/DataScreen/Multiline/index.vue

@@ -1,269 +0,0 @@
-<template>
-  <div ref="chartsRef" class="echarts" />
-</template>
-<script lang="ts" setup>
-  import * as echarts from 'echarts'
-  import { EChartsType } from 'echarts/core'
-  import { onMounted, ref } from 'vue'
-  const chartsRef = ref<HTMLElement | null>()
-
-  let colorList = ['#46ea91', '#2ba0ff', '#ed593b', '#7357ff', '#f2d750']
-  const options = {
-    legend: {
-      icon: 'circle',
-      top: '5%',
-      right: '5%',
-      itemWidth: 6,
-      itemGap: 5,
-      textStyle: {
-        color: '#fff',
-        padding: [3, 0, 0, 0],
-      },
-    },
-    tooltip: {
-      trigger: 'axis',
-    },
-    grid: {
-      top: '14%',
-      left: '3%',
-      right: '4%',
-      bottom: '10%',
-      containLabel: true,
-    },
-    xAxis: [
-      {
-        type: 'category',
-        data: ['1', '2', '3', '4', '5', '6', '7', '8'],
-        axisLine: {
-          lineStyle: {
-            color: '#33BBFF',
-          },
-        },
-        axisTick: {
-          show: false,
-        },
-        axisLabel: {
-          interval: 0,
-          textStyle: {
-            color: '#5FBBEB',
-          },
-          // 默认x轴字体大小
-          fontSize: 12,
-          // margin:文字到x轴的距离
-          margin: 10,
-        },
-        axisPointer: {
-          label: {
-            // padding: [11, 5, 7],
-            padding: [0, 0, 0, 0],
-            // 这里的margin和axisLabel的margin要一致!
-            margin: 10,
-            // 移入时的字体大小
-            fontSize: 12,
-            backgroundColor: 'rgba(0,0,0,0)',
-          },
-        },
-        boundaryGap: false,
-      },
-    ],
-    yAxis: [
-      {
-        name: '单位/件',
-        axisTick: {
-          show: false,
-        },
-        axisLine: {
-          show: true,
-          lineStyle: {
-            color: '#05D5FF',
-          },
-        },
-        axisLabel: {
-          textStyle: {
-            color: '#5FBBEB',
-          },
-        },
-        splitLine: {
-          show: false,
-        },
-      },
-    ],
-    series: [
-      {
-        name: '咨询',
-        type: 'line',
-        data: [100, 20, 30, 102, 15, 30, 20, 18],
-        symbolSize: 1,
-        symbol: 'circle',
-        smooth: true,
-        showSymbol: false,
-        lineStyle: {
-          width: 2,
-          color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
-            {
-              offset: 0,
-              color: '#90ffc6',
-            },
-            {
-              offset: 1,
-              color: '#46ea91',
-            },
-          ]),
-          shadowColor: 'rgba(144, 255, 198, .3)',
-          shadowBlur: 5,
-          shadowOffsetY: 5,
-        },
-        itemStyle: {
-          normal: {
-            color: colorList[0],
-            borderColor: colorList[0],
-          },
-        },
-      },
-      {
-        name: '求助',
-        type: 'line',
-        data: [20, 12, 11, 14, 25, 16, 10, 20],
-        symbolSize: 1,
-        symbol: 'circle',
-        smooth: true,
-        showSymbol: false,
-        lineStyle: {
-          width: 2,
-          color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
-            {
-              offset: 0,
-              color: '#67bcfc',
-            },
-            {
-              offset: 1,
-              color: '#2ba0ff',
-            },
-          ]),
-          shadowColor: 'rgba(105, 188, 252,.3)',
-          shadowBlur: 5,
-          shadowOffsetY: 5,
-        },
-        itemStyle: {
-          normal: {
-            color: colorList[1],
-            borderColor: colorList[1],
-          },
-        },
-      },
-      {
-        name: '无效',
-        type: 'line',
-        data: [150, 120, 170, 140, 100, 160, 110, 110],
-        symbolSize: 1,
-        symbol: 'circle',
-        smooth: true,
-        showSymbol: false,
-        lineStyle: {
-          width: 2,
-          color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
-            {
-              offset: 0,
-              color: '#fc937e ',
-            },
-            {
-              offset: 1,
-              color: '#ed593b',
-            },
-          ]),
-          shadowColor: 'rgb(252, 147, 126,.3)',
-          shadowBlur: 2,
-          shadowOffsetY: 2,
-        },
-        itemStyle: {
-          normal: {
-            color: colorList[2],
-            borderColor: colorList[2],
-          },
-        },
-      },
-      {
-        name: '投诉举报',
-        type: 'line',
-        data: [200, 80, 100, 30, 60, 50, 110, 20],
-        symbolSize: 1,
-        symbol: 'circle',
-        smooth: true,
-        showSymbol: false,
-        lineStyle: {
-          width: 2,
-          color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
-            {
-              offset: 0,
-              color: '#a390ff',
-            },
-            {
-              offset: 1,
-              color: '#7357ff',
-            },
-          ]),
-          shadowColor: 'rgba(115, 87, 255, .1)',
-          shadowBlur: 5,
-          shadowOffsetY: 5,
-        },
-        itemStyle: {
-          normal: {
-            color: colorList[3],
-            borderColor: colorList[3],
-          },
-        },
-      },
-      {
-        name: '建议',
-        type: 'line',
-        data: [20, 80, 150, 30, 60, 50, 50, 20],
-        symbolSize: 1,
-        symbol: 'circle',
-        smooth: true,
-        showSymbol: false,
-        lineStyle: {
-          width: 2,
-          color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
-            {
-              offset: 0,
-              color: '#ffeb86',
-            },
-            {
-              offset: 1,
-              color: '#f2d750',
-            },
-          ]),
-          shadowColor: 'rgba(255, 235, 134, .5)',
-          shadowBlur: 5,
-          shadowOffsetY: 5,
-        },
-        itemStyle: {
-          normal: {
-            color: colorList[4],
-            borderColor: colorList[4],
-          },
-        },
-      },
-    ],
-  }
-
-  let chart: EChartsType
-  const initChart = () => {
-    const chart = echarts.init(chartsRef.value)
-    chart.setOption(options)
-    return chart
-  }
-  onMounted(() => {
-    chart = initChart()
-    window.addEventListener('resize', function () {
-      chart && chart.resize()
-    })
-  })
-</script>
-
-<style lang="scss" scoped>
-  .echarts {
-    width: 100%;
-    height: 100%;
-  }
-</style>

+ 0 - 117
src/components/DataScreen/barEcharts/index.vue

@@ -1,117 +0,0 @@
-<template>
-  <div ref="chartsRef" class="echarts" />
-</template>
-<script setup lang="ts">
-  import BarCharts from './components/bar.vue'
-  import * as echarts from 'echarts'
-  import { EChartsType } from 'echarts/core'
-  import { onMounted, ref, reactive } from 'vue'
-  const chartsRef = ref<HTMLElement | null>()
-  const data = [154, 230, 224, 218, 135, 147, 260]
-  const color = ['#fa796f', '#54c1fb', '#ca6cd4', '#59dcc1', '#09a4ea', '#e98f4d', '#ea8e49']
-  const dataOptions = []
-
-  data.forEach((item, index) => {
-    let obj = {
-      value: data[index],
-      itemStyle: {
-        color: color[index],
-      },
-    }
-    dataOptions.push(obj)
-  })
-
-  const options = {
-    color,
-    grid: {
-      top: '10%',
-      left: '3%',
-      right: '4%',
-      bottom: '10%',
-      containLabel: true,
-    },
-    tooltip: {
-      trigger: 'axis',
-      backgroundColor: 'rgba(0,0,0,0.7)',
-      borderWidth: 0,
-      borderColor: 'rgba(0,0,0,0.7)',
-      formatter: (name, val) => {
-        const tipHtml = `
-                     <div class="m-info" style=" opacity: 0.95;font-size: 12px; color: white;" >
-                         <div class="title" ></div>
-                         <div class="title" >完成占比${name[0].value}</div>
-                 </div>`
-        return tipHtml
-      },
-    },
-    yAxis: {
-      type: 'value',
-      // 设置坐标轴的 文字样式
-      axisLabel: {
-        color: '#bbdaff',
-        margin: 20, // 刻度标签与轴线之间的距离。
-      },
-      axisTick: {
-        // 取消坐标轴刻度线
-        show: false,
-      },
-      // 坐标轴轴线相关设置。
-      splitLine: {
-        lineStyle: {
-          color: '#2d5baf',
-        },
-      },
-    },
-    xAxis: {
-      type: 'category',
-      splitLine: {
-        show: false,
-      },
-      // 坐标轴轴线相关设置。
-      axisLine: {
-        lineStyle: {
-          color: '#2d5baf',
-        },
-      },
-      data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
-      axisLabel: {
-        // 设置坐标轴的 文字样式
-        color: '#bbdaff',
-        margin: 20, // 刻度标签与轴线之间的距离。
-      },
-      axisTick: {
-        // 取消坐标轴刻度线
-        show: false,
-      },
-    },
-    series: [
-      {
-        data: dataOptions,
-        type: 'bar',
-        barMaxWidth: 18,
-        markLine: {
-          silent: true,
-        },
-      },
-    ],
-  }
-
-  let chart: EChartsType
-  const initChart = () => {
-    const chart = echarts.init(chartsRef.value)
-    chart.setOption(options)
-    return chart
-  }
-  onMounted(() => {
-    chart = initChart()
-    window.addEventListener('resize', function () {
-      chart && chart.resize()
-    })
-  })
-</script>
-<style lang="scss" scoped>
-  .echarts {
-    height: 100%;
-    width: 100%;
-  }
-</style>

+ 0 - 111
src/components/DataScreen/lineEcharts/index.vue

@@ -1,111 +0,0 @@
-<template>
-  <div ref="chartsRef" class="echarts" />
-</template>
-<script setup lang="ts">
-  import BarCharts from './components/bar.vue'
-  import * as echarts from 'echarts'
-  import { EChartsType } from 'echarts/core'
-  import { onMounted, ref, reactive } from 'vue'
-  const chartsRef = ref<HTMLElement | null>()
-
-  const options = {
-    grid: {
-      top: '10%',
-      left: '3%',
-      right: '4%',
-      bottom: '10%',
-      containLabel: true,
-    },
-    tooltip: {
-      trigger: 'axis',
-      backgroundColor: 'rgba(0,0,0,0.7)',
-      borderWidth: 0,
-      borderColor: 'rgba(0,0,0,0.7)',
-      formatter: (name, val) => {
-        const tipHtml = `
-                     <div class="m-info" style=" opacity: 0.95;font-size: 12px; color: white;" >
-                         <div class="title" ></div>
-                         <div class="title" >完成占比${name[0].data}</div>
-                 </div>`
-        return tipHtml
-      },
-    },
-    yAxis: {
-      // 设置坐标轴的 文字样式
-      axisLabel: {
-        color: '#bbdaff',
-        margin: 20, // 刻度标签与轴线之间的距离。
-      },
-      // 坐标轴轴线相关设置。
-      splitLine: {
-        lineStyle: {
-          color: '#2d5baf',
-        },
-      },
-    },
-    xAxis: {
-      splitLine: {
-        show: false,
-      },
-      // 坐标轴轴线相关设置。
-      axisLine: {
-        lineStyle: {
-          color: '#2d5baf',
-        },
-      },
-      type: 'category',
-      data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
-      axisLabel: {
-        // 设置坐标轴的 文字样式
-        color: '#bbdaff',
-        margin: 20, // 刻度标签与轴线之间的距离。
-      },
-      boundaryGap: false, // 设置坐标轴两边的留白 ,从刻度原点开始,
-      axisTick: {
-        // 取消坐标轴刻度线
-        show: false,
-      },
-    },
-    series: [
-      {
-        data: [154, 230, 224, 218, 135, 147, 260],
-        type: 'line',
-        // smooth:false,   //关键点,为true是不支持虚线的,实线就用true
-        symbolSize: 12, // 拐点圆的大小
-        symbol: 'circle',
-        markLine: {
-          silent: true,
-        },
-        itemStyle: {
-          normal: {
-            color: '#920783', // 设置 symbol的颜色
-            lineStyle: {
-              width: 3,
-              color: '#920783',
-              type: 'solid', // 'dotted'虚线 'solid'实线
-            },
-          },
-        },
-      },
-    ],
-  }
-
-  let chart: EChartsType
-  const initChart = () => {
-    const chart = echarts.init(chartsRef.value)
-    chart.setOption(options)
-    return chart
-  }
-  onMounted(() => {
-    chart = initChart()
-    window.addEventListener('resize', function () {
-      chart && chart.resize()
-    })
-  })
-</script>
-<style lang="scss" scoped>
-  .echarts {
-    height: 100%;
-    width: 100%;
-  }
-</style>

+ 0 - 38
src/components/DataScreen/migrationEcharts/data.js

@@ -1,38 +0,0 @@
-export const cityIconData = [
-  {
-    adcode: 650000,
-    name: '新疆维吾尔自治区',
-    value: [88.999903, 43.607078],
-  },
-  {
-    // adcode: 150000,
-    name: '内蒙古自治区',
-    value: [119.24787, 42.205741],
-  },
-  ,
-  {
-    // adcode: 150000,
-    name: '内蒙古自治区',
-    value: [110.627161, 41.16628],
-  },
-  {
-    // adcode: 540000,
-    name: '西藏自治区',
-    value: [89.483714, 30.251951],
-  },
-  {
-    // adcode: 630000,
-    name: '青海省',
-    value: [102.064693, 37.084008],
-  },
-  {
-    // adcode: 530000,
-    name: '云南省',
-    value: [102.187665, 25.083688],
-  },
-  {
-    // adcode: 610000,
-    name: '陕西省',
-    value: [109.20663, 35.018625],
-  },
-]

+ 0 - 332
src/components/DataScreen/migrationEcharts/index.vue

@@ -1,332 +0,0 @@
-<template>
-  <div :id="id" :class="className" :style="{ height: height, width: width }" />
-</template>
-<script lang="ts" setup>
-  import { geoJson } from './map.js'
-  import * as echarts from 'echarts'
-  import { EChartsType } from 'echarts/core'
-  import { onMounted, onUnmounted } from 'vue'
-  import { cityIconData } from './data.js'
-  import logo from '@/assets/image/logo.png'
-  const props = defineProps({
-    className: {
-      type: String,
-      default: 'chart',
-    },
-    config: {
-      type: Object,
-      default: () => {},
-    },
-    id: {
-      type: String,
-      default: 'chart',
-    },
-    width: {
-      type: String,
-      default: '200px',
-    },
-    height: {
-      type: String,
-      default: '200px',
-    },
-  })
-
-  var geoGpsMap = [109.1162, 34.2004]
-  var geoCoordMap = {
-    江苏: [118.8062, 31.9208],
-    内蒙古: [110.3467, 41.4899],
-    辽宁: [123.1238, 42.1216],
-    陕西: [109.1162, 34.2004],
-    甘肃: [103.5901, 36.3043],
-    青海: [101.4038, 36.8207],
-    新疆: [87.9236, 43.5883],
-
-    河南: [113.4668, 34.6234],
-    西藏: [91.091762, 30.037072],
-    浙江: [119.5313, 29.8773],
-    福建: [119.4543, 25.9222],
-    湖南: [113.0823, 28.2568],
-    四川: [113.0823, 28.2568],
-    云南: [102.9199, 25.4663],
-    广东: [113.12244, 23.009505],
-    海南: [110.3893, 19.8516],
-  }
-
-  var value = {
-    江苏: 10000,
-    内蒙古: 10000,
-    辽宁: 10000,
-    陕西: 10000,
-    福建: 10000,
-    甘肃: 10000,
-    青海: 10000,
-    新疆: 10000,
-    湖北: 10000,
-    浙江: 10000,
-    河南: 10000,
-    湖南: 10000,
-    云南: 10000,
-    广东: 10000,
-    海南: 10000,
-    西藏: 10000,
-  }
-  var colors = '#f9b207'
-
-  var year = ['长春', '长春', '青岛', '青岛', '成都', '成都']
-  var mapData = []
-
-  /* 柱子Y名称 */
-  var categoryData = []
-  var barData = []
-
-  for (var key in geoCoordMap) {
-    mapData.push({
-      year: '陕西',
-      name: key,
-      value: value[key] / 100,
-      value1: value[key] / 100,
-    })
-  }
-
-  mapData.sort(function sortNumber(a, b) {
-    return a.value - b.value
-  })
-  for (var j = 0; j < mapData.length; j++) {
-    barData.push(mapData[j].value1)
-    categoryData.push(mapData[j].name)
-  }
-
-  echarts.registerMap('china', geoJson)
-  var convertData = function (data) {
-    var res = []
-    for (var i = 0; i < data.length; i++) {
-      var geoCoord = geoCoordMap[data[i].name]
-      if (geoCoord) {
-        res.push({
-          name: data[i].name,
-          value: geoCoord.concat(data[i].value),
-        })
-      }
-    }
-    return res
-  }
-  var convertToLineData = function (data, gps) {
-    var res = []
-    for (var i = 0; i < data.length; i++) {
-      var dataItem = data[i]
-      var toCoord = geoCoordMap[dataItem.name]
-      // debugger;
-      var fromCoord = gps // 郑州
-      //  var toCoord = geoGps[Math.random()*3];
-      if (fromCoord && toCoord) {
-        res.push([
-          {
-            coord: fromCoord,
-            value: dataItem.value,
-          },
-          {
-            coord: toCoord,
-          },
-        ])
-      }
-    }
-    return res
-  }
-
-  const options = {
-    tooltip: {
-      trigger: 'item',
-      formatter(val) {
-        // console.log('val==========',val)
-      },
-    },
-    // backgroundColor: '#001540',// 设置背景色
-    geo: {
-      show: true,
-      map: 'china',
-      roam: true,
-      zoom: 1,
-      center: [101.4038, 36.8207],
-      label: {
-        emphasis: {
-          show: false,
-        },
-      },
-      itemStyle: {
-        normal: {
-          borderColor: 'rgba(147, 235, 248, 1)',
-          borderWidth: 1,
-          areaColor: {
-            type: 'radial',
-            x: 0.5,
-            y: 0.5,
-            r: 0.8,
-            colorStops: [
-              {
-                offset: 0,
-                color: 'rgba(147, 235, 248, 0)', // 0% 处的颜色
-              },
-              {
-                offset: 1,
-                color: 'rgba(147, 235, 248, .2)', // 100% 处的颜色
-              },
-            ],
-            globalCoord: false, // 缺省为 false
-          },
-          shadowColor: 'rgba(128, 217, 248, 1)',
-          // shadowColor: 'rgba(255, 255, 255, 1)',
-          shadowOffsetX: -2,
-          shadowOffsetY: 2,
-          shadowBlur: 10,
-        },
-        emphasis: {
-          areaColor: '#389BB7',
-          borderWidth: 0,
-        },
-      },
-    },
-    series: [
-      // 地图?
-      {
-        type: 'map',
-        map: 'china',
-        geoIndex: 0,
-        aspectScale: 0.75, // 长宽比
-        showLegendSymbol: false, // 存在legend时显示
-        label: {
-          normal: {
-            show: false,
-          },
-          emphasis: {
-            show: false,
-            textStyle: {
-              color: '#fff',
-            },
-          },
-        },
-
-        roam: true,
-        itemStyle: {
-          normal: {
-            areaColor: '#031525',
-            borderColor: '#FFFFFF',
-          },
-          emphasis: {
-            areaColor: '#2B91B7',
-          },
-        },
-        animation: false,
-      },
-      // 地图点的动画效果
-      {
-        //  name: 'Top 5',
-        type: 'effectScatter',
-        coordinateSystem: 'geo',
-        data: convertData(
-          mapData
-            .sort(function (a, b) {
-              return b.value - a.value
-            })
-            .slice(0, 20)
-        ),
-        symbolSize: function (val) {
-          return val[2] / 10
-        },
-        showEffectOn: 'render',
-        rippleEffect: {
-          brushType: 'stroke',
-        },
-        hoverAnimation: true,
-        label: {
-          normal: {
-            formatter: '{b}',
-            position: 'right',
-            show: true,
-          },
-        },
-        itemStyle: {
-          normal: {
-            color: colors,
-            shadowBlur: 10,
-            shadowColor: colors,
-          },
-        },
-        zlevel: 1,
-      },
-      // 地图线的动画效果
-      {
-        type: 'lines',
-        zlevel: 2,
-        effect: {
-          show: true,
-          period: 4, // 箭头指向速度,值越小速度越快
-          trailLength: 0.02, // 特效尾迹长度[0,1]值越大,尾迹越长重
-          symbol: 'arrow', // 箭头图标
-          symbolSize: 3, // 图标大小
-        },
-        lineStyle: {
-          normal: {
-            color: colors,
-            width: 0.1, // 尾迹线条宽度
-            opacity: 0.5, // 尾迹线条透明度
-            curveness: 0.3, // 尾迹线条曲直度
-          },
-        },
-        data: convertToLineData(mapData, geoGpsMap),
-      },
-      {
-        type: 'scatter',
-        zlevel: 16,
-        coordinateSystem: 'geo',
-        symbolSize: 30,
-        symbol: `image://${logo}`,
-        data: cityIconData,
-        rippleEffect: {
-          period: 4,
-          brushType: 'stroke',
-          scale: 4,
-        },
-        tooltip: {
-          trigger: 'item',
-          padding: 0,
-          borderColor: 'black',
-          background: 'rgba(0,0,0,0.7)',
-          textStyle: {
-            fontSize: 20,
-          },
-          formatter(val) {
-            console.log('val=======', val)
-            let tipHtml = `
-                     <div class="m-info" style=" opacity: 0.95;background: rgba(25,27,29,1);" >
-                         <div class="title" style="padding-left: 12px;
-                         padding-top: 10px;
-                         padding-bottom: 10px;
-                         background: rgba(25,27,29,1);font-size: 20px;color: white;padding-right: 20px">${val.name}</div>
-<!--                         <div class="content" style=" padding: 12px; background: rgba(0,2,4,1);">-->
-          <!--                               <div style=" font-size: 22px; color: #ff0000;">258944</div>-->
-          <!--                        </div>-->
-          </div>`
-            return tipHtml
-          },
-        },
-      },
-    ],
-  }
-  let chart: EChartsType
-  const initChart = () => {
-    const chart = echarts.init(document.getElementById(props.id))
-    chart.setOption(options)
-    return chart
-  }
-
-  onUnmounted(() => {
-    chart && chart.dispose()
-  })
-
-  onMounted(() => {
-    chart = initChart()
-    window.addEventListener('resize', function () {
-      chart && chart.resize()
-    })
-  })
-</script>

+ 0 - 3043
src/components/DataScreen/migrationEcharts/map.js

@@ -1,3043 +0,0 @@
-export const geoJson = {
-  type: 'FeatureCollection',
-  features: [
-    {
-      type: 'Feature',
-      id: 'xin_jiang',
-      properties: { name: '新疆', cp: [84.9023, 41.748], childNum: 18 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [96.416, 42.7588],
-            [96.416, 42.7148],
-            [95.9766, 42.4951],
-            [96.0645, 42.3193],
-            [96.2402, 42.2314],
-            [95.9766, 41.9238],
-            [95.2734, 41.6162],
-            [95.1855, 41.792],
-            [94.5703, 41.4844],
-            [94.043, 41.0889],
-            [93.8672, 40.6934],
-            [93.0762, 40.6494],
-            [92.6367, 39.6387],
-            [92.373, 39.3311],
-            [92.373, 39.1113],
-            [92.373, 39.0234],
-            [90.1758, 38.4961],
-            [90.3516, 38.2324],
-            [90.6152, 38.3203],
-            [90.5273, 37.8369],
-            [91.0547, 37.4414],
-            [91.3184, 37.0898],
-            [90.7031, 36.7822],
-            [90.791, 36.6064],
-            [91.0547, 36.5186],
-            [91.0547, 36.0791],
-            [90.8789, 36.0352],
-            [90, 36.2549],
-            [89.9121, 36.0791],
-            [89.7363, 36.0791],
-            [89.209, 36.2988],
-            [88.7695, 36.3428],
-            [88.5938, 36.4746],
-            [87.3633, 36.4307],
-            [86.2207, 36.167],
-            [86.1328, 35.8594],
-            [85.6055, 35.6836],
-            [85.0781, 35.7275],
-            [84.1992, 35.376],
-            [83.1445, 35.4199],
-            [82.8809, 35.6836],
-            [82.4414, 35.7275],
-            [82.002, 35.332],
-            [81.6504, 35.2441],
-            [80.4199, 35.4199],
-            [80.2441, 35.2881],
-            [80.332, 35.1563],
-            [80.2441, 35.2002],
-            [79.8926, 34.8047],
-            [79.8047, 34.4971],
-            [79.1016, 34.4531],
-            [79.0137, 34.3213],
-            [78.2227, 34.7168],
-            [78.0469, 35.2441],
-            [78.0469, 35.5078],
-            [77.4316, 35.4639],
-            [76.8164, 35.6396],
-            [76.5527, 35.8594],
-            [76.2012, 35.8154],
-            [75.9375, 36.0352],
-            [76.0254, 36.4746],
-            [75.8496, 36.6943],
-            [75.498, 36.7383],
-            [75.4102, 36.958],
-            [75.0586, 37.002],
-            [74.8828, 36.9141],
-            [74.7949, 37.0459],
-            [74.5313, 37.0898],
-            [74.5313, 37.2217],
-            [74.8828, 37.2217],
-            [75.1465, 37.4414],
-            [74.8828, 37.5732],
-            [74.9707, 37.749],
-            [74.8828, 38.4521],
-            [74.3555, 38.6719],
-            [74.1797, 38.6719],
-            [74.0918, 38.54],
-            [73.8281, 38.584],
-            [73.7402, 38.8477],
-            [73.8281, 38.9795],
-            [73.4766, 39.375],
-            [73.916, 39.5068],
-            [73.916, 39.6826],
-            [73.8281, 39.7705],
-            [74.0039, 40.0342],
-            [74.8828, 40.3418],
-            [74.7949, 40.5176],
-            [75.2344, 40.4297],
-            [75.5859, 40.6494],
-            [75.7617, 40.2979],
-            [76.377, 40.3857],
-            [76.9043, 41.001],
-            [77.6074, 41.001],
-            [78.1348, 41.2207],
-            [78.1348, 41.3965],
-            [80.1563, 42.0557],
-            [80.2441, 42.2754],
-            [80.1563, 42.627],
-            [80.2441, 42.8467],
-            [80.5078, 42.8906],
-            [80.4199, 43.0664],
-            [80.7715, 43.1982],
-            [80.4199, 44.165],
-            [80.4199, 44.6045],
-            [79.9805, 44.8242],
-            [79.9805, 44.9561],
-            [81.7383, 45.3955],
-            [82.0898, 45.2197],
-            [82.5293, 45.2197],
-            [82.2656, 45.6592],
-            [83.0566, 47.2412],
-            [83.6719, 47.0215],
-            [84.7266, 47.0215],
-            [84.9023, 46.8896],
-            [85.5176, 47.0654],
-            [85.6934, 47.2852],
-            [85.5176, 48.1201],
-            [85.7813, 48.4277],
-            [86.5723, 48.5596],
-            [86.8359, 48.8232],
-            [86.748, 48.9551],
-            [86.8359, 49.1309],
-            [87.8027, 49.1748],
-            [87.8906, 48.999],
-            [87.7148, 48.9111],
-            [88.0664, 48.7354],
-            [87.9785, 48.6035],
-            [88.5059, 48.3838],
-            [88.6816, 48.1641],
-            [89.1211, 47.9883],
-            [89.5605, 48.0322],
-            [89.7363, 47.8564],
-            [90.0879, 47.8564],
-            [90.3516, 47.6807],
-            [90.5273, 47.2412],
-            [90.8789, 46.9775],
-            [91.0547, 46.582],
-            [90.8789, 46.3184],
-            [91.0547, 46.0107],
-            [90.7031, 45.7471],
-            [90.7031, 45.5273],
-            [90.8789, 45.2197],
-            [91.582, 45.0879],
-            [93.5156, 44.9561],
-            [94.7461, 44.3408],
-            [95.3613, 44.2969],
-            [95.3613, 44.0332],
-            [95.5371, 43.9014],
-            [95.8887, 43.2422],
-            [96.3281, 42.9346],
-            [96.416, 42.7588],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'xi_zang',
-      properties: { name: '西藏', cp: [88.7695, 31.6846], childNum: 7 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [79.0137, 34.3213],
-            [79.1016, 34.4531],
-            [79.8047, 34.4971],
-            [79.8926, 34.8047],
-            [80.2441, 35.2002],
-            [80.332, 35.1563],
-            [80.2441, 35.2881],
-            [80.4199, 35.4199],
-            [81.6504, 35.2441],
-            [82.002, 35.332],
-            [82.4414, 35.7275],
-            [82.8809, 35.6836],
-            [83.1445, 35.4199],
-            [84.1992, 35.376],
-            [85.0781, 35.7275],
-            [85.6055, 35.6836],
-            [86.1328, 35.8594],
-            [86.2207, 36.167],
-            [87.3633, 36.4307],
-            [88.5938, 36.4746],
-            [88.7695, 36.3428],
-            [89.209, 36.2988],
-            [89.7363, 36.0791],
-            [89.3848, 36.0352],
-            [89.4727, 35.9033],
-            [89.7363, 35.7715],
-            [89.7363, 35.4199],
-            [89.4727, 35.376],
-            [89.4727, 35.2441],
-            [89.5605, 34.8926],
-            [89.8242, 34.8486],
-            [89.7363, 34.6729],
-            [89.8242, 34.3652],
-            [89.6484, 34.0137],
-            [90.0879, 33.4863],
-            [90.7031, 33.1348],
-            [91.4063, 33.1348],
-            [91.9336, 32.8271],
-            [92.1973, 32.8271],
-            [92.2852, 32.7393],
-            [92.9883, 32.7393],
-            [93.5156, 32.4756],
-            [93.7793, 32.5635],
-            [94.1309, 32.4316],
-            [94.6582, 32.6074],
-            [95.1855, 32.4316],
-            [95.0098, 32.2998],
-            [95.1855, 32.3438],
-            [95.2734, 32.2119],
-            [95.3613, 32.168],
-            [95.3613, 31.9922],
-            [95.4492, 31.8164],
-            [95.8008, 31.6846],
-            [95.9766, 31.8164],
-            [96.1523, 31.5967],
-            [96.2402, 31.9482],
-            [96.5039, 31.7285],
-            [96.8555, 31.6846],
-            [96.7676, 31.9922],
-            [97.2949, 32.0801],
-            [97.3828, 32.5635],
-            [97.7344, 32.5195],
-            [98.1738, 32.3438],
-            [98.4375, 31.8604],
-            [98.877, 31.4209],
-            [98.6133, 31.2012],
-            [98.9648, 30.7617],
-            [99.1406, 29.2676],
-            [98.9648, 29.1357],
-            [98.9648, 28.8281],
-            [98.7891, 28.8721],
-            [98.7891, 29.0039],
-            [98.7012, 28.916],
-            [98.6133, 28.5205],
-            [98.7891, 28.3447],
-            [98.7012, 28.2129],
-            [98.3496, 28.125],
-            [98.2617, 28.3887],
-            [98.1738, 28.125],
-            [97.5586, 28.5205],
-            [97.2949, 28.0811],
-            [97.3828, 27.9053],
-            [97.0313, 27.7295],
-            [96.5039, 28.125],
-            [95.7129, 28.2568],
-            [95.3613, 28.125],
-            [95.2734, 27.9492],
-            [94.2188, 27.5537],
-            [93.8672, 27.0264],
-            [93.6035, 26.9385],
-            [92.1094, 26.8506],
-            [92.0215, 27.4658],
-            [91.582, 27.5537],
-            [91.582, 27.9053],
-            [91.4063, 28.0371],
-            [91.0547, 27.8613],
-            [90.7031, 28.0811],
-            [89.8242, 28.2129],
-            [89.6484, 28.1689],
-            [89.1211, 27.5977],
-            [89.1211, 27.334],
-            [89.0332, 27.2021],
-            [88.7695, 27.4219],
-            [88.8574, 27.9932],
-            [88.6816, 28.125],
-            [88.1543, 27.9053],
-            [87.8906, 27.9492],
-            [87.7148, 27.8174],
-            [87.0996, 27.8174],
-            [86.748, 28.125],
-            [86.5723, 28.125],
-            [86.4844, 27.9053],
-            [86.1328, 28.125],
-            [86.0449, 27.9053],
-            [85.6934, 28.3447],
-            [85.6055, 28.2568],
-            [85.166, 28.3447],
-            [85.166, 28.6523],
-            [84.9023, 28.5645],
-            [84.4629, 28.7402],
-            [84.2871, 28.8721],
-            [84.1992, 29.2236],
-            [84.1113, 29.2676],
-            [83.584, 29.1797],
-            [83.2324, 29.5752],
-            [82.1777, 30.0586],
-            [82.0898, 30.3223],
-            [81.3867, 30.3662],
-            [81.2109, 30.0146],
-            [81.0352, 30.2344],
-            [80.0684, 30.5859],
-            [79.7168, 30.9375],
-            [79.0137, 31.0693],
-            [78.75, 31.333],
-            [78.8379, 31.5967],
-            [78.6621, 31.8164],
-            [78.75, 31.9043],
-            [78.4863, 32.124],
-            [78.3984, 32.5195],
-            [78.75, 32.6953],
-            [78.9258, 32.3438],
-            [79.2773, 32.5635],
-            [79.1016, 33.1787],
-            [78.6621, 33.6621],
-            [78.6621, 34.1016],
-            [78.9258, 34.1455],
-            [79.0137, 34.3213],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'nei_meng_gu',
-      properties: { name: '内蒙古', cp: [117.5977, 44.3408], childNum: 12 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [97.207, 42.8027],
-            [99.4922, 42.583],
-            [100.8105, 42.6709],
-            [101.7773, 42.4951],
-            [102.041, 42.2314],
-            [102.7441, 42.1436],
-            [103.3594, 41.8799],
-            [103.8867, 41.792],
-            [104.502, 41.8799],
-            [104.502, 41.6602],
-            [105.0293, 41.5723],
-            [105.7324, 41.9238],
-            [107.4023, 42.4512],
-            [109.4238, 42.4512],
-            [110.3906, 42.7588],
-            [111.0059, 43.3301],
-            [111.9727, 43.6816],
-            [111.9727, 43.8135],
-            [111.4453, 44.3848],
-            [111.7969, 45],
-            [111.9727, 45.0879],
-            [113.6426, 44.7363],
-            [114.1699, 44.9561],
-            [114.5215, 45.3955],
-            [115.6641, 45.4395],
-            [116.1914, 45.7031],
-            [116.2793, 45.9668],
-            [116.543, 46.2744],
-            [117.334, 46.3623],
-            [117.4219, 46.582],
-            [117.7734, 46.5381],
-            [118.3008, 46.7578],
-            [118.7402, 46.7139],
-            [118.916, 46.7578],
-            [119.0918, 46.6699],
-            [119.707, 46.626],
-            [119.9707, 46.7139],
-            [119.707, 47.1973],
-            [118.4766, 47.9883],
-            [117.8613, 48.0322],
-            [117.334, 47.6807],
-            [116.8066, 47.9004],
-            [116.1914, 47.8564],
-            [115.9277, 47.6807],
-            [115.5762, 47.9004],
-            [115.4883, 48.1641],
-            [115.8398, 48.252],
-            [115.8398, 48.5596],
-            [116.7188, 49.834],
-            [117.7734, 49.5264],
-            [118.5645, 49.9219],
-            [119.2676, 50.0977],
-            [119.3555, 50.3174],
-            [119.1797, 50.3613],
-            [119.5313, 50.7568],
-            [119.5313, 50.8887],
-            [119.707, 51.0645],
-            [120.1465, 51.6797],
-            [120.6738, 51.9434],
-            [120.7617, 52.1191],
-            [120.7617, 52.251],
-            [120.5859, 52.3389],
-            [120.6738, 52.5146],
-            [120.4102, 52.6465],
-            [120.0586, 52.6025],
-            [120.0586, 52.7344],
-            [120.8496, 53.2617],
-            [121.4648, 53.3496],
-            [121.8164, 53.042],
-            [121.2012, 52.5586],
-            [121.6406, 52.4268],
-            [121.7285, 52.2949],
-            [121.9922, 52.2949],
-            [122.168, 52.5146],
-            [122.6953, 52.251],
-            [122.6074, 52.0752],
-            [122.959, 51.3281],
-            [123.3105, 51.2402],
-            [123.6621, 51.3721],
-            [124.3652, 51.2842],
-            [124.541, 51.3721],
-            [124.8926, 51.3721],
-            [125.0684, 51.6357],
-            [125.332, 51.6357],
-            [126.0352, 51.0205],
-            [125.7715, 50.7568],
-            [125.7715, 50.5371],
-            [125.332, 50.1416],
-            [125.1563, 49.834],
-            [125.2441, 49.1748],
-            [124.8047, 49.1309],
-            [124.4531, 48.1201],
-            [124.2773, 48.5156],
-            [122.4316, 47.373],
-            [123.0469, 46.7139],
-            [123.3984, 46.8896],
-            [123.3984, 46.9775],
-            [123.4863, 46.9775],
-            [123.5742, 46.8457],
-            [123.5742, 46.8896],
-            [123.5742, 46.6699],
-            [123.0469, 46.582],
-            [123.2227, 46.2305],
-            [122.7832, 46.0107],
-            [122.6953, 45.7031],
-            [122.4316, 45.8789],
-            [122.2559, 45.791],
-            [121.8164, 46.0107],
-            [121.7285, 45.7471],
-            [121.9043, 45.7031],
-            [122.2559, 45.2637],
-            [122.0801, 44.8682],
-            [122.3438, 44.2529],
-            [123.1348, 44.4727],
-            [123.4863, 43.7256],
-            [123.3105, 43.5059],
-            [123.6621, 43.374],
-            [123.5742, 43.0225],
-            [123.3105, 42.9785],
-            [123.1348, 42.8027],
-            [122.7832, 42.7148],
-            [122.3438, 42.8467],
-            [122.3438, 42.6709],
-            [121.9922, 42.7148],
-            [121.7285, 42.4512],
-            [121.4648, 42.4951],
-            [120.498, 42.0996],
-            [120.1465, 41.7041],
-            [119.8828, 42.1875],
-            [119.5313, 42.3633],
-            [119.3555, 42.2754],
-            [119.2676, 41.7041],
-            [119.4434, 41.6162],
-            [119.2676, 41.3086],
-            [118.3887, 41.3086],
-            [118.125, 41.748],
-            [118.3008, 41.792],
-            [118.3008, 42.0996],
-            [118.125, 42.0557],
-            [117.9492, 42.2314],
-            [118.0371, 42.4072],
-            [117.7734, 42.627],
-            [117.5098, 42.583],
-            [117.334, 42.4512],
-            [116.8945, 42.4072],
-            [116.8066, 42.0117],
-            [116.2793, 42.0117],
-            [116.0156, 41.792],
-            [115.9277, 41.9238],
-            [115.2246, 41.5723],
-            [114.9609, 41.6162],
-            [114.873, 42.0996],
-            [114.5215, 42.1436],
-            [114.1699, 41.792],
-            [114.2578, 41.5723],
-            [113.9063, 41.4404],
-            [113.9941, 41.2207],
-            [113.9063, 41.1328],
-            [114.082, 40.7373],
-            [114.082, 40.5176],
-            [113.8184, 40.5176],
-            [113.5547, 40.3418],
-            [113.2031, 40.3857],
-            [112.7637, 40.166],
-            [112.3242, 40.2539],
-            [111.9727, 39.5947],
-            [111.4453, 39.6387],
-            [111.3574, 39.4189],
-            [111.0938, 39.375],
-            [111.0938, 39.5947],
-            [110.6543, 39.2871],
-            [110.127, 39.4629],
-            [110.2148, 39.2871],
-            [109.8633, 39.2432],
-            [109.9512, 39.1553],
-            [108.9844, 38.3203],
-            [109.0723, 38.0127],
-            [108.8965, 37.9688],
-            [108.8086, 38.0127],
-            [108.7207, 37.7051],
-            [108.1934, 37.6172],
-            [107.666, 37.8809],
-            [107.3145, 38.1006],
-            [106.7871, 38.1885],
-            [106.5234, 38.3203],
-            [106.9629, 38.9795],
-            [106.7871, 39.375],
-            [106.3477, 39.2871],
-            [105.9082, 38.7158],
-            [105.8203, 37.793],
-            [104.3262, 37.4414],
-            [103.4473, 37.8369],
-            [103.3594, 38.0127],
-            [103.5352, 38.1445],
-            [103.4473, 38.3643],
-            [104.2383, 38.9795],
-            [104.0625, 39.4189],
-            [103.3594, 39.3311],
-            [103.0078, 39.1113],
-            [102.4805, 39.2432],
-            [101.8652, 39.1113],
-            [102.041, 38.8916],
-            [101.7773, 38.6719],
-            [101.3379, 38.7598],
-            [101.25, 39.0234],
-            [100.9863, 38.9355],
-            [100.8105, 39.4189],
-            [100.5469, 39.4189],
-            [100.0195, 39.7705],
-            [99.4922, 39.8584],
-            [100.1074, 40.2539],
-            [100.1953, 40.6494],
-            [99.9316, 41.001],
-            [99.2285, 40.8691],
-            [99.0527, 40.6934],
-            [98.9648, 40.7813],
-            [98.7891, 40.6055],
-            [98.5254, 40.7373],
-            [98.6133, 40.6494],
-            [98.3496, 40.5615],
-            [98.3496, 40.9131],
-            [97.4707, 41.4844],
-            [97.8223, 41.6162],
-            [97.8223, 41.748],
-            [97.207, 42.8027],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'qing_hai',
-      properties: { name: '青海', cp: [96.2402, 35.4199], childNum: 8 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [89.7363, 36.0791],
-            [89.9121, 36.0791],
-            [90, 36.2549],
-            [90.8789, 36.0352],
-            [91.0547, 36.0791],
-            [91.0547, 36.5186],
-            [90.791, 36.6064],
-            [90.7031, 36.7822],
-            [91.3184, 37.0898],
-            [91.0547, 37.4414],
-            [90.5273, 37.8369],
-            [90.6152, 38.3203],
-            [90.3516, 38.2324],
-            [90.1758, 38.4961],
-            [92.373, 39.0234],
-            [92.373, 39.1113],
-            [93.1641, 39.1992],
-            [93.1641, 38.9795],
-            [93.6914, 38.9355],
-            [93.8672, 38.7158],
-            [94.3066, 38.7598],
-            [94.5703, 38.3643],
-            [95.0098, 38.4082],
-            [95.4492, 38.2764],
-            [95.7129, 38.3643],
-            [96.2402, 38.1006],
-            [96.416, 38.2324],
-            [96.6797, 38.1885],
-            [96.6797, 38.4521],
-            [97.1191, 38.584],
-            [97.0313, 39.1992],
-            [98.1738, 38.8037],
-            [98.3496, 39.0234],
-            [98.6133, 38.9355],
-            [98.7891, 39.0674],
-            [99.1406, 38.9355],
-            [99.8438, 38.3643],
-            [100.1953, 38.2764],
-            [100.0195, 38.4521],
-            [100.1074, 38.4961],
-            [100.459, 38.2764],
-            [100.7227, 38.2324],
-            [101.1621, 37.8369],
-            [101.5137, 37.8809],
-            [101.7773, 37.6172],
-            [101.9531, 37.7051],
-            [102.1289, 37.4414],
-            [102.5684, 37.1777],
-            [102.4805, 36.958],
-            [102.6563, 36.8262],
-            [102.5684, 36.7383],
-            [102.832, 36.3428],
-            [103.0078, 36.2549],
-            [102.9199, 36.0791],
-            [102.9199, 35.9033],
-            [102.6563, 35.7715],
-            [102.832, 35.5957],
-            [102.4805, 35.5957],
-            [102.3047, 35.4199],
-            [102.3926, 35.2002],
-            [101.9531, 34.8486],
-            [101.9531, 34.6289],
-            [102.2168, 34.4092],
-            [102.1289, 34.2773],
-            [101.6895, 34.1016],
-            [100.9863, 34.3652],
-            [100.8105, 34.2773],
-            [101.25, 33.6621],
-            [101.5137, 33.7061],
-            [101.6016, 33.5303],
-            [101.7773, 33.5303],
-            [101.6895, 33.3105],
-            [101.7773, 33.2227],
-            [101.6016, 33.1348],
-            [101.1621, 33.2227],
-            [101.25, 32.6953],
-            [100.7227, 32.6514],
-            [100.7227, 32.5195],
-            [100.3711, 32.7393],
-            [100.1074, 32.6514],
-            [100.1074, 32.8711],
-            [99.8438, 33.0029],
-            [99.7559, 32.7393],
-            [99.2285, 32.915],
-            [99.2285, 33.0469],
-            [98.877, 33.1787],
-            [98.4375, 34.0576],
-            [97.8223, 34.1895],
-            [97.6465, 34.1016],
-            [97.7344, 33.9258],
-            [97.3828, 33.8818],
-            [97.4707, 33.5742],
-            [97.7344, 33.3984],
-            [97.3828, 32.8711],
-            [97.4707, 32.6953],
-            [97.7344, 32.5195],
-            [97.3828, 32.5635],
-            [97.2949, 32.0801],
-            [96.7676, 31.9922],
-            [96.8555, 31.6846],
-            [96.5039, 31.7285],
-            [96.2402, 31.9482],
-            [96.1523, 31.5967],
-            [95.9766, 31.8164],
-            [95.8008, 31.6846],
-            [95.4492, 31.8164],
-            [95.3613, 31.9922],
-            [95.3613, 32.168],
-            [95.2734, 32.2119],
-            [95.1855, 32.3438],
-            [95.0098, 32.2998],
-            [95.1855, 32.4316],
-            [94.6582, 32.6074],
-            [94.1309, 32.4316],
-            [93.7793, 32.5635],
-            [93.5156, 32.4756],
-            [92.9883, 32.7393],
-            [92.2852, 32.7393],
-            [92.1973, 32.8271],
-            [91.9336, 32.8271],
-            [91.4063, 33.1348],
-            [90.7031, 33.1348],
-            [90.0879, 33.4863],
-            [89.6484, 34.0137],
-            [89.8242, 34.3652],
-            [89.7363, 34.6729],
-            [89.8242, 34.8486],
-            [89.5605, 34.8926],
-            [89.4727, 35.2441],
-            [89.4727, 35.376],
-            [89.7363, 35.4199],
-            [89.7363, 35.7715],
-            [89.4727, 35.9033],
-            [89.3848, 36.0352],
-            [89.7363, 36.0791],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'si_chuan',
-      properties: { name: '四川', cp: [102.9199, 30.1904], childNum: 21 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [101.7773, 33.5303],
-            [101.8652, 33.5742],
-            [101.9531, 33.4424],
-            [101.8652, 33.0908],
-            [102.4805, 33.4424],
-            [102.2168, 33.9258],
-            [102.9199, 34.3213],
-            [103.0957, 34.1895],
-            [103.1836, 33.7939],
-            [104.1504, 33.6182],
-            [104.2383, 33.3984],
-            [104.4141, 33.3105],
-            [104.3262, 33.2227],
-            [104.4141, 33.0469],
-            [104.3262, 32.8711],
-            [104.4141, 32.7393],
-            [105.2051, 32.6074],
-            [105.3809, 32.7393],
-            [105.3809, 32.8711],
-            [105.4688, 32.915],
-            [105.5566, 32.7393],
-            [106.084, 32.8711],
-            [106.084, 32.7393],
-            [106.3477, 32.6514],
-            [107.0508, 32.6953],
-            [107.1387, 32.4756],
-            [107.2266, 32.4316],
-            [107.4023, 32.5195],
-            [108.0176, 32.168],
-            [108.2813, 32.2559],
-            [108.5449, 32.2119],
-            [108.3691, 32.168],
-            [108.2813, 31.9043],
-            [108.5449, 31.6846],
-            [108.1934, 31.5088],
-            [107.9297, 30.8496],
-            [107.4902, 30.8496],
-            [107.4023, 30.7617],
-            [107.4902, 30.6299],
-            [107.0508, 30.0146],
-            [106.7871, 30.0146],
-            [106.6113, 30.3223],
-            [106.2598, 30.1904],
-            [105.8203, 30.4541],
-            [105.6445, 30.2783],
-            [105.5566, 30.1025],
-            [105.7324, 29.8828],
-            [105.293, 29.5313],
-            [105.4688, 29.3115],
-            [105.7324, 29.2676],
-            [105.8203, 28.96],
-            [106.2598, 28.8721],
-            [106.3477, 28.5205],
-            [105.9961, 28.7402],
-            [105.6445, 28.4326],
-            [105.9082, 28.125],
-            [106.1719, 28.125],
-            [106.3477, 27.8174],
-            [105.6445, 27.6416],
-            [105.5566, 27.7734],
-            [105.293, 27.7295],
-            [105.2051, 27.9932],
-            [105.0293, 28.0811],
-            [104.8535, 27.9053],
-            [104.4141, 27.9492],
-            [104.3262, 28.0371],
-            [104.4141, 28.125],
-            [104.4141, 28.2568],
-            [104.2383, 28.4326],
-            [104.4141, 28.6084],
-            [103.8867, 28.6523],
-            [103.7988, 28.3008],
-            [103.4473, 28.125],
-            [103.4473, 27.7734],
-            [102.9199, 27.29],
-            [103.0078, 26.3672],
-            [102.6563, 26.1914],
-            [102.5684, 26.3672],
-            [102.1289, 26.1035],
-            [101.8652, 26.0596],
-            [101.6016, 26.2354],
-            [101.6895, 26.3672],
-            [101.4258, 26.5869],
-            [101.4258, 26.8066],
-            [101.4258, 26.7188],
-            [101.1621, 27.0264],
-            [101.1621, 27.1582],
-            [100.7227, 27.8613],
-            [100.3711, 27.8174],
-            [100.2832, 27.7295],
-            [100.0195, 28.125],
-            [100.1953, 28.3447],
-            [99.668, 28.8281],
-            [99.4043, 28.5205],
-            [99.4043, 28.1689],
-            [99.2285, 28.3008],
-            [99.1406, 29.2676],
-            [98.9648, 30.7617],
-            [98.6133, 31.2012],
-            [98.877, 31.4209],
-            [98.4375, 31.8604],
-            [98.1738, 32.3438],
-            [97.7344, 32.5195],
-            [97.4707, 32.6953],
-            [97.3828, 32.8711],
-            [97.7344, 33.3984],
-            [97.4707, 33.5742],
-            [97.3828, 33.8818],
-            [97.7344, 33.9258],
-            [97.6465, 34.1016],
-            [97.8223, 34.1895],
-            [98.4375, 34.0576],
-            [98.877, 33.1787],
-            [99.2285, 33.0469],
-            [99.2285, 32.915],
-            [99.7559, 32.7393],
-            [99.8438, 33.0029],
-            [100.1074, 32.8711],
-            [100.1074, 32.6514],
-            [100.3711, 32.7393],
-            [100.7227, 32.5195],
-            [100.7227, 32.6514],
-            [101.25, 32.6953],
-            [101.1621, 33.2227],
-            [101.6016, 33.1348],
-            [101.7773, 33.2227],
-            [101.6895, 33.3105],
-            [101.7773, 33.5303],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'hei_long_jiang',
-      properties: { name: '黑龙江', cp: [128.1445, 48.5156], childNum: 13 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [121.4648, 53.3496],
-            [123.6621, 53.5693],
-            [124.8926, 53.0859],
-            [125.0684, 53.2178],
-            [125.5957, 53.0859],
-            [125.6836, 52.9102],
-            [126.123, 52.7783],
-            [126.0352, 52.6025],
-            [126.2109, 52.5146],
-            [126.3867, 52.2949],
-            [126.3867, 52.207],
-            [126.5625, 52.1631],
-            [126.4746, 51.9434],
-            [126.9141, 51.3721],
-            [126.8262, 51.2842],
-            [127.002, 51.3281],
-            [126.9141, 51.1084],
-            [127.2656, 50.7568],
-            [127.3535, 50.2734],
-            [127.6172, 50.2295],
-            [127.5293, 49.8779],
-            [127.793, 49.6143],
-            [128.7598, 49.5703],
-            [129.1113, 49.3506],
-            [129.4629, 49.4385],
-            [130.2539, 48.8672],
-            [130.6934, 48.8672],
-            [130.5176, 48.6475],
-            [130.8691, 48.2959],
-            [130.6934, 48.1201],
-            [131.0449, 47.6807],
-            [132.5391, 47.7246],
-            [132.627, 47.9443],
-            [133.0664, 48.1201],
-            [133.5059, 48.1201],
-            [134.209, 48.3838],
-            [135.0879, 48.4277],
-            [134.7363, 48.252],
-            [134.5605, 47.9883],
-            [134.7363, 47.6807],
-            [134.5605, 47.4609],
-            [134.3848, 47.4609],
-            [134.209, 47.2852],
-            [134.209, 47.1533],
-            [133.8574, 46.5381],
-            [133.9453, 46.2744],
-            [133.5059, 45.835],
-            [133.418, 45.5713],
-            [133.2422, 45.5273],
-            [133.0664, 45.1318],
-            [132.8906, 45.0439],
-            [131.9238, 45.3516],
-            [131.5723, 45.0439],
-            [131.0449, 44.8682],
-            [131.3086, 44.0771],
-            [131.2207, 43.7256],
-            [131.3086, 43.4619],
-            [130.8691, 43.418],
-            [130.5176, 43.6377],
-            [130.3418, 43.9893],
-            [129.9902, 43.8574],
-            [129.9023, 44.0332],
-            [129.8145, 43.9014],
-            [129.2871, 43.8135],
-            [129.1992, 43.5938],
-            [128.8477, 43.5498],
-            [128.4961, 44.165],
-            [128.4082, 44.4727],
-            [128.0566, 44.3408],
-            [128.0566, 44.1211],
-            [127.7051, 44.1211],
-            [127.5293, 44.6045],
-            [127.0898, 44.6045],
-            [127.002, 44.7803],
-            [127.0898, 45],
-            [126.9141, 45.1318],
-            [126.5625, 45.2637],
-            [126.0352, 45.1758],
-            [125.7715, 45.3076],
-            [125.6836, 45.5273],
-            [125.0684, 45.3955],
-            [124.8926, 45.5273],
-            [124.3652, 45.4395],
-            [124.0137, 45.7471],
-            [123.9258, 46.2305],
-            [123.2227, 46.2305],
-            [123.0469, 46.582],
-            [123.5742, 46.6699],
-            [123.5742, 46.8896],
-            [123.5742, 46.8457],
-            [123.4863, 46.9775],
-            [123.3984, 46.9775],
-            [123.3984, 46.8896],
-            [123.0469, 46.7139],
-            [122.4316, 47.373],
-            [124.2773, 48.5156],
-            [124.4531, 48.1201],
-            [124.8047, 49.1309],
-            [125.2441, 49.1748],
-            [125.1563, 49.834],
-            [125.332, 50.1416],
-            [125.7715, 50.5371],
-            [125.7715, 50.7568],
-            [126.0352, 51.0205],
-            [125.332, 51.6357],
-            [125.0684, 51.6357],
-            [124.8926, 51.3721],
-            [124.541, 51.3721],
-            [124.3652, 51.2842],
-            [123.6621, 51.3721],
-            [123.3105, 51.2402],
-            [122.959, 51.3281],
-            [122.6074, 52.0752],
-            [122.6953, 52.251],
-            [122.168, 52.5146],
-            [121.9922, 52.2949],
-            [121.7285, 52.2949],
-            [121.6406, 52.4268],
-            [121.2012, 52.5586],
-            [121.8164, 53.042],
-            [121.4648, 53.3496],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'gan_su',
-      properties: { name: '甘肃', cp: [95.7129, 40.166], childNum: 14 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [96.416, 42.7148],
-            [97.207, 42.8027],
-            [97.8223, 41.748],
-            [97.8223, 41.6162],
-            [97.4707, 41.4844],
-            [98.3496, 40.9131],
-            [98.3496, 40.5615],
-            [98.6133, 40.6494],
-            [98.5254, 40.7373],
-            [98.7891, 40.6055],
-            [98.9648, 40.7813],
-            [99.0527, 40.6934],
-            [99.2285, 40.8691],
-            [99.9316, 41.001],
-            [100.1953, 40.6494],
-            [100.1074, 40.2539],
-            [99.4922, 39.8584],
-            [100.0195, 39.7705],
-            [100.5469, 39.4189],
-            [100.8105, 39.4189],
-            [100.9863, 38.9355],
-            [101.25, 39.0234],
-            [101.3379, 38.7598],
-            [101.7773, 38.6719],
-            [102.041, 38.8916],
-            [101.8652, 39.1113],
-            [102.4805, 39.2432],
-            [103.0078, 39.1113],
-            [103.3594, 39.3311],
-            [104.0625, 39.4189],
-            [104.2383, 38.9795],
-            [103.4473, 38.3643],
-            [103.5352, 38.1445],
-            [103.3594, 38.0127],
-            [103.4473, 37.8369],
-            [104.3262, 37.4414],
-            [104.5898, 37.4414],
-            [104.5898, 37.2217],
-            [104.8535, 37.2217],
-            [105.293, 36.8262],
-            [105.2051, 36.6943],
-            [105.4688, 36.123],
-            [105.293, 35.9912],
-            [105.3809, 35.7715],
-            [105.7324, 35.7275],
-            [105.8203, 35.5518],
-            [105.9961, 35.4639],
-            [105.9082, 35.4199],
-            [105.9961, 35.4199],
-            [106.084, 35.376],
-            [106.2598, 35.4199],
-            [106.3477, 35.2441],
-            [106.5234, 35.332],
-            [106.4355, 35.6836],
-            [106.6992, 35.6836],
-            [106.9629, 35.8154],
-            [106.875, 36.123],
-            [106.5234, 36.2549],
-            [106.5234, 36.4746],
-            [106.4355, 36.5625],
-            [106.6113, 36.7822],
-            [106.6113, 37.0898],
-            [107.3145, 37.0898],
-            [107.3145, 36.9141],
-            [108.7207, 36.3428],
-            [108.6328, 35.9912],
-            [108.5449, 35.8594],
-            [108.6328, 35.5518],
-            [108.5449, 35.2881],
-            [107.7539, 35.2881],
-            [107.7539, 35.1123],
-            [107.8418, 35.0244],
-            [107.666, 34.9365],
-            [107.2266, 34.8926],
-            [106.9629, 35.0684],
-            [106.6113, 35.0684],
-            [106.5234, 34.7607],
-            [106.3477, 34.585],
-            [106.6992, 34.3213],
-            [106.5234, 34.2773],
-            [106.6113, 34.1455],
-            [106.4355, 33.9258],
-            [106.5234, 33.5303],
-            [105.9961, 33.6182],
-            [105.7324, 33.3984],
-            [105.9961, 33.1787],
-            [105.9082, 33.0029],
-            [105.4688, 32.915],
-            [105.3809, 32.8711],
-            [105.3809, 32.7393],
-            [105.2051, 32.6074],
-            [104.4141, 32.7393],
-            [104.3262, 32.8711],
-            [104.4141, 33.0469],
-            [104.3262, 33.2227],
-            [104.4141, 33.3105],
-            [104.2383, 33.3984],
-            [104.1504, 33.6182],
-            [103.1836, 33.7939],
-            [103.0957, 34.1895],
-            [102.9199, 34.3213],
-            [102.2168, 33.9258],
-            [102.4805, 33.4424],
-            [101.8652, 33.0908],
-            [101.9531, 33.4424],
-            [101.8652, 33.5742],
-            [101.7773, 33.5303],
-            [101.6016, 33.5303],
-            [101.5137, 33.7061],
-            [101.25, 33.6621],
-            [100.8105, 34.2773],
-            [100.9863, 34.3652],
-            [101.6895, 34.1016],
-            [102.1289, 34.2773],
-            [102.2168, 34.4092],
-            [101.9531, 34.6289],
-            [101.9531, 34.8486],
-            [102.3926, 35.2002],
-            [102.3047, 35.4199],
-            [102.4805, 35.5957],
-            [102.832, 35.5957],
-            [102.6563, 35.7715],
-            [102.9199, 35.9033],
-            [102.9199, 36.0791],
-            [103.0078, 36.2549],
-            [102.832, 36.3428],
-            [102.5684, 36.7383],
-            [102.6563, 36.8262],
-            [102.4805, 36.958],
-            [102.5684, 37.1777],
-            [102.1289, 37.4414],
-            [101.9531, 37.7051],
-            [101.7773, 37.6172],
-            [101.5137, 37.8809],
-            [101.1621, 37.8369],
-            [100.7227, 38.2324],
-            [100.459, 38.2764],
-            [100.1074, 38.4961],
-            [100.0195, 38.4521],
-            [100.1953, 38.2764],
-            [99.8438, 38.3643],
-            [99.1406, 38.9355],
-            [98.7891, 39.0674],
-            [98.6133, 38.9355],
-            [98.3496, 39.0234],
-            [98.1738, 38.8037],
-            [97.0313, 39.1992],
-            [97.1191, 38.584],
-            [96.6797, 38.4521],
-            [96.6797, 38.1885],
-            [96.416, 38.2324],
-            [96.2402, 38.1006],
-            [95.7129, 38.3643],
-            [95.4492, 38.2764],
-            [95.0098, 38.4082],
-            [94.5703, 38.3643],
-            [94.3066, 38.7598],
-            [93.8672, 38.7158],
-            [93.6914, 38.9355],
-            [93.1641, 38.9795],
-            [93.1641, 39.1992],
-            [92.373, 39.1113],
-            [92.373, 39.3311],
-            [92.6367, 39.6387],
-            [93.0762, 40.6494],
-            [93.8672, 40.6934],
-            [94.043, 41.0889],
-            [94.5703, 41.4844],
-            [95.1855, 41.792],
-            [95.2734, 41.6162],
-            [95.9766, 41.9238],
-            [96.2402, 42.2314],
-            [96.0645, 42.3193],
-            [95.9766, 42.4951],
-            [96.416, 42.7148],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'yun_nan',
-      properties: { name: '云南', cp: [101.8652, 25.1807], childNum: 16 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [98.1738, 28.125],
-            [98.2617, 28.3887],
-            [98.3496, 28.125],
-            [98.7012, 28.2129],
-            [98.7891, 28.3447],
-            [98.6133, 28.5205],
-            [98.7012, 28.916],
-            [98.7891, 29.0039],
-            [98.7891, 28.8721],
-            [98.9648, 28.8281],
-            [98.9648, 29.1357],
-            [99.1406, 29.2676],
-            [99.2285, 28.3008],
-            [99.4043, 28.1689],
-            [99.4043, 28.5205],
-            [99.668, 28.8281],
-            [100.1953, 28.3447],
-            [100.0195, 28.125],
-            [100.2832, 27.7295],
-            [100.3711, 27.8174],
-            [100.7227, 27.8613],
-            [101.1621, 27.1582],
-            [101.1621, 27.0264],
-            [101.4258, 26.7188],
-            [101.4258, 26.8066],
-            [101.4258, 26.5869],
-            [101.6895, 26.3672],
-            [101.6016, 26.2354],
-            [101.8652, 26.0596],
-            [102.1289, 26.1035],
-            [102.5684, 26.3672],
-            [102.6563, 26.1914],
-            [103.0078, 26.3672],
-            [102.9199, 27.29],
-            [103.4473, 27.7734],
-            [103.4473, 28.125],
-            [103.7988, 28.3008],
-            [103.8867, 28.6523],
-            [104.4141, 28.6084],
-            [104.2383, 28.4326],
-            [104.4141, 28.2568],
-            [104.4141, 28.125],
-            [104.3262, 28.0371],
-            [104.4141, 27.9492],
-            [104.8535, 27.9053],
-            [105.0293, 28.0811],
-            [105.2051, 27.9932],
-            [105.293, 27.7295],
-            [105.2051, 27.3779],
-            [104.5898, 27.334],
-            [104.4141, 27.4658],
-            [104.1504, 27.2461],
-            [103.8867, 27.4219],
-            [103.623, 27.0264],
-            [103.7109, 26.9824],
-            [103.7109, 26.7627],
-            [103.8867, 26.543],
-            [104.4141, 26.6748],
-            [104.6777, 26.4111],
-            [104.3262, 25.708],
-            [104.8535, 25.2246],
-            [104.5898, 25.0488],
-            [104.6777, 24.9609],
-            [104.502, 24.7412],
-            [104.6777, 24.3457],
-            [104.7656, 24.4775],
-            [105.0293, 24.4336],
-            [105.2051, 24.082],
-            [105.4688, 24.0381],
-            [105.5566, 24.126],
-            [105.9961, 24.126],
-            [106.1719, 23.8184],
-            [106.1719, 23.5547],
-            [105.6445, 23.4229],
-            [105.5566, 23.2031],
-            [105.293, 23.3789],
-            [104.8535, 23.1592],
-            [104.7656, 22.8516],
-            [104.3262, 22.6758],
-            [104.1504, 22.8076],
-            [103.9746, 22.5439],
-            [103.623, 22.7637],
-            [103.5352, 22.5879],
-            [103.3594, 22.8076],
-            [103.0957, 22.4561],
-            [102.4805, 22.7637],
-            [102.3047, 22.4121],
-            [101.8652, 22.3682],
-            [101.7773, 22.5],
-            [101.6016, 22.1924],
-            [101.8652, 21.6211],
-            [101.7773, 21.1377],
-            [101.6016, 21.2256],
-            [101.25, 21.1816],
-            [101.1621, 21.7529],
-            [100.6348, 21.4453],
-            [100.1074, 21.4893],
-            [99.9316, 22.0605],
-            [99.2285, 22.1484],
-            [99.4043, 22.5879],
-            [99.3164, 22.7197],
-            [99.4922, 23.0713],
-            [98.877, 23.2031],
-            [98.7012, 23.9502],
-            [98.877, 24.126],
-            [98.1738, 24.082],
-            [97.7344, 23.8623],
-            [97.5586, 23.9063],
-            [97.7344, 24.126],
-            [97.6465, 24.4336],
-            [97.5586, 24.4336],
-            [97.5586, 24.7412],
-            [97.7344, 24.8291],
-            [97.8223, 25.2686],
-            [98.1738, 25.4004],
-            [98.1738, 25.6201],
-            [98.3496, 25.5762],
-            [98.5254, 25.8398],
-            [98.7012, 25.8838],
-            [98.6133, 26.0596],
-            [98.7012, 26.1475],
-            [98.7891, 26.5869],
-            [98.7012, 27.5098],
-            [98.5254, 27.6416],
-            [98.3496, 27.5098],
-            [98.1738, 28.125],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'guang_xi',
-      properties: { name: '广西', cp: [108.2813, 23.6426], childNum: 14 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [104.502, 24.7412],
-            [104.6777, 24.6094],
-            [105.2051, 24.9609],
-            [105.9961, 24.6533],
-            [106.1719, 24.7852],
-            [106.1719, 24.9609],
-            [106.875, 25.1807],
-            [107.0508, 25.2686],
-            [106.9629, 25.4883],
-            [107.2266, 25.6201],
-            [107.4902, 25.2246],
-            [107.7539, 25.2246],
-            [107.8418, 25.1367],
-            [108.1055, 25.2246],
-            [108.1934, 25.4443],
-            [108.3691, 25.5322],
-            [108.6328, 25.3125],
-            [108.6328, 25.5762],
-            [109.0723, 25.5322],
-            [108.9844, 25.752],
-            [109.3359, 25.708],
-            [109.5117, 26.0156],
-            [109.7754, 25.8838],
-            [109.9512, 26.1914],
-            [110.2148, 25.9717],
-            [110.5664, 26.3232],
-            [111.1816, 26.3232],
-            [111.2695, 26.2354],
-            [111.2695, 25.8838],
-            [111.4453, 25.8398],
-            [111.0059, 25.0049],
-            [111.0938, 24.9609],
-            [111.3574, 25.1367],
-            [111.5332, 24.6533],
-            [111.709, 24.7852],
-            [112.0605, 24.7412],
-            [111.8848, 24.6533],
-            [112.0605, 24.3457],
-            [111.8848, 24.2139],
-            [111.8848, 23.9941],
-            [111.7969, 23.8184],
-            [111.6211, 23.8184],
-            [111.6211, 23.6865],
-            [111.3574, 23.4668],
-            [111.4453, 23.0273],
-            [111.2695, 22.8076],
-            [110.7422, 22.5439],
-            [110.7422, 22.2803],
-            [110.6543, 22.1484],
-            [110.3027, 22.1484],
-            [110.3027, 21.8848],
-            [109.9512, 21.8408],
-            [109.8633, 21.665],
-            [109.7754, 21.6211],
-            [109.7754, 21.4014],
-            [109.5996, 21.4453],
-            [109.1602, 21.3574],
-            [109.248, 20.874],
-            [109.0723, 20.9619],
-            [109.0723, 21.5332],
-            [108.7207, 21.5332],
-            [108.6328, 21.665],
-            [108.2813, 21.4893],
-            [107.8418, 21.6211],
-            [107.4023, 21.6211],
-            [107.0508, 21.7969],
-            [107.0508, 21.9287],
-            [106.6992, 22.0166],
-            [106.6113, 22.4121],
-            [106.7871, 22.7637],
-            [106.6992, 22.8955],
-            [105.9082, 22.9395],
-            [105.5566, 23.0713],
-            [105.5566, 23.2031],
-            [105.6445, 23.4229],
-            [106.1719, 23.5547],
-            [106.1719, 23.8184],
-            [105.9961, 24.126],
-            [105.5566, 24.126],
-            [105.4688, 24.0381],
-            [105.2051, 24.082],
-            [105.0293, 24.4336],
-            [104.7656, 24.4775],
-            [104.6777, 24.3457],
-            [104.502, 24.7412],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'hu_nan',
-      properties: { name: '湖南', cp: [111.5332, 27.3779], childNum: 14 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [109.248, 28.4766],
-            [109.248, 29.1357],
-            [109.5117, 29.6191],
-            [109.6875, 29.6191],
-            [109.7754, 29.751],
-            [110.4785, 29.6631],
-            [110.6543, 29.751],
-            [110.4785, 30.0146],
-            [110.8301, 30.1465],
-            [111.7969, 29.9268],
-            [112.2363, 29.5313],
-            [112.5, 29.6191],
-            [112.6758, 29.5752],
-            [112.9395, 29.7949],
-            [113.0273, 29.751],
-            [112.9395, 29.4873],
-            [113.0273, 29.4434],
-            [113.5547, 29.8389],
-            [113.5547, 29.707],
-            [113.7305, 29.5752],
-            [113.6426, 29.3115],
-            [113.7305, 29.0918],
-            [113.9063, 29.0479],
-            [114.1699, 28.8281],
-            [114.082, 28.5645],
-            [114.2578, 28.3447],
-            [113.7305, 27.9492],
-            [113.6426, 27.5977],
-            [113.6426, 27.3779],
-            [113.8184, 27.29],
-            [113.7305, 27.1143],
-            [113.9063, 26.9385],
-            [113.9063, 26.6309],
-            [114.082, 26.5869],
-            [113.9941, 26.1914],
-            [114.2578, 26.1475],
-            [113.9941, 26.0596],
-            [113.9063, 25.4443],
-            [113.6426, 25.3125],
-            [113.2031, 25.5322],
-            [112.8516, 25.3564],
-            [113.0273, 25.2246],
-            [113.0273, 24.9609],
-            [112.8516, 24.917],
-            [112.5879, 25.1367],
-            [112.2363, 25.1807],
-            [112.1484, 24.873],
-            [112.0605, 24.7412],
-            [111.709, 24.7852],
-            [111.5332, 24.6533],
-            [111.3574, 25.1367],
-            [111.0938, 24.9609],
-            [111.0059, 25.0049],
-            [111.4453, 25.8398],
-            [111.2695, 25.8838],
-            [111.2695, 26.2354],
-            [111.1816, 26.3232],
-            [110.5664, 26.3232],
-            [110.2148, 25.9717],
-            [109.9512, 26.1914],
-            [109.7754, 25.8838],
-            [109.5117, 26.0156],
-            [109.4238, 26.2793],
-            [109.248, 26.3232],
-            [109.4238, 26.5869],
-            [109.3359, 26.7188],
-            [109.5117, 26.8066],
-            [109.5117, 27.0264],
-            [109.3359, 27.1582],
-            [108.8965, 27.0264],
-            [108.8086, 27.1143],
-            [109.4238, 27.5977],
-            [109.3359, 27.9053],
-            [109.3359, 28.2568],
-            [109.248, 28.4766],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'shan_xi_1',
-      properties: { name: '陕西', cp: [109.5996, 35.6396], childNum: 10 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [105.4688, 32.915],
-            [105.9082, 33.0029],
-            [105.9961, 33.1787],
-            [105.7324, 33.3984],
-            [105.9961, 33.6182],
-            [106.5234, 33.5303],
-            [106.4355, 33.9258],
-            [106.6113, 34.1455],
-            [106.5234, 34.2773],
-            [106.6992, 34.3213],
-            [106.3477, 34.585],
-            [106.5234, 34.7607],
-            [106.6113, 35.0684],
-            [106.9629, 35.0684],
-            [107.2266, 34.8926],
-            [107.666, 34.9365],
-            [107.8418, 35.0244],
-            [107.7539, 35.1123],
-            [107.7539, 35.2881],
-            [108.5449, 35.2881],
-            [108.6328, 35.5518],
-            [108.5449, 35.8594],
-            [108.6328, 35.9912],
-            [108.7207, 36.3428],
-            [107.3145, 36.9141],
-            [107.3145, 37.0898],
-            [107.3145, 37.6172],
-            [107.666, 37.8809],
-            [108.1934, 37.6172],
-            [108.7207, 37.7051],
-            [108.8086, 38.0127],
-            [108.8965, 37.9688],
-            [109.0723, 38.0127],
-            [108.9844, 38.3203],
-            [109.9512, 39.1553],
-            [109.8633, 39.2432],
-            [110.2148, 39.2871],
-            [110.127, 39.4629],
-            [110.6543, 39.2871],
-            [111.0938, 39.5947],
-            [111.0938, 39.375],
-            [111.1816, 39.2432],
-            [110.918, 38.7158],
-            [110.8301, 38.4961],
-            [110.4785, 38.1885],
-            [110.4785, 37.9688],
-            [110.8301, 37.6611],
-            [110.3906, 37.002],
-            [110.4785, 36.123],
-            [110.5664, 35.6396],
-            [110.2148, 34.8926],
-            [110.2148, 34.6729],
-            [110.3906, 34.585],
-            [110.4785, 34.2334],
-            [110.6543, 34.1455],
-            [110.6543, 33.8379],
-            [111.0059, 33.5303],
-            [111.0059, 33.2666],
-            [110.7422, 33.1348],
-            [110.5664, 33.2666],
-            [110.3027, 33.1787],
-            [109.5996, 33.2666],
-            [109.4238, 33.1348],
-            [109.7754, 33.0469],
-            [109.7754, 32.915],
-            [110.127, 32.7393],
-            [110.127, 32.6074],
-            [109.6875, 32.6074],
-            [109.5117, 32.4316],
-            [109.5996, 31.7285],
-            [109.248, 31.7285],
-            [109.0723, 31.9482],
-            [108.5449, 32.2119],
-            [108.2813, 32.2559],
-            [108.0176, 32.168],
-            [107.4023, 32.5195],
-            [107.2266, 32.4316],
-            [107.1387, 32.4756],
-            [107.0508, 32.6953],
-            [106.3477, 32.6514],
-            [106.084, 32.7393],
-            [106.084, 32.8711],
-            [105.5566, 32.7393],
-            [105.4688, 32.915],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'guang_dong',
-      properties: { name: '广东', cp: [113.4668, 22.8076], childNum: 21 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [109.7754, 21.4014],
-            [109.7754, 21.6211],
-            [109.8633, 21.665],
-            [109.9512, 21.8408],
-            [110.3027, 21.8848],
-            [110.3027, 22.1484],
-            [110.6543, 22.1484],
-            [110.7422, 22.2803],
-            [110.7422, 22.5439],
-            [111.2695, 22.8076],
-            [111.4453, 23.0273],
-            [111.3574, 23.4668],
-            [111.6211, 23.6865],
-            [111.6211, 23.8184],
-            [111.7969, 23.8184],
-            [111.8848, 23.9941],
-            [111.8848, 24.2139],
-            [112.0605, 24.3457],
-            [111.8848, 24.6533],
-            [112.0605, 24.7412],
-            [112.1484, 24.873],
-            [112.2363, 25.1807],
-            [112.5879, 25.1367],
-            [112.8516, 24.917],
-            [113.0273, 24.9609],
-            [113.0273, 25.2246],
-            [112.8516, 25.3564],
-            [113.2031, 25.5322],
-            [113.6426, 25.3125],
-            [113.9063, 25.4443],
-            [113.9941, 25.2686],
-            [114.6094, 25.4004],
-            [114.7852, 25.2686],
-            [114.6973, 25.1367],
-            [114.4336, 24.9609],
-            [114.1699, 24.6973],
-            [114.4336, 24.5215],
-            [115.4004, 24.7852],
-            [115.8398, 24.5654],
-            [115.752, 24.7852],
-            [115.9277, 24.917],
-            [116.2793, 24.7852],
-            [116.3672, 24.873],
-            [116.543, 24.6094],
-            [116.7188, 24.6533],
-            [116.9824, 24.1699],
-            [116.9824, 23.9063],
-            [117.1582, 23.5547],
-            [117.334, 23.2471],
-            [116.8945, 23.3789],
-            [116.6309, 23.1152],
-            [116.543, 22.8516],
-            [115.9277, 22.7197],
-            [115.6641, 22.7637],
-            [115.5762, 22.6318],
-            [115.0488, 22.6758],
-            [114.6094, 22.3682],
-            [114.3457, 22.5439],
-            [113.9941, 22.5],
-            [113.8184, 22.1924],
-            [114.3457, 22.1484],
-            [114.4336, 22.0166],
-            [114.082, 21.9287],
-            [113.9941, 21.7969],
-            [113.5547, 22.0166],
-            [113.1152, 21.8408],
-            [112.9395, 21.5771],
-            [112.4121, 21.4453],
-            [112.2363, 21.5332],
-            [111.5332, 21.4893],
-            [111.2695, 21.3574],
-            [110.7422, 21.3574],
-            [110.6543, 21.2256],
-            [110.7422, 20.918],
-            [110.4785, 20.874],
-            [110.6543, 20.2588],
-            [110.5664, 20.2588],
-            [110.3906, 20.127],
-            [110.0391, 20.127],
-            [109.8633, 20.127],
-            [109.8633, 20.3027],
-            [109.5996, 20.918],
-            [109.7754, 21.4014],
-            [109.7754, 21.4014],
-          ],
-          [
-            [113.5986, 22.1649],
-            [113.6096, 22.1265],
-            [113.5547, 22.11],
-            [113.5437, 22.2034],
-            [113.5767, 22.2034],
-            [113.5986, 22.1649],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'ji_lin',
-      properties: { name: '吉林', cp: [126.4746, 43.5938], childNum: 9 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [123.2227, 46.2305],
-            [123.9258, 46.2305],
-            [124.0137, 45.7471],
-            [124.3652, 45.4395],
-            [124.8926, 45.5273],
-            [125.0684, 45.3955],
-            [125.6836, 45.5273],
-            [125.7715, 45.3076],
-            [126.0352, 45.1758],
-            [126.5625, 45.2637],
-            [126.9141, 45.1318],
-            [127.0898, 45],
-            [127.002, 44.7803],
-            [127.0898, 44.6045],
-            [127.5293, 44.6045],
-            [127.7051, 44.1211],
-            [128.0566, 44.1211],
-            [128.0566, 44.3408],
-            [128.4082, 44.4727],
-            [128.4961, 44.165],
-            [128.8477, 43.5498],
-            [129.1992, 43.5938],
-            [129.2871, 43.8135],
-            [129.8145, 43.9014],
-            [129.9023, 44.0332],
-            [129.9902, 43.8574],
-            [130.3418, 43.9893],
-            [130.5176, 43.6377],
-            [130.8691, 43.418],
-            [131.3086, 43.4619],
-            [131.3086, 43.3301],
-            [131.1328, 42.9346],
-            [130.4297, 42.7148],
-            [130.6055, 42.6709],
-            [130.6055, 42.4512],
-            [130.2539, 42.7588],
-            [130.2539, 42.8906],
-            [130.166, 42.9785],
-            [129.9023, 43.0225],
-            [129.7266, 42.4951],
-            [129.375, 42.4512],
-            [128.9355, 42.0117],
-            [128.0566, 42.0117],
-            [128.3203, 41.5723],
-            [128.1445, 41.3525],
-            [127.0898, 41.5283],
-            [127.1777, 41.5723],
-            [126.9141, 41.792],
-            [126.6504, 41.6602],
-            [126.4746, 41.3965],
-            [126.123, 40.957],
-            [125.6836, 40.8691],
-            [125.5957, 40.9131],
-            [125.7715, 41.2207],
-            [125.332, 41.6602],
-            [125.332, 41.9678],
-            [125.4199, 42.0996],
-            [125.332, 42.1436],
-            [124.8926, 42.8027],
-            [124.8926, 43.0664],
-            [124.7168, 43.0664],
-            [124.4531, 42.8467],
-            [124.2773, 43.2422],
-            [123.8379, 43.4619],
-            [123.6621, 43.374],
-            [123.3105, 43.5059],
-            [123.4863, 43.7256],
-            [123.1348, 44.4727],
-            [122.3438, 44.2529],
-            [122.0801, 44.8682],
-            [122.2559, 45.2637],
-            [121.9043, 45.7031],
-            [121.7285, 45.7471],
-            [121.8164, 46.0107],
-            [122.2559, 45.791],
-            [122.4316, 45.8789],
-            [122.6953, 45.7031],
-            [122.7832, 46.0107],
-            [123.2227, 46.2305],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'he_bei',
-      properties: { name: '河北', cp: [115.4004, 37.9688], childNum: 11 },
-      geometry: {
-        type: 'MultiPolygon',
-        coordinates: [
-          [
-            [
-              [114.5215, 39.5068],
-              [114.3457, 39.8584],
-              [113.9941, 39.9902],
-              [114.5215, 40.3418],
-              [114.3457, 40.3857],
-              [114.2578, 40.6055],
-              [114.082, 40.7373],
-              [113.9063, 41.1328],
-              [113.9941, 41.2207],
-              [113.9063, 41.4404],
-              [114.2578, 41.5723],
-              [114.1699, 41.792],
-              [114.5215, 42.1436],
-              [114.873, 42.0996],
-              [114.9609, 41.6162],
-              [115.2246, 41.5723],
-              [115.9277, 41.9238],
-              [116.0156, 41.792],
-              [116.2793, 42.0117],
-              [116.8066, 42.0117],
-              [116.8945, 42.4072],
-              [117.334, 42.4512],
-              [117.5098, 42.583],
-              [117.7734, 42.627],
-              [118.0371, 42.4072],
-              [117.9492, 42.2314],
-              [118.125, 42.0557],
-              [118.3008, 42.0996],
-              [118.3008, 41.792],
-              [118.125, 41.748],
-              [118.3887, 41.3086],
-              [119.2676, 41.3086],
-              [118.8281, 40.8252],
-              [119.2676, 40.5176],
-              [119.5313, 40.5615],
-              [119.707, 40.1221],
-              [119.8828, 39.9463],
-              [119.5313, 39.6826],
-              [119.4434, 39.4189],
-              [118.916, 39.0674],
-              [118.4766, 38.9355],
-              [118.125, 39.0234],
-              [118.0371, 39.1992],
-              [118.0371, 39.2432],
-              [117.8613, 39.4189],
-              [117.9492, 39.5947],
-              [117.6855, 39.5947],
-              [117.5098, 39.7705],
-              [117.5098, 39.9902],
-              [117.6855, 39.9902],
-              [117.6855, 40.0781],
-              [117.4219, 40.21],
-              [117.2461, 40.5176],
-              [117.4219, 40.6494],
-              [116.9824, 40.6934],
-              [116.6309, 41.0449],
-              [116.3672, 40.9131],
-              [116.4551, 40.7813],
-              [116.1914, 40.7813],
-              [116.1035, 40.6055],
-              [115.752, 40.5615],
-              [115.9277, 40.2539],
-              [115.4004, 39.9463],
-              [115.4883, 39.6387],
-              [115.752, 39.5068],
-              [116.1914, 39.5947],
-              [116.3672, 39.4629],
-              [116.543, 39.5947],
-              [116.8066, 39.5947],
-              [116.8945, 39.1113],
-              [116.7188, 38.9355],
-              [116.7188, 38.8037],
-              [117.2461, 38.54],
-              [117.5977, 38.6279],
-              [117.9492, 38.3203],
-              [117.4219, 37.8369],
-              [116.8066, 37.8369],
-              [116.4551, 37.4854],
-              [116.2793, 37.5732],
-              [116.2793, 37.3535],
-              [116.0156, 37.3535],
-              [115.752, 36.9141],
-              [115.3125, 36.5186],
-              [115.4883, 36.167],
-              [115.3125, 36.0791],
-              [115.1367, 36.2109],
-              [114.9609, 36.0791],
-              [114.873, 36.123],
-              [113.7305, 36.3428],
-              [113.4668, 36.6504],
-              [113.7305, 36.8701],
-              [113.7305, 37.1338],
-              [114.1699, 37.6611],
-              [113.9941, 37.7051],
-              [113.8184, 38.1445],
-              [113.5547, 38.2764],
-              [113.5547, 38.54],
-              [113.8184, 38.8037],
-              [113.8184, 38.9355],
-              [113.9063, 39.0234],
-              [114.3457, 39.0674],
-              [114.5215, 39.5068],
-            ],
-          ],
-          [
-            [
-              [117.2461, 40.0781],
-              [117.1582, 39.8145],
-              [117.1582, 39.6387],
-              [116.8945, 39.6826],
-              [116.8945, 39.8145],
-              [116.8066, 39.9902],
-              [117.2461, 40.0781],
-            ],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'hu_bei',
-      properties: { name: '湖北', cp: [112.2363, 31.1572], childNum: 17 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [110.2148, 31.1572],
-            [110.127, 31.377],
-            [109.6875, 31.5527],
-            [109.7754, 31.6846],
-            [109.5996, 31.7285],
-            [109.5117, 32.4316],
-            [109.6875, 32.6074],
-            [110.127, 32.6074],
-            [110.127, 32.7393],
-            [109.7754, 32.915],
-            [109.7754, 33.0469],
-            [109.4238, 33.1348],
-            [109.5996, 33.2666],
-            [110.3027, 33.1787],
-            [110.5664, 33.2666],
-            [110.7422, 33.1348],
-            [111.0059, 33.2666],
-            [111.5332, 32.6074],
-            [112.3242, 32.3438],
-            [113.2031, 32.4316],
-            [113.4668, 32.2998],
-            [113.7305, 32.4316],
-            [113.8184, 31.8604],
-            [113.9941, 31.7725],
-            [114.1699, 31.8604],
-            [114.5215, 31.7725],
-            [114.6094, 31.5527],
-            [114.7852, 31.4648],
-            [115.1367, 31.5967],
-            [115.2246, 31.4209],
-            [115.4004, 31.4209],
-            [115.5762, 31.2012],
-            [116.0156, 31.0254],
-            [115.752, 30.6738],
-            [116.1035, 30.1904],
-            [116.1035, 29.8389],
-            [115.9277, 29.707],
-            [115.4883, 29.7949],
-            [114.873, 29.3994],
-            [114.2578, 29.3555],
-            [113.9063, 29.0479],
-            [113.7305, 29.0918],
-            [113.6426, 29.3115],
-            [113.7305, 29.5752],
-            [113.5547, 29.707],
-            [113.5547, 29.8389],
-            [113.0273, 29.4434],
-            [112.9395, 29.4873],
-            [113.0273, 29.751],
-            [112.9395, 29.7949],
-            [112.6758, 29.5752],
-            [112.5, 29.6191],
-            [112.2363, 29.5313],
-            [111.7969, 29.9268],
-            [110.8301, 30.1465],
-            [110.4785, 30.0146],
-            [110.6543, 29.751],
-            [110.4785, 29.6631],
-            [109.7754, 29.751],
-            [109.6875, 29.6191],
-            [109.5117, 29.6191],
-            [109.248, 29.1357],
-            [109.0723, 29.3555],
-            [108.9844, 29.3115],
-            [108.6328, 29.8389],
-            [108.457, 29.7949],
-            [108.5449, 30.2344],
-            [108.457, 30.4102],
-            [108.6328, 30.5859],
-            [108.8086, 30.498],
-            [109.0723, 30.6299],
-            [109.1602, 30.542],
-            [109.248, 30.6299],
-            [109.4238, 30.542],
-            [109.8633, 30.8936],
-            [110.0391, 30.8057],
-            [110.2148, 31.1572],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'gui_zhou',
-      properties: { name: '贵州', cp: [106.6113, 26.9385], childNum: 9 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [104.1504, 27.2461],
-            [104.4141, 27.4658],
-            [104.5898, 27.334],
-            [105.2051, 27.3779],
-            [105.293, 27.7295],
-            [105.5566, 27.7734],
-            [105.6445, 27.6416],
-            [106.3477, 27.8174],
-            [106.1719, 28.125],
-            [105.9082, 28.125],
-            [105.6445, 28.4326],
-            [105.9961, 28.7402],
-            [106.3477, 28.5205],
-            [106.5234, 28.5645],
-            [106.4355, 28.7842],
-            [106.5234, 28.7842],
-            [106.6113, 28.6523],
-            [106.6113, 28.5205],
-            [106.6992, 28.4766],
-            [106.875, 28.7842],
-            [107.4023, 28.8721],
-            [107.4023, 29.1797],
-            [107.5781, 29.2236],
-            [107.8418, 29.1357],
-            [107.8418, 29.0039],
-            [108.2813, 29.0918],
-            [108.3691, 28.6523],
-            [108.5449, 28.6523],
-            [108.5449, 28.3887],
-            [108.7207, 28.4766],
-            [108.7207, 28.2129],
-            [109.0723, 28.2129],
-            [109.248, 28.4766],
-            [109.3359, 28.2568],
-            [109.3359, 27.9053],
-            [109.4238, 27.5977],
-            [108.8086, 27.1143],
-            [108.8965, 27.0264],
-            [109.3359, 27.1582],
-            [109.5117, 27.0264],
-            [109.5117, 26.8066],
-            [109.3359, 26.7188],
-            [109.4238, 26.5869],
-            [109.248, 26.3232],
-            [109.4238, 26.2793],
-            [109.5117, 26.0156],
-            [109.3359, 25.708],
-            [108.9844, 25.752],
-            [109.0723, 25.5322],
-            [108.6328, 25.5762],
-            [108.6328, 25.3125],
-            [108.3691, 25.5322],
-            [108.1934, 25.4443],
-            [108.1055, 25.2246],
-            [107.8418, 25.1367],
-            [107.7539, 25.2246],
-            [107.4902, 25.2246],
-            [107.2266, 25.6201],
-            [106.9629, 25.4883],
-            [107.0508, 25.2686],
-            [106.875, 25.1807],
-            [106.1719, 24.9609],
-            [106.1719, 24.7852],
-            [105.9961, 24.6533],
-            [105.2051, 24.9609],
-            [104.6777, 24.6094],
-            [104.502, 24.7412],
-            [104.6777, 24.9609],
-            [104.5898, 25.0488],
-            [104.8535, 25.2246],
-            [104.3262, 25.708],
-            [104.6777, 26.4111],
-            [104.4141, 26.6748],
-            [103.8867, 26.543],
-            [103.7109, 26.7627],
-            [103.7109, 26.9824],
-            [103.623, 27.0264],
-            [103.8867, 27.4219],
-            [104.1504, 27.2461],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'shan_dong',
-      properties: { name: '山东', cp: [118.7402, 36.4307], childNum: 17 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [115.4883, 36.167],
-            [115.3125, 36.5186],
-            [115.752, 36.9141],
-            [116.0156, 37.3535],
-            [116.2793, 37.3535],
-            [116.2793, 37.5732],
-            [116.4551, 37.4854],
-            [116.8066, 37.8369],
-            [117.4219, 37.8369],
-            [117.9492, 38.3203],
-            [118.125, 38.1445],
-            [118.916, 38.1445],
-            [119.3555, 37.6611],
-            [119.0039, 37.5293],
-            [119.0039, 37.3535],
-            [119.3555, 37.1338],
-            [119.707, 37.1338],
-            [119.8828, 37.3975],
-            [120.498, 37.8369],
-            [120.5859, 38.1445],
-            [120.9375, 38.4521],
-            [121.0254, 37.8369],
-            [121.2012, 37.6611],
-            [121.9043, 37.4854],
-            [122.168, 37.6172],
-            [122.2559, 37.4854],
-            [122.6074, 37.4854],
-            [122.6953, 37.3535],
-            [122.6074, 36.9141],
-            [122.4316, 36.7822],
-            [121.8164, 36.8701],
-            [121.7285, 36.6943],
-            [121.1133, 36.6064],
-            [121.1133, 36.4307],
-            [121.377, 36.2549],
-            [120.7617, 36.167],
-            [120.9375, 35.8594],
-            [120.6738, 36.0352],
-            [119.707, 35.4639],
-            [119.9707, 34.9805],
-            [119.3555, 35.0244],
-            [119.2676, 35.1123],
-            [118.916, 35.0244],
-            [118.7402, 34.7168],
-            [118.4766, 34.6729],
-            [118.3887, 34.4092],
-            [118.2129, 34.4092],
-            [118.125, 34.6289],
-            [117.9492, 34.6729],
-            [117.5977, 34.4531],
-            [117.334, 34.585],
-            [117.2461, 34.4531],
-            [116.8066, 34.9365],
-            [116.4551, 34.8926],
-            [116.3672, 34.6289],
-            [116.1914, 34.585],
-            [115.5762, 34.585],
-            [115.4004, 34.8486],
-            [114.7852, 35.0684],
-            [115.0488, 35.376],
-            [115.2246, 35.4199],
-            [115.4883, 35.7275],
-            [116.1035, 36.0791],
-            [115.3125, 35.8154],
-            [115.4883, 36.167],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'jiang_xi',
-      properties: { name: '江西', cp: [116.0156, 27.29], childNum: 11 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [114.2578, 28.3447],
-            [114.082, 28.5645],
-            [114.1699, 28.8281],
-            [113.9063, 29.0479],
-            [114.2578, 29.3555],
-            [114.873, 29.3994],
-            [115.4883, 29.7949],
-            [115.9277, 29.707],
-            [116.1035, 29.8389],
-            [116.2793, 29.7949],
-            [116.7188, 30.0586],
-            [116.8945, 29.9268],
-            [116.7188, 29.751],
-            [116.7188, 29.6191],
-            [117.1582, 29.707],
-            [117.0703, 29.8389],
-            [117.1582, 29.9268],
-            [117.5098, 29.6191],
-            [118.0371, 29.5752],
-            [118.2129, 29.3994],
-            [118.0371, 29.1797],
-            [118.0371, 29.0479],
-            [118.3887, 28.7842],
-            [118.4766, 28.3447],
-            [118.4766, 28.3008],
-            [118.3008, 28.0811],
-            [117.7734, 27.8174],
-            [117.5098, 27.9932],
-            [116.9824, 27.6416],
-            [117.1582, 27.29],
-            [117.0703, 27.1143],
-            [116.543, 26.8066],
-            [116.6309, 26.4551],
-            [116.3672, 26.2354],
-            [116.4551, 26.1035],
-            [116.1914, 25.8838],
-            [116.0156, 25.2686],
-            [115.8398, 25.2246],
-            [115.9277, 24.917],
-            [115.752, 24.7852],
-            [115.8398, 24.5654],
-            [115.4004, 24.7852],
-            [114.4336, 24.5215],
-            [114.1699, 24.6973],
-            [114.4336, 24.9609],
-            [114.6973, 25.1367],
-            [114.7852, 25.2686],
-            [114.6094, 25.4004],
-            [113.9941, 25.2686],
-            [113.9063, 25.4443],
-            [113.9941, 26.0596],
-            [114.2578, 26.1475],
-            [113.9941, 26.1914],
-            [114.082, 26.5869],
-            [113.9063, 26.6309],
-            [113.9063, 26.9385],
-            [113.7305, 27.1143],
-            [113.8184, 27.29],
-            [113.6426, 27.3779],
-            [113.6426, 27.5977],
-            [113.7305, 27.9492],
-            [114.2578, 28.3447],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'he_nan',
-      properties: { name: '河南', cp: [113.4668, 33.8818], childNum: 17 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [110.3906, 34.585],
-            [110.8301, 34.6289],
-            [111.1816, 34.8047],
-            [111.5332, 34.8486],
-            [111.7969, 35.0684],
-            [112.0605, 35.0684],
-            [112.0605, 35.2881],
-            [112.7637, 35.2002],
-            [113.1152, 35.332],
-            [113.6426, 35.6836],
-            [113.7305, 36.3428],
-            [114.873, 36.123],
-            [114.9609, 36.0791],
-            [115.1367, 36.2109],
-            [115.3125, 36.0791],
-            [115.4883, 36.167],
-            [115.3125, 35.8154],
-            [116.1035, 36.0791],
-            [115.4883, 35.7275],
-            [115.2246, 35.4199],
-            [115.0488, 35.376],
-            [114.7852, 35.0684],
-            [115.4004, 34.8486],
-            [115.5762, 34.585],
-            [116.1914, 34.585],
-            [116.1914, 34.4092],
-            [116.543, 34.2773],
-            [116.6309, 33.9258],
-            [116.1914, 33.7061],
-            [116.0156, 33.9697],
-            [115.6641, 34.0576],
-            [115.5762, 33.9258],
-            [115.5762, 33.6621],
-            [115.4004, 33.5303],
-            [115.3125, 33.1787],
-            [114.873, 33.1348],
-            [114.873, 33.0029],
-            [115.1367, 32.8711],
-            [115.2246, 32.6074],
-            [115.5762, 32.4316],
-            [115.8398, 32.5195],
-            [115.9277, 31.7725],
-            [115.4883, 31.6846],
-            [115.4004, 31.4209],
-            [115.2246, 31.4209],
-            [115.1367, 31.5967],
-            [114.7852, 31.4648],
-            [114.6094, 31.5527],
-            [114.5215, 31.7725],
-            [114.1699, 31.8604],
-            [113.9941, 31.7725],
-            [113.8184, 31.8604],
-            [113.7305, 32.4316],
-            [113.4668, 32.2998],
-            [113.2031, 32.4316],
-            [112.3242, 32.3438],
-            [111.5332, 32.6074],
-            [111.0059, 33.2666],
-            [111.0059, 33.5303],
-            [110.6543, 33.8379],
-            [110.6543, 34.1455],
-            [110.4785, 34.2334],
-            [110.3906, 34.585],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'liao_ning',
-      properties: { name: '辽宁', cp: [122.3438, 41.0889], childNum: 14 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [119.2676, 41.3086],
-            [119.4434, 41.6162],
-            [119.2676, 41.7041],
-            [119.3555, 42.2754],
-            [119.5313, 42.3633],
-            [119.8828, 42.1875],
-            [120.1465, 41.7041],
-            [120.498, 42.0996],
-            [121.4648, 42.4951],
-            [121.7285, 42.4512],
-            [121.9922, 42.7148],
-            [122.3438, 42.6709],
-            [122.3438, 42.8467],
-            [122.7832, 42.7148],
-            [123.1348, 42.8027],
-            [123.3105, 42.9785],
-            [123.5742, 43.0225],
-            [123.6621, 43.374],
-            [123.8379, 43.4619],
-            [124.2773, 43.2422],
-            [124.4531, 42.8467],
-            [124.7168, 43.0664],
-            [124.8926, 43.0664],
-            [124.8926, 42.8027],
-            [125.332, 42.1436],
-            [125.4199, 42.0996],
-            [125.332, 41.9678],
-            [125.332, 41.6602],
-            [125.7715, 41.2207],
-            [125.5957, 40.9131],
-            [125.6836, 40.8691],
-            [124.541, 40.21],
-            [124.1016, 39.6826],
-            [123.3984, 39.6826],
-            [123.1348, 39.4189],
-            [123.1348, 39.0234],
-            [122.0801, 39.0234],
-            [121.5527, 38.7158],
-            [121.1133, 38.6719],
-            [120.9375, 38.9795],
-            [121.377, 39.1992],
-            [121.2012, 39.5508],
-            [122.0801, 40.3857],
-            [121.9922, 40.6934],
-            [121.7285, 40.8252],
-            [121.2012, 40.8252],
-            [120.5859, 40.21],
-            [119.8828, 39.9463],
-            [119.707, 40.1221],
-            [119.5313, 40.5615],
-            [119.2676, 40.5176],
-            [118.8281, 40.8252],
-            [119.2676, 41.3086],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'shan_xi_2',
-      properties: { name: '山西', cp: [112.4121, 37.6611], childNum: 11 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [110.918, 38.7158],
-            [111.1816, 39.2432],
-            [111.0938, 39.375],
-            [111.3574, 39.4189],
-            [111.4453, 39.6387],
-            [111.9727, 39.5947],
-            [112.3242, 40.2539],
-            [112.7637, 40.166],
-            [113.2031, 40.3857],
-            [113.5547, 40.3418],
-            [113.8184, 40.5176],
-            [114.082, 40.5176],
-            [114.082, 40.7373],
-            [114.2578, 40.6055],
-            [114.3457, 40.3857],
-            [114.5215, 40.3418],
-            [113.9941, 39.9902],
-            [114.3457, 39.8584],
-            [114.5215, 39.5068],
-            [114.3457, 39.0674],
-            [113.9063, 39.0234],
-            [113.8184, 38.9355],
-            [113.8184, 38.8037],
-            [113.5547, 38.54],
-            [113.5547, 38.2764],
-            [113.8184, 38.1445],
-            [113.9941, 37.7051],
-            [114.1699, 37.6611],
-            [113.7305, 37.1338],
-            [113.7305, 36.8701],
-            [113.4668, 36.6504],
-            [113.7305, 36.3428],
-            [113.6426, 35.6836],
-            [113.1152, 35.332],
-            [112.7637, 35.2002],
-            [112.0605, 35.2881],
-            [112.0605, 35.0684],
-            [111.7969, 35.0684],
-            [111.5332, 34.8486],
-            [111.1816, 34.8047],
-            [110.8301, 34.6289],
-            [110.3906, 34.585],
-            [110.2148, 34.6729],
-            [110.2148, 34.8926],
-            [110.5664, 35.6396],
-            [110.4785, 36.123],
-            [110.3906, 37.002],
-            [110.8301, 37.6611],
-            [110.4785, 37.9688],
-            [110.4785, 38.1885],
-            [110.8301, 38.4961],
-            [110.918, 38.7158],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'an_hui',
-      properties: { name: '安徽', cp: [117.2461, 32.0361], childNum: 17 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [116.6309, 33.9258],
-            [116.543, 34.2773],
-            [116.1914, 34.4092],
-            [116.1914, 34.585],
-            [116.3672, 34.6289],
-            [116.8945, 34.4092],
-            [117.1582, 34.0576],
-            [117.5977, 34.0137],
-            [117.7734, 33.7061],
-            [118.125, 33.75],
-            [117.9492, 33.2227],
-            [118.0371, 33.1348],
-            [118.2129, 33.2227],
-            [118.3008, 32.7832],
-            [118.7402, 32.7393],
-            [118.916, 32.959],
-            [119.1797, 32.8271],
-            [119.1797, 32.4756],
-            [118.5645, 32.5635],
-            [118.6523, 32.2119],
-            [118.4766, 32.168],
-            [118.3887, 31.9482],
-            [118.916, 31.5527],
-            [118.7402, 31.377],
-            [118.8281, 31.2451],
-            [119.3555, 31.2891],
-            [119.4434, 31.1572],
-            [119.6191, 31.1133],
-            [119.6191, 31.0693],
-            [119.4434, 30.6738],
-            [119.2676, 30.6299],
-            [119.3555, 30.4102],
-            [118.916, 30.3223],
-            [118.916, 29.9707],
-            [118.7402, 29.707],
-            [118.2129, 29.3994],
-            [118.0371, 29.5752],
-            [117.5098, 29.6191],
-            [117.1582, 29.9268],
-            [117.0703, 29.8389],
-            [117.1582, 29.707],
-            [116.7188, 29.6191],
-            [116.7188, 29.751],
-            [116.8945, 29.9268],
-            [116.7188, 30.0586],
-            [116.2793, 29.7949],
-            [116.1035, 29.8389],
-            [116.1035, 30.1904],
-            [115.752, 30.6738],
-            [116.0156, 31.0254],
-            [115.5762, 31.2012],
-            [115.4004, 31.4209],
-            [115.4883, 31.6846],
-            [115.9277, 31.7725],
-            [115.8398, 32.5195],
-            [115.5762, 32.4316],
-            [115.2246, 32.6074],
-            [115.1367, 32.8711],
-            [114.873, 33.0029],
-            [114.873, 33.1348],
-            [115.3125, 33.1787],
-            [115.4004, 33.5303],
-            [115.5762, 33.6621],
-            [115.5762, 33.9258],
-            [115.6641, 34.0576],
-            [116.0156, 33.9697],
-            [116.1914, 33.7061],
-            [116.6309, 33.9258],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'fu_jian',
-      properties: { name: '福建', cp: [118.3008, 25.9277], childNum: 9 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [118.4766, 28.3008],
-            [118.8281, 28.2568],
-            [118.7402, 28.0371],
-            [118.916, 27.4658],
-            [119.2676, 27.4219],
-            [119.6191, 27.6855],
-            [119.7949, 27.29],
-            [120.2344, 27.4219],
-            [120.4102, 27.1582],
-            [120.7617, 27.0264],
-            [120.6738, 26.8945],
-            [120.2344, 26.8506],
-            [120.2344, 26.7188],
-            [120.4102, 26.6748],
-            [120.498, 26.3672],
-            [120.2344, 26.2793],
-            [120.4102, 26.1475],
-            [120.0586, 26.1914],
-            [119.9707, 25.9277],
-            [119.7949, 25.9277],
-            [119.9707, 25.4004],
-            [119.7949, 25.2686],
-            [119.5313, 25.1367],
-            [119.4434, 25.0049],
-            [119.2676, 25.0928],
-            [118.916, 24.8291],
-            [118.6523, 24.5215],
-            [118.4766, 24.5215],
-            [118.4766, 24.4336],
-            [118.2129, 24.3457],
-            [118.2129, 24.1699],
-            [117.8613, 23.9941],
-            [117.7734, 23.7744],
-            [117.5098, 23.5986],
-            [117.1582, 23.5547],
-            [116.9824, 23.9063],
-            [116.9824, 24.1699],
-            [116.7188, 24.6533],
-            [116.543, 24.6094],
-            [116.3672, 24.873],
-            [116.2793, 24.7852],
-            [115.9277, 24.917],
-            [115.8398, 25.2246],
-            [116.0156, 25.2686],
-            [116.1914, 25.8838],
-            [116.4551, 26.1035],
-            [116.3672, 26.2354],
-            [116.6309, 26.4551],
-            [116.543, 26.8066],
-            [117.0703, 27.1143],
-            [117.1582, 27.29],
-            [116.9824, 27.6416],
-            [117.5098, 27.9932],
-            [117.7734, 27.8174],
-            [118.3008, 28.0811],
-            [118.4766, 28.3008],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'zhe_jiang',
-      properties: { name: '浙江', cp: [120.498, 29.0918], childNum: 11 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [118.2129, 29.3994],
-            [118.7402, 29.707],
-            [118.916, 29.9707],
-            [118.916, 30.3223],
-            [119.3555, 30.4102],
-            [119.2676, 30.6299],
-            [119.4434, 30.6738],
-            [119.6191, 31.0693],
-            [119.6191, 31.1133],
-            [119.9707, 31.1572],
-            [120.498, 30.8057],
-            [120.9375, 31.0254],
-            [121.2891, 30.6738],
-            [121.9922, 30.8057],
-            [122.6953, 30.8936],
-            [122.8711, 30.7178],
-            [122.959, 30.1465],
-            [122.6074, 30.1025],
-            [122.6074, 29.9268],
-            [122.168, 29.5313],
-            [122.3438, 28.8721],
-            [121.9922, 28.8721],
-            [121.9922, 28.4326],
-            [121.7285, 28.3447],
-            [121.7285, 28.2129],
-            [121.4648, 28.2129],
-            [121.5527, 28.0371],
-            [121.2891, 27.9492],
-            [121.1133, 27.4219],
-            [120.6738, 27.334],
-            [120.6738, 27.1582],
-            [120.9375, 27.0264],
-            [120.7617, 27.0264],
-            [120.4102, 27.1582],
-            [120.2344, 27.4219],
-            [119.7949, 27.29],
-            [119.6191, 27.6855],
-            [119.2676, 27.4219],
-            [118.916, 27.4658],
-            [118.7402, 28.0371],
-            [118.8281, 28.2568],
-            [118.4766, 28.3008],
-            [118.4766, 28.3447],
-            [118.3887, 28.7842],
-            [118.0371, 29.0479],
-            [118.0371, 29.1797],
-            [118.2129, 29.3994],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'jiang_su',
-      properties: { name: '江苏', cp: [120.0586, 32.915], childNum: 13 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [116.3672, 34.6289],
-            [116.4551, 34.8926],
-            [116.8066, 34.9365],
-            [117.2461, 34.4531],
-            [117.334, 34.585],
-            [117.5977, 34.4531],
-            [117.9492, 34.6729],
-            [118.125, 34.6289],
-            [118.2129, 34.4092],
-            [118.3887, 34.4092],
-            [118.4766, 34.6729],
-            [118.7402, 34.7168],
-            [118.916, 35.0244],
-            [119.2676, 35.1123],
-            [119.3555, 35.0244],
-            [119.3555, 34.8486],
-            [119.707, 34.585],
-            [120.3223, 34.3652],
-            [120.9375, 33.0469],
-            [121.0254, 32.6514],
-            [121.377, 32.4756],
-            [121.4648, 32.168],
-            [121.9043, 31.9922],
-            [121.9922, 31.6846],
-            [121.9922, 31.5967],
-            [121.2012, 31.8604],
-            [121.1133, 31.7285],
-            [121.377, 31.5088],
-            [121.2012, 31.4648],
-            [120.9375, 31.0254],
-            [120.498, 30.8057],
-            [119.9707, 31.1572],
-            [119.6191, 31.1133],
-            [119.4434, 31.1572],
-            [119.3555, 31.2891],
-            [118.8281, 31.2451],
-            [118.7402, 31.377],
-            [118.916, 31.5527],
-            [118.3887, 31.9482],
-            [118.4766, 32.168],
-            [118.6523, 32.2119],
-            [118.5645, 32.5635],
-            [119.1797, 32.4756],
-            [119.1797, 32.8271],
-            [118.916, 32.959],
-            [118.7402, 32.7393],
-            [118.3008, 32.7832],
-            [118.2129, 33.2227],
-            [118.0371, 33.1348],
-            [117.9492, 33.2227],
-            [118.125, 33.75],
-            [117.7734, 33.7061],
-            [117.5977, 34.0137],
-            [117.1582, 34.0576],
-            [116.8945, 34.4092],
-            [116.3672, 34.6289],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'chong_qing',
-      properties: { name: '重庆', cp: [107.7539, 30.1904], childNum: 40 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [108.5449, 31.6846],
-            [108.2813, 31.9043],
-            [108.3691, 32.168],
-            [108.5449, 32.2119],
-            [109.0723, 31.9482],
-            [109.248, 31.7285],
-            [109.5996, 31.7285],
-            [109.7754, 31.6846],
-            [109.6875, 31.5527],
-            [110.127, 31.377],
-            [110.2148, 31.1572],
-            [110.0391, 30.8057],
-            [109.8633, 30.8936],
-            [109.4238, 30.542],
-            [109.248, 30.6299],
-            [109.1602, 30.542],
-            [109.0723, 30.6299],
-            [108.8086, 30.498],
-            [108.6328, 30.5859],
-            [108.457, 30.4102],
-            [108.5449, 30.2344],
-            [108.457, 29.7949],
-            [108.6328, 29.8389],
-            [108.9844, 29.3115],
-            [109.0723, 29.3555],
-            [109.248, 29.1357],
-            [109.248, 28.4766],
-            [109.0723, 28.2129],
-            [108.7207, 28.2129],
-            [108.7207, 28.4766],
-            [108.5449, 28.3887],
-            [108.5449, 28.6523],
-            [108.3691, 28.6523],
-            [108.2813, 29.0918],
-            [107.8418, 29.0039],
-            [107.8418, 29.1357],
-            [107.5781, 29.2236],
-            [107.4023, 29.1797],
-            [107.4023, 28.8721],
-            [106.875, 28.7842],
-            [106.6992, 28.4766],
-            [106.6113, 28.5205],
-            [106.6113, 28.6523],
-            [106.5234, 28.7842],
-            [106.4355, 28.7842],
-            [106.5234, 28.5645],
-            [106.3477, 28.5205],
-            [106.2598, 28.8721],
-            [105.8203, 28.96],
-            [105.7324, 29.2676],
-            [105.4688, 29.3115],
-            [105.293, 29.5313],
-            [105.7324, 29.8828],
-            [105.5566, 30.1025],
-            [105.6445, 30.2783],
-            [105.8203, 30.4541],
-            [106.2598, 30.1904],
-            [106.6113, 30.3223],
-            [106.7871, 30.0146],
-            [107.0508, 30.0146],
-            [107.4902, 30.6299],
-            [107.4023, 30.7617],
-            [107.4902, 30.8496],
-            [107.9297, 30.8496],
-            [108.1934, 31.5088],
-            [108.5449, 31.6846],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'ning_xia',
-      properties: { name: '宁夏', cp: [105.9961, 37.3096], childNum: 5 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [104.3262, 37.4414],
-            [105.8203, 37.793],
-            [105.9082, 38.7158],
-            [106.3477, 39.2871],
-            [106.7871, 39.375],
-            [106.9629, 38.9795],
-            [106.5234, 38.3203],
-            [106.7871, 38.1885],
-            [107.3145, 38.1006],
-            [107.666, 37.8809],
-            [107.3145, 37.6172],
-            [107.3145, 37.0898],
-            [106.6113, 37.0898],
-            [106.6113, 36.7822],
-            [106.4355, 36.5625],
-            [106.5234, 36.4746],
-            [106.5234, 36.2549],
-            [106.875, 36.123],
-            [106.9629, 35.8154],
-            [106.6992, 35.6836],
-            [106.4355, 35.6836],
-            [106.5234, 35.332],
-            [106.3477, 35.2441],
-            [106.2598, 35.4199],
-            [106.084, 35.376],
-            [105.9961, 35.4199],
-            [106.084, 35.4639],
-            [105.9961, 35.4639],
-            [105.8203, 35.5518],
-            [105.7324, 35.7275],
-            [105.3809, 35.7715],
-            [105.293, 35.9912],
-            [105.4688, 36.123],
-            [105.2051, 36.6943],
-            [105.293, 36.8262],
-            [104.8535, 37.2217],
-            [104.5898, 37.2217],
-            [104.5898, 37.4414],
-            [104.3262, 37.4414],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'hai_nan',
-      properties: { name: '海南', cp: [109.9512, 19.2041], childNum: 18 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [108.6328, 19.3799],
-            [109.0723, 19.6436],
-            [109.248, 19.9512],
-            [109.5996, 20.0391],
-            [110.0391, 20.127],
-            [110.3906, 20.127],
-            [110.5664, 20.2588],
-            [110.6543, 20.2588],
-            [111.0938, 19.9512],
-            [111.2695, 19.9951],
-            [110.6543, 19.1602],
-            [110.5664, 18.6768],
-            [110.2148, 18.5889],
-            [110.0391, 18.3691],
-            [109.8633, 18.3691],
-            [109.6875, 18.1055],
-            [108.9844, 18.2813],
-            [108.6328, 18.457],
-            [108.6328, 19.3799],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'tai_wan',
-      properties: { name: '台湾', cp: [121.0254, 23.5986], childNum: 1 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [121.9043, 25.0488],
-            [121.9922, 25.0049],
-            [121.8164, 24.7412],
-            [121.9043, 24.5654],
-            [121.6406, 24.0381],
-            [121.377, 23.1152],
-            [121.0254, 22.6758],
-            [120.8496, 22.0605],
-            [120.7617, 21.9287],
-            [120.6738, 22.3242],
-            [120.2344, 22.5879],
-            [120.0586, 23.0713],
-            [120.1465, 23.6865],
-            [121.0254, 25.0488],
-            [121.5527, 25.3125],
-            [121.9043, 25.0488],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'bei_jing',
-      properties: { name: '北京', cp: [116.4551, 40.2539], childNum: 19 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [117.4219, 40.21],
-            [117.334, 40.1221],
-            [117.2461, 40.0781],
-            [116.8066, 39.9902],
-            [116.8945, 39.8145],
-            [116.8945, 39.6826],
-            [116.8066, 39.5947],
-            [116.543, 39.5947],
-            [116.3672, 39.4629],
-            [116.1914, 39.5947],
-            [115.752, 39.5068],
-            [115.4883, 39.6387],
-            [115.4004, 39.9463],
-            [115.9277, 40.2539],
-            [115.752, 40.5615],
-            [116.1035, 40.6055],
-            [116.1914, 40.7813],
-            [116.4551, 40.7813],
-            [116.3672, 40.9131],
-            [116.6309, 41.0449],
-            [116.9824, 40.6934],
-            [117.4219, 40.6494],
-            [117.2461, 40.5176],
-            [117.4219, 40.21],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'tian_jin',
-      properties: { name: '天津', cp: [117.4219, 39.4189], childNum: 18 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [116.8066, 39.5947],
-            [116.8945, 39.6826],
-            [117.1582, 39.6387],
-            [117.1582, 39.8145],
-            [117.2461, 40.0781],
-            [117.334, 40.1221],
-            [117.4219, 40.21],
-            [117.6855, 40.0781],
-            [117.6855, 39.9902],
-            [117.5098, 39.9902],
-            [117.5098, 39.7705],
-            [117.6855, 39.5947],
-            [117.9492, 39.5947],
-            [117.8613, 39.4189],
-            [118.0371, 39.2432],
-            [118.0371, 39.1992],
-            [117.8613, 39.1113],
-            [117.5977, 38.6279],
-            [117.2461, 38.54],
-            [116.7188, 38.8037],
-            [116.7188, 38.9355],
-            [116.8945, 39.1113],
-            [116.8066, 39.5947],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'shang_hai',
-      properties: { name: '上海', cp: [121.4648, 31.2891], childNum: 19 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [120.9375, 31.0254],
-            [121.2012, 31.4648],
-            [121.377, 31.5088],
-            [121.1133, 31.7285],
-            [121.2012, 31.8604],
-            [121.9922, 31.5967],
-            [121.9043, 31.1572],
-            [121.9922, 30.8057],
-            [121.2891, 30.6738],
-            [120.9375, 31.0254],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'xiang_gang',
-      properties: { name: '香港', cp: [114.2578, 22.3242], childNum: 1 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [114.6094, 22.4121],
-            [114.5215, 22.1484],
-            [114.3457, 22.1484],
-            [113.9063, 22.1484],
-            [113.8184, 22.1924],
-            [113.9063, 22.4121],
-            [114.1699, 22.5439],
-            [114.3457, 22.5439],
-            [114.4336, 22.5439],
-            [114.4336, 22.4121],
-            [114.6094, 22.4121],
-          ],
-        ],
-      },
-    },
-    {
-      type: 'Feature',
-      id: 'ao_men',
-      properties: { name: '澳门', cp: [113.5547, 22.1484], childNum: 1 },
-      geometry: {
-        type: 'Polygon',
-        coordinates: [
-          [
-            [113.5986, 22.1649],
-            [113.6096, 22.1265],
-            [113.5547, 22.11],
-            [113.5437, 22.2034],
-            [113.5767, 22.2034],
-            [113.5986, 22.1649],
-          ],
-        ],
-      },
-    },
-  ],
-}

+ 0 - 183
src/components/DataScreen/pie/index.vue

@@ -1,183 +0,0 @@
-<template>
-  <div ref="chartsRef" class="echarts" />
-</template>
-<script lang="ts" setup>
-  import * as echarts from 'echarts'
-  import { EChartsType } from 'echarts/core'
-  import { onMounted, ref } from 'vue'
-  const chartsRef = ref<HTMLElement | null>()
-  var trafficWay = [
-    {
-      name: 'Ⅰ类',
-      value: 20,
-    },
-    {
-      name: 'Ⅱ类',
-      value: 20,
-    },
-    {
-      name: 'Ⅲ类',
-      value: 20,
-    },
-    {
-      name: 'Ⅳ类',
-      value: 20,
-    },
-    { name: 'Ⅴ类', value: 20 },
-    { name: '劣Ⅴ类', value: 20 },
-  ]
-
-  var data = []
-  var color = ['#fd566a', '#9787ff', '#fdb36a', '#fdd56a', '#6da7ff', '#63e1f2', '#ff3000']
-  for (var i = 0; i < trafficWay.length; i++) {
-    data.push(
-      {
-        value: trafficWay[i].value,
-        name: trafficWay[i].name,
-        itemStyle: {
-          normal: {
-            borderWidth: 5,
-            shadowBlur: 20,
-            borderColor: color[i],
-            shadowColor: color[i],
-          },
-        },
-      },
-      {
-        value: 2,
-        name: '',
-        itemStyle: {
-          normal: {
-            label: {
-              show: false,
-            },
-            labelLine: {
-              show: false,
-            },
-            color: 'rgba(0, 0, 0, 0)',
-            borderColor: 'rgba(0, 0, 0, 0)',
-            borderWidth: 0,
-          },
-        },
-      }
-    )
-  }
-  var seriesOption = [
-    {
-      name: '',
-      type: 'pie',
-      clockWise: false,
-      radius: [105, 109],
-      hoverAnimation: false,
-      itemStyle: {
-        normal: {
-          label: {
-            show: true,
-            position: 'outside',
-
-            formatter: function (params) {
-              var percent = 0
-              var total = 0
-              for (var i = 0; i < trafficWay.length; i++) {
-                total += trafficWay[i].value
-              }
-              percent = ((params.value / total) * 100).toFixed(0)
-              if (params.name !== '') {
-                return params.name + '\t' + percent + '%'
-              } else {
-                return ''
-              }
-            },
-          },
-          labelLine: {
-            length: 10,
-            length2: 20,
-            show: true,
-            color: '#00ffff',
-          },
-        },
-      },
-      data: data,
-    },
-  ]
-  let options = {
-    color: color,
-    title: [
-      {
-        text: '水质监测',
-        top: '44%',
-        textAlign: 'center',
-        left: '49.50%',
-        backgroundColor: '#163253',
-        borderRadius: 100,
-        textStyle: {
-          color: '#fff',
-          fontSize: 20,
-          fontWeight: '400',
-        },
-      },
-      {
-        text: '水环境监测站',
-        top: '49%',
-        textAlign: 'center',
-        left: '49.50%',
-        textStyle: {
-          color: '#fff',
-          fontSize: 20,
-          fontWeight: '400',
-        },
-      },
-      {
-        text: '9',
-        top: '53%',
-        textAlign: 'center',
-        left: '48%',
-        textStyle: {
-          color: '#f6ea2f',
-          fontSize: 25,
-          fontWeight: '800',
-          fontStyle: 'italic',
-        },
-      },
-      {
-        text: '个',
-        top: '53.5%',
-        textAlign: 'center',
-        left: '50.5%',
-        textStyle: {
-          color: '#fff',
-          fontSize: 16,
-          fontWeight: '400',
-        },
-      },
-    ],
-    tooltip: {
-      show: false,
-    },
-
-    toolbox: {
-      show: false,
-    },
-    series: seriesOption,
-  }
-
-  let chart: EChartsType
-  const initChart = () => {
-    const chart = echarts.init(chartsRef.value)
-    chart.setOption(options)
-    return chart
-  }
-  onMounted(() => {
-    chart = initChart()
-    window.addEventListener('resize', function () {
-      chart && chart.resize()
-    })
-  })
-</script>
-
-<style lang="scss" scoped>
-  .echarts {
-    width: 100%;
-    height: 100%;
-  }
-</style>

+ 0 - 18
src/components/PageWrapLayout/index.scss

@@ -1,18 +0,0 @@
-.m-container-layout {
-  width: 100%;
-  height: 100%;
-  display: flex;
-  padding: 10px 12px;
-  box-sizing: border-box;
-  .m-container-layout-inner {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-    background: white;
-    padding: 20px;
-    width: 100%;
-    height: 100%;
-    box-sizing: border-box;
-  }
-}

+ 0 - 13
src/components/PageWrapLayout/index.vue

@@ -1,13 +0,0 @@
-<template>
-  <div class="m-container-layout">
-    <div class="m-container-layout-inner">
-      <slot></slot>
-    </div>
-  </div>
-</template>
-
-<script lang="ts" setup></script>
-
-<style lang="scss" scoped>
-  @import './index.scss';
-</style>

+ 0 - 116
src/components/RightClickMenu/index.vue

@@ -1,116 +0,0 @@
-<template>
-  <div v-if="isShow" ref="rightMenu" class="g-right-click-menu" :style="style">
-    <div
-      v-for="(item, index) in data"
-      :key="index"
-      class="operating"
-      @click.stop="operatingRightAction($event, item)"
-    >
-      {{ item.label }}
-    </div>
-  </div>
-</template>
-<script lang="ts">
-  export default {
-    props: {
-      data: {
-        type: Array,
-        default: () => [],
-      },
-      left: {
-        type: Number,
-        default: 0,
-      },
-      type: {
-        type: Number,
-        default: 1,
-      },
-      dataInfo: {
-        type: Object,
-        default: () => {},
-      },
-      top: {
-        type: Number,
-        default: 0,
-      },
-      isViewInfo: {
-        type: Boolean,
-        default: true,
-      },
-    },
-    data() {
-      return {
-        isShow: false,
-      }
-    },
-    computed: {
-      style() {
-        let clientHeight = document.body.clientHeight
-        let y = this.top
-        if (clientHeight - y < 100) {
-          return `left:${this.left}px;bottom:${clientHeight - y}px`
-        } else {
-          return `left:${this.left}px;top:${this.top}px`
-        }
-      },
-    },
-    watch: {
-      left: {
-        handler(newName, oldName) {
-          if (newName) {
-            this.isShow = true
-          }
-        },
-        // 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法
-        // immediate: true
-      },
-    },
-    mounted() {
-      let _self = this
-      window.addEventListener('click', function () {
-        _self.isShow = false
-      })
-      window.addEventListener('mousedown', function (e) {
-        if (e.which === 3) {
-          _self.isShow = false
-        }
-      })
-    },
-    methods: {
-      /**
-       * @func 点击操作
-       * @param val 1、置顶/取消置顶 2、开启/关闭免打扰 3、开启/关闭星标 4、删除会话
-       */
-      operatingRightAction($event, val) {
-        this.$emit('ok', $event, val)
-        this.isShow = false
-      },
-    },
-  }
-</script>
-<style lang="scss" scoped>
-  .g-right-click-menu {
-    left: 0;
-    background: white;
-    width: 148px;
-    height: auto;
-    position: fixed;
-    //border: 1px solid #c4c4c4;
-    z-index: 9;
-    //box-shadow: 0 1px 2px 0px rgba(0, 0, 0, 0.1);
-    box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
-    .operating {
-      font-size: 12px;
-      padding-left: 23px;
-      cursor: pointer;
-      line-height: 27px;
-    }
-    .operating:hover {
-      background: #e2e2e2;
-    }
-
-    .last-delete {
-      border-top: 1px solid #ededed;
-    }
-  }
-</style>

+ 0 - 26
src/components/SwitchDark/index.vue

@@ -1,26 +0,0 @@
-<template>
-  <el-switch
-    v-model="themeConfig.isDark"
-    inline-prompt
-    :active-icon="Sunny"
-    :inactive-icon="Moon"
-    @change="switchDark"
-  />
-</template>
-
-<script setup lang="ts" name="switchDark">
-  import { Sunny, Moon } from '@element-plus/icons-vue'
-  import { computed, ref } from 'vue'
-  import { useSettingStore } from '@/store/modules/setting'
-
-  const SettingStore = useSettingStore()
-  // 设置信息
-  const themeConfig = computed(() => SettingStore.themeConfig)
-
-  // 切换暗黑模式
-  const switchDark = () => {
-    const body = document.documentElement as HTMLElement
-    if (themeConfig.value.isDark) body.setAttribute('class', 'dark')
-    else body.setAttribute('class', '')
-  }
-</script>

+ 0 - 163
src/components/Theme/index.vue

@@ -1,163 +0,0 @@
-<template>
-  <div>
-    <el-drawer v-model="drawer" title="主题配置" size="300px">
-      <div class="theme-item">
-        <label>导航栏布局</label>
-        <el-select
-          v-model="layout"
-          placeholder="请选择"
-          style="width: 150px"
-          @change="(val) => changeSwitch('mode', val)"
-        >
-          <el-option label="纵向" value="vertical"></el-option>
-          <el-option label="横向" value="horizontal"></el-option>
-          <el-option label="分栏" value="columns"></el-option>
-        </el-select>
-      </div>
-      <div class="theme-item">
-        <label>主题颜色</label>
-        <el-color-picker v-model="primary" :predefine="predefineColor" @change="changePrimary" />
-      </div>
-      <div class="theme-item">
-        <label>暗黑模式</label>
-        <switch-dark></switch-dark>
-      </div>
-      <div class="theme-item">
-        <label>灰色模式</label>
-        <el-switch v-model="gray" @change="(val) => changeGrayWeak('gray', val)" />
-      </div>
-      <div class="theme-item">
-        <label>色弱模式</label>
-        <el-switch v-model="weak" @change="(val) => changeGrayWeak('weak', val)" />
-      </div>
-      <div class="theme-item">
-        <label>标签栏</label>
-        <el-switch v-model="showTag" @change="(val) => changeSwitch('showTag', val)" />
-      </div>
-      <div class="theme-item">
-        <label>侧边栏 Logo</label>
-        <el-switch v-model="showLogo" @change="(val) => changeSwitch('showLogo', val)" />
-      </div>
-      <div class="theme-item">
-        <label>保持一个子菜单的展开</label>
-        <el-switch v-model="uniqueOpened" @change="(val) => changeSwitch('uniqueOpened', val)" />
-      </div>
-      <div class="theme-item">
-        <label>固定header</label>
-        <el-switch v-model="fixedHeader" @change="(val) => changeSwitch('fixedHeader', val)" />
-      </div>
-    </el-drawer>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import { computed, ref, watch } from 'vue'
-  import { ElMessage } from 'element-plus'
-  import { openLoading, closeLoading } from '@/utils/element'
-  import SwitchDark from '@/components/SwitchDark/index.vue'
-  import { PRIMARY_COLOR } from '@/config/index'
-  import { useSettingStore } from '@/store/modules/setting'
-
-  const SettingStore = useSettingStore()
-  const layout = ref(SettingStore.themeConfig.mode)
-  const showTag = ref(SettingStore.themeConfig.showTag)
-  const showLogo = ref(SettingStore.themeConfig.showLogo)
-  const uniqueOpened = ref(SettingStore.themeConfig.uniqueOpened)
-  const primary = ref(SettingStore.themeConfig.primary)
-  const fixedHeader = ref(SettingStore.themeConfig.fixedHeader)
-  const gray = ref(SettingStore.themeConfig.gray)
-  const weak = ref(SettingStore.themeConfig.weak)
-
-  const drawer = computed({
-    get() {
-      return SettingStore.themeConfig.showSetting
-    },
-    set() {
-      changeSwitch('showSetting', !SettingStore.themeConfig.showSetting)
-    },
-  })
-
-  // 预定义主题颜色
-  const predefineColor = [
-    '#409EFF',
-    '#1890ff',
-    '#304156',
-    '#212121',
-    '#11a983',
-    '#13c2c2',
-    '#6959CD',
-    '#f5222d',
-  ]
-
-  const operator = (type) => {
-    switch (type) {
-      case 1:
-        drawer.value = true
-        return
-      case 2:
-        window.open('https://github.com/zouzhibin/vue-admin-perfect')
-        return
-    }
-  }
-
-  // 进行配置
-  const changeSwitch = (key, val) => {
-    SettingStore.setThemeConfig({ key, val })
-    if (key === 'mode') {
-      openLoading()
-      setTimeout(() => {
-        closeLoading()
-      }, 600)
-    }
-  }
-
-  // 监听布局变化
-  watch(
-    () => layout.value,
-    () => {
-      const body = document.body as HTMLElement
-      body.setAttribute('class', `layout-${layout.value}`)
-    },
-    { immediate: true }
-  )
-
-  // 修改主题颜色
-  const changePrimary = (val) => {
-    if (!val) {
-      primary.value = val = PRIMARY_COLOR
-      ElMessage({ type: 'success', message: `主题颜色已重置为 ${PRIMARY_COLOR}` })
-    }
-    document.documentElement.style.setProperty('--el-color-primary', val)
-    changeSwitch('primary', val)
-  }
-
-  // 修改灰色模式
-  const changeGrayWeak = (type, val) => {
-    const body = document.documentElement as HTMLElement
-    if (!val) return body.setAttribute('style', '')
-    if (type === 'gray') body.setAttribute('style', 'filter: grayscale(1)')
-    if (type === 'weak') body.setAttribute('style', 'filter: invert(80%)')
-    changeSwitch(type, val)
-  }
-</script>
-
-<style lang="scss" scoped>
-  ::v-deep(.el-drawer__header) {
-    border-bottom: 1px solid #ebeef5;
-    padding: 15px 20px 14px;
-    margin-bottom: 0;
-  }
-  :deep(.el-drawer__title) {
-    font-weight: bold;
-    color: black;
-  }
-  .theme-item {
-    width: 100%;
-    display: flex;
-    margin-bottom: 15px;
-    align-items: center;
-    font-size: 14px;
-    color: black;
-    justify-content: space-between;
-  }
-</style>

+ 0 - 8
src/components/pipeline/index.vue

@@ -1,8 +0,0 @@
-<template>
-  <div class="zb-pipeline">
-    <zb-pipeline-start />
-  </div>
-</template>
-<script lang="ts" setup>
-  import ZbPipelineStart from './zb-pipeline-start'
-</script>

+ 0 - 150
src/components/pipeline/zb-pipeline-start.vue

@@ -1,150 +0,0 @@
-<template>
-  <div class="zb-pipeline-start-wrapper">
-    <div class="zb-pipeline-start" :class="control === value ? 'active' : ''" @click="handleClick">
-      <div class="zb-pipeline-start-header">
-        <zb-icon type="play-filled" />
-      </div>
-      <div class="zb-pipeline-start-body">
-        <div class="zb-pipeline-start-title">开始</div>
-        <div class="zb-pipeline-start-tooltip">
-          <el-tooltip placement="top-start" content="点击进行构建基础设置">
-            <el-icon>
-              <Help />
-            </el-icon>
-          </el-tooltip>
-          <!--          <zb-tooltip placement="right">-->
-          <!--            <zb-icon type="help" />-->
-          <!--            <div slot="content">点击进行构建基础设置</div>-->
-          <!--          </zb-tooltip>-->
-        </div>
-      </div>
-    </div>
-    <slot></slot>
-  </div>
-</template>
-<script lang="ts" setup>
-  import { Help } from '@element-plus/icons-vue'
-</script>
-<style>
-  /* zb-pipeline-start-wrapper */
-  .zb-pipeline-start-wrapper {
-    position: relative;
-    padding: 0 40px;
-  }
-
-  /* zb-pipeline-start */
-  .zb-pipeline-start {
-    cursor: pointer;
-    user-select: none;
-    position: relative;
-    display: flex;
-    justify-content: flex-start;
-    align-items: stretch;
-    width: 200px;
-    height: 40px;
-    border-radius: 2px;
-    background-color: #fff;
-  }
-  .zb-pipeline-start:after {
-    content: '';
-    position: absolute;
-    top: 20px;
-    right: -40px;
-    display: block;
-    width: 40px;
-    height: 1px;
-    background-color: #2d8cf0;
-  }
-  .zb-pipeline-start .zb-pipeline-start-header {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    width: 40px;
-    border-width: 1px 0 1px 1px;
-    border-style: solid;
-    border-color: #2d8cf0;
-    border-radius: 2px 0 0 2px;
-    background-color: #2d8cf0;
-    color: #fff;
-    font-size: 14px;
-    font-weight: 600;
-    transition: all 0.2s cubic-bezier(0.23, 1, 0.32, 1);
-  }
-  .zb-pipeline-start .zb-pipeline-start-body {
-    flex: 1;
-    display: flex;
-    border-width: 1px 1px 1px 0;
-    border-style: solid;
-    border-color: #e3e8f0;
-    border-radius: 0 2px 2px 0;
-    padding: 0 8px;
-    overflow: hidden;
-    transition: all 0.2s cubic-bezier(0.23, 1, 0.32, 1);
-  }
-  .zb-pipeline-start .zb-pipeline-start-title {
-    flex: 1;
-    display: block;
-    overflow: hidden;
-    color: #262626;
-    font-size: 14px;
-    font-weight: 600;
-    line-height: 38px;
-    white-space: nowrap;
-    text-overflow: ellipsis;
-  }
-  .zb-pipeline-start .zb-pipeline-start-tooltip {
-    cursor: pointer;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    margin-left: 8px;
-  }
-  .zb-pipeline-start .zb-pipeline-start-tooltip .zb-tooltip {
-    display: block;
-  }
-  .zb-pipeline-start .zb-pipeline-start-tooltip .zb-icon {
-    display: block;
-    color: #595959;
-    font-size: 14px;
-  }
-
-  /* zb-pipeline-start hover */
-  .zb-pipeline-start:hover {
-  }
-  .zb-pipeline-start:hover:after {
-  }
-  .zb-pipeline-start:hover .zb-pipeline-start-header {
-    border-color: #2d8cf0;
-  }
-  .zb-pipeline-start:hover .zb-pipeline-start-body {
-    border-color: #2d8cf0;
-  }
-  .zb-pipeline-start:hover .zb-pipeline-start-title {
-  }
-  .zb-pipeline-start:hover .zb-pipeline-start-tooltip {
-  }
-  .zb-pipeline-start:hover .zb-pipeline-start-tooltip .zb-tooltip {
-  }
-  .zb-pipeline-start:hover .zb-pipeline-start-tooltip .zb-icon {
-  }
-
-  /* zb-pipeline-start active */
-  .zb-pipeline-start.active {
-  }
-  .zb-pipeline-start.active:after {
-  }
-  .zb-pipeline-start.active .zb-pipeline-start-header {
-    border-color: #2d8cf0;
-  }
-  .zb-pipeline-start.active .zb-pipeline-start-body {
-    border-color: #2d8cf0;
-  }
-  .zb-pipeline-start.active .zb-pipeline-start-title {
-  }
-  .zb-pipeline-start.active .zb-pipeline-start-tooltip {
-  }
-  .zb-pipeline-start.active .zb-pipeline-start-tooltip .zb-tooltip {
-  }
-  .zb-pipeline-start.active .zb-pipeline-start-tooltip .zb-icon {
-  }
-</style>

+ 0 - 30
src/components/u-container-layout/index.vue

@@ -1,30 +0,0 @@
-<template>
-  <div class="m-container-layout">
-    <div class="m-container-layout-inner">
-      <slot></slot>
-    </div>
-  </div>
-</template>
-
-<script lang="ts" setup></script>
-
-<style lang="scss" scoped>
-  .m-container-layout {
-    width: 100%;
-    height: 100%;
-    display: flex;
-    padding: 10px 12px;
-    box-sizing: border-box;
-    .m-container-layout-inner {
-      flex: 1;
-      display: flex;
-      flex-direction: column;
-      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-      background: white;
-      padding: 20px;
-      width: 100%;
-      height: 100%;
-      box-sizing: border-box;
-    }
-  }
-</style>

+ 5 - 2
src/config/index.ts

@@ -13,13 +13,14 @@ export const PRIMARY_COLOR = '#409eff'
 const ht = window.location.protocol
 const ho = window.location.host.split('.')[1]
 const c = import.meta.env.VITE_APP_ENV
-let Host00, Host85, Host05
+let Host00, Host85, Host05, Host80
 switch (c) {
   // 测试环境
   case 'test':
     Host00 = ht + '//secure.' + ho + '.com'
     Host85 = ht + '//ad.' + ho + '.com'
     Host05 = ht + '//file.' + ho + '.com'
+    Host80 = ht + '//secure.' + ho + '.com'
     // Host05 = "http://103.171.34.61:8705"
     break
   // 生产环境
@@ -27,6 +28,7 @@ switch (c) {
     Host00 = ht + '//secure.' + ho + '.com'
     Host85 = ht + '//ad.' + ho + '.com'
     Host05 = ht + '//file.' + ho + '.com'
+    Host80 = ht + '//secure.' + ho + '.com'
     break
 
   default:
@@ -35,6 +37,7 @@ switch (c) {
     Host85 = 'https://ad.44a5c8109e4.com'
     // Host85="http://103.171.34.61:8500" // 测试
     Host05 = 'http://103.171.34.61:8705'
+    Host80 = 'http://192.168.0.30:8000'
     Host85 = 'http://192.168.0.18:8500' // 高超本地
     // Host85="http://192.168.0.30:8500"
     break
@@ -43,7 +46,7 @@ const config = {
   Host00,
   Host85,
   Host05,
-  Host80: ht + '//secure.' + ho + '.com',
+  Host80,
   Code: {
     StatusOK: 200,
     StatusFail: 400,

+ 0 - 218
src/layout/LayoutColumns/index.vue

@@ -1,218 +0,0 @@
-<template>
-  <div class="main-columns">
-    <div class="layout-columns-aside">
-      <div class="logo flex-center">
-        <img src="@/assets/image/logo.png" alt="logo" />
-      </div>
-      <el-scrollbar>
-        <div class="menu-wrap">
-          <div
-            v-for="item in menusRoutes"
-            :key="item.path"
-            class="item-menu-wrap"
-            :class="{
-              'active-menu': activeCurrentMenu === item.path,
-            }"
-            @click="handleChangeMenu(item)"
-          >
-            <el-icon :size="20">
-              <component :is="item?.meta?.icon"></component>
-            </el-icon>
-            <span class="title">{{ item?.meta?.title }}</span>
-          </div>
-        </div>
-      </el-scrollbar>
-    </div>
-
-    <div class="layout-columns-sub" :style="{ width: isCollapse ? '60px' : '210px' }">
-      <div class="logo flex-center">
-        <span v-show="subMenus.length">{{ isCollapse ? 'Vue' : 'Vue Admin Perfect' }}</span>
-      </div>
-      <el-scrollbar>
-        <el-menu
-          :collapse="isCollapse"
-          :router="false"
-          :default-active="activeMenu"
-          :unique-opened="SettingStore.themeConfig.uniqueOpened"
-          :collapse-transition="false"
-          class="menu-columns"
-        >
-          <SubMenu :menu-list="subMenus" />
-        </el-menu>
-      </el-scrollbar>
-    </div>
-
-    <div class="container">
-      <div class="layout-header">
-        <div class="header-tool">
-          <HeaderToolLeft />
-          <HeaderToolRight />
-        </div>
-        <TagsView v-if="themeConfig.showTag" />
-      </div>
-      <Main />
-      <Footer />
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-  import { ref, computed, watch } from 'vue'
-  import { useRoute, useRouter } from 'vue-router'
-  import { usePermissionStore } from '@/store/modules/permission'
-  import { useSettingStore } from '@/store/modules/setting'
-  import Footer from '../components/Footer/index.vue'
-  import SubMenu from '../components/SubMenu/SubMenu.vue'
-  import TagsView from '../components/TagsView/index.vue'
-  const PermissionStore = usePermissionStore()
-  const SettingStore = useSettingStore()
-  const route = useRoute()
-  const router = useRouter()
-  import HeaderToolRight from '../components/Header/ToolRight.vue'
-  import HeaderToolLeft from '../components/Header/ToolLeft.vue'
-  import Main from '../components/Main/index.vue'
-  // 获取路由
-  const permission_routes = computed(() => PermissionStore.permission_routes)
-
-  // 获取路由
-  const menusRoutes = computed(() => {
-    return PermissionStore.permission_routes.filter((item) => !item.hidden)
-  })
-
-  const activeCurrentMenu = ref('')
-  // 主题配置
-  const themeConfig = computed(() => SettingStore.themeConfig)
-  const isCollapse = computed(() => !SettingStore.isCollapse)
-  const activeMenu = computed(() => {
-    const { meta, path } = route
-    return path
-  })
-  const basePath = ref<string>('/')
-  const subMenus = ref([])
-
-  watch(
-    () => [route],
-    () => {
-      if (!menusRoutes.value.length) return
-      const [firstMenu] = route.matched
-      activeCurrentMenu.value = firstMenu.path
-      let menuItem = menusRoutes.value.find((item) => firstMenu.path === item.path)
-      if (menuItem && menuItem.children?.length) {
-        subMenus.value = menuItem.children
-      } else {
-        subMenus.value = []
-      }
-      basePath.value = firstMenu.path
-    },
-    {
-      deep: true,
-      immediate: true,
-    }
-  )
-
-  const handleChangeMenu = (item) => {
-    router.push(item.path)
-  }
-</script>
-
-<style lang="scss" scoped>
-  .main-columns {
-    display: flex;
-    flex-direction: row !important;
-    height: 100%;
-    width: 100%;
-  }
-  .layout-columns-aside {
-    flex-shrink: 0;
-    width: 80px;
-    height: 100%;
-    background-color: #304156;
-    .el-scrollbar {
-      height: calc(100% - 55px);
-    }
-    .logo {
-      box-sizing: border-box;
-      height: 50px;
-      img {
-        width: 32px;
-        object-fit: contain;
-      }
-    }
-    .menu-wrap {
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-      justify-content: center;
-      .item-menu-wrap {
-        display: flex;
-        flex-direction: column;
-        align-items: center;
-        justify-content: center;
-        height: 70px;
-        width: 70px;
-        cursor: pointer;
-        transition: all 0.3s ease;
-      }
-      .active-menu {
-        background: $primaryColor;
-        border-radius: 5px;
-      }
-      .title {
-        color: #e5eaf3;
-      }
-      .el-icon {
-        color: #e5eaf3;
-      }
-    }
-  }
-
-  .layout-columns-sub {
-    flex-shrink: 0;
-    width: 200px;
-    box-sizing: border-box;
-    flex-direction: column;
-    overflow: hidden;
-    transition: all 0.3s ease;
-    background: white;
-    border-right: 1px solid #eee;
-    .el-scrollbar {
-      height: calc(100vh - 50px);
-    }
-    .logo {
-      width: 100%;
-      box-sizing: border-box;
-      height: 50px;
-      border-bottom: 1px solid #eee;
-      span {
-        font-weight: bold;
-        white-space: nowrap;
-      }
-    }
-    ::v-deep(.menu-columns) {
-      border-right: none;
-    }
-  }
-  .container {
-    flex: 1;
-    overflow: hidden;
-    display: flex;
-    flex-direction: column;
-  }
-  .layout-header {
-    background: white;
-    transition: width 0.28s;
-    flex-shrink: 0;
-    box-sizing: border-box;
-    box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
-    .header-tool {
-      height: 50px;
-      width: 100%;
-      border-bottom: 1px solid #eee;
-      display: flex;
-      align-items: center;
-      padding: 0 10px 0 0;
-      box-sizing: border-box;
-      justify-content: space-between;
-    }
-  }
-</style>

+ 0 - 34
src/layout/LayoutHorizontal/HeaderHorizontal/index.scss

@@ -1,34 +0,0 @@
-.m-layout-header {
-  width: 100%;
-  transition: width 0.28s;
-  flex-shrink: 0;
-  box-sizing: border-box;
-  box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
-  .header-inner {
-    height: 50px;
-    width: 100%;
-    border-bottom: 1px solid #eee;
-    display: flex;
-    background-color: $menuBg;
-    align-items: center;
-    padding: 0 10px 0 0;
-    box-sizing: border-box;
-    justify-content: space-between;
-  }
-}
-.fixed-header {
-  position: fixed;
-  top: 0;
-  right: 0;
-  z-index: 9;
-}
-
-.menu-horizontal {
-  flex: 1;
-  overflow: hidden;
-  height: 100%;
-
-  :deep(.el-menu-item) {
-    height: 100%;
-  }
-}

+ 0 - 61
src/layout/LayoutHorizontal/HeaderHorizontal/index.vue

@@ -1,61 +0,0 @@
-<template>
-  <!--纵向布局-->
-  <Height />
-  <div
-    class="m-layout-header"
-    :class="{
-      'fixed-header': themeConfig.fixedHeader,
-    }"
-  >
-    <div class="header-inner">
-      <el-menu
-        mode="horizontal"
-        :default-active="activeMenu"
-        background-color="#304156"
-        text-color="#bfcbd9"
-        :unique-opened="SettingStore.themeConfig.uniqueOpened"
-        :collapse-transition="false"
-        class="menu-horizontal"
-      >
-        <SubItem v-for="route in permission_routes" :key="route.path" :item="route" />
-      </el-menu>
-      <HeaderToolRight />
-    </div>
-    <TagsView v-if="themeConfig.showTag" />
-  </div>
-</template>
-
-<script lang="ts" setup>
-  // 引入组件
-  import Height from '../../components/Header/components/Height.vue'
-  import HeaderToolRight from '../../components/Header/ToolRight.vue'
-  import TagsView from '../../components/TagsView/index.vue'
-  import SubItem from '../../components/SubMenu/SubItem.vue'
-  import { useRoute } from 'vue-router'
-  import { usePermissionStore } from '@/store/modules/permission'
-  const PermissionStore = usePermissionStore()
-
-  const route = useRoute()
-
-  // 获取路由
-  const permission_routes = computed(() => PermissionStore.permission_routes)
-  import { computed } from 'vue'
-  import { useSettingStore } from '@/store/modules/setting'
-  const SettingStore = useSettingStore()
-
-  const activeMenu = computed(() => {
-    const { meta, path } = route
-    if (meta.activeMenu) {
-      return meta.activeMenu
-    }
-    return path
-  })
-
-  // 主题配置
-  const themeConfig = computed(() => SettingStore.themeConfig)
-  const isCollapse = computed(() => !SettingStore.isCollapse)
-</script>
-
-<style lang="scss" scoped>
-  @import './index.scss';
-</style>

+ 0 - 24
src/layout/LayoutHorizontal/index.vue

@@ -1,24 +0,0 @@
-<template>
-  <div class="main-container">
-    <UHeader />
-    <Main />
-    <Footer />
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import Sidebar from '../components/Sidebar/index.vue'
-  import UHeader from './HeaderHorizontal/index.vue'
-  import Main from '../components/Main/index.vue'
-  import Footer from '../components/Footer/index.vue'
-</script>
-
-<style lang="scss" scoped>
-  .main-container {
-    display: flex;
-    flex: 1;
-    box-sizing: border-box;
-    flex-direction: column;
-    min-height: 100%;
-  }
-</style>

+ 0 - 67
src/layout/LayoutVertical/HeaderVertical/index.scss

@@ -1,67 +0,0 @@
-.mobile {
-  .m-layout-header {
-    left: 0 !important;
-    width: 100% !important;
-  }
-}
-.show-tag {
-  height: 90px;
-}
-
-.zb-no-fixed-header {
-  width: 100% !important;
-}
-
-.m-layout-header {
-  width: 100%;
-  background: white;
-  transition: width 0.28s;
-  flex-shrink: 0;
-  box-sizing: border-box;
-  box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
-
-  .header-inner {
-    height: 50px;
-    width: 100%;
-    border-bottom: 1px solid #eee;
-    display: flex;
-    align-items: center;
-    padding: 0 10px 0 0;
-    box-sizing: border-box;
-    justify-content: space-between;
-  }
-}
-.fixed-header {
-  position: fixed;
-  top: 0;
-  right: 0;
-  z-index: 9;
-}
-.collapse {
-  width: calc(100% - 60px);
-}
-.no-collapse {
-  width: calc(100% - 210px);
-}
-
-.el-dropdown {
-  display: flex;
-  height: 100%;
-  align-items: center;
-}
-
-.transverseMenu {
-  display: flex;
-  .el-menu {
-    overflow: hidden;
-  }
-  :deep(.el-menu-item) {
-    height: 100% !important;
-  }
-  .tool-bar-right {
-    display: flex;
-    justify-content: flex-end;
-    min-width: 300px;
-    flex-shrink: 0;
-  }
-}

+ 0 - 38
src/layout/LayoutVertical/HeaderVertical/index.vue

@@ -1,38 +0,0 @@
-<template>
-  <!--纵向布局-->
-  <Height />
-  <div
-    class="m-layout-header"
-    :class="{
-      'fixed-header': themeConfig.fixedHeader,
-      collapse: themeConfig.fixedHeader && isCollapse,
-      'no-collapse': themeConfig.fixedHeader && !isCollapse,
-    }"
-  >
-    <div class="header-inner">
-      <HeaderToolLeft />
-      <HeaderToolRight />
-    </div>
-    <TagsView v-if="themeConfig.showTag" />
-  </div>
-</template>
-
-<script lang="ts" setup>
-  // 引入组件
-  import Height from '../../components/Header/components/Height.vue'
-  import HeaderToolRight from '../../components/Header/ToolRight.vue'
-  import HeaderToolLeft from '../../components/Header/ToolLeft.vue'
-  import TagsView from '../../components/TagsView/index.vue'
-
-  import { computed } from 'vue'
-  import { useSettingStore } from '@/store/modules/setting'
-  const SettingStore = useSettingStore()
-
-  // 主题配置
-  const themeConfig = computed(() => SettingStore.themeConfig)
-  const isCollapse = computed(() => !SettingStore.isCollapse)
-</script>
-
-<style lang="scss" scoped>
-  @import './index.scss';
-</style>

+ 0 - 46
src/layout/LayoutVertical/index.vue

@@ -1,46 +0,0 @@
-<template>
-  <!--纵向布局-->
-  <Sidebar />
-  <div class="main-container">
-    <HeaderVertical />
-    <Main />
-    <Footer />
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import Sidebar from '../components/Sidebar/index.vue'
-  import HeaderVertical from './HeaderVertical/index.vue'
-  import Main from '../components/Main/index.vue'
-  import Footer from '../components/Footer/index.vue'
-</script>
-
-<style lang="scss" scoped>
-  .g-container-layout {
-    height: 100%;
-    width: 100%;
-    .main-container {
-      display: flex;
-      flex: 1;
-      box-sizing: border-box;
-      flex-direction: column;
-    }
-    &.mobile.openSidebar {
-      position: fixed;
-      top: 0;
-    }
-  }
-  .sidebar-container {
-    display: flex;
-    flex-direction: column;
-  }
-  .drawer-bg {
-    background: #000;
-    opacity: 0.3;
-    width: 100%;
-    top: 0;
-    height: 100%;
-    position: absolute;
-    z-index: 90;
-  }
-</style>

+ 0 - 19
src/layout/components/Footer/index.vue

@@ -1,19 +0,0 @@
-<template>
-  <div class="footer-layout">
-    <span href="/" target="_blank">2022 © VUE-ADMIN-PERFECT By ZB Technology.</span>
-  </div>
-</template>
-
-<style scoped lang="scss">
-  .footer-layout {
-    height: 40px;
-    font-size: 12px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    background: #ffffff;
-    border-top: 1px solid #e4e7ed;
-    flex-shrink: 0;
-    color: rgba(0, 0, 0, 0.45);
-  }
-</style>

+ 0 - 19
src/layout/components/Header/ToolLeft.vue

@@ -1,19 +0,0 @@
-<template>
-  <div class="m-tool-left">
-    <CollapseIcon />
-    <Hamburger />
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import CollapseIcon from './components/CollapseIcon.vue'
-  import Hamburger from './components/Hamburger.vue'
-</script>
-
-<style lang="scss" scoped>
-  .m-tool-left {
-    display: flex;
-    align-items: center;
-    height: 100%;
-  }
-</style>

+ 0 - 23
src/layout/components/Header/ToolRight.vue

@@ -1,23 +0,0 @@
-<template>
-  <div class="m-tool-right">
-    <Language class="item-children" />
-    <ScreenFull class="item-children" />
-    <Avatar />
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import ScreenFull from './components/ScreenFull.vue'
-  import Avatar from './components/Avatar.vue'
-  import Language from './components/Language.vue'
-</script>
-
-<style lang="scss" scoped>
-  .m-tool-right {
-    display: flex;
-    align-items: center;
-    .item-children {
-      margin-right: 22px;
-    }
-  }
-</style>

+ 0 - 100
src/layout/components/Header/components/Avatar.vue

@@ -1,100 +0,0 @@
-<template>
-  <el-dropdown>
-    <span class="el-dropdown-link">
-      {{ user.name || 'UserName' }}
-      <el-icon class="header-icon el-icon--right">
-        <arrow-down />
-      </el-icon>
-    </span>
-    <template #dropdown>
-      <el-dropdown-menu>
-        <el-dropdown-item :command="3" divided @click="modifyPassword">
-          <el-icon><Edit /></el-icon>
-          {{ $t('Label.UpdatePwd') }}
-        </el-dropdown-item>
-        <el-dropdown-item :command="4" divided @click="logOut">
-          <el-icon><SwitchButton /></el-icon>
-          Logout
-        </el-dropdown-item>
-      </el-dropdown-menu>
-    </template>
-  </el-dropdown>
-
-  <PersonalDialog ref="person" />
-</template>
-
-<script lang="ts" setup>
-  import { useRouter } from 'vue-router'
-  import { ElMessage, ElMessageBox } from 'element-plus'
-  import { computed, ref, inject } from 'vue'
-
-  import { useUserStore } from '@/store/modules/user'
-  import { useTagsViewStore } from '@/store/modules/tagsView'
-  import { usePermissionStore } from '@/store/modules/permission'
-  import PersonalDialog from './PersonalDialog.vue'
-
-  import { safeGetUser, safeGetDisplay } from '@/utils/safeJson'
-  const router = useRouter()
-  const UserStore = useUserStore()
-  const TagsViewStore = useTagsViewStore()
-  const PermissionStore = usePermissionStore()
-  const session = inject('session')
-
-  const user = computed(() => {
-    console.log(safeGetUser(session), ' thisad')
-    return safeGetUser(session)
-  })
-
-  const currentRoles = computed({
-    get() {
-      return UserStore.roles[0]
-    },
-    set(val) {
-      ;(async () => {
-        await UserStore.getInfo([val])
-        router.push({
-          path: '/',
-        })
-        location.reload()
-      })()
-    },
-  })
-
-  // 用户信息
-  const userInfo = computed(() => UserStore.userInfo)
-  const person = ref()
-
-  const logOut = async () => {
-    ElMessageBox.confirm('您是否确认退出登录?', '温馨提示', {
-      confirmButtonText: '确定',
-      cancelButtonText: '取消',
-      type: 'warning',
-    })
-      .then(async () => {
-        await UserStore.logout()
-        await router.push({ path: '/login' })
-        TagsViewStore.clearVisitedView()
-        PermissionStore.clearRoutes()
-        ElMessage({
-          type: 'success',
-          message: '退出登录成功!',
-        })
-      })
-      .catch(() => {})
-  }
-  const modifyPassword = () => {
-    person.value.show()
-  }
-</script>
-
-<style lang="scss" scoped>
-  .avatar {
-    margin-right: 6px;
-  }
-  .el-dropdown-link {
-    cursor: pointer;
-    //color: var(--el-color-primary);
-    display: flex;
-    align-items: center;
-  }
-</style>

+ 0 - 30
src/layout/components/Header/components/CollapseIcon.vue

@@ -1,30 +0,0 @@
-<template>
-  <div class="hamburger-container" @click="handleCollapse">
-    <el-icon v-if="isCollapse" class="icon"><expand /></el-icon>
-    <el-icon v-else class="icon"><fold /></el-icon>
-  </div>
-</template>
-<script lang="ts" setup>
-  import { useSettingStore } from '@/store/modules/setting'
-  import { computed } from 'vue'
-  const SettingStore = useSettingStore()
-  const isCollapse = computed(() => !SettingStore.isCollapse)
-  const handleCollapse = () => {
-    SettingStore.setCollapse(isCollapse.value)
-  }
-</script>
-<style lang="scss" scoped>
-  .hamburger-container {
-    padding: 0px 15px;
-    height: 100%;
-    display: flex;
-    align-items: center;
-    &:hover {
-      background: rgba(0, 0, 0, 0.025);
-    }
-    .icon {
-      font-size: 24px;
-      cursor: pointer;
-    }
-  }
-</style>

+ 0 - 38
src/layout/components/Header/components/Hamburger.vue

@@ -1,38 +0,0 @@
-<template>
-  <el-breadcrumb class="app-breadcrumb" separator="/">
-    <transition-group name="breadcrumb">
-      <el-breadcrumb-item v-if="matched[0].meta.title !== '首页'" key="home" :to="{ path: '/' }">
-        <div class="breadcrumb-item">
-          <span class="breadcrumb-title">首页</span>
-        </div>
-      </el-breadcrumb-item>
-      <el-breadcrumb-item v-for="(item, index) in matched" :key="item.name">
-        <span
-          v-if="item.redirect === 'noRedirect' || index == matched.length - 1"
-          class="no-redirect"
-        >
-          {{ item.meta.title }}
-        </span>
-        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
-      </el-breadcrumb-item>
-    </transition-group>
-  </el-breadcrumb>
-</template>
-
-<script lang="ts" setup>
-  import { computed } from 'vue'
-  import { useRoute, useRouter } from 'vue-router'
-
-  const route = useRoute()
-  const router = useRouter()
-
-  const handleLink = (item) => {
-    router.push({
-      path: item.path,
-    })
-  }
-
-  const matched = computed(() =>
-    route.matched.filter((item) => item.meta && item.meta.title && item.meta.breadcrumb !== false)
-  )
-</script>

+ 0 - 178
src/layout/components/Header/components/HeaderSearch.vue

@@ -1,178 +0,0 @@
-<template>
-  <div class="m-headerSearch">
-    <el-tooltip effect="dark" content="菜单搜索" placement="bottom">
-      <el-icon class="bell header-icon" style="font-size: 22px" @click="handleSearch">
-        <Search />
-      </el-icon>
-    </el-tooltip>
-    <el-dialog v-model="isShowSearch" width="600px" destroy-on-close :show-close="false">
-      <el-select
-        ref="headerSearchSelect"
-        v-model="search"
-        style="width: 100%"
-        :remote-method="querySearch"
-        filterable
-        default-first-option
-        remote
-        placeholder="菜单搜索 :支持菜单名称、路径"
-        class="header-search-select"
-        @change="change"
-      >
-        <el-option
-          v-for="item in options"
-          :key="item.item.path"
-          :value="item.item.path"
-          :label="item && item.item.title && item.item.title.length && item.item.title.join(' > ')"
-        ></el-option>
-      </el-select>
-    </el-dialog>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import { computed, onMounted, ref, watch } from 'vue'
-  import path from 'path-browserify'
-  import Fuse from 'fuse.js'
-  import { useVueFuse } from 'vue-fuse'
-  import { useRouter } from 'vue-router'
-  const router = useRouter()
-  const isShowSearch = ref(false)
-  const options = ref([])
-  const searchPool = ref([])
-  const search = ref('')
-  const fuse = ref(null)
-  import { usePermissionStore } from '@/store/modules/permission'
-  const PermissionStore = usePermissionStore()
-  const routes = computed(() => PermissionStore.routes)
-
-  const handleSearch = () => {
-    isShowSearch.value = true
-  }
-
-  const initFuse = (list) => {
-    fuse.value = new Fuse(list, {
-      shouldSort: true,
-      threshold: 0.4,
-      location: 0,
-      distance: 100,
-      maxPatternLength: 32,
-      minMatchCharLength: 1,
-      keys: [
-        {
-          name: 'title',
-          weight: 0.7,
-        },
-        {
-          name: 'path',
-          weight: 0.3,
-        },
-      ],
-    })
-  }
-
-  watch(searchPool, (list) => {
-    initFuse(list)
-  })
-
-  // 筛选出可以在侧栏中显示的路线 生成标题
-  const generateRoutes = (routes, basePath = '/', prefixTitle = []) => {
-    let res = []
-
-    for (const router of routes) {
-      // 忽略隐藏的路由
-      if (router.hidden) {
-        continue
-      }
-
-      const data = {
-        path: path.resolve(basePath, router.path),
-        title: [...prefixTitle],
-      }
-      if (router.meta && router.meta.title) {
-        data.title = [...data.title, router.meta.title]
-
-        if (router.redirect !== 'noRedirect') {
-          // 仅推送带有标题的路由
-          // 特殊情况:需要排除无重定向的父路由器
-          res.push(data)
-        }
-      }
-      // 递归子路由
-      if (router.children) {
-        const tempRoutes = generateRoutes(router.children, data.path, data.title)
-        if (tempRoutes.length >= 1) {
-          res = [...res, ...tempRoutes]
-        }
-      }
-    }
-    return res
-  }
-
-  const change = (val) => {
-    if (val) {
-      router.push({
-        path: val,
-      })
-    }
-    options.value = []
-    search.value = ''
-    isShowSearch.value = false
-  }
-  onMounted(() => {
-    searchPool.value = generateRoutes(JSON.parse(JSON.stringify(routes.value)))
-  })
-
-  const querySearch = (query) => {
-    if (query !== '') {
-      options.value = fuse.value.search(query)
-    } else {
-      options.value = []
-    }
-  }
-</script>
-
-<style lang="scss" scoped>
-  .m-headerSearch {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    cursor: pointer;
-    transition: all 0.3s;
-    .item-info-pop {
-      display: flex;
-      align-items: center;
-    }
-    .bell {
-      color: black;
-    }
-    .item-child {
-      display: flex;
-      align-items: center;
-      font-size: 13px;
-    }
-  }
-  .transverseMenu {
-    .bell {
-      color: white;
-    }
-  }
-  .header-search-select {
-  }
-  /* 菜单搜索样式 */
-  .m-headerSearch {
-    :deep(.el-dialog) {
-      .el-dialog__header {
-        display: none;
-      }
-      .el-dialog__body {
-        padding: 0;
-      }
-    }
-    .header-search-select {
-      height: 50px;
-      :deep(.el-input__wrapper) {
-        height: 50px;
-      }
-    }
-  }
-</style>

+ 0 - 13
src/layout/components/Header/components/Height.vue

@@ -1,13 +0,0 @@
-<template>
-  <div
-    v-if="themeConfig.fixedHeader"
-    :style="{ height: `${themeConfig.showTag ? 90 : 50}px` }"
-  ></div>
-</template>
-
-<script lang="ts" setup>
-  import { computed } from 'vue'
-  import { useSettingStore } from '@/store/modules/setting'
-  const SettingStore = useSettingStore()
-  const themeConfig = computed(() => SettingStore.themeConfig)
-</script>

+ 0 - 89
src/layout/components/Header/components/Language.vue

@@ -1,89 +0,0 @@
-<template>
-  <div class="m-screenful">
-    <el-dropdown trigger="click" class="language">
-      <span class="el-dropdown-link">
-        {{ langName }}
-        <el-icon class="el-icon--right">
-          <arrow-down />
-        </el-icon>
-      </span>
-      <template #dropdown>
-        <el-dropdown-menu>
-          <el-dropdown-item @click="SwitchLanguage('cn')">中文简体</el-dropdown-item>
-          <el-dropdown-item @click="SwitchLanguage('en')">English</el-dropdown-item>
-        </el-dropdown-menu>
-      </template>
-    </el-dropdown>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import { ArrowDown } from '@element-plus/icons-vue'
-  import axios from 'axios'
-  import { getCurrentInstance, onMounted, inject, ref } from 'vue'
-  import { useI18n } from 'vue-i18n'
-  const reload = inject('reload')
-  // 引入session
-  const session = inject('session')
-  const { locale } = useI18n()
-  const langs = {
-    cn: '中文简体',
-    en: 'English',
-  }
-  // vue3实例
-  const v3This = getCurrentInstance()
-  //显示语言
-  let langName = ref('')
-
-  // 切换显示语言
-  const SwitchLanguage = (lang) => {
-    if (lang != session.Get('lang')) {
-      switchLang(lang)
-    }
-  }
-  //修改语言
-  const switchLang = async (lang) => {
-    locale.value = lang
-    langName.value = langs[lang]
-    session.Set('lang', lang)
-    axios.defaults.headers.common['Language'] = sessionStorage.getItem('lang')
-    setTimeout(() => {
-      reload()
-    }, 800)
-  }
-
-  // 初始化显示语言
-  const initLanguage = () => {
-    console.log(v3This, 'this')
-    if (!session.Get('lang')) {
-      session.Set('lang', 'cn')
-    }
-    let lang = session.Get('lang') || 'cn'
-    locale.value = lang
-    langName.value = langs[lang]
-  }
-
-  onMounted(() => {
-    initLanguage()
-  })
-</script>
-
-<style lang="scss" scoped>
-  .m-screenful {
-    display: flex;
-    align-items: center;
-    padding-right: 0;
-    justify-content: center;
-    cursor: pointer;
-    transition: all 0.3s;
-    .language {
-      .el-dropdown-link {
-        background-color: rgba(247, 247, 250, 1);
-        border: none;
-        border-radius: 30px;
-        padding: 6px 20px;
-        cursor: pointer;
-      }
-    }
-  }
-</style>

+ 0 - 86
src/layout/components/Header/components/PersonalDialog.vue

@@ -1,86 +0,0 @@
-<template>
-  <el-dialog v-model="dialogVisible" title="修改密码" width="40%">
-    <el-form
-      ref="ruleFormRef"
-      :model="ruleForm"
-      :rules="rules"
-      label-width="120px"
-      class="demo-ruleForm"
-      :size="formSize"
-    >
-      <el-form-item label="姓名">
-        <el-input v-model="ruleForm.name" disabled></el-input>
-      </el-form-item>
-      <el-form-item label="旧的密码" prop="password">
-        <el-input v-model="ruleForm.password" type="password"></el-input>
-      </el-form-item>
-      <el-form-item label="新的密码" prop="configPassword">
-        <el-input v-model="ruleForm.configPassword" type="password"></el-input>
-      </el-form-item>
-    </el-form>
-    <template #footer>
-      <span class="dialog-footer">
-        <el-button @click="dialogVisible = false">取消</el-button>
-        <el-button type="primary" @click="submitForm(ruleFormRef)">确定</el-button>
-      </span>
-    </template>
-  </el-dialog>
-</template>
-
-<script lang="ts" setup>
-  import { ref, defineExpose, reactive } from 'vue'
-  import type { ElForm } from 'element-plus'
-  const dialogVisible = ref(false)
-  import { useUserStore } from '@/store/modules/user'
-  const UserStore = useUserStore()
-  const show = () => {
-    dialogVisible.value = true
-  }
-  const hide = () => {
-    dialogVisible.value = false
-  }
-  type FormInstance = InstanceType<typeof ElForm>
-
-  const formSize = ref('')
-  const ruleFormRef = ref<FormInstance>()
-  const ruleForm = reactive({
-    name: UserStore.userInfo.username,
-    password: UserStore.userInfo.password,
-    configPassword: '',
-  })
-  const rules = reactive({
-    configPassword: [
-      {
-        required: true,
-        message: '请输入新的密码',
-        trigger: 'blur',
-      },
-    ],
-  })
-  const submitForm = (formEl: FormInstance | undefined) => {
-    if (!formEl) return
-    formEl.validate((valid) => {
-      if (valid) {
-        console.log('submit!')
-      } else {
-        console.log('error submit!')
-        return false
-      }
-    })
-  }
-
-  const resetForm = (formEl: FormInstance | undefined) => {
-    if (!formEl) return
-    formEl.resetFields()
-  }
-
-  defineExpose({
-    show,
-  })
-</script>
-
-<style scoped>
-  .dialog-footer button:first-child {
-    margin-right: 10px;
-  }
-</style>

+ 0 - 93
src/layout/components/Header/components/Remind.vue

@@ -1,93 +0,0 @@
-<template>
-  <div class="m-info">
-    <el-popover width="200px" placement="bottom">
-      <template #reference>
-        <el-badge :value="3" class="item-info-pop">
-          <el-icon class="bell header-icon" style="font-size: 20px"><Bell /></el-icon>
-        </el-badge>
-      </template>
-      <div>
-        <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
-          <el-tab-pane label="通知" name="first">
-            <div class="item-child">
-              GitHub开源地址:
-              <el-button
-                type="primary"
-                link
-                @click="toGitHub('https://github.com/zouzhibin/vue-admin-perfect')"
-              >
-                点我
-              </el-button>
-            </div>
-            <el-divider style="margin-bottom: 15px" />
-            <div class="item-child">
-              Gitee开源地址:
-              <el-button
-                type="primary"
-                link
-                @click="toGitHub('https://gitee.com/yuanzbz/vue-admin-perfect')"
-              >
-                点我
-              </el-button>
-            </div>
-            <el-divider />
-            <div class="item-child">
-              github开源地址:
-              <el-button
-                type="primary"
-                link
-                @click="toGitHub('https://github.com/zouzhibin/vue-admin-perfect')"
-              >
-                点我
-              </el-button>
-            </div>
-          </el-tab-pane>
-        </el-tabs>
-      </div>
-    </el-popover>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import { ref } from 'vue'
-  import type { TabsPaneContext } from 'element-plus'
-
-  const activeName = ref('first')
-  const toGitHub = (link) => {
-    window.open(link)
-  }
-  const handleClick = (tab: TabsPaneContext, event: Event) => {
-    console.log(tab, event)
-  }
-</script>
-
-<style lang="scss" scoped>
-  .m-info {
-    display: inline-flex;
-    align-items: center;
-    justify-content: center;
-    cursor: pointer;
-    transition: all 0.3s;
-    .item-info-pop {
-      display: flex;
-      align-items: center;
-    }
-    .bell {
-      color: black;
-    }
-    .item-child {
-      display: flex;
-      align-items: center;
-      font-size: 13px;
-    }
-  }
-  ::v-deep(.el-divider--horizontal) {
-    margin-bottom: 10px;
-    margin-top: 10px;
-  }
-  .transverseMenu {
-    .bell {
-      color: white;
-    }
-  }
-</style>

+ 0 - 27
src/layout/components/Header/components/ScreenFull.vue

@@ -1,27 +0,0 @@
-<template>
-  <div class="m-screenful">
-    <el-tooltip effect="dark" content="全屏" placement="bottom">
-      <svg-icon
-        :icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'"
-        class-name="header-icon"
-        @click="toggle"
-      />
-    </el-tooltip>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import { useFullscreen } from '@vueuse/core'
-  const { toggle, isFullscreen } = useFullscreen()
-</script>
-
-<style lang="scss" scoped>
-  .m-screenful {
-    display: flex;
-    align-items: center;
-    padding-right: 0;
-    justify-content: center;
-    cursor: pointer;
-    transition: all 0.3s;
-  }
-</style>

+ 0 - 44
src/layout/components/Header/components/Setting.vue

@@ -1,44 +0,0 @@
-<template>
-  <div class="m-setting">
-    <el-tooltip effect="dark" content="主题设置" placement="bottom">
-      <el-icon style="font-size: 20px" class="bell header-icon">
-        <Setting @click="changeSwitch('showSetting', true)" />
-      </el-icon>
-    </el-tooltip>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import { useSettingStore } from '@/store/modules/setting'
-  const SettingStore = useSettingStore()
-  const changeSwitch = (key, val) => {
-    SettingStore.setThemeConfig({ key, val })
-  }
-</script>
-
-<style lang="scss" scoped>
-  .m-setting {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    cursor: pointer;
-    transition: all 0.3s;
-    .item-info-pop {
-      display: flex;
-      align-items: center;
-    }
-    .bell {
-      color: black;
-    }
-    .item-child {
-      display: flex;
-      align-items: center;
-      font-size: 13px;
-    }
-  }
-  .transverseMenu {
-    .bell {
-      color: white;
-    }
-  }
-</style>

+ 0 - 50
src/layout/components/Header/components/globalComSize.vue

@@ -1,50 +0,0 @@
-<template>
-  <el-dropdown trigger="hover" @command="setAssemblySize">
-    <svg-icon
-      class-name="size-icon header-icon"
-      icon-class="size"
-      style="font-size: 20px; cursor: pointer"
-    />
-    <template #dropdown>
-      <el-dropdown-menu>
-        <el-dropdown-item
-          v-for="item in assemblySizeList"
-          :key="item"
-          :disabled="globalComSize === item"
-          :command="item"
-        >
-          {{ assemblySizeListCh[item] }}
-        </el-dropdown-item>
-      </el-dropdown-menu>
-    </template>
-  </el-dropdown>
-</template>
-
-<script setup lang="ts">
-  import { reactive, computed } from 'vue'
-  import { useSettingStore } from '@/store/modules/setting'
-  const SettingStore = useSettingStore()
-
-  const globalComSize = computed((): string => SettingStore.themeConfig.globalComSize)
-
-  const assemblySizeListCh = reactive<{ [key: string]: any }>({
-    default: '默认',
-    large: '大型',
-    small: '小型',
-  })
-
-  const assemblySizeList = reactive<string[]>(['default', 'large', 'small'])
-
-  const setAssemblySize = (item: string) => {
-    if (globalComSize.value === item) return
-    SettingStore.setThemeConfig({ key: 'globalComSize', val: item })
-  }
-</script>
-
-<style scoped lang="scss">
-  .transverseMenu {
-    .size-icon {
-      color: white;
-    }
-  }
-</style>

+ 0 - 39
src/layout/components/Main/index.vue

@@ -1,39 +0,0 @@
-<template>
-  <div class="app-main">
-    <router-view v-slot="{ Component, route }">
-      <transition name="fade-slide" mode="out-in" appear>
-        <keep-alive v-if="isReload" :include="cacheRoutes">
-          <component :is="useWrapComponents(Component, route)" :key="route.path" />
-        </keep-alive>
-      </transition>
-    </router-view>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import { useWrapComponents } from '@/hooks/useWrapComponents'
-  import { computed, ref } from 'vue'
-  import { useSettingStore } from '@/store/modules/setting'
-  import { usePermissionStore } from '@/store/modules/permission'
-  const SettingStore = useSettingStore()
-  const PermissionStore = usePermissionStore()
-  const cacheRoutes = computed(() => PermissionStore.keepAliveRoutes)
-  const isReload = computed(() => SettingStore.isReload)
-</script>
-
-<style lang="scss" scoped>
-  .app-main {
-    flex: 1;
-    display: flex;
-    overflow-x: hidden;
-    width: 100%;
-    box-sizing: border-box;
-    .app-main-inner {
-      flex: 1;
-      display: flex;
-      overflow-x: hidden;
-      width: 100%;
-      box-sizing: border-box;
-    }
-  }
-</style>

+ 0 - 22
src/layout/components/Mobile/index.vue

@@ -1,22 +0,0 @@
-<template>
-  <div v-if="device === 'mobile' && !isCollapse" class="drawer-bg" @click="handleClickOutside" />
-</template>
-
-<script lang="ts" setup>
-  import { computed } from 'vue'
-  import { useResizeHandler } from '@/hooks/useResizeHandler'
-  import { useSettingStore } from '@/store/modules/setting'
-
-  let { device } = useResizeHandler()
-  const SettingStore = useSettingStore()
-
-  // 是否折叠
-  const isCollapse = computed(() => !SettingStore.isCollapse)
-
-  // 移动端点击
-  const handleClickOutside = () => {
-    SettingStore.closeSideBar({ withoutAnimation: false })
-  }
-</script>
-
-<style lang="scss" scoped></style>

+ 0 - 57
src/layout/components/Sidebar/components/Logo.vue

@@ -1,57 +0,0 @@
-<template>
-  <div class="sidebar-logo-container">
-    <transition name="sidebarLogoFadeCl">
-      <router-link v-if="isCollapse" key="collapse" class="sidebar-logo-link" to="/">
-        <img src="@/assets/image/logo.png" class="sidebar-logo" />
-      </router-link>
-      <router-link v-else key="expand" class="sidebar-logo-link" to="/">
-        <img src="@/assets/image/logo.png" class="sidebar-logo" />
-        <h1 class="sidebar-title">Vue Admin Perfect</h1>
-      </router-link>
-    </transition>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  defineProps<{ isCollapse: boolean }>()
-</script>
-
-<style lang="scss" scoped>
-  .sidebarLogoFadeCl-enter-active {
-    transition: opacity 2s;
-  }
-  .sidebarLogoFadeCl-enter-from,
-  .sidebarLogoFadeCl-leave-to {
-    opacity: 0;
-  }
-  .sidebar-logo-container {
-    position: relative;
-    width: 100%;
-    height: 50px;
-    line-height: 50px;
-    background: #2b2f3a;
-    text-align: center;
-    overflow: hidden;
-
-    & .sidebar-logo-link {
-      height: 100%;
-      width: 100%;
-
-      & .sidebar-logo {
-        width: 32px;
-        height: 32px;
-        vertical-align: middle;
-      }
-      & .sidebar-title {
-        display: inline-block;
-        margin: 0;
-        color: #fff;
-        font-weight: 600;
-        margin-left: 12px;
-        line-height: 50px;
-        font-size: 14px;
-        vertical-align: middle;
-      }
-    }
-  }
-</style>

+ 0 - 54
src/layout/components/Sidebar/index.vue

@@ -1,54 +0,0 @@
-<template>
-  <div class="sidebar-container" :class="{ 'has-logo': themeConfig.showLogo }">
-    <Logo v-if="themeConfig.showLogo" :is-collapse="isCollapse" />
-    <el-scrollbar wrap-class="scrollbar-wrapper">
-      <el-menu
-        :default-active="activeMenu"
-        background-color="#304156"
-        text-color="#bfcbd9"
-        :unique-opened="SettingStore.themeConfig.uniqueOpened"
-        :collapse-transition="false"
-        class="el-menu-vertical-demo"
-        :collapse="isCollapse"
-      >
-        <SubItem v-for="route in permission_routes" :key="route.path" :item="route" />
-      </el-menu>
-    </el-scrollbar>
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import Logo from './components/Logo.vue'
-  import SubItem from '../SubMenu/SubItem.vue'
-  import { useSettingStore } from '@/store/modules/setting'
-  import { usePermissionStore } from '@/store/modules/permission'
-  import { computed } from 'vue'
-  import { useRoute } from 'vue-router'
-
-  // 在setup中获取store
-  const route = useRoute()
-  const PermissionStore = usePermissionStore()
-  const SettingStore = useSettingStore()
-
-  // 是否折叠
-  const isCollapse = computed(() => !SettingStore.isCollapse)
-  // 设置
-  const themeConfig = computed(() => SettingStore.themeConfig)
-
-  // 获取路由
-  const permission_routes = computed(() => PermissionStore.permission_routes)
-
-  const activeMenu = computed(() => {
-    const { meta, path } = route
-    if (meta.activeMenu) {
-      return meta.activeMenu
-    }
-    return path
-  })
-</script>
-
-<style lang="scss">
-  .el-menu-vertical-demo:not(.el-menu--collapse) {
-    height: 100%;
-  }
-</style>

+ 0 - 49
src/layout/components/SubMenu/Link.vue

@@ -1,49 +0,0 @@
-<template>
-  <component :is="type" v-bind="linkProps(to)">
-    <slot />
-  </component>
-</template>
-
-<script lang="ts">
-  import { isExternal } from '@/utils/validate.js'
-
-  export default {
-    props: {
-      to: {
-        type: String,
-        required: true,
-      },
-    },
-    computed: {
-      isExternal() {
-        return isExternal(this.to)
-      },
-      type() {
-        if (this.isExternal) {
-          return 'a'
-        }
-        return 'router-link'
-      },
-    },
-    methods: {
-      linkProps(to) {
-        if (this.isExternal) {
-          return {
-            href: to,
-            target: '_blank',
-            rel: 'noopener',
-          }
-        }
-        return {
-          to: to,
-        }
-      },
-    },
-  }
-</script>
-
-<style lang="scss" scoped>
-  a {
-    text-decoration: none;
-  }
-</style>

+ 0 - 33
src/layout/components/SubMenu/MenuItem.vue

@@ -1,33 +0,0 @@
-<template>
-  <el-menu-item :index="subItem.path" @click="handleClickMenu(subItem)">
-    <el-icon>
-      <component :is="subItem?.meta?.icon"></component>
-    </el-icon>
-    <template #title>
-      <span>{{ subItem?.meta?.title }}</span>
-    </template>
-  </el-menu-item>
-</template>
-
-<script setup lang="ts">
-  import { ref } from 'vue'
-  import { useRouter } from 'vue-router'
-  import { isExternal } from '@/utils/validate'
-
-  const router = useRouter()
-  let props = defineProps({
-    menuList: {
-      type: Array,
-      default: () => [],
-    },
-    subItem: {
-      type: Object,
-      default: () => {},
-    },
-  })
-
-  const handleClickMenu = (subItem) => {
-    if (isExternal(subItem.path)) return window.open(subItem.path, '_blank')
-    router.push(subItem.path)
-  }
-</script>

+ 0 - 74
src/layout/components/SubMenu/SubItem.vue

@@ -1,74 +0,0 @@
-<template>
-  <template v-if="!item.hidden">
-    <template v-if="!item.alwaysShow && hasOneShowingChild(item.children, item)">
-      <app-link v-if="onlyOneChild.meta" :to="onlyOneChild.path">
-        <el-menu-item :index="onlyOneChild.path">
-          <el-icon :size="20">
-            <component :is="onlyOneChild?.meta.icon"></component>
-          </el-icon>
-          <template #title>{{ onlyOneChild.meta && onlyOneChild.meta.title }}</template>
-        </el-menu-item>
-      </app-link>
-    </template>
-    <el-sub-menu v-else :index="item.path" teleported>
-      <template #title>
-        <el-icon :size="20"><component :is="item.meta?.icon"></component></el-icon>
-        <span>{{ item.meta && item.meta.title }}</span>
-      </template>
-      <sub-item v-for="child in item.children" :key="child.path" :item="child" />
-    </el-sub-menu>
-  </template>
-</template>
-
-<script lang="ts" setup>
-  import { isExternal } from '@/utils/validate.js'
-  import AppLink from './Link.vue'
-  import path from 'path-browserify'
-  import { ref, computed } from 'vue'
-  const props = defineProps({
-    item: {
-      type: Object,
-      required: true,
-    },
-    basePath: {
-      type: String,
-      default: '',
-    },
-  })
-
-  const onlyOneChild = ref(null)
-  const hasOneShowingChild = (children = [], parent) => {
-    const showingChildren = children.filter((item) => {
-      // 过滤掉需要隐藏的菜单
-      if (item.hidden) {
-        return false
-      } else {
-        // 临时设置(如果只有一个显示子项,则将使用)
-        onlyOneChild.value = item
-        return true
-      }
-    })
-
-    // 当只有一个子路由器时,默认情况下会显示该子路由器
-    if (showingChildren.length === 1) {
-      return true
-    }
-    // 如果没有要显示的子路由器,则显示父路由器
-    if (showingChildren.length === 0) {
-      onlyOneChild.value = { ...parent, noShowingChildren: true }
-      return true
-    }
-
-    return false
-  }
-
-  const resolvePath = (routePath) => {
-    if (isExternal(routePath)) {
-      return routePath
-    }
-    if (isExternal(props.basePath)) {
-      return props.basePath
-    }
-    return path.resolve(props.basePath, routePath)
-  }
-</script>

+ 0 - 51
src/layout/components/SubMenu/SubMenu.vue

@@ -1,51 +0,0 @@
-<template>
-  <template v-for="subItem in menuList" :key="subItem.path">
-    <template v-if="!subItem.hidden">
-      <template v-if="!subItem.alwaysShow && hasOneChild(subItem.children, subItem)">
-        <MenuItem :sub-item="hasOneChild(subItem.children, subItem)" />
-      </template>
-      <el-sub-menu v-else :index="subItem.path">
-        <template #title>
-          <el-icon>
-            <component :is="subItem?.meta?.icon"></component>
-          </el-icon>
-          <span>{{ subItem?.meta?.title }}</span>
-        </template>
-        <SubMenu :menu-list="subItem.children" />
-      </el-sub-menu>
-    </template>
-  </template>
-</template>
-
-<script setup lang="ts">
-  import { ref } from 'vue'
-  import MenuItem from './MenuItem.vue'
-
-  let props = defineProps({
-    menuList: {
-      type: Array,
-      default: () => [],
-    },
-  })
-
-  const hasOneChild = (children = [], parent) => {
-    const showingChildren = children.filter((item) => {
-      // 过滤掉需要隐藏的菜单
-      if (item.hidden) {
-        return false
-      } else {
-        return true
-      }
-    })
-    // 当只有一个子路由器时,默认情况下会显示该子路由器
-    if (showingChildren.length === 1) {
-      // (如果只有一个显示子项,则将使用)
-      return showingChildren[0]
-    }
-    // 如果没有要显示的子路由器,则显示父路由器
-    if (showingChildren.length === 0) {
-      return parent
-    }
-    return false
-  }
-</script>

+ 0 - 67
src/layout/components/TagsView/components/MoreButton.vue

@@ -1,67 +0,0 @@
-<template>
-  <el-dropdown trigger="hover">
-    <el-button size="small" type="primary">
-      <span>更多</span>
-      <el-icon class="el-icon--right"><arrow-down /></el-icon>
-    </el-button>
-    <template #dropdown>
-      <el-dropdown-menu>
-        <el-dropdown-item @click="refresh">
-          <el-icon :size="14"><Refresh /></el-icon>
-          刷新当页
-        </el-dropdown-item>
-        <el-dropdown-item @click="closeCurrentTab">
-          <el-icon :size="14"><FolderRemove /></el-icon>
-          关闭当前
-        </el-dropdown-item>
-        <el-dropdown-item @click="closeOtherTab">
-          <el-icon :size="14"><Close /></el-icon>
-          关闭其他
-        </el-dropdown-item>
-        <el-dropdown-item @click="closeAllTab">
-          <el-icon :size="14"><FolderDelete /></el-icon>
-          关闭所有
-        </el-dropdown-item>
-      </el-dropdown-menu>
-    </template>
-  </el-dropdown>
-</template>
-<script lang="ts" setup>
-  import { computed } from 'vue'
-  import { useSettingStore } from '@/store/modules/setting'
-  import { useTagsViewStore } from '@/store/modules/tagsView'
-  import { useRouter, useRoute } from 'vue-router'
-  const router = useRouter()
-  const route = useRoute()
-  const SettingStore = useSettingStore()
-  const TagsViewStore = useTagsViewStore()
-  const visitedViews = computed(() => TagsViewStore.visitedViews)
-  const refresh = () => {
-    SettingStore.setReload()
-  }
-  // 关闭当前
-  const closeCurrentTab = (event) => {
-    TagsViewStore.toLastView(route.path)
-    TagsViewStore.delView(route.path)
-  }
-  // 关闭其他
-  const closeOtherTab = async () => {
-    TagsViewStore.delOtherViews(route.path)
-  }
-
-  // 关闭所有 去首页
-  const closeAllTab = async () => {
-    await TagsViewStore.delAllViews()
-    TagsViewStore.goHome()
-  }
-</script>
-<style lang="scss" scoped>
-  .more {
-    background-color: $primaryColor;
-    color: white;
-    .tags-view-item {
-      display: flex;
-      align-items: center;
-    }
-  }
-</style>

+ 0 - 162
src/layout/components/TagsView/index.vue

@@ -1,162 +0,0 @@
-<template>
-  <div class="m-tags-view">
-    <div class="tags-view">
-      <el-tabs v-model="activeTabsValue" type="card" @tab-click="tabClick" @tab-remove="removeTab">
-        <el-tab-pane
-          v-for="item in visitedViews"
-          :key="item.path"
-          :path="item.path"
-          :label="item.title"
-          :name="item.path"
-          :closable="!(item.meta && item.meta.affix)"
-        >
-          <template #label>
-            <el-icon v-if="item.icon" class="tabs-icon">
-              <component :is="item.icon"></component>
-            </el-icon>
-            {{ item.title }}
-          </template>
-        </el-tab-pane>
-      </el-tabs>
-    </div>
-    <div class="right-btn">
-      <MoreButton />
-    </div>
-  </div>
-</template>
-<script lang="ts" setup>
-  import { computed, watch, ref, onMounted } from 'vue'
-  import { useRoute, useRouter } from 'vue-router'
-  import { TabsPaneContext } from 'element-plus'
-  import MoreButton from './components/MoreButton'
-  import path from 'path-browserify'
-  import { useTagsViewStore } from '@/store/modules/tagsView'
-  import { usePermissionStore } from '@/store/modules/permission'
-
-  const route = useRoute()
-  const router = useRouter()
-  const TagsViewStore = useTagsViewStore()
-  const PermissionStore = usePermissionStore()
-  const visitedViews = computed(() => TagsViewStore.visitedViews)
-  const routes = computed(() => PermissionStore.routes)
-
-  const addTags = () => {
-    const { name } = route
-    if (name === 'Login') {
-      return
-    }
-    if (name) {
-      TagsViewStore.addView(route)
-    }
-    return false
-  }
-  let affixTags = ref([])
-  function filterAffixTags(routes, basePath = '/') {
-    let tags = []
-    routes.forEach((route) => {
-      if (route.meta && route.meta.affix) {
-        const tagPath = path.resolve(basePath, route.path)
-        tags.push({
-          fullPath: tagPath,
-          path: tagPath,
-          name: route.name,
-          meta: { ...route.meta },
-        })
-      }
-      if (route.children) {
-        const tempTags = filterAffixTags(route.children, route.path)
-        if (tempTags.length >= 1) {
-          tags = [...tags, ...tempTags]
-        }
-      }
-    })
-    return tags
-  }
-  const initTags = () => {
-    let routesNew = routes.value
-    let affixTag = (affixTags.value = filterAffixTags(routesNew))
-    for (const tag of affixTag) {
-      if (tag.name) {
-        TagsViewStore.addVisitedView(tag)
-      }
-    }
-  }
-  onMounted(() => {
-    initTags()
-    addTags()
-  })
-  watch(route, () => {
-    addTags()
-  })
-  let tabIndex = 2
-  const activeTabsValue = computed({
-    get: () => {
-      return TagsViewStore.activeTabsValue
-    },
-    set: (val) => {
-      TagsViewStore.setTabsMenuValue(val)
-    },
-  })
-  function toLastView(activeTabPath) {
-    let index = visitedViews.value.findIndex((item) => item.path === activeTabPath)
-    const nextTab = visitedViews.value[index + 1] || visitedViews.value[index - 1]
-    if (!nextTab) return
-    router.push(nextTab.path)
-    TagsViewStore.addVisitedView(nextTab)
-  }
-  const tabClick = (tabItem: TabsPaneContext) => {
-    let path = tabItem.props.name as string
-    router.push(path)
-  }
-
-  const isActive = (path) => {
-    return path === route.path
-  }
-  const removeTab = async (activeTabPath: string) => {
-    if (isActive(activeTabPath)) {
-      toLastView(activeTabPath)
-    }
-    await TagsViewStore.delView(activeTabPath)
-  }
-</script>
-<style lang="scss" scoped>
-  .m-tags-view {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    padding-left: 10px;
-    padding-right: 10px;
-    background: white;
-    .right-btn {
-      height: 100%;
-      flex-shrink: 0;
-    }
-  }
-  .tags-view {
-    flex: 1;
-    overflow: hidden;
-    box-sizing: border-box;
-  }
-
-  .tags-view {
-    .el-tabs--card :deep(.el-tabs__header) {
-      box-sizing: border-box;
-      height: 40px;
-      padding: 0 10px;
-      margin: 0;
-    }
-    :deep(.el-tabs) {
-      .el-tabs__nav {
-        border: none;
-      }
-      .el-tabs__header .el-tabs__item {
-        border: none;
-        color: #cccccc;
-      }
-      .el-tabs__header .el-tabs__item.is-active {
-        color: $primaryColor;
-        border-bottom: 2px solid $primaryColor;
-      }
-    }
-  }
-</style>

+ 0 - 85
src/layout/index.vue

@@ -1,85 +0,0 @@
-<template>
-  <div class="g-container-layout" :class="classObj">
-    <Mobile />
-    <LayoutVertical v-if="device === 'mobile'" />
-    <component :is="LayoutComponents[themeConfig.mode]" v-else />
-    <Theme />
-  </div>
-</template>
-
-<script lang="ts" setup>
-  import { computed, watch } from 'vue'
-  import Theme from '@/components/Theme/index.vue'
-  import Mobile from './components/Mobile/index.vue'
-  import { useSettingStore } from '@/store/modules/setting'
-  import { useResizeHandler } from '@/hooks/useResizeHandler'
-  import LayoutVertical from './LayoutVertical/index.vue'
-  import LayoutHorizontal from './LayoutHorizontal/index.vue'
-  import LayoutColumns from './LayoutColumns/index.vue'
-
-  const SettingStore = useSettingStore()
-  const themeConfig = computed(() => SettingStore.themeConfig)
-  const LayoutComponents = {
-    horizontal: LayoutHorizontal,
-    vertical: LayoutVertical,
-    columns: LayoutColumns,
-  }
-
-  // 是否折叠
-  const isCollapse = computed(() => {
-    return !SettingStore.isCollapse
-  })
-  let { device } = useResizeHandler()
-
-  watch(
-    () => device.value,
-    (val) => {
-      let vertical = val === 'mobile' ? 'vertical' : themeConfig.value.mode
-      const body = document.body as HTMLElement
-      body.setAttribute('class', `layout-${vertical}`)
-    },
-    {
-      immediate: true,
-    }
-  )
-
-  // 当屏幕切换的时候进行变换
-  const classObj = computed(() => {
-    return {
-      hideSidebar: !SettingStore.isCollapse,
-      openSidebar: SettingStore.isCollapse,
-      withoutAnimation: SettingStore.withoutAnimation,
-      mobile: device.value === 'mobile',
-    }
-  })
-</script>
-
-<style lang="scss" scoped>
-  .g-container-layout {
-    height: 100%;
-    width: 100%;
-    .main-container {
-      display: flex;
-      flex: 1;
-      box-sizing: border-box;
-      flex-direction: column;
-    }
-    &.mobile.openSidebar {
-      position: fixed;
-      top: 0;
-    }
-  }
-  .sidebar-container {
-    display: flex;
-    flex-direction: column;
-  }
-  .drawer-bg {
-    background: #000;
-    opacity: 0.3;
-    width: 100%;
-    top: 0;
-    height: 100%;
-    position: absolute;
-    z-index: 90;
-  }
-</style>

+ 18 - 16
src/routers/modules/uCard.ts

@@ -40,22 +40,24 @@ const uCardRoute = {
     //     name: 'R-CardOperate',
     //     component: () => import(/* webpackChunkName: "CardOperate" */ '@/views/card/CardOperate.vue'),
     //   },
-    //   {
-    //     meta: {
-    //       OnBreadCrumb: true,
-    //     },
-    //     path: 'userOrder',
-    //     name: 'R-UserOrder',
-    //     component: () => import(/* webpackChunkName: "UserOrder" */ '@/views/card/UserOrder.vue'),
-    //   },
-    //   {
-    //     meta: {
-    //       OnBreadCrumb: true,
-    //     },
-    //     path: 'userRights',
-    //     name: 'R-UserRights',
-    //     component: () => import(/* webpackChunkName: "UserRights" */ '@/views/card/UserRights.vue'),
-    //   },
+    {
+      meta: {
+        OnBreadCrumb: true,
+      },
+      path: 'userOrder',
+      name: 'R-UserOrder',
+      component: () =>
+        import(/* webpackChunkName: "UserOrder" */ '@/views/card/CardUserOrder/index.vue'),
+    },
+    {
+      meta: {
+        OnBreadCrumb: true,
+      },
+      path: 'userRights',
+      name: 'R-UserRights',
+      component: () =>
+        import(/* webpackChunkName: "UserRights" */ '@/views/card/CardUserRights/index.vue'),
+    },
     //   {
     //     meta: {
     //       OnBreadCrumb: true,

+ 24 - 0
src/service/ucard.ts

@@ -203,6 +203,30 @@ class UCardService extends Service {
   async globalCurrenciesList(params = {}) {
     return await this.post('/wasabi/global/currencies/list', params)
   }
+  // 钱包记录分页列表
+  async getRecordPage(params = {}) {
+    return await this.post('/wasabi/card/wallet/record/page', params)
+  }
+  // 手机区号获取
+  async countryGet(params = {}) {
+    return await this.post('/country/get', params)
+  }
+  // 正则更新删除
+  async permissionDelete(params = {}) {
+    return await this.post('/wasabi/card/permission/delete', params)
+  }
+  // 正则更新
+  async permissionUpdate(params = {}) {
+    return await this.post('/wasabi/card/permission/update', params)
+  }
+  // 正则add
+  async permissionAdd(params = {}) {
+    return await this.post('/wasabi/card/permission/add', params)
+  }
+  // 正则列表
+  async permissionPage(params = {}) {
+    return await this.post('/wasabi/card/permission/page', params)
+  }
 }
 
 export default new UCardService()

+ 6 - 1
src/styles/cwg_common.scss

@@ -462,7 +462,7 @@ a {
         flex-wrap: wrap;
 
         .el-date-editor {
-          top: 1px;
+          //top: 1px;
         }
       }
     }
@@ -1056,3 +1056,8 @@ input[type="number"] {
 .div-hidden{
   display: none !important;
 }
+.el-input.el-input--default.el-input--suffix {
+  // 固定宽度
+
+  width: 192px !important;
+}

+ 22 - 0
src/utils/getStatusColor.ts

@@ -0,0 +1,22 @@
+/**
+ * 根据状态获取文字样式
+ * @param status
+ */
+export const getStatusColor = (status = '') => {
+  let color = 'crm_state_blue'
+  switch (status) {
+    case 'wait_process':
+      color = 'crm_state_yellow'
+      break
+    case 'processing':
+      color = 'crm_state_orange'
+      break
+    case 'success':
+      color = 'crm_state_blue'
+      break
+    case 'fail':
+      color = 'crm_state_gray'
+      break
+  }
+  return `state ${color}`
+}

+ 28 - 0
src/views/card/CardTransactions/const.ts

@@ -0,0 +1,28 @@
+export const searchTagOptions = [
+  { label: 'Label.CidAccount', value: 1 },
+  { label: 'Ucard.KycAuth.item2', value: 2 },
+  { label: 'Ucard.KycAuth.item3', value: 3 },
+  { label: 'Ucard.Transactions.s2', value: 5 },
+]
+export const transactionTypeOptions = [
+  { label: 'Ucard.Transactions.t1', value: 'auth' },
+  { label: 'Ucard.Transactions.t2', value: 'refund' },
+  { label: 'Ucard.Transactions.t3', value: 'verification' },
+  { label: 'Ucard.Transactions.t4', value: 'Void' },
+  { label: 'Ucard.Transactions.t5', value: 'maintain_fee' },
+]
+export const statusOptions = [
+  { label: 'Ucard.Transactions.t18', value: 'success' },
+  { label: 'Ucard.Transactions.t25', value: 'fail' },
+  { label: 'card.Status.t5', value: 'wait_process' },
+  { label: 'card.Status.t3', value: 'processing' },
+  { label: 'Ucard.Transactions.t24', value: 'authorized' },
+]
+
+export const transactionTypeMap = {
+  auth: 'Ucard.Transactions.t1',
+  refund: 'Ucard.Transactions.t2',
+  verification: 'Ucard.Transactions.t3',
+  Void: 'Ucard.Transactions.t4',
+  maintain_fee: 'Ucard.Transactions.t5',
+}

+ 127 - 119
src/views/card/CardTransactions/index.vue

@@ -3,7 +3,8 @@
     id="review_Email"
     v-loading="pictLoading"
     class="view"
-    :element-loading-background="loadingBackground"
+    element-loading-background="rgba(43, 48, 67, 0.65)"
+    element-loading-spinner="el-icon-loading"
   >
     <div class="crm_search">
       <el-form ref="formRef" label-position="" :model="search" label-width="">
@@ -15,10 +16,12 @@
                 class="crm_search_down crm-border-radius-no"
                 :placeholder="$t('Placeholder.Choose')"
               >
-                <el-option :label="$t('Label.CidAccount')" :value="1"></el-option>
-                <el-option :label="$t('Ucard.KycAuth.item2')" :value="2"></el-option>
-                <el-option :label="$t('Ucard.KycAuth.item3')" :value="3"></el-option>
-                <el-option :label="$t('Ucard.Transactions.s2')" :value="5"></el-option>
+                <el-option
+                  v-for="option in searchTagOptions"
+                  :key="option.value"
+                  :label="$t(option.label)"
+                  :value="option.value"
+                ></el-option>
               </el-select>
             </el-form-item>
             <el-form-item style="margin-right: 10px">
@@ -55,17 +58,6 @@
                 :placeholder="$t('Placeholder.Input')"
                 @keyup.enter="toSearch"
               ></el-input>
-              <el-select
-                v-if="search.tag == 7"
-                v-model="search.dataType"
-                class="crm-border-left-no crm-border-radius-no"
-                clearable
-                :placeholder="$t('Placeholder.Choose')"
-                @change="toSearch"
-              >
-                <el-option value="A" :label="$t('Ucard.Transactions.t1')"></el-option>
-                <el-option value="S" :label="$t('Ucard.Transactions.t17')"></el-option>
-              </el-select>
             </el-form-item>
             <el-form-item style="margin-right: 10px">
               <el-input
@@ -84,12 +76,12 @@
                 :placeholder="$t('Ucard.Transactions.s3')"
                 @change="toSearch"
               >
-                <el-option value="auth" :label="$t('Ucard.Transactions.t1')"></el-option>
-                <el-option value="refund" :label="$t('Ucard.Transactions.t2')"></el-option>
-                <el-option value="verification" :label="$t('Ucard.Transactions.t3')"></el-option>
-                <el-option value="Void" :label="$t('Ucard.Transactions.t4')"></el-option>
-                <el-option value="withdraw" :label="$t('R-VirtualCard-Btn11')"></el-option>
-                <el-option value="maintain_fee" :label="$t('Ucard.Transactions.t5')"></el-option>
+                <el-option
+                  v-for="option in transactionTypeOptions"
+                  :key="option.value"
+                  :label="$t(option.label)"
+                  :value="option.value"
+                ></el-option>
               </el-select>
             </el-form-item>
             <el-form-item>
@@ -100,11 +92,12 @@
                 :placeholder="$t('Ucard.Transactions.s5')"
                 @change="toSearch"
               >
-                <el-option value="success" :label="$t('Ucard.Transactions.t18')"></el-option>
-                <el-option value="fail" :label="$t('Ucard.Transactions.t25')"></el-option>
-                <el-option value="wait_process" :label="$t('card.Status.t5')"></el-option>
-                <el-option value="processing" :label="$t('card.Status.t3')"></el-option>
-                <el-option value="authorized" :label="$t('Ucard.Transactions.t24')"></el-option>
+                <el-option
+                  v-for="option in statusOptions"
+                  :key="option.value"
+                  :label="$t(option.label)"
+                  :value="option.value"
+                ></el-option>
               </el-select>
             </el-form-item>
             <el-form-item>
@@ -143,9 +136,9 @@
               <span v-if="scope.row.firstName">{{ scope.row.firstName + ' ' }}</span>
               <span v-if="scope.row.middle">{{ scope.row.middle + ' ' }}</span>
               <span v-if="scope.row.lastName">{{ scope.row.lastName }}</span>
-              <span v-if="!scope.row.firstName && !scope.row.lastName && !scope.row.middle"
-                >--</span
-              >
+              <span v-if="!scope.row.firstName && !scope.row.lastName && !scope.row.middle">{{
+                '--'
+              }}</span>
             </template>
           </el-table-column>
           <el-table-column prop="" align="left" :label="$t('Label.Email')">
@@ -174,16 +167,9 @@
           <el-table-column prop="tradeNo" align="left" :label="$t('Ucard.Transactions.item8')" />
           <el-table-column prop="type" align="left" :label="$t('Ucard.Transactions.item9')">
             <template #default="scope">
-              <span v-if="scope.row.type === 'auth'">{{ $t('Ucard.Transactions.t1') }}</span>
-              <span v-else-if="scope.row.type === 'refund'">{{ $t('Ucard.Transactions.t2') }}</span>
-              <span v-else-if="scope.row.type === 'verification'">{{
-                $t('Ucard.Transactions.t3')
-              }}</span>
-              <!--              <span v-else-if="scope.row.type === 'auth'">{{ $t('Ucard.Transactions.t4') }}</span>-->
-              <span v-else-if="scope.row.type === 'withdraw'">{{ $t('R-VirtualCard-Btn11') }}</span>
-              <span v-else-if="scope.row.type === 'maintain_fee'">{{
-                $t('Ucard.Transactions.t5')
-              }}</span>
+              <span>
+                {{ $t(transactionTypeMap[scope.row.type]) }}
+              </span>
             </template>
           </el-table-column>
           <el-table-column prop="status" align="left" :label="$t('Ucard.Transactions.item11')">
@@ -222,7 +208,7 @@
                       :command="{ type: 1, row: scope.row }"
                     >
                       <el-icon><Operation /></el-icon>
-                      <span>{{ $t('R-Hire-Check') }}</span>
+                      {{ $t('R-Hire-Check') }}
                     </el-dropdown-item>
                   </el-dropdown-menu>
                 </template>
@@ -232,24 +218,11 @@
         </el-table>
       </div>
     </div>
-    <div v-if="pagerInfo.rowTotal" class="crm_pagination">
-      <div class="crm_page_total">
-        <span>{{ $t('Page.total.item1') }}</span>
-        <span>{{ pagerInfo.rowTotal }}</span>
-        <span>{{ $t('Page.total.item2') }}</span>
-      </div>
-      <el-pagination
-        class="page"
-        background
-        layout="sizes, prev, pager, next"
-        :page-sizes="[10, 20, 50, 100]"
-        :page-size="pagerInfo.row"
-        :total="pagerInfo.rowTotal"
-        @current-change="handleCurrentChange"
-        @size-change="handleSizeChange"
-      >
-      </el-pagination>
-    </div>
+    <PagePagination
+      :pager-info="pagerInfo"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange"
+    />
     <detailed-info-cid
       :dialog-info-cid="dialogInfoCid"
       :form-info="formInfo"
@@ -270,30 +243,35 @@
 </template>
 
 <script setup>
-  import { ref, reactive, computed, onMounted, watch, inject } from 'vue'
+  import { ref, reactive, computed, watch, onMounted, inject } from 'vue'
   import { useRouter } from 'vue-router'
+  import { ElMessage } from 'element-plus'
   import Service from '@/service/ucard'
-  import Config from '@/config/index'
+  import Config from '@/config'
   import Service1 from '@/service/customer'
-  import { Operation, Search } from '@element-plus/icons-vue'
-  import { useI18n } from 'vue-i18n'
-  import DetailedInfoCid from '@/views/components/DetailedInfoCid'
-  import ViewCardSingle from '@/views/components/ViewCardSingle'
+  import PagePagination from '@/components/pagePagination/index.vue'
+  import DetailedInfoCid from '@/views/components/DetailedInfoCid/index.vue'
+  import ViewCardSingle from '@/views/components/ViewCardSingle/index.vue'
   import { exportExcel } from '@/utils/export'
+  import {
+    searchTagOptions,
+    statusOptions,
+    transactionTypeMap,
+    transactionTypeOptions,
+  } from '@/views/card/CardTransactions/const'
+  import { Operation } from '@element-plus/icons-vue'
+  import { useI18n } from 'vue-i18n'
 
+  const { Code } = Config
   const { t } = useI18n()
-  const router = useRouter()
   const Session = inject('session')
-  const pigeon = inject('pigeon')
-  const { Code } = Config
+  const router = useRouter()
 
   // 响应式数据
   const pictLoading = ref(false)
   const dialogInfoTradingSingle = ref(false)
   const formSingle = ref({})
   const editorType = ref(4)
-  const formRef = ref(null)
-
   const search = reactive({
     tag: 1,
     mobile: '',
@@ -305,13 +283,12 @@
     dataType: '',
     status: '',
   })
-
   const mock_tableData = ref([])
   const pagerInfo = reactive({ row: 10, current: 1, pageTotal: 0, rowTotal: 0 })
   const dialogInfoCid = ref(false)
   const formInfo = ref({})
 
-  const loadingBackground = 'rgba(43, 48, 67, 0.65)'
+  const formRef = ref()
 
   // 计算属性
   const display = computed(() => {
@@ -319,42 +296,42 @@
   })
 
   // 方法
+  // 导出
   const exportAgents = async () => {
-    exportExcel(
-      pigeon,
-      '/wasabi/card/transac/record/export',
-      { ...search },
-      'Bank_Card_Transactions'
-    )
+    exportExcel('/wasabi/card/transac/record/export', { ...search }, 'Bank_Card_Transactions')
   }
-  //银行卡详情
+
+  // 银行卡详情
   const cardOpen = (cardNumber) => {
     router.push({ name: 'R-CardDetail', params: { cardNumber: cardNumber } })
   }
-  //详细信息cid 大概不要了
+
+  // 详细信息cid
   const accountOpen = (cId) => {
     router.push({ name: 'R-CustomerDetail', params: { cId: cId } })
   }
 
   const searchSingleCid = async (cId) => {
-    let res = await Service1.cidRealSingle({
+    const res = await Service1.cidRealSingle({
       id: cId,
     })
     if (res.code == Code.StatusOK) {
-      if (editor.value) {
-        formList.value = res.data
-        dialogInfoAdd.value = true
-      } else {
-        formInfo.value = res.data
-        searchRealAll(cId)
-      }
+      // 注意:这里原代码有 editor 变量,但组件中未定义,保持原逻辑
+      // if (this.editor) {
+      //   this.formList = res.data;
+      //   this.dialogInfoAdd = true;
+      // } else {
+      formInfo.value = res.data
+      searchRealAll(cId)
+      // }
     } else {
-      pigeon.MessageError(res.msg)
+      ElMessage.error(res.msg)
     }
   }
 
+  // 获取cid下的真实账户信息
   const searchRealAll = async (cId) => {
-    let res = await Service1.realCustomerListAll({
+    const res = await Service1.realCustomerListAll({
       cId: cId,
       page: {
         current: 1,
@@ -365,10 +342,11 @@
       formInfo.value.realList = res.data
       dialogInfoCid.value = true
     } else {
-      pigeon.MessageError(res.msg)
+      ElMessage.error(res.msg)
     }
   }
 
+  // 详细信息关闭cid/pibno
   const closeDia = () => {
     dialogInfoCid.value = false
   }
@@ -382,16 +360,18 @@
     searchFunc()
   }
 
+  // 更新
   const updateCardTypes = async () => {
-    let res = await Service.updateCardTypes({})
+    const res = await Service.updateCardTypes({})
     if (res.code == Code.StatusOK) {
-      pigeon.MessageOK(t('Msg.SearchSuccess'))
+      ElMessage.success(t('Msg.SearchSuccess'))
       searchFunc()
     } else {
-      pigeon.MessageError(res.msg)
+      ElMessage.error(res.msg)
     }
   }
 
+  // 查看
   const closeSingle = () => {
     dialogInfoTradingSingle.value = false
   }
@@ -405,31 +385,37 @@
     }
   }
 
+  // 列表
   const searchFunc = async () => {
     pictLoading.value = true
-    if (!display.value['R-Transactions-Search'].show) {
-      pigeon.MessageWarning(t('Msg.NotDisplay'))
+    if (!display.value['R-Transactions-Search']?.show) {
+      ElMessage.warning(t('Msg.NotDisplay'))
       pictLoading.value = false
       return
     }
-    let res = await Service.transactionsList({
-      ...search,
-      page: {
-        current: pagerInfo.current,
-        row: pagerInfo.row,
-      },
-    })
-    if (res.code == Code.StatusOK) {
-      mock_tableData.value = res.data
-      if (res.page != null) {
-        pagerInfo.rowTotal = res.page.rowTotal
-        pagerInfo.pageTotal = res.page.pageTotal
+
+    try {
+      const res = await Service.transactionsList({
+        ...search,
+        page: {
+          current: pagerInfo.current,
+          row: pagerInfo.row,
+        },
+      })
+      if (res.code == Code.StatusOK) {
+        mock_tableData.value = res.data
+        if (res.page != null) {
+          pagerInfo.rowTotal = res.page.rowTotal
+          pagerInfo.pageTotal = res.page.pageTotal
+        } else {
+          pagerInfo.rowTotal = 0
+        }
+        ElMessage.success(t('Msg.SearchSuccess'))
       } else {
-        pagerInfo.rowTotal = 0
+        ElMessage.error(res.msg)
       }
-      pigeon.MessageOK(t('Msg.SearchSuccess'))
-    } else {
-      pigeon.MessageError(res.msg)
+    } catch (error) {
+      ElMessage.error(res.msg)
     }
     pictLoading.value = false
   }
@@ -444,6 +430,11 @@
     searchFunc()
   }
 
+  // 生命周期
+  onMounted(() => {
+    searchFunc()
+  })
+
   // 监听器
   watch(
     () => search.tag,
@@ -458,15 +449,32 @@
       search.status = ''
     }
   )
-
-  // 生命周期
-  onMounted(() => {
-    searchFunc()
-  })
 </script>
-
 <style scoped lang="scss">
-  @import 'index.scss';
+  #review_Email {
+    .crm_search {
+      .search_action_btn {
+        .delete {
+          background-color: #a1a1a1;
+        }
+
+        .delete.active {
+          background-color: #368fec;
+        }
+      }
+    }
+
+    .el-table .state {
+      display: inline-block;
+      min-width: 80px;
+      max-width: 150px;
+      box-sizing: border-box;
+      line-height: 1.5;
+      border-radius: 2px;
+      padding: 2px 10px;
+      color: #ffffff;
+    }
+  }
 </style>
 <style lang="scss">
   #review_Email {

+ 24 - 0
src/views/card/CardUserOrder/const.ts

@@ -0,0 +1,24 @@
+// 选项配置
+export const options = {
+  1: 'card.Status.t16',
+  2: 'card.Status.t17',
+  3: 'card.Status.t18',
+  4: 'card.Status.t19',
+  5: 'card.Status.t20',
+  6: 'card.Status.t21',
+  7: 'card.Status.t23',
+  8: 'card.Status.t24',
+  9: 'card.Status.t25',
+}
+
+export const searchTagOptions = [
+  { label: 'Label.CidAccount', value: 1 },
+  { label: 'Ucard.KycAuth.item2', value: 2 },
+  { label: 'Ucard.KycAuth.item3', value: 3 },
+]
+
+export const statusOptions = [
+  { label: 'card.Status.t3', value: 1 },
+  { label: 'card.Status.t1', value: 2 },
+  { label: 'card.Status.t2', value: 3 },
+]

+ 394 - 0
src/views/card/CardUserOrder/index.vue

@@ -0,0 +1,394 @@
+<template>
+  <div
+    id="review_Email"
+    v-loading="pictLoading"
+    class="view"
+    element-loading-background="rgba(43, 48, 67, 0.65)"
+    element-loading-spinner="el-icon-loading"
+  >
+    <div class="crm_search">
+      <el-form ref="formRef" label-position="" :model="search" label-width="">
+        <el-row>
+          <el-col :span="24" :md="24" :lg="24">
+            <el-form-item>
+              <el-select
+                v-model="search.tag"
+                class="crm_search_down crm-border-radius-no"
+                :placeholder="$t('Placeholder.Choose')"
+              >
+                <el-option
+                  v-for="option in searchTagOptions"
+                  :key="option.value"
+                  :label="$t(option.label)"
+                  :value="option.value"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item style="margin-right: 10px">
+              <el-input
+                v-if="search.tag == 1"
+                v-model.trim="search.cId"
+                class="crm-border-left-no crm-border-radius-no"
+                clearable
+                :placeholder="$t('Placeholder.Input')"
+                @keyup.enter="toSearch"
+              ></el-input>
+              <el-input
+                v-if="search.tag == 2"
+                v-model.trim="search.mobile"
+                class="crm-border-left-no crm-border-radius-no"
+                clearable
+                :placeholder="$t('Placeholder.Input')"
+                @keyup.enter="toSearch"
+              ></el-input>
+              <el-input
+                v-if="search.tag == 3"
+                v-model.trim="search.email"
+                class="crm-border-left-no crm-border-radius-no"
+                clearable
+                :placeholder="$t('Placeholder.Input')"
+                @keyup.enter="toSearch"
+              ></el-input>
+            </el-form-item>
+            <el-form-item style="margin-right: 10px">
+              <el-select
+                v-model="search.type"
+                filterable
+                clearable
+                class="crm-border-radius-no select_down"
+                :placeholder="$t('card.Form.f52')"
+                @change="toSearch"
+              >
+                <el-option :label="$t('card.Status.t22')" :value="null"></el-option>
+                <el-option
+                  v-for="(label, key) in options"
+                  :key="key"
+                  :label="$t(label)"
+                  :value="key"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item style="margin-right: 10px">
+              <el-select
+                v-model="search.status"
+                filterable
+                clearable
+                class="crm-border-radius-no select_down"
+                :placeholder="$t('Label.State')"
+                @change="toSearch"
+              >
+                <el-option
+                  v-for="option in statusOptions"
+                  :key="option.value"
+                  :label="$t(option.label)"
+                  :value="option.value"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-date-picker
+                v-model="search.date"
+                class="crm_date_pick crm-border-radius-no"
+                type="daterange"
+                unlink-panels
+                value-format="yyyy-MM-dd"
+                range-separator="-"
+                :start-placeholder="$t('Placeholder.Start')"
+                :end-placeholder="$t('Placeholder.End')"
+              >
+              </el-date-picker>
+            </el-form-item>
+            <el-form-item>
+              <el-button class="crm-border-radius-no crm-border-left-no" @click="toSearch">
+                <el-icon><Search /></el-icon>
+              </el-button>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item>
+          <el-button
+            v-if="display['R-UserOrder-Export'] && display['R-UserOrder-Export'].show"
+            type="primary"
+            style="margin-left: 8px"
+            @click="exportAgents"
+            >{{ $t('Btn.Export') }}</el-button
+          >
+        </el-form-item>
+      </el-form>
+
+      <div class="card-mock-demo" style="margin: 30px 0">
+        <el-table :data="mock_tableData" stripe style="margin-top: 20px; width: 100%">
+          <el-table-column prop="cId" align="left" :label="$t('Ucard.UserOrder.item1')">
+            <template #default="scope">
+              <span
+                v-if="scope.row.cId"
+                class="crm-text-underline"
+                style="cursor: pointer"
+                @click="accountOpen(scope.row.cId)"
+                >{{ scope.row.cId }}</span
+              >
+              <span v-else>--</span>
+            </template>
+          </el-table-column>
+          <el-table-column :label="$t('Ucard.UserOrder.item14')">
+            <template #default="scope">
+              {{ scope.row.lastName }}{{ scope.row.firstName }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="email" align="left" :label="$t('Ucard.UserOrder.item15')" />
+          <el-table-column prop="mobile" align="left" :label="$t('Ucard.UserOrder.item16')">
+            <template #default="scope"> {{ scope.row.areaCode }} {{ scope.row.mobile }} </template>
+          </el-table-column>
+          <el-table-column prop="type" align="left" :label="$t('card.Form.f52')">
+            <template #default="scope">
+              <span v-if="scope.row.type && options[scope.row.type]">
+                {{ $t(options[scope.row.type]) }}
+              </span>
+              <span v-else>--</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="amount" align="left" :label="$t('card.Form.f55')" />
+          <el-table-column prop="fee" align="left" :label="$t('card.Form.f30')" />
+          <el-table-column prop="addTime" align="left" :label="$t('card.Form.f51')" />
+          <el-table-column prop="status" align="left" :label="$t('Label.State')">
+            <template #default="scope">
+              <span v-if="scope.row.status == '2'" class="state crm_state_blue">{{
+                $t('card.Status.t1')
+              }}</span>
+              <span v-else-if="scope.row.status == '3'" class="state crm_state_gray">{{
+                $t('card.Status.t2')
+              }}</span>
+              <span v-else class="state crm_state_orange">
+                {{ $t('card.Status.t3') }}
+              </span>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </div>
+    <trading-info-add
+      :dialog-info-trading-add="dialogInfoTradingAdd"
+      :editor="editor"
+      :add-type="addType"
+      :my-info="myInfo"
+      :form-list="formList"
+      @confirm-to-reload="confirmToReload"
+      @close-add="closeAdd"
+    ></trading-info-add>
+
+    <PagePagination
+      :pager-info="pagerInfo"
+      @size-change="handleSizeChange"
+      @current-change="handleCurrentChange"
+    />
+    <detailed-info-cid
+      :dialog-info-cid="dialogInfoCid"
+      :form-info="formInfo"
+      :is-trading="true"
+      @close="closeCidDialog"
+    />
+  </div>
+</template>
+
+<script setup>
+  import { ref, reactive, computed, watch, onMounted, inject } from 'vue'
+  import { useRouter } from 'vue-router'
+  import { ElMessage } from 'element-plus'
+  import Service from '@/service/ucard'
+  import PagePagination from '@/components/pagePagination'
+  import Config from '@/config/index'
+  import TradingInfoAdd from '@/views/components/PaymentTransfer'
+  import DetailedInfoCid from '@/views/components/DetailedInfoCid'
+  import { exportExcel } from '@/utils/export'
+  import { options, searchTagOptions, statusOptions } from './const'
+  import { useI18n } from 'vue-i18n'
+
+  const { Code } = Config
+  const router = useRouter()
+  const Session = inject('session')
+  const pigeon = inject('pigeon')
+  const { t } = useI18n()
+
+  // 响应式数据
+  const pictLoading = ref(false)
+  const dialogInfoTradingAdd = ref(false)
+  const dialogInfoCid = ref(false)
+  const formInfo = ref({})
+  const editor = ref('')
+  const addType = ref('')
+  const formList = ref({})
+  const myInfo = ref({})
+  const mock_tableData = ref([])
+  const pagerInfo = reactive({ row: 10, current: 1, pageTotal: 0, rowTotal: 0 })
+  const banksData = ref([])
+  const formRef = ref()
+
+  // 搜索数据
+  const search = reactive({
+    tag: 1,
+    cId: '',
+    mobile: '',
+    email: '',
+    currency: '',
+    amount: '',
+    type: '',
+    startDate: '',
+    endDate: '',
+    date: null,
+  })
+
+  // 计算属性
+  const display = computed(() => {
+    return JSON.parse(Session.Get('display', true))
+  })
+
+  // 方法
+  // 导出
+  const exportAgents = async () => {
+    if (search.date == null) {
+      search.startDate = ''
+      search.endDate = ''
+    } else if (search.date.length == 0) {
+      search.startDate = ''
+      search.endDate = ''
+    } else {
+      search.startDate = search.date[0]
+      search.endDate = search.date[1]
+    }
+
+    exportExcel(pigeon, '/wasabi/card/wallet/record/export', { ...search }, 'Wallet_Balance_Record')
+  }
+
+  const closeAdd = (val) => {
+    dialogInfoTradingAdd.value = val
+  }
+
+  const closeDiaAdd = () => {
+    dialogInfoTradingAdd.value = false
+  }
+
+  const confirmToReload = () => {
+    closeDiaAdd()
+    searchFunc()
+  }
+
+  const toSearch = () => {
+    pagerInfo.current = 1
+    searchFunc()
+  }
+
+  // 列表
+  const searchFunc = async () => {
+    if (!display.value['R-UserOrder-Search']?.show) {
+      ElMessage.warning(t('Msg.NotDisplay'))
+      return
+    }
+
+    if (search.date == null) {
+      search.startDate = ''
+      search.endDate = ''
+    } else if (search.date.length == 0) {
+      search.startDate = ''
+      search.endDate = ''
+    } else {
+      search.startDate = search.date[0]
+      search.endDate = search.date[1]
+    }
+
+    pictLoading.value = true
+    try {
+      const res = await Service.getRecordPage({
+        ...search,
+        page: {
+          current: pagerInfo.current,
+          row: pagerInfo.row,
+        },
+      })
+
+      if (res.code === Code.StatusOK) {
+        mock_tableData.value = res.data || []
+        pagerInfo.rowTotal = res.page?.rowTotal || 0
+        pagerInfo.pageTotal = res.page?.pageTotal || 0
+        ElMessage.success(t('Msg.SearchSuccess'))
+      } else {
+        ElMessage.error(res.msg)
+      }
+    } catch (error) {
+      ElMessage.error(t('Msg.SearchFailed'))
+    } finally {
+      pictLoading.value = false
+    }
+  }
+
+  const handleSizeChange = (val) => {
+    pagerInfo.row = val
+    searchFunc()
+  }
+
+  const handleCurrentChange = (val) => {
+    pagerInfo.current = val
+    searchFunc()
+  }
+
+  // 详细信息cid
+  const accountOpen = (cId) => {
+    router.push({ name: 'R-CustomerDetail', params: { cId: cId } })
+  }
+
+  const closeCidDialog = (val) => {
+    dialogInfoCid.value = val
+  }
+
+  // 监听器
+  watch(
+    () => search.tag,
+    () => {
+      search.cId = ''
+      search.mobile = ''
+      search.email = ''
+      search.currency = ''
+      search.amount = ''
+      search.type = ''
+    }
+  )
+
+  // 生命周期
+  onMounted(() => {
+    searchFunc()
+  })
+</script>
+<style scoped lang="scss">
+  #review_Email {
+    .crm_search {
+      .search_action_btn {
+        .delete {
+          background-color: #a1a1a1;
+        }
+
+        .delete.active {
+          background-color: #368fec;
+        }
+      }
+    }
+
+    .el-table .state {
+      display: inline-block;
+      min-width: 80px;
+      max-width: 150px;
+      box-sizing: border-box;
+      line-height: 1.5;
+      border-radius: 2px;
+      padding: 2px 10px;
+      color: #ffffff;
+    }
+  }
+</style>
+<style lang="scss">
+  #review_Email {
+    .dialog_header_w {
+      .crm_search_down {
+        width: 400px;
+      }
+    }
+  }
+</style>

+ 12 - 0
src/views/card/CardUserRights/const.ts

@@ -0,0 +1,12 @@
+// 定义选项数组
+export const tagOptions = [
+  { value: 1, label: 'card.Info.t21' },
+  { value: 2, label: 'card.Info.t22' },
+  { value: 3, label: 'card.Info.t29' },
+  { value: 4, label: 'card.Info.t30' },
+]
+
+export const enableStatusOptions = [
+  { value: 0, label: 'Documentary.tradingCenter.item47' },
+  { value: 1, label: 'Documentary.tradingCenter.item46' },
+]

+ 613 - 0
src/views/card/CardUserRights/index.vue

@@ -0,0 +1,613 @@
+<template>
+  <div
+    id="review_Email"
+    v-loading="pictLoading"
+    class="view"
+    element-loading-background="rgba(43, 48, 67, 0.65)"
+    element-loading-spinner="el-icon-loading"
+  >
+    <div class="crm_search">
+      <el-form ref="formRef" :model="search" label-position="" label-width="">
+        <el-row>
+          <el-col :lg="24" :md="24" :span="24">
+            <el-form-item>
+              <el-select
+                v-model="search.tag"
+                :placeholder="$t('Placeholder.Choose')"
+                class="crm_search_down crm-border-radius-no"
+              >
+                <el-option
+                  v-for="item in tagOptions"
+                  :key="item.value"
+                  :label="t(item.label)"
+                  :value="item.value"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-input
+                v-if="search.tag == 1"
+                v-model.trim="search.cIdRegexp"
+                :placeholder="$t('Placeholder.Input')"
+                class="crm-border-left-no crm-border-radius-no"
+                clearable
+                @keyup.enter="toSearch"
+              ></el-input>
+              <el-select
+                v-if="search.tag == 2"
+                v-model="search.enableStatus"
+                :placeholder="$t('Placeholder.Choose')"
+                class="crm-border-left-no crm-border-radius-no"
+                clearable
+                @change="toSearch"
+              >
+                <el-option
+                  v-for="item in enableStatusOptions"
+                  :key="item.value"
+                  :label="t(item.label)"
+                  :value="item.value"
+                ></el-option>
+              </el-select>
+              <!-- 邮箱 -->
+              <el-input
+                v-if="search.tag == 3"
+                v-model.trim="search.cIdRegexp"
+                :placeholder="$t('Placeholder.Input')"
+                class="crm-border-left-no crm-border-radius-no"
+                clearable
+                @keyup.enter="toSearch"
+              ></el-input>
+              <!-- 手机号 -->
+              <el-input
+                v-if="search.tag == 4"
+                v-model.trim="search.cIdRegexp"
+                :placeholder="$t('Placeholder.Input')"
+                class="crm-border-left-no crm-border-radius-no"
+                clearable
+                @keyup.enter="toSearch"
+              ></el-input>
+            </el-form-item>
+            <el-form-item>
+              <el-button class="crm-border-radius-no crm-border-left-no" @click="toSearch">
+                <el-icon><Search /></el-icon>
+              </el-button>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item v-if="display['R-UserRights-Add'].show">
+          <div class="search_action_btn">
+            <span class="crm-cursor delete active" @click="approvalAll">
+              {{ $t('R-UserRights-Add') }}
+            </span>
+          </div>
+        </el-form-item>
+      </el-form>
+
+      <div class="card-mock-demo" style="margin: 30px 0">
+        <el-table
+          :data="mock_tableData"
+          stripe
+          style="margin-top: 20px; width: 100%"
+          @selection-change="handleSelectionChange"
+        >
+          <!-- <el-table-column
+            align="left"
+            type="selection"
+            width="55"
+            :selectable="checkSelectable"
+          >
+          </el-table-column> -->
+
+          <el-table-column :label="$t('card.Info.t21')" align="left" prop="cIdRegexp" />
+          <!-- <el-table-column
+            prop="addTime"
+            align="left"
+            :label="$t('Ucard.Recharge.item9')"
+          /> -->
+          <!-- 手机号 -->
+          <el-table-column :label="$t('card.Info.t30')" align="left" prop="phoneRegexp" />
+          <!-- 邮箱 -->
+          <el-table-column :label="$t('card.Info.t29')" align="left" prop="emailRegexp" />
+          <el-table-column
+            :label="$t('Apply_info.AddressInfo.Country')"
+            align="left"
+            prop="emailRegexp"
+          >
+            <template #default="scope">
+              {{ lang == 'cn' ? scope.row.countryNames : scope.row.countryEnNames }}
+            </template>
+          </el-table-column>
+          <el-table-column
+            :label="$t('Apply_info.AddressInfo.Region')"
+            align="left"
+            prop="emailRegexp"
+          >
+            <template #default="scope">
+              {{ lang == 'cn' ? scope.row.stateNames : scope.row.stateEnNames }}
+            </template>
+          </el-table-column>
+          <el-table-column
+            :label="$t('Apply_info.AddressInfo.City')"
+            align="left"
+            prop="emailRegexp"
+          >
+            <template #default="scope">
+              {{ lang == 'cn' ? scope.row.cityNames : scope.row.cityEnNames }}
+            </template>
+          </el-table-column>
+          <el-table-column :label="$t('card.Info.t23')" align="left" prop="addTime" />
+          <el-table-column :label="$t('card.Info.t22')" align="left" prop="enableStatus">
+            <template #default="scope">
+              <el-switch
+                v-model="scope.row.enableStatus"
+                :active-text="$t('Documentary.tradingCenter.item46')"
+                :active-value="1"
+                :inactive-text="$t('Documentary.tradingCenter.item47')"
+                :inactive-value="0"
+                active-color="#368FEC"
+                class="crm_switch"
+                inactive-color="#EB3F57"
+                @change="selectChange(scope.row)"
+              >
+              </el-switch>
+            </template>
+          </el-table-column>
+          <el-table-column :label="$t('Label.Action')" align="center" prop="opt">
+            <template #default="scope">
+              <el-dropdown trigger="click" @command="handleCommand">
+                <span class="el-dropdown-link crm-cursor">
+                  <i class="iconfont iconcaidan" style="font-weight: bold; font-size: 20px"></i>
+                </span>
+                <template #dropdown>
+                  <el-dropdown-menu>
+                    <el-dropdown-item
+                      v-if="display['R-UserRights-Delete'].show"
+                      :command="{ type: 1, row: scope.row }"
+                    >
+                      <el-icon><Delete /></el-icon>
+                      {{ $t('R-UserRights-Delete') }}
+                    </el-dropdown-item>
+                  </el-dropdown-menu>
+                </template>
+              </el-dropdown>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </div>
+    <PagePagination
+      :pager-info="pagerInfo"
+      @current-change="handleCurrentChange"
+      @size-change="handleSizeChange"
+    />
+    <el-dialog
+      v-if="approvalAllDialog"
+      v-model="approvalAllDialog"
+      :rules="rules"
+      :title="$t('card.Info.t26')"
+      width="600px"
+    >
+      <el-form
+        :model="form"
+        :rules="rules"
+        class="business-edit-form"
+        label-position="right"
+        label-width="150px"
+      >
+        <el-form-item :label="$t('card.Info.t21') + ':'" prop="cIdRegexp">
+          <el-input v-model="form.cIdRegexp" :placeholder="$t('Placeholder.Input')"></el-input>
+        </el-form-item>
+        <el-form-item :label="t('card.Info.t29') + ':'" prop="emailRegexp">
+          <el-input v-model="form.emailRegexp" :placeholder="$t('Placeholder.Input')"></el-input>
+        </el-form-item>
+        <el-form-item :label="$t('card.Info.t30') + ':'" prop="phoneRegexp">
+          <el-input v-model="form.phoneRegexp" :placeholder="$t('Placeholder.Input')"></el-input>
+        </el-form-item>
+        <el-form-item :label="$t('card.Info.t31') + ':'" prop="areaList">
+          <el-cascader
+            v-model="form.areaList"
+            class="crm_search_down width-100"
+            :show-all-levels="false"
+            :options="options"
+            filterable
+            :placeholder="$t('Placeholder.Choose')"
+            :props="cascaderProps"
+            clearable
+          ></el-cascader>
+        </el-form-item>
+        <el-form-item :label="$t('card.Info.t22') + ':'" class="crm_switch" prop="enableStatus">
+          <el-switch
+            v-model="form.enableStatus"
+            :active-text="$t('Documentary.tradingCenter.item46')"
+            :active-value="1"
+            :inactive-text="$t('Documentary.tradingCenter.item47')"
+            :inactive-value="0"
+            active-color="#368FEC"
+            class="crm_switch"
+            inactive-color="#EB3F57"
+          >
+          </el-switch>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="approvalAllDialog = false">
+            {{ $t('Ucard.Business.p32') }}
+          </el-button>
+          <el-button type="primary" @click="permissionAdd">
+            {{ $t('card.Btn.Confirm') }}
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+  import { ref, reactive, computed, onMounted, watch, inject } from 'vue'
+  import { useI18n } from 'vue-i18n'
+  import { ElMessage, ElMessageBox } from 'element-plus'
+  import PagePagination from '@/components/pagePagination'
+  import Service from '@/service/ucard'
+  import Config from '@/config/index'
+  import { enableStatusOptions, tagOptions } from '@/views/card/CardUserRights/const'
+  import { Search, Delete } from '@element-plus/icons-vue'
+
+  const { t } = useI18n()
+  const { Code } = Config
+  const Session = inject('session')
+
+  // Refs
+  const formRef = ref(null)
+  const pictLoading = ref(false)
+  const approvalAllDialog = ref(false)
+  const multipleSelection = ref([])
+
+  // Reactive data
+  const search = reactive({
+    tag: 1,
+    enableStatus: '',
+    cIdRegexp: '',
+    emailRegexp: '',
+    phoneRegexp: '',
+  })
+
+  const mock_tableData = ref([])
+
+  const pagerInfo = reactive({ row: 10, current: 1, pageTotal: 0, rowTotal: 0 })
+
+  const form = reactive({
+    cIdRegexp: null,
+    enableStatus: 1,
+    emailRegexp: null,
+    phoneRegexp: null,
+    areaList: null,
+  })
+
+  const options = ref([])
+
+  const rules = reactive({
+    enableStatus: [
+      {
+        required: true,
+        message: t('vaildate.select.empty'),
+        trigger: 'blur',
+      },
+    ],
+    cIdRegexp: [
+      {
+        message: t('vaildate.input.empty'),
+        trigger: 'blur',
+      },
+    ],
+    emailRegexp: [
+      {
+        message: t('vaildate.input.empty'),
+        trigger: 'blur',
+      },
+    ],
+    phoneRegexp: [
+      {
+        message: t('vaildate.input.empty'),
+        trigger: 'blur',
+      },
+    ],
+  })
+
+  const lang = computed(() => Session.Get('lang') || 'cn')
+  const display = computed(() => {
+    const displayStr = Session.Get('display', true)
+    return displayStr ? JSON.parse(displayStr) : {}
+  })
+
+  const user = computed(() => {
+    const userStr = Session.Get('user', true)
+    return userStr ? JSON.parse(userStr) : {}
+  })
+
+  // 联级选择参数
+  const cascaderProps = reactive({
+    multiple: true,
+    checkStrictly: true,
+    lazy: true,
+    async lazyLoad(node, resolve) {
+      const { value } = node
+      const pid = value ? value.split(',')[0] : ''
+
+      try {
+        const res = await Service.countryGet({ pid })
+        if (res.code == Code.StatusOK) {
+          const nodes = res.data.map((item) => {
+            const name = lang.value == 'cn' ? item.name : item.enName
+            return {
+              id: item.id,
+              label: name,
+              value: `${item.id},${item.name},${item.enName},${item.code ?? ''}`,
+              leaf: item.leaf,
+            }
+          })
+          resolve(nodes)
+        } else {
+          resolve([])
+        }
+      } catch (error) {
+        console.error('加载地区数据失败:', error)
+        resolve([])
+      }
+    },
+  })
+
+  // Methods
+  const handleCommand = (command) => {
+    if (command.type == 1) {
+      ElMessageBox.confirm(t('card.Msg.m14'), t('card.Msg.m13'), {
+        confirmButtonText: t('card.Btn.Confirm'),
+        cancelButtonText: t('card.Btn.Cancel'),
+        type: 'warning',
+      }).then(async () => {
+        const res = await Service.permissionDelete({
+          id: command.row.id,
+          cId: user.value.cId,
+        })
+        if (res.code == 200) {
+          ElMessage.success(t('Msg.DeleteSuccess'))
+          toSearch()
+        } else {
+          ElMessage.error(res.msg)
+        }
+      })
+    }
+  }
+
+  const selectChange = async (val) => {
+    try {
+      const res = await Service.permissionUpdate({
+        id: val.id,
+        enableStatus: val.enableStatus,
+        cId: user.value.cId,
+      })
+      if (res.code == 200) {
+        ElMessage.success(t('card.Info.t27'))
+        searchFunc()
+      } else {
+        ElMessage.error(res.msg)
+      }
+    } catch (error) {
+      ElMessage.error(t('Msg.SystemError'))
+    }
+  }
+
+  //选择多项
+  const handleSelectionChange = (val) => {
+    multipleSelection.value = []
+    val.forEach((item) => {
+      if (item.approveStatus == '2' || item.approveStatus == '3') return
+      multipleSelection.value.push(item.id)
+    })
+  }
+
+  const checkSelectable = (row) => {
+    return row.approveStatus == '1'
+  }
+
+  const approvalAll = () => {
+    approvalAllDialog.value = true
+  }
+
+  // 添加
+  const permissionAdd = async () => {
+    const { cIdRegexp, enableStatus, emailRegexp, phoneRegexp, areaList } = form
+
+    let countryEnNames = []
+    let stateEnNames = []
+    let countryCodes = []
+    let cityEnNames = []
+    let countryNames = []
+    let stateNames = []
+    let cityNames = []
+
+    if (areaList && areaList.length) {
+      // 地区数据处理
+      areaList.forEach((item) => {
+        if (item && item.length) {
+          item.forEach((child, childIndex) => {
+            if (child) {
+              const items = child.split(',')
+              // 0 id 1 name 2 enname 3 code 国家有,别的没有
+              if (childIndex === 0) {
+                countryNames.push(items[1] ?? '')
+                countryEnNames.push(items[2] ?? '')
+                countryCodes.push(items[3] ?? '')
+              } else if (childIndex === 1) {
+                stateNames.push(items[1] ?? '')
+                stateEnNames.push(items[2] ?? '')
+              } else {
+                cityNames.push(items[1] ?? '')
+                cityEnNames.push(items[2] ?? '')
+              }
+            }
+          })
+        }
+      })
+    }
+
+    const params = {
+      cId: user.value.cId,
+      cIdRegexp,
+      enableStatus,
+      emailRegexp,
+      phoneRegexp,
+      countryEnNames: [...new Set(countryEnNames)].join(','),
+      countryCodes: [...new Set(countryCodes)].join(','),
+      stateEnNames: [...new Set(stateEnNames)].join(','),
+      cityEnNames: [...new Set(cityEnNames)].join(','),
+      countryNames: [...new Set(countryNames)].join(','),
+      stateNames: [...new Set(stateNames)].join(','),
+      cityNames: [...new Set(cityNames)].join(','),
+    }
+
+    const res = await Service.permissionAdd(params)
+    if (res.code == 200) {
+      Object.assign(form, {
+        cIdRegexp: null,
+        enableStatus: 1,
+        approveStatus: null,
+        emailRegexp: null,
+        phoneRegexp: null,
+        areaList: null,
+      })
+      approvalAllDialog.value = false
+      ElMessage.success(t('card.Info.t28'))
+      toSearch()
+    } else {
+      ElMessage.error(res.msg)
+    }
+  }
+
+  const toSearch = () => {
+    pagerInfo.current = 1
+    searchFunc()
+  }
+
+  // 列表
+  const searchFunc = async () => {
+    pictLoading.value = true
+
+    if (!display.value['R-UserRights-Search']?.show) {
+      ElMessage.warning(t('Msg.NotDisplay'))
+      pictLoading.value = false
+      return
+    }
+
+    const res = await Service.permissionPage({
+      ...search,
+      page: {
+        current: pagerInfo.current,
+        row: pagerInfo.row,
+      },
+    })
+
+    if (res.code == Code.StatusOK) {
+      mock_tableData.value = res.data
+      if (res.page != null) {
+        pagerInfo.rowTotal = res.page.rowTotal
+        pagerInfo.pageTotal = res.page.pageTotal
+      } else {
+        pagerInfo.rowTotal = 0
+      }
+      ElMessage.success(t('Msg.SearchSuccess'))
+    } else {
+      ElMessage.error(res.msg)
+    }
+    pictLoading.value = false
+  }
+
+  const handleSizeChange = (val) => {
+    pagerInfo.row = val
+    searchFunc()
+  }
+
+  const handleCurrentChange = (val) => {
+    pagerInfo.current = val
+    searchFunc()
+  }
+
+  // 获取国家列表
+  const getCountry = async () => {
+    const res = await Service.countryGet({})
+    if (res.code == Code.StatusOK) {
+      options.value = res.data.map((item) => {
+        const name = lang.value == 'cn' ? item.name : item.enName
+        return {
+          id: item.id,
+          label: name,
+          value: `${item.id},${item.name},${item.enName},${item.code ?? ''}`,
+        }
+      })
+    } else {
+      ElMessage.error(res.msg)
+    }
+  }
+
+  // Lifecycle hooks
+  onMounted(() => {
+    searchFunc()
+    getCountry()
+  })
+
+  // Watchers
+  watch(
+    () => search.tag,
+    () => {
+      search.cIdRegexp = ''
+      search.enableStatus = ''
+      search.emailRegexp = ''
+      search.phoneRegexp = ''
+    }
+  )
+</script>
+
+<style lang="scss" scoped>
+  #review_Email {
+    .crm_search {
+      .search_action_btn {
+        .delete {
+          background-color: #a1a1a1;
+        }
+
+        .delete.active {
+          background-color: #368fec;
+        }
+      }
+    }
+
+    .el-table .state {
+      display: inline-block;
+      min-width: 80px;
+      max-width: 150px;
+      box-sizing: border-box;
+      line-height: 1.5;
+      border-radius: 2px;
+      padding: 2px 10px;
+      color: #ffffff;
+    }
+
+    .crm_switch {
+      :deep(.el-form-item__content) {
+        text-align: left;
+      }
+    }
+  }
+</style>
+<style lang="scss">
+  #review_Email {
+    .dialog_header_w {
+      .crm_search_down {
+        width: 400px;
+      }
+    }
+    .width-100 {
+      width: 100% !important;
+    }
+  }
+</style>

+ 3 - 5
src/views/card/GlobalCurrency/index.vue

@@ -71,11 +71,9 @@
               </el-select>
             </el-form-item>
             <el-form-item>
-              <el-button
-                class="crm-border-radius-no crm-border-left-no"
-                icon="el-icon-search"
-                @click="toSearch"
-              ></el-button>
+              <el-button class="crm-border-radius-no crm-border-left-no" @click="toSearch">
+                <el-icon><Search /></el-icon>
+              </el-button>
             </el-form-item>
           </el-col>
         </el-row>

+ 7 - 0
src/views/card/VirtualCard/const.ts

@@ -0,0 +1,7 @@
+// 销卡状态
+export const cancelStatus = {
+  wait_process: 'Ucard.VirtualCard.t11',
+  processing: 'Ucard.VirtualCard.t5',
+  success: 'Ucard.VirtualCard.t6',
+  fail: 'Ucard.VirtualCard.t10',
+}

+ 46 - 13
src/views/card/VirtualCard/index.vue

@@ -100,14 +100,18 @@
             </el-form-item>
             <el-form-item>
               <el-select
-                v-model="search.cardStatus"
+                v-model="search.cancelStatus"
                 class="crm-border-radius-no"
                 clearable
                 :placeholder="$t('card.Btn.b23')"
                 @change="toSearch"
               >
-                <el-option :label="$t('Ucard.VirtualCard.t7')" :value="1"></el-option>
-                <el-option :label="$t('card.Btn.b17')" :value="2"></el-option>
+                <el-option
+                  v-for="(value, key) in cancelStatus"
+                  :key="key"
+                  :label="$t(value)"
+                  :value="key"
+                ></el-option>
               </el-select>
             </el-form-item>
             <el-form-item>
@@ -173,7 +177,7 @@
           <el-table-column prop="cvv" align="left" :label="$t('Ucard.VirtualCard.item4')">
             <template #default="scope">
               <span v-if="scope.row.expireDate" class="cvv" @click="getQueryCvv(scope.row.id)"
-                >*** <i class="el-icon-view"></i
+                >*** <el-icon><View /></el-icon
               ></span>
             </template>
           </el-table-column>
@@ -228,12 +232,14 @@
               <span v-else class="state crm_state_red">{{ $t('card.Btn.b18') }}</span>
             </template>
           </el-table-column>
-          <el-table-column prop="cardStatus" align="left" :label="$t('card.Btn.b23')">
+          <el-table-column prop="cancelStatus" align="left" :label="$t('card.Btn.b23')">
             <template #default="scope">
-              <span v-if="scope.row.cardStatus != 'cancel'" class="state crm_state_blue">{{
-                $t('Ucard.VirtualCard.t7')
-              }}</span>
-              <span v-else class="state crm_state_red">{{ $t('card.Btn.b17') }}</span>
+              <span v-if="scope.row.cancelStatus == null" class="state crm_state_blue">
+                {{ $t('Ucard.VirtualCard.t7') }}
+              </span>
+              <span v-else :class="`state ${getStatusColor(scope.row.cancelStatus)}`">
+                {{ $t(cancelStatus[scope.row.cancelStatus]) }}
+              </span>
             </template>
           </el-table-column>
           <el-table-column prop="" align="center" :label="$t('Label.Action')">
@@ -251,7 +257,7 @@
                       <el-icon><Operation /></el-icon>
                       <span>{{ $t('R-VirtualCard-Btn1') }}</span>
                     </el-dropdown-item>
-                    <template v-if="scope.row.cardStatus != 'cancel'">
+                    <template v-if="scope.row.cancelStatus != 'success'">
                       <el-dropdown-item
                         v-if="
                           display['R-VirtualCard-Btn3'].show &&
@@ -331,6 +337,18 @@
                         <el-icon><CircleCheck /></el-icon>
                         <span>{{ $t('R-VirtualCard-Btn7') }}</span>
                       </el-dropdown-item>
+                      <el-dropdown-item
+                        v-if="
+                          display['R-VirtualCard-Btn12'].show &&
+                          ['success', 'processing'].includes(scope.row.cancelStatus)
+                        "
+                        :command="{ type: 14, row: scope.row }"
+                      >
+                        <el-icon><Delete /></el-icon>
+                        <span>
+                          {{ $t('R-VirtualCard-Btn12') }}
+                        </span>
+                      </el-dropdown-item>
                     </template>
                   </el-dropdown-menu>
                 </template>
@@ -471,9 +489,11 @@
   import DetailedInfoCid from '@/views/components/DetailedInfoCid'
   import ViewCardSingle from '@/views/components/ViewCardSingle'
   import { exportExcel } from '@/utils/export'
-  import { CircleCheck, Operation, Refresh, Search } from '@element-plus/icons-vue'
+  import { CircleCheck, Delete, Operation, Refresh, Search } from '@element-plus/icons-vue'
   import { useI18n } from 'vue-i18n'
   import { copyText } from '@/utils/untils'
+  import { cancelStatus } from '@/views/card/VirtualCard/const'
+  import { getStatusColor } from '@/utils/getStatusColor'
 
   const { t } = useI18n()
   const router = useRouter()
@@ -501,7 +521,7 @@
     status: '',
     freezeStatus: '',
     blockedStatus: '',
-    cardStatus: '',
+    cancelStatus: '',
   })
 
   const editor = ref('')
@@ -621,6 +641,16 @@
   const closeSingle = () => {
     dialogInfoTradingSingle.value = false
   }
+  const cancelCard = async (row) => {
+    console.log(row)
+    const res = await Service.cancelCard({ cardNo: row.cardNo, cId: user.value.cId })
+    if (res.code == Code.StatusOK) {
+      pigeon.MessageOK(t('Msg.Success19'))
+      searchFunc()
+    } else {
+      pigeon.MessageError(res.msg)
+    }
+  }
 
   const handleCommand = (command) => {
     if (
@@ -632,7 +662,7 @@
       pigeon.MessageOK(t('card.Info.t25'))
       return
     }
-    if (command.type != 0 && command.row.cardStatus == 'cancel') {
+    if (command.type != 0 && command.row.cancelStatus == 'success') {
       pigeon.MessageOK(t('card.New2.p5'))
       return
     }
@@ -696,6 +726,9 @@
         dialogInfoTradingAdd.value = true
         formList.value = command.row
         break
+      case 14:
+        cancelCard(command.row)
+        break
     }
   }
 

+ 59 - 0
src/views/components/PaymentTransfer/const.ts

@@ -0,0 +1,59 @@
+export const relationshipOptions = [
+  { value: 'BROTHER', label: 'Ucard.PaymentTransfer.item12' },
+  { value: 'BROTHER_IN_LAW', label: 'Ucard.PaymentTransfer.item13' },
+  { value: 'COUSIN', label: 'Ucard.PaymentTransfer.item14' },
+  { value: 'DAUGHTER', label: 'Ucard.PaymentTransfer.item15' },
+  { value: 'FATHER', label: 'Ucard.PaymentTransfer.item16' },
+  { value: 'FATHER_IN_LAW', label: 'Ucard.PaymentTransfer.item17' },
+  { value: 'FRIEND', label: 'Ucard.PaymentTransfer.item18' },
+  { value: 'GRAND_FATHER', label: 'Ucard.PaymentTransfer.item19' },
+  { value: 'GRAND_MOTHER', label: 'Ucard.PaymentTransfer.item20' },
+  { value: 'HUSBAND', label: 'Ucard.PaymentTransfer.item21' },
+  { value: 'MOTHER', label: 'Ucard.PaymentTransfer.item22' },
+  { value: 'MOTHER_IN_LAW', label: 'Ucard.PaymentTransfer.item23' },
+  { value: 'NEPHEW', label: 'Ucard.PaymentTransfer.item24' },
+  { value: 'NIECE', label: 'Ucard.PaymentTransfer.item25' },
+  { value: 'SELF', label: 'Ucard.PaymentTransfer.item26' },
+  { value: 'SISTER', label: 'Ucard.PaymentTransfer.item27' },
+  { value: 'SISTER_IN_LAW', label: 'Ucard.PaymentTransfer.item28' },
+  { value: 'SON', label: 'Ucard.PaymentTransfer.item29' },
+  { value: 'UNCLE', label: 'Ucard.PaymentTransfer.item30' },
+  { value: 'WIFE', label: 'Ucard.PaymentTransfer.item31' },
+  { value: 'OTHER', label: 'Ucard.PaymentTransfer.item32' },
+]
+
+export const sourceFundsOptions = [
+  { value: 'CASH', label: 'Ucard.PaymentTransfer.item34' },
+  { value: 'BUSINESS', label: 'Ucard.PaymentTransfer.item35' },
+  { value: 'GIFT', label: 'Ucard.PaymentTransfer.item36' },
+  { value: 'SALARY', label: 'Ucard.PaymentTransfer.item37' },
+  { value: 'LOTTERY', label: 'Ucard.PaymentTransfer.item38' },
+  { value: 'SAVINGS', label: 'Ucard.PaymentTransfer.item39' },
+  { value: 'OTHER', label: 'Ucard.PaymentTransfer.item40' },
+]
+
+export const payPurposeOptions = [
+  { value: 'PURCHASE_OF_GOODS_OR_SERVICES', label: 'Ucard.PaymentTransfer.item42' },
+  { value: 'FREIGHT_AND_TRANSPORTATION_COSTS', label: 'Ucard.PaymentTransfer.item43' },
+  { value: 'EDUCATION_EXPENSES', label: 'Ucard.PaymentTransfer.item44' },
+  { value: 'IMMIGRATION_INVESTMENT', label: 'Ucard.PaymentTransfer.item45' },
+  { value: 'CHARITABLE_DONATIONS', label: 'Ucard.PaymentTransfer.item46' },
+  { value: 'FAMILY_SUPPORT', label: 'Ucard.PaymentTransfer.item47' },
+  { value: 'DIVIDEND_OR_INTEREST_PAYMENTS', label: 'Ucard.PaymentTransfer.item48' },
+  { value: 'INTERNATIONAL_TRADE', label: 'Ucard.PaymentTransfer.item49' },
+]
+export const idNoTypeOptions = [
+  { value: 'PASSPORT', label: 'Ucard.PaymentTransfer.item57' },
+  { value: 'EUROPEAN_ID', label: 'Ucard.PaymentTransfer.item58' },
+]
+export const idNoType2Options = [
+  { value: 'PASSPORT', label: 'Ucard.PaymentTransfer.item89' },
+  { value: 'EUROPEAN_ID', label: 'Ucard.PaymentTransfer.item90' },
+]
+
+export const bankAccountTypeOptions = [
+  { value: 'CHECKING', label: 'Ucard.PaymentTransfer.item98' },
+  { value: 'SAVINGS', label: 'Ucard.PaymentTransfer.item99' },
+  { value: 'DEPOSIT', label: 'Ucard.PaymentTransfer.item100' },
+  { value: 'OTHERS', label: 'Ucard.PaymentTransfer.item101' },
+]

+ 312 - 0
src/views/components/PaymentTransfer/index.scss

@@ -0,0 +1,312 @@
+
+.payment-transfer-drawer {
+  :deep(.el-drawer) {
+    display: flex;
+    flex-direction: column;
+  }
+
+  :deep(.el-drawer__header) {
+    margin-bottom: 0;
+    padding: 16px 20px;
+  }
+
+  :deep(.el-drawer__body) {
+    flex: 1;
+    overflow: hidden;
+    padding: 0;
+    position: relative;
+  }
+}
+
+.drawer-content {
+  position: relative;
+  min-height: 100%;
+  padding: 24px 32px 0 32px;
+  background: #fff;
+  max-height: calc(100vh - 40px);
+  overflow-y: auto;
+  padding-bottom: 64px;
+}
+
+.el-form {
+  margin-bottom: 0;
+}
+
+.el-form-item {
+  margin-bottom: 24px;
+}
+
+.el-input,
+.el-select {
+  width: 100%;
+}
+
+.btn.crm-cursor {
+  display: block;
+  width: 30%;
+  margin-left: 40%;
+  text-align: center;
+  background: #368fec;
+  color: #fff;
+  border-radius: 2px;
+  font-size: 16px;
+  height: 40px;
+  line-height: 40px;
+  cursor: pointer;
+}
+
+.btn.crm-cursor[disabled],
+.btn.crm-cursor.is-disabled {
+  background: #a1a1a1;
+  color: #fff;
+  cursor: not-allowed;
+}
+
+.el-form .el-form-item__label {
+  font-weight: 400;
+  color: #222;
+  font-size: 15px;
+}
+
+.el-form .el-form-item__content {
+  font-size: 15px;
+}
+
+.el-form .el-input__inner,
+.el-form .el-select .el-input__inner {
+  height: 40px;
+  font-size: 15px;
+}
+
+.el-form .el-select .el-input__inner {
+  padding-right: 30px;
+}
+
+.el-form .el-select .el-input__icon {
+  right: 10px;
+}
+
+.el-form .el-form-item.is-required .el-form-item__label:before {
+  color: #eb3f57;
+  margin-right: 4px;
+}
+
+.el-form .el-form-item__error {
+  font-size: 13px;
+  color: #eb3f57;
+  margin-top: 2px;
+}
+
+.el-form .el-button {
+  width: auto;
+  min-width: 120px;
+  font-size: 16px;
+  border-radius: 2px;
+  margin-top: 24px;
+}
+
+.el-form .el-button + .el-button {
+  margin-left: 0;
+  margin-top: 12px;
+}
+
+// 结果区块样式
+.el-form[style*="margin-top: 20px"] {
+  margin-top: 32px !important;
+  background: #f7f8fa;
+  border-radius: 4px;
+  padding: 24px 24px 8px 24px;
+}
+
+.el-form[style*="margin-top: 20px"] .el-form-item {
+  margin-bottom: 12px;
+}
+
+.el-form[style*="margin-top: 20px"] .el-form-item__label {
+  color: #888;
+  font-size: 14px;
+}
+
+.el-form[style*="margin-top: 20px"] .el-form-item__content {
+  color: #222;
+  font-size: 16px;
+}
+
+/* 只针对代付页面的按钮做样式调整 */
+.payment-form {
+  /* 让按钮容器右对齐 */
+  .el-form-item[style*='text-align: right'],
+  .button-container {
+    text-align: right !important;
+  }
+
+  /* 让按钮宽度自适应 */
+  .el-button {
+    width: auto !important;
+    min-width: 120px;
+    margin-top: 0;
+  }
+}
+
+.payment-form .button-container {
+  text-align: right;
+  background: #fff;
+  padding: 24px 0 0 0;
+  max-width: 420px;
+  margin-left: auto;
+  margin-right: 0;
+}
+
+.payment-form .button-container .el-button + .el-button {
+  margin-left: 24px;
+}
+
+/* 只美化调单信息或文件区块 */
+.dispute-submit-container {
+  padding: 0 0 32px 0;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.dispute-form {
+  background: #fff;
+  border-radius: 10px;
+  padding: 32px 32px 20px 32px;
+  margin-bottom: 24px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
+  width: 420px;
+  max-width: 100%;
+}
+
+.dispute-form .el-form-item {
+  margin-bottom: 22px;
+}
+
+.dispute-form .el-form-item__label {
+  font-size: 15px;
+  color: #222;
+}
+
+.dispute-form .el-form-item__content {
+  font-size: 15px;
+}
+
+.dispute-form .el-input__inner,
+.dispute-form .el-select .el-input__inner {
+  height: 40px;
+  font-size: 15px;
+}
+
+.dispute-form .el-select .el-input__inner {
+  padding-right: 30px;
+}
+
+.dispute-form .el-select .el-input__icon {
+  right: 10px;
+}
+
+.dispute-form .el-form-item__error {
+  font-size: 13px;
+  color: #eb3f57;
+  margin-top: 2px;
+}
+
+.dispute-form .note {
+  color: #aaa;
+  font-size: 13px;
+  margin-left: 4px;
+}
+
+.dispute-form .add-btn-container {
+  margin: 18px 0 24px 0;
+}
+
+.dispute-form .el-button {
+  min-width: 120px;
+  height: 40px;
+  font-size: 15px;
+  border-radius: 6px;
+}
+
+.dispute-form .el-button + .el-button {
+  margin-left: 16px;
+}
+
+.dispute-form .section-divider {
+  margin: 24px 0 12px 0;
+  border-top: 1px solid #f0f0f0;
+  padding-top: 16px;
+}
+
+.dispute-form .subsection-title {
+  font-size: 17px;
+  font-weight: 500;
+  margin-bottom: 8px;
+  color: #368fec;
+}
+
+.dispute-form .form-tip {
+  color: #aaa;
+  font-size: 13px;
+  margin-bottom: 10px;
+}
+
+.dispute-form .info-item,
+.dispute-form .file-item {
+  background: #fafbfc;
+  border-radius: 6px;
+  padding: 16px 48px 10px 16px;
+  margin-bottom: 14px;
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.02);
+  position: relative;
+}
+
+.dispute-form .remove-btn {
+  position: absolute;
+  top: 4px;
+  right: 4px;
+  float: none;
+  margin: 0;
+  z-index: 2;
+  width: 28px;
+  height: 28px;
+  min-width: 28px;
+  min-height: 28px;
+  border-radius: 50%;
+  background: #fff;
+  color: #bbb;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
+  padding: 0;
+  font-size: 18px;
+  border: 1px solid #e5e6eb;
+  transition: color 0.2s, background 0.2s;
+}
+
+.dispute-form .remove-btn:hover {
+  color: #888;
+  background: #f5f5f5;
+}
+
+.dispute-form .upload-preview {
+  margin-top: 10px;
+  display: flex;
+  align-items: center;
+}
+
+.dispute-form .preview-image {
+  width: 60px;
+  height: 60px;
+  object-fit: cover;
+  border-radius: 4px;
+  border: 1px solid #e5e6eb;
+  margin-right: 10px;
+}
+
+.dispute-form .preview-actions {
+  display: flex;
+  flex-direction: column;
+}

+ 1696 - 0
src/views/components/PaymentTransfer/index.vue

@@ -0,0 +1,1696 @@
+<template>
+  <el-drawer
+    :model-value="dialogInfoTradingAdd"
+    :title="getDrawerTitle"
+    :size="addType === 'payment' || addType === 'ucardValidate' ? '50%' : '25%'"
+    :before-close="close"
+    custom-class="payment-transfer-drawer"
+    :wrapper-closable="true"
+    :modal-append-to-body="false"
+    :append-to-body="true"
+  >
+    <div class="drawer-content">
+      <template v-if="addType == 'rate'">
+        <el-form ref="rateFormRef" :rules="rateRules" :model="rateForm" label-width="120px">
+          <el-form-item prop="currency" :label="$t('Ucard.PaymentTransfer.item2')">
+            <el-input
+              id="currency"
+              v-model="rateForm.currency"
+              :placeholder="$t('Placeholder.Input')"
+              readonly
+            ></el-input>
+          </el-form-item>
+
+          <el-form-item prop="targetCountry" :label="$t('Ucard.PaymentTransfer.item4')">
+            <el-select
+              id="targetCountry"
+              v-model="rateForm.targetCountry"
+              :placeholder="$t('Placeholder.Choose')"
+              filterable
+              allow-create
+              default-first-option
+            >
+              <el-option
+                v-for="item in targetCountryOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item prop="targetCurrency" :label="$t('Ucard.PaymentTransfer.item3')">
+            <el-select
+              id="targetCurrency"
+              v-model="rateForm.targetCurrency"
+              :placeholder="$t('Placeholder.Choose')"
+              filterable
+              allow-create
+              default-first-option
+            >
+              <el-option
+                v-for="item in targetCurrencyOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </el-form-item>
+        </el-form>
+
+        <span v-loading="loadingStates.rateQuery" class="btn crm-cursor" @click="confirmRateQuery">
+          {{ $t('Btn.Search') }}
+        </span>
+
+        <!-- 显示查询结果 -->
+        <el-form v-if="rateResult" label-width="120px" style="margin-top: 20px">
+          <el-form-item :label="$t('Ucard.PaymentTransfer.item2')">
+            {{ rateResult.currency }}
+          </el-form-item>
+          <el-form-item :label="$t('Ucard.PaymentTransfer.item3')">
+            {{ rateResult.targetCurrency }}
+          </el-form-item>
+          <el-form-item :label="$t('Ucard.PaymentTransfer.item5')">
+            {{ rateResult.exchangeRate }}
+          </el-form-item>
+        </el-form>
+      </template>
+
+      <template v-if="addType == 'payment' || addType == 'ucardValidate'">
+        <div v-if="bankSummary" class="bank-config-summary" style="margin-bottom: 12px">
+          <el-alert :title="bankSummary" type="info" :closable="false" show-icon />
+        </div>
+        <el-form
+          ref="paymentFormRef"
+          :rules="paymentRules"
+          :model="paymentForm"
+          label-width="160px"
+          class="payment-form"
+        >
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="bankId" :label="$t('Ucard.PaymentTransfer.item7')">
+                <el-select
+                  id="paymentBankId"
+                  v-model="paymentForm.bankId"
+                  :placeholder="$t('Placeholder.Choose')"
+                  filterable
+                  allow-create
+                  default-first-option
+                  @change="onBankChange"
+                >
+                  <el-option
+                    v-for="item in targetBankOptions"
+                    :key="item.value"
+                    :label="item.label"
+                    :value="item.value"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="uniqueId" :label="$t('Ucard.PaymentTransfer.item8')">
+                <el-input
+                  id="uniqueId"
+                  v-model="paymentForm.uniqueId"
+                  readonly
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <h3 style="padding: 15px; font-size: 16px">{{ $t('Ucard.PaymentTransfer.item6') }}</h3>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="amount" :label="$t('Ucard.PaymentTransfer.item9')">
+                <el-input
+                  id="amount"
+                  v-model="paymentForm.amount"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="postscript" :label="$t('Ucard.PaymentTransfer.item10')">
+                <el-input
+                  id="postscript"
+                  v-model="paymentForm.postscript"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="relationship" :label="$t('Ucard.PaymentTransfer.item11')">
+                <el-select
+                  id="relationship"
+                  v-model="paymentForm.relationship"
+                  :placeholder="$t('Placeholder.Choose')"
+                >
+                  <el-option
+                    v-for="item in relationshipOptions"
+                    :key="item.value"
+                    :label="$t(item.label)"
+                    :value="item.value"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="sourceFunds" :label="$t('Ucard.PaymentTransfer.item33')">
+                <el-select
+                  id="sourceFunds"
+                  v-model="paymentForm.sourceFunds"
+                  :placeholder="$t('Placeholder.Choose')"
+                >
+                  <el-option
+                    v-for="item in sourceFundsOptions"
+                    :key="item.value"
+                    :label="$t(item.label)"
+                    :value="item.value"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payPurpose" :label="$t('Ucard.PaymentTransfer.item41')">
+                <el-select
+                  id="payPurpose"
+                  v-model="paymentForm.payPurpose"
+                  :placeholder="$t('Placeholder.Choose')"
+                >
+                  <el-option
+                    v-for="item in payPurposeOptions"
+                    :key="item.value"
+                    :label="$t(item.label)"
+                    :value="item.value"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 付款人信息 -->
+          <h3 style="padding: 15px; font-size: 16px">{{ $t('Ucard.PaymentTransfer.item50') }}</h3>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payer.payerType" :label="$t('Ucard.PaymentTransfer.item51')">
+                <el-select
+                  id="payerType"
+                  v-model="paymentForm.payer.payerType"
+                  :placeholder="$t('Placeholder.Choose')"
+                >
+                  <el-option
+                    value="INDIVIDUAL"
+                    :label="$t('Ucard.PaymentTransfer.item52')"
+                  ></el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="payer.payerLastName" :label="$t('Ucard.PaymentTransfer.item53')">
+                <el-input
+                  id="payerLastName"
+                  v-model="paymentForm.payer.payerLastName"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payer.payerFirstName" :label="$t('Ucard.PaymentTransfer.item54')">
+                <el-input
+                  id="payerFirstName"
+                  v-model="paymentForm.payer.payerFirstName"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="payer.payerIdNo" :label="$t('Ucard.PaymentTransfer.item55')">
+                <el-input
+                  id="payerIdNo"
+                  v-model="paymentForm.payer.payerIdNo"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payer.payerIdNoType" :label="$t('Ucard.PaymentTransfer.item56')">
+                <el-select
+                  id="payerIdNoType"
+                  v-model="paymentForm.payer.payerIdNoType"
+                  :placeholder="$t('Placeholder.Choose')"
+                >
+                  <el-option
+                    v-for="item in idNoTypeOptions"
+                    :key="item.value"
+                    :label="$t(item.label)"
+                    :value="item.value"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="payer.payerIdCountry" :label="$t('Ucard.PaymentTransfer.item59')">
+                <el-select
+                  id="payerIdCountry"
+                  v-model="paymentForm.payer.payerIdCountry"
+                  filterable
+                  :placeholder="$t('Ucard.PaymentTransfer.item60')"
+                  style="width: 100%"
+                >
+                  <el-option
+                    v-for="item in countryCityList"
+                    :key="item.id"
+                    :label="item.cnName"
+                    :value="item.id"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payer.payerBirthday" :label="$t('Ucard.PaymentTransfer.item61')">
+                <el-date-picker
+                  id="payerBirthday"
+                  v-model="paymentForm.payer.payerBirthday"
+                  style="width: 100%"
+                  type="date"
+                  format="yyyy-MM-dd"
+                  value-format="yyyy-MM-dd"
+                  :placeholder="$t('Placeholder.ChooseDate')"
+                ></el-date-picker>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item
+                prop="payer.payerNationalityCountry"
+                :label="$t('Ucard.PaymentTransfer.item62')"
+              >
+                <el-select
+                  id="payerNationalityCountry"
+                  v-model="paymentForm.payer.payerNationalityCountry"
+                  filterable
+                  :placeholder="$t('Ucard.PaymentTransfer.item63')"
+                  style="width: 100%"
+                >
+                  <el-option
+                    v-for="item in countryCityList"
+                    :key="item.id"
+                    :label="item.cnName"
+                    :value="item.code"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payer.payerMobile" :label="$t('Ucard.PaymentTransfer.item64')">
+                <el-input
+                  id="payerMobile"
+                  v-model="paymentForm.payer.payerMobile"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item
+                prop="payer.payerCountryCode"
+                :label="$t('Ucard.PaymentTransfer.item65')"
+              >
+                <el-select
+                  id="payerCountryCode"
+                  v-model="paymentForm.payer.payerCountryCode"
+                  filterable
+                  :placeholder="$t('Ucard.PaymentTransfer.item66')"
+                  style="width: 100%"
+                  @change="handlePayerCountryChange"
+                >
+                  <el-option
+                    v-for="item in countryCityList"
+                    :key="item.id"
+                    :label="item.cnName"
+                    :value="item.code"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payer.payerCityCode" :label="$t('Ucard.PaymentTransfer.item67')">
+                <el-select
+                  id="payerCityCode"
+                  v-model="paymentForm.payer.payerCityCode"
+                  filterable
+                  :placeholder="$t('Ucard.PaymentTransfer.item68')"
+                  style="width: 100%"
+                  :disabled="!paymentForm.payer.payerCountryCode"
+                >
+                  <el-option
+                    v-for="item in payerCityList"
+                    :key="item.id"
+                    :label="item.cnName"
+                    :value="item.code"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="payer.payerAddress" :label="$t('Ucard.PaymentTransfer.item69')">
+                <el-input
+                  id="payerAddress"
+                  v-model="paymentForm.payer.payerAddress"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payer.payerPostCode" :label="$t('Ucard.PaymentTransfer.item70')">
+                <el-input
+                  id="payerPostCode"
+                  v-model="paymentForm.payer.payerPostCode"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item
+                prop="payer.payerOccupation"
+                :label="$t('Ucard.PaymentTransfer.item71')"
+              >
+                <el-input
+                  id="payerOccupation"
+                  v-model="paymentForm.payer.payerOccupation"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <!-- 付款人信息区块结尾插入校验付款人按钮 -->
+          <div style="margin: 16px 15px 32px 0; text-align: right">
+            <el-button type="warning" :loading="loadingStates.validatePayer" @click="validatePayer">
+              {{ $t('Ucard.PaymentTransfer.item72') }}
+            </el-button>
+          </div>
+
+          <!-- 收款人信息 -->
+          <h3 style="padding: 15px; font-size: 16px">{{ $t('Ucard.PaymentTransfer.item73') }}</h3>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payee.benAccountNum" :label="$t('Ucard.PaymentTransfer.item75')">
+                <el-input
+                  id="benAccountNum"
+                  v-model="paymentForm.payee.benAccountNum"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="payee.benAccountName" :label="$t('Ucard.PaymentTransfer.item76')">
+                <el-input
+                  id="benAccountName"
+                  v-model="paymentForm.payee.benAccountName"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payee.benCountryCode" :label="$t('Ucard.PaymentTransfer.item77')">
+                <el-select
+                  id="benCountryCode"
+                  v-model="paymentForm.payee.benCountryCode"
+                  filterable
+                  :placeholder="$t('Ucard.PaymentTransfer.item78')"
+                  style="width: 100%"
+                  @change="handlePayeeCountryChange"
+                >
+                  <el-option
+                    v-for="item in countryCityList"
+                    :key="item.id"
+                    :label="item.cnName"
+                    :value="item.code"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="payee.benCityCode" :label="$t('Ucard.PaymentTransfer.item79')">
+                <el-select
+                  id="benCityCode"
+                  v-model="paymentForm.payee.benCityCode"
+                  filterable
+                  :placeholder="$t('Ucard.PaymentTransfer.item80')"
+                  style="width: 100%"
+                  :disabled="!paymentForm.payee.benCountryCode"
+                >
+                  <el-option
+                    v-for="item in payeeCityList"
+                    :key="item.id"
+                    :label="item.cnName"
+                    :value="item.code"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payee.benAddress" :label="$t('Ucard.PaymentTransfer.item81')">
+                <el-input
+                  id="benAddress"
+                  v-model="paymentForm.payee.benAddress"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="payee.benPostCode" :label="$t('Ucard.PaymentTransfer.item82')">
+                <el-input
+                  id="benPostCode"
+                  v-model="paymentForm.payee.benPostCode"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payee.benLastName" :label="$t('Ucard.PaymentTransfer.item83')">
+                <el-input
+                  id="benLastName"
+                  v-model="paymentForm.payee.benLastName"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="payee.benFirstName" :label="$t('Ucard.PaymentTransfer.item84')">
+                <el-input
+                  id="benFirstName"
+                  v-model="paymentForm.payee.benFirstName"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payee.benBankCode" :label="$t('Ucard.PaymentTransfer.item85')">
+                <el-input
+                  id="benBankCode"
+                  v-model="paymentForm.payee.benBankCode"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item
+                prop="payee.benNationalityCountry"
+                :label="$t('Ucard.PaymentTransfer.item86')"
+              >
+                <el-select
+                  id="benNationalityCountry"
+                  v-model="paymentForm.payee.benNationalityCountry"
+                  filterable
+                  :placeholder="$t('Ucard.PaymentTransfer.item87')"
+                  style="width: 100%"
+                >
+                  <el-option
+                    v-for="item in countryCityList"
+                    :key="item.id"
+                    :label="item.cnName"
+                    :value="item.code"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payee.benIdNoType" :label="$t('Ucard.PaymentTransfer.item88')">
+                <el-select
+                  id="benIdNoType"
+                  v-model="paymentForm.payee.benIdNoType"
+                  :placeholder="$t('Placeholder.Choose')"
+                >
+                  <el-option
+                    v-for="item in idNoType2Options"
+                    :key="item.value"
+                    :label="$t(item.label)"
+                    :value="item.value"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="payee.benIdNo" :label="$t('Ucard.PaymentTransfer.item91')">
+                <el-input
+                  id="benIdNo"
+                  v-model="paymentForm.payee.benIdNo"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item
+                prop="payee.benIdExpirationDate"
+                :label="$t('Ucard.PaymentTransfer.item92')"
+              >
+                <el-date-picker
+                  id="benIdExpirationDate"
+                  v-model="paymentForm.payee.benIdExpirationDate"
+                  style="width: 100%"
+                  type="date"
+                  format="yyyy-MM-dd"
+                  value-format="yyyy-MM-dd"
+                  :placeholder="$t('Placeholder.ChooseDate')"
+                ></el-date-picker>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="payee.benBirthday" :label="$t('Ucard.PaymentTransfer.item93')">
+                <el-date-picker
+                  id="benBirthday"
+                  v-model="paymentForm.payee.benBirthday"
+                  style="width: 100%"
+                  type="date"
+                  format="yyyy-MM-dd"
+                  value-format="yyyy-MM-dd"
+                  :placeholder="$t('Placeholder.ChooseDate')"
+                ></el-date-picker>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item prop="payee.benMobileCode" :label="$t('Ucard.PaymentTransfer.item94')">
+                <el-select
+                  id="benMobileCode"
+                  v-model="paymentForm.payee.benMobileCode"
+                  filterable
+                  :placeholder="$t('Ucard.PaymentTransfer.item95')"
+                  style="width: 100%"
+                >
+                  <el-option
+                    v-for="item in countryList"
+                    :key="item.id"
+                    :label="'+' + item.callingCode + ' ' + item.enName"
+                    :value="item.callingCode"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item prop="payee.benMobile" :label="$t('Ucard.PaymentTransfer.item96')">
+                <el-input
+                  id="benMobile"
+                  v-model="paymentForm.payee.benMobile"
+                  :placeholder="$t('Placeholder.Input')"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item
+                prop="payee.benBankAccountType"
+                :label="$t('Ucard.PaymentTransfer.item97')"
+              >
+                <el-select
+                  id="benBankAccountType"
+                  v-model="paymentForm.payee.benBankAccountType"
+                  :placeholder="$t('Placeholder.Choose')"
+                >
+                  <el-option
+                    v-for="item in bankAccountTypeOptions"
+                    :key="item.value"
+                    :label="$t(item.label)"
+                    :value="item.value"
+                  />
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <div style="padding: 16px 15px 32px 0; text-align: right">
+            <el-button
+              type="warning"
+              :loading="loadingStates.validatePayee"
+              @click="validatePayee"
+              >{{ $t('Ucard.PaymentTransfer.item102') }}</el-button
+            >
+          </div>
+
+          <div class="button-container">
+            <el-button type="primary" :loading="loadingStates.validateAll" @click="validateAll">{{
+              $t('Ucard.PaymentTransfer.item104')
+            }}</el-button>
+            <el-button
+              type="primary"
+              :loading="loadingStates.ucardTransfer"
+              @click="ucardTransfer"
+              >{{ $t('Ucard.PaymentTransfer.item105') }}</el-button
+            >
+          </div>
+        </el-form>
+      </template>
+      <!-- 提交调单信息或文件 -->
+      <template v-if="addType == 'dispute'">
+        <div class="dispute-submit-container">
+          <h3 class="section-title">{{ $t('Ucard.PaymentTransfer.text1') }}</h3>
+
+          <el-form
+            ref="disputeFormRef"
+            :model="disputeForm"
+            :rules="disputeRules"
+            label-width="120px"
+            class="dispute-form"
+          >
+            <!-- 订单号 -->
+            <el-form-item prop="orderNo" :label="$t('Ucard.PaymentTransfer.text2')" required>
+              <el-input
+                v-model="disputeForm.orderNo"
+                :placeholder="$t('Ucard.PaymentTransfer.text3')"
+              ></el-input>
+              <span class="note">{{ $t('Ucard.PaymentTransfer.text4') }}</span>
+            </el-form-item>
+
+            <!-- 订单信息部分 -->
+            <div class="section-divider">
+              <h4 class="subsection-title">{{ $t('Ucard.PaymentTransfer.text5') }}</h4>
+              <p class="form-tip">{{ $t('Ucard.PaymentTransfer.text6') }}</p>
+            </div>
+
+            <div
+              v-for="(info, index) in disputeForm.transferInfos"
+              :key="'transfer-info-' + index"
+              class="info-item"
+            >
+              <el-form-item
+                :prop="`transferInfos.${index}.code`"
+                :rules="{
+                  required: true,
+                  message: $t('Ucard.PaymentTransfer.text7'),
+                  trigger: 'change',
+                }"
+                :label="$t('Ucard.PaymentTransfer.text8')"
+              >
+                <el-select v-model="info.code" :placeholder="$t('Ucard.PaymentTransfer.text9')">
+                  <el-option
+                    v-for="(label, code) in infoTypeDict"
+                    :key="code"
+                    :value="code"
+                    :label="label"
+                  ></el-option>
+                </el-select>
+              </el-form-item>
+
+              <el-form-item
+                :prop="`transferInfos.${index}.content`"
+                :rules="{
+                  required: true,
+                  message: $t('Ucard.PaymentTransfer.text10'),
+                  trigger: 'blur',
+                }"
+                :label="$t('Ucard.PaymentTransfer.text11')"
+              >
+                <el-input
+                  v-model="info.content"
+                  :placeholder="$t('Ucard.PaymentTransfer.text12')"
+                ></el-input>
+                <span class="note">{{ $t('Ucard.PaymentTransfer.text13') }}</span>
+              </el-form-item>
+
+              <el-button
+                v-if="index > 0"
+                type="danger"
+                size="small"
+                circle
+                class="remove-btn"
+                @click="removeInfo(index)"
+              >
+                <el-icon><Delete /></el-icon>
+              </el-button>
+            </div>
+
+            <div class="add-btn-container">
+              <el-button type="primary" @click="addInfo">
+                <el-icon><Plus /></el-icon>
+                {{ $t('Ucard.PaymentTransfer.text14') }}
+              </el-button>
+            </div>
+
+            <!-- 订单文件部分 -->
+            <div class="section-divider">
+              <h4 class="subsection-title">{{ $t('Ucard.PaymentTransfer.text15') }}</h4>
+              <p class="form-tip">{{ $t('Ucard.PaymentTransfer.text16') }}</p>
+            </div>
+
+            <div
+              v-for="(file, index) in disputeForm.transferFiles"
+              :key="'transfer-file-' + index"
+              class="file-item"
+            >
+              <el-form-item
+                :prop="`transferFiles.${index}.code`"
+                :rules="{
+                  required: true,
+                  message: $t('Ucard.PaymentTransfer.text17'),
+                  trigger: 'change',
+                }"
+                :label="$t('Ucard.PaymentTransfer.text18')"
+              >
+                <el-select v-model="file.code" :placeholder="$t('Ucard.PaymentTransfer.text19')">
+                  <el-option
+                    v-for="(label, code) in fileTypeDict"
+                    :key="code"
+                    :value="code"
+                    :label="label"
+                  ></el-option>
+                </el-select>
+              </el-form-item>
+
+              <el-form-item
+                :prop="`transferFiles.${index}.content`"
+                :rules="{
+                  required: true,
+                  message: $t('Ucard.PaymentTransfer.text20'),
+                  trigger: 'change',
+                }"
+                :label="$t('Ucard.PaymentTransfer.text21')"
+              >
+                <el-upload
+                  :http-request="(option) => handleKycFileUpload(option, index)"
+                  :show-file-list="false"
+                  :action="uploadUrl"
+                  :headers="headers"
+                  :before-upload="beforeFileUpload"
+                >
+                  <el-button type="primary" :loading="loadingStates.fileUpload">{{
+                    $t('Ucard.PaymentTransfer.text22')
+                  }}</el-button>
+                </el-upload>
+
+                <div v-if="file.content" class="upload-preview">
+                  <img :src="file.content" class="preview-image" />
+                  <div class="preview-actions">
+                    <el-button type="text" @click="removeFile(index)">{{
+                      $t('Ucard.PaymentTransfer.text23')
+                    }}</el-button>
+                  </div>
+                </div>
+                <el-icon v-else><Plus /></el-icon>
+                <span class="note">{{ $t('Ucard.PaymentTransfer.text24') }}</span>
+              </el-form-item>
+
+              <el-button
+                v-if="index > 0"
+                type="danger"
+                size="small"
+                circle
+                class="remove-btn"
+                @click="removeFile(index)"
+              >
+                <el-icon><Delete /></el-icon>
+              </el-button>
+            </div>
+          </el-form>
+        </div>
+      </template>
+    </div>
+  </el-drawer>
+</template>
+<script setup>
+  import { ref, reactive, computed, watch, onMounted, inject } from 'vue'
+  import { useI18n } from 'vue-i18n'
+  import Config from '@/config/index'
+  import Service from '@/service/ucard'
+  import {
+    bankAccountTypeOptions,
+    idNoType2Options,
+    idNoTypeOptions,
+    payPurposeOptions,
+    relationshipOptions,
+    sourceFundsOptions,
+  } from '@/views/components/PaymentTransfer/const'
+  import { Delete, Plus } from '@element-plus/icons-vue'
+  import { ElMessage } from 'element-plus'
+
+  const { t } = useI18n()
+  const { Code } = Config
+  const Session = inject('session')
+
+  // Props
+  const props = defineProps({
+    dialogInfoTradingAdd: {
+      type: Boolean,
+      default: false,
+    },
+    addType: {
+      default: '',
+    },
+    editor: {
+      default: '',
+    },
+    myInfo: {
+      default: '',
+    },
+    formList: {
+      default: '',
+    },
+  })
+
+  // Emits
+  const emit = defineEmits(['closeAdd'])
+
+  // Refs
+  const rateFormRef = ref(null)
+  const paymentFormRef = ref(null)
+  const disputeFormRef = ref(null)
+
+  // Reactive data
+  const imgUrl = Config.Host85
+  const uploadUrl = Config.Host85 + '/ucard/upload/file'
+  const headers = reactive({
+    'Access-Token': Session.Get('access_token') || '',
+  })
+
+  const loadingStates = reactive({
+    rateQuery: false,
+    validatePayer: false,
+    validatePayee: false,
+    validateAll: false,
+    ucardTransfer: false,
+    fileUpload: false,
+  })
+
+  const rateForm = reactive({
+    currency: 'EUR',
+    targetCurrency: '',
+    targetCountry: '',
+  })
+
+  const rateRules = reactive({
+    targetCurrency: [{ required: true, message: t('Ucard.PaymentTransfer.ms1'), trigger: 'blur' }],
+    targetCountry: [{ required: true, message: t('Ucard.PaymentTransfer.ms2'), trigger: 'blur' }],
+  })
+
+  const rateResult = ref(null)
+
+  // 代付相关数据
+  const paymentForm = reactive({
+    bankId: 2671,
+    uniqueId: 'af3f6910-023a-4d88-a17a-12322ad194a4',
+    originOrderNo: '',
+    amount: 200,
+    postscript: 'testorder',
+    relationship: 'OTHER',
+    sourceFunds: 'SAVINGS',
+    payPurpose: 'INTERNATIONAL_TRADE',
+    payer: {
+      payerType: 'INDIVIDUAL',
+      payerLastName: 'zhang',
+      payerFirstName: 'tom',
+      payerIdNo: 'ES125664',
+      payerIdNoType: 'PASSPORT',
+      payerIdCountry: 'SG',
+      payerBirthday: '1990-10-10',
+      payerNationalityCountry: 'SG',
+      payerMobile: '+65012345678',
+      payerCountryCode: 'SG',
+      payerCityCode: 'SG_1',
+      payerAddress: '21 Tampines Ave 1, Singapore 529757',
+      payerPostCode: '999002',
+      payerOccupation: 'worker',
+    },
+    payee: {
+      bankId: 2671,
+      benAccountNum: '235486845630',
+      benAccountName: 'wangfei',
+      benCountryCode: 'SG',
+      benCityCode: 'SG_1',
+      benAddress: '21 Tampines Ave 1, Singapore 529757',
+      benPostCode: '999002',
+      benTransBankSwift: '',
+      benLastName: 'zhang',
+      benFirstName: 'alex',
+      benNationalityCountry: 'SG',
+      benIdNoType: 'PASSPORT',
+      benIdNo: '1334924322424',
+      benIdExpirationDate: '2030-01-01',
+      benBirthday: '2001-01-01',
+      benMobileCode: '+67',
+      benMobile: '18326559132',
+      benBankAccountType: 'SAVINGS',
+    },
+  })
+
+  const paymentRules = reactive({
+    bankId: [{ required: true, message: t('Ucard.PaymentTransfer.ms3'), trigger: 'blur' }],
+    uniqueId: [{ required: true, message: t('Ucard.PaymentTransfer.ms4'), trigger: 'blur' }],
+    amount: [
+      { required: true, message: t('Ucard.PaymentTransfer.ms6'), trigger: 'blur' },
+      { validator: validatePass, trigger: ['change', 'blur'] },
+    ],
+    postscript: [
+      { required: true, message: t('Ucard.PaymentTransfer.ms7'), trigger: 'blur' },
+      {
+        min: 5,
+        max: 64,
+        message: t('Ucard.PaymentTransfer.ms8'),
+        trigger: 'blur',
+      },
+      {
+        validator: validOnlySupportEnglish,
+        trigger: ['change', 'blur'],
+      },
+    ],
+    payer: {
+      payerLastName: [
+        { required: true, message: t('Ucard.PaymentTransfer.ms9'), trigger: 'blur' },
+        {
+          min: 2,
+          max: 50,
+          message: t('Ucard.PaymentTransfer.ms10'),
+          trigger: 'blur',
+        },
+        {
+          validator: validatePassChinessCharacters,
+          trigger: ['change', 'blur'],
+        },
+      ],
+      payerFirstName: [
+        { required: true, message: t('Ucard.PaymentTransfer.ms9'), trigger: 'blur' },
+        {
+          min: 2,
+          max: 50,
+          message: t('Ucard.PaymentTransfer.ms10'),
+          trigger: 'blur',
+        },
+        {
+          validator: validatePassChinessCharacters,
+          trigger: ['change', 'blur'],
+        },
+      ],
+      payerIdNo: [
+        {
+          required: true,
+          message: t('Ucard.PaymentTransfer.ms11'),
+          trigger: 'blur',
+        },
+        {
+          min: 6,
+          max: 18,
+          message: t('Ucard.PaymentTransfer.ms12'),
+          trigger: 'blur',
+        },
+        {
+          validator: validatePassChinessCharacters,
+          trigger: ['change', 'blur'],
+        },
+      ],
+      payerIdNoType: [
+        {
+          required: true,
+          message: t('Ucard.PaymentTransfer.ms13'),
+          trigger: 'change',
+        },
+      ],
+      payerIdCountry: [
+        { required: true, message: t('Ucard.PaymentTransfer.ms14'), trigger: 'blur' },
+        { min: 2, max: 2, message: t('Ucard.PaymentTransfer.ms15'), trigger: 'blur' },
+      ],
+      payerBirthday: [
+        { required: true, message: t('Ucard.PaymentTransfer.ms16'), trigger: 'change' },
+      ],
+      payerNationalityCountry: [
+        { required: true, message: t('Ucard.PaymentTransfer.ms17'), trigger: 'blur' },
+      ],
+      payerMobile: [
+        { required: true, message: t('Ucard.PaymentTransfer.ms18'), trigger: 'blur' },
+        {
+          min: 8,
+          max: 15,
+          message: t('Ucard.PaymentTransfer.ms19'),
+          trigger: 'blur',
+        },
+      ],
+      payerCountryCode: [
+        { required: true, message: t('Ucard.PaymentTransfer.ms20'), trigger: 'blur' },
+        { min: 2, max: 2, message: t('Ucard.PaymentTransfer.ms21'), trigger: 'blur' },
+      ],
+      payerCityCode: [
+        { required: true, message: t('Ucard.PaymentTransfer.ms22'), trigger: 'blur' },
+      ],
+      payerAddress: [
+        { required: true, message: t('Ucard.PaymentTransfer.ms23'), trigger: 'blur' },
+        {
+          min: 10,
+          max: 100,
+          message: t('Ucard.PaymentTransfer.ms24'),
+          trigger: 'blur',
+        },
+        {
+          validator: validatePassChinessCharacters,
+          trigger: ['change', 'blur'],
+        },
+      ],
+      payerPostCode: [
+        { required: true, message: t('Ucard.PaymentTransfer.ms25'), trigger: 'blur' },
+        {
+          min: 3,
+          max: 9,
+          message: t('Ucard.PaymentTransfer.ms26'),
+          trigger: ['change', 'blur'],
+        },
+      ],
+      payerOccupation: [
+        { required: true, message: t('Ucard.PaymentTransfer.ms27'), trigger: 'blur' },
+        {
+          min: 3,
+          max: 20,
+          message: t('Ucard.PaymentTransfer.ms28'),
+          trigger: 'blur',
+        },
+        {
+          validator: validOnlySupportEnglish,
+          trigger: ['change', 'blur'],
+        },
+      ],
+    },
+    payee: {
+      benAccountNum: [
+        { required: true, message: t('Ucard.PaymentTransfer.ms29'), trigger: 'blur' },
+        {
+          validator: validatePassChinessCharacters,
+          trigger: ['change', 'blur'],
+        },
+        {
+          min: 2,
+          max: 48,
+          message: t('Ucard.PaymentTransfer.ms30'),
+          trigger: 'blur',
+        },
+      ],
+      benAccountName: [
+        { required: true, message: t('Ucard.PaymentTransfer.ms31'), trigger: 'blur' },
+        {
+          min: 1,
+          max: 100,
+          message: t('Ucard.PaymentTransfer.ms32'),
+          trigger: 'blur',
+        },
+      ],
+      benLastName: [
+        {
+          min: 2,
+          max: 60,
+          message: t('Ucard.PaymentTransfer.ms33'),
+          trigger: 'change',
+        },
+      ],
+      benfirstName: [
+        {
+          min: 2,
+          max: 60,
+          message: t('Ucard.PaymentTransfer.ms34'),
+          trigger: 'change',
+        },
+      ],
+    },
+  })
+
+  const paymentResult = ref(null)
+
+  const payerForm = reactive({
+    payerType: 'INDIVIDUAL',
+    payerLastName: '',
+    payerFirstName: '',
+    payerIdNo: '',
+    payerIdNoType: '',
+    payerIdCountry: '',
+    payerBirthday: '',
+    payerNationalityCountry: '',
+    payerMobile: '',
+    payerCountryCode: '',
+    payerCityCode: '',
+    payerAddress: '',
+    payerPostCode: '',
+    payerOccupation: '',
+  })
+
+  const payerValidateResult = ref(null)
+
+  const payeeForm = reactive({
+    bankId: '',
+    benAccountNum: '',
+    benAccountName: '',
+    benCountryCode: '',
+    benCityCode: '',
+    benAddress: '',
+    benPostCode: '',
+    benBankCode: '',
+    benTransBankSwift: '',
+    benLastName: '',
+    benFirstName: '',
+    benNationalityCountry: '',
+    benIdNoType: '',
+    benIdNo: '',
+    benIdExpirationDate: '',
+    benBirthday: '',
+    benMobileCode: '',
+    benMobile: '',
+    benBankAccountType: '',
+  })
+
+  const payeeRules = reactive({
+    bankId: [{ required: true, message: t('Ucard.PaymentTransfer.ms35'), trigger: 'blur' }],
+    benAccountNum: [
+      { required: true, message: t('Ucard.PaymentTransfer.ms36'), trigger: 'blur' },
+      {
+        min: 2,
+        max: 48,
+        message: t('Ucard.PaymentTransfer.ms37'),
+        trigger: 'blur',
+      },
+    ],
+    benAccountName: [
+      { required: true, message: t('Ucard.PaymentTransfer.ms38'), trigger: 'blur' },
+      {
+        min: 1,
+        max: 100,
+        message: t('Ucard.PaymentTransfer.ms39'),
+        trigger: 'blur',
+      },
+    ],
+  })
+
+  const payeeValidateResult = ref(null)
+
+  const disputeForm = reactive({
+    orderNo: '',
+    transferInfos: [{ code: '', content: '' }],
+    transferFiles: [{ code: '', content: '' }],
+  })
+
+  const disputeRules = reactive({
+    orderNo: [{ required: true, message: t('Ucard.PaymentTransfer.ms40'), trigger: 'blur' }],
+  })
+
+  const disputeResult = ref(null)
+
+  const infoTypeDict = computed(() => ({
+    1: t('Ucard.PaymentTransfer.ms41'),
+    2: t('Ucard.PaymentTransfer.ms42'),
+    3: t('Ucard.PaymentTransfer.ms43'),
+    4: t('Ucard.PaymentTransfer.ms44'),
+    5: t('Ucard.PaymentTransfer.ms45'),
+    6: t('Ucard.PaymentTransfer.ms46'),
+    16: t('Ucard.PaymentTransfer.ms47'),
+  }))
+
+  const fileTypeDict = computed(() => ({
+    21: t('Ucard.PaymentTransfer.ms48'),
+    22: t('Ucard.PaymentTransfer.ms49'),
+    23: t('Ucard.PaymentTransfer.ms50'),
+    24: t('Ucard.PaymentTransfer.ms51'),
+    25: t('Ucard.PaymentTransfer.ms52'),
+    26: t('Ucard.PaymentTransfer.ms53'),
+  }))
+
+  const targetCurrencyOptions = ref([])
+  const targetCountryOptions = ref([])
+  const targetBankOptions = ref([])
+  const bankConfigList = ref([])
+  const bankSummary = ref('')
+  const countryCityList = ref([])
+  const payerCityList = ref([])
+  const payeeCityList = ref([])
+  const countryList = ref([])
+  const allCountryBanks = ref([])
+
+  // Computed properties
+  const getDrawerTitle = computed(() => {
+    const titles = {
+      rate: t('Ucard.UserOrder.p6'),
+      payment: t('Ucard.UserOrder.p1'),
+      ucardValidate: t('Ucard.UserOrder.p2'),
+      payerValidate: t('Ucard.UserOrder.p3'),
+      payeeValidate: t('Ucard.UserOrder.p4'),
+      dispute: t('Ucard.UserOrder.p8'),
+    }
+    return titles[props.addType] || ''
+  })
+
+  // Methods
+  // 统一的文件上传处理
+  async function handleFileUpload(option, type, index) {
+    const loadingKey = type === 'kyc' ? 'fileUpload' : `${type}Upload`
+    loadingStates[loadingKey] = true
+
+    try {
+      const formData = new FormData()
+      formData.append('file', option.file)
+
+      const res = await Service.ucardUpload(formData)
+      if (res.code === 200 && res.data) {
+        if (type === 'kyc') {
+          disputeForm.transferFiles[index].content = res.data
+        } else {
+          // 这里需要根据具体逻辑调整
+        }
+        ElMessage.success(t('Ucard.PaymentTransfer.ms54'))
+        option.onSuccess(res, option.file)
+      } else {
+        throw new Error(res.msg)
+      }
+    } catch (error) {
+      ElMessage.error(error.message || t('Ucard.PaymentTransfer.ms55'))
+      option.onError()
+    } finally {
+      loadingStates[loadingKey] = false
+    }
+  }
+
+  // 统一的表单验证方法
+  async function validateForm(formRef) {
+    try {
+      await formRef.value.validate()
+      return true
+    } catch (error) {
+      ElMessage.warning(t('Ucard.PaymentTransfer.ms58'))
+      return false
+    }
+  }
+
+  // 统一的API调用方法
+  async function callApi(apiMethod, params, successMessage, errorMessage) {
+    try {
+      const res = await apiMethod(params)
+      if (res.code === Code.StatusOK) {
+        ElMessage.success(t(successMessage))
+        return res.data
+      } else {
+        throw new Error(res.msg)
+      }
+    } catch (error) {
+      ElMessage.error(error.message || t(errorMessage))
+      return null
+    }
+  }
+
+  // 使用统一的方法重写现有方法
+  async function handleKycFileUpload(option, index) {
+    return handleFileUpload(option, 'kyc', index)
+  }
+
+  async function validatePayee() {
+    loadingStates.validatePayee = true
+    try {
+      await callApi(
+        Service.ucardValidatePayee,
+        {
+          ...paymentForm.payee,
+          bankId: paymentForm.bankId,
+        },
+        'Ucard.PaymentTransfer.ms72',
+        'Ucard.PaymentTransfer.ms55'
+      )
+    } finally {
+      loadingStates.validatePayee = false
+    }
+  }
+
+  async function validatePayer() {
+    loadingStates.validatePayer = true
+    try {
+      await callApi(
+        Service.ucardValidatePayer,
+        paymentForm.payer,
+        'Ucard.PaymentTransfer.ms73',
+        'Ucard.PaymentTransfer.ms55'
+      )
+    } finally {
+      loadingStates.validatePayer = false
+    }
+  }
+
+  async function validateAll() {
+    loadingStates.validateAll = true
+    try {
+      const { ...rest } = paymentForm
+      await callApi(
+        Service.ucardValidate,
+        rest,
+        'Ucard.PaymentTransfer.ms74',
+        'Ucard.PaymentTransfer.ms55'
+      )
+    } finally {
+      loadingStates.validateAll = false
+    }
+  }
+
+  async function ucardTransfer() {
+    loadingStates.ucardTransfer = true
+    try {
+      const result = await callApi(
+        Service.ucardTransfer,
+        paymentForm,
+        'Ucard.PaymentTransfer.ms75',
+        'Ucard.PaymentTransfer.ms55'
+      )
+      if (result) {
+        paymentResult.value = result
+        emit('closeAdd', false)
+      }
+    } finally {
+      loadingStates.ucardTransfer = false
+    }
+  }
+
+  // 优化表单重置方法
+  function resetForm() {
+    const defaultForms = {
+      dispute: {
+        orderNo: '',
+        transferInfos: [{ code: '', content: '' }],
+        transferFiles: [{ code: '', content: '' }],
+      },
+      rate: {
+        currency: 'EUR',
+        targetCurrency: '',
+        targetCountry: '',
+      },
+      payment: {
+        bankId: 2671,
+        uniqueId: 'af3f6910-023a-4d88-a17a-12322ad194a4',
+        // ... 其他默认值
+      },
+    }
+
+    Object.keys(defaultForms).forEach((formType) => {
+      const formRef =
+        formType === 'rate'
+          ? rateFormRef
+          : formType === 'payment'
+          ? paymentFormRef
+          : formType === 'dispute'
+          ? disputeFormRef
+          : null
+
+      if (formRef && formRef.value) {
+        formRef.value.resetFields()
+        if (formType === 'rate') {
+          Object.assign(rateForm, defaultForms[formType])
+        } else if (formType === 'payment') {
+          Object.assign(paymentForm, defaultForms[formType])
+        } else if (formType === 'dispute') {
+          Object.assign(disputeForm, defaultForms[formType])
+        }
+      }
+    })
+  }
+
+  function close() {
+    emit('closeAdd', false)
+  }
+
+  async function confirmRateQuery() {
+    try {
+      await rateFormRef.value.validate()
+      loadingStates.rateQuery = true
+      try {
+        let res = await Service.ucardRate(rateForm)
+        if (res.code == Code.StatusOK) {
+          rateResult.value = res.data
+          // 注意:这里使用了 $pigeon,在 Vue 3 中可能需要调整
+          // this.$pigeon.MessageOK(t('Ucard.PaymentTransfer.ms64'))
+          ElMessage.success(t('Ucard.PaymentTransfer.ms64'))
+        } else {
+          // this.$pigeon.MessageError(res.msg)
+          ElMessage.error(res.msg)
+        }
+      } catch (error) {
+        // console.error("查询法币汇率失败:", error)
+        // this.$pigeon.MessageError(t("Ucard.PaymentTransfer.ms65"))
+        ElMessage.error(t('Ucard.PaymentTransfer.ms65'))
+      } finally {
+        loadingStates.rateQuery = false
+      }
+    } catch (error) {
+      return false
+    }
+  }
+
+  async function loadBankOptions() {
+    if (allCountryBanks.value.length) return
+    const res = await Service.ucardBanks()
+    if (res && (res.code === 0 || res.code === 200) && Array.isArray(res.data)) {
+      allCountryBanks.value = res.data
+      targetCountryOptions.value = res.data
+        .filter((item) => item.country && item.countryName)
+        .map((item) => ({
+          value: item.country,
+          label: `${item.country}(${item.countryName})`,
+        }))
+    }
+  }
+
+  async function loadBankConfigList() {
+    const res = await Service.ucardBanks()
+    if (res && (res.code === 0 || res.code === 200) && Array.isArray(res.data)) {
+      const allBanks = res.data.flatMap((item) => item.bankList || [])
+      bankConfigList.value = allBanks
+      targetBankOptions.value = allBanks.map((bank) => ({
+        label: bank.bankName + '(' + bank.bankId + ')',
+        value: bank.bankId,
+      }))
+      const names = allBanks.map((b) => b.bankName).filter(Boolean)
+      bankSummary.value = `支持银行:${names.slice(0, 5).join('、')}${
+        names.length > 5 ? ' 等' + names.length + '家' : ''
+      }`
+    } else {
+      bankConfigList.value = []
+      targetBankOptions.value = []
+      bankSummary.value = ''
+    }
+  }
+
+  function onBankChange(bankId) {
+    const bank = bankConfigList.value.find((b) => b.bankId === bankId)
+    if (bank) {
+      paymentForm.feeAmount = bank.feeAmount
+      paymentForm.feeRate = bank.feeRate
+      paymentForm.paymentType = bank.paymentType
+    } else {
+      paymentForm.feeAmount = ''
+      paymentForm.feeRate = ''
+      paymentForm.paymentType = ''
+    }
+  }
+
+  function validatePass(rule, value, callback) {
+    if (value < 100) {
+      callback(new Error(t('Ucard.PaymentTransfer.ms67')))
+    }
+    callback()
+  }
+
+  function validatePassChinessCharacters(rule, value, cb) {
+    if (/^[^\u4e00-\u9fa5]+$/.test(value)) {
+      cb()
+    } else {
+      cb(new Error(t('Ucard.PaymentTransfer.ms68')))
+    }
+  }
+
+  function validFilesValueLen(rule, value, cb, minLen, maxLen) {
+    if (minLen < value.length < maxLen) {
+      cb()
+    } else {
+      cb(new Error(t('Ucard.PaymentTransfer.ms69') + `${minLen}-${maxLen}`))
+    }
+  }
+
+  function validOnlySupportEnglish(rule, value, cb) {
+    if (/^[a-zA-Z]+$/.test(value)) {
+      cb()
+    } else {
+      cb(new Error(t('Ucard.PaymentTransfer.ms70')))
+    }
+  }
+
+  function handlePayeeCountryChange(countryCode) {
+    paymentForm.payee.benCityCode = ''
+    if (countryCode) {
+      getCityListForSelect(countryCode, 'payee')
+    } else {
+      payeeCityList.value = []
+    }
+  }
+
+  async function getCountryListForSelect() {
+    const res = await Service.ucardCountryCity({ code: '' })
+    if (res.code === 200 || res.code === 0) {
+      countryCityList.value = res.data || []
+    }
+  }
+
+  async function getCityListForSelect(countryCode, type = 'payer') {
+    const res = await Service.ucardCountryCity({ code: countryCode })
+    if (res.code === 200 || res.code === 0) {
+      if (type === 'payer') {
+        payerCityList.value = res.data || []
+      } else {
+        payeeCityList.value = res.data || []
+      }
+    }
+  }
+
+  async function handlePayerCountryChange(countryCode) {
+    paymentForm.payer.payerCityCode = ''
+    if (countryCode) {
+      await getCityListForSelect(countryCode, 'payer')
+    } else {
+      payerCityList.value = []
+    }
+  }
+
+  async function getCountryList() {
+    const res = await Service.countryGet({})
+    if (res.code === 200 || res.code === 0) {
+      countryList.value = res.data
+    } else {
+      ElMessage.error(res.msg || t('Ucard.PaymentTransfer.ms71'))
+    }
+  }
+
+  function addInfo() {
+    disputeForm.transferInfos.push({ code: '', content: '' })
+  }
+
+  function removeInfo(index) {
+    disputeForm.transferInfos.splice(index, 1)
+  }
+
+  function addFile() {
+    disputeForm.transferFiles.push({ code: '', content: '' })
+  }
+
+  function removeFile(index) {
+    disputeForm.transferFiles.splice(index, 1)
+  }
+
+  function beforeFileUpload(file) {
+    const isImage =
+      file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg'
+    const isLt2M = file.size / 1024 / 1024 < 2
+
+    if (!isImage) {
+      ElMessage.error(t('Ucard.PaymentTransfer.ms56'))
+      return false
+    }
+
+    if (!isLt2M) {
+      ElMessage.error(t('Ucard.PaymentTransfer.ms57'))
+      return false
+    }
+
+    return true
+  }
+
+  // Watchers
+  watch(
+    () => props.formList,
+    (form) => {
+      if (form && form.uniqueId) {
+        paymentForm.uniqueId = form.uniqueId
+      }
+    },
+    { immediate: true }
+  )
+
+  watch(
+    () => rateForm.targetCountry,
+    (newCountry) => {
+      if (newCountry && allCountryBanks.value.length) {
+        const countryObj = allCountryBanks.value.find((item) => item.country === newCountry)
+        if (countryObj && countryObj.currency && countryObj.currencyName) {
+          targetCurrencyOptions.value = [
+            {
+              value: countryObj.currency,
+              label: `${countryObj.currency}(${countryObj.currencyName})`,
+            },
+          ]
+        } else {
+          targetCurrencyOptions.value = []
+        }
+      } else {
+        targetCurrencyOptions.value = []
+      }
+      rateForm.targetCurrency = ''
+    },
+    { immediate: true }
+  )
+
+  watch(
+    () => props.addType,
+    (type) => {
+      if (type == '3' || type == '2') {
+        // cardTypesList() // 这个方法在代码中未定义,需要确认
+      }
+      if (type == 'rate') {
+        targetCurrencyOptions.value = []
+        targetCountryOptions.value = []
+        loadBankOptions()
+      }
+      if (type == 'payment' || type == 'ucardValidate') {
+        loadBankConfigList()
+      }
+    }
+  )
+
+  // Lifecycle hooks
+  onMounted(() => {
+    getCountryList()
+    getCountryListForSelect()
+  })
+</script>
+
+<style lang="scss" scoped>
+  @import './index.scss';
+</style>

+ 1 - 2
tsconfig.json

@@ -1,5 +1,6 @@
 {
   "compilerOptions": {
+    "resolveJsonModule": true,
     "target": "ESNext",
     "module": "ESNext",
     "moduleResolution": "Node",
@@ -20,5 +21,3 @@
   "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
   "exclude": ["node_modules", "dist"]
 }
-
-