doum
3 天以前 6500da411f234b8ad0ee493909d515bf9eeecdd5
最新版本541200007
已添加4个文件
已修改19个文件
896 ■■■■ 文件已修改
admin/.env.development 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/package-lock.json 165 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/business/jkSketchCustomer.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/assets/icons/location-blue.png 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/assets/icons/location-red.png 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaJkSketchLineListWindow.vue 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaJkSketchLineMapWindow.vue 176 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaJkSketchResultWindow.vue 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/jkCustomer.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/JkSketchCloudController.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/JkSketchCustomerCloudController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/core/tsp/DistanceCustomerSimpleModel.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/JkCustomer.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/JkCustomerNavigation.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/JkSketch.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/JkSketchCustomer.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/JkSketchLine.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/JkSketchCustomerService.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/JkSketchService.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/JkCustomerServiceImpl.java 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/JkSketchCustomerServiceImpl.java 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/JkSketchServiceImpl.java 265 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/.env.development
@@ -7,3 +7,6 @@
# VUE_APP_API_URL  = 'http://10.50.250.253:8088/gateway_interface'
#key:045542fc5f436b75e6c911c5c84ff8cd
#密钥:8bd38497f9aee2b75e7a888a4dfd1e6c
VUE_APP_AMAP_KEY='045542fc5f436b75e6c911c5c84ff8cd'
admin/package-lock.json
@@ -4,6 +4,11 @@
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "@amap/amap-jsapi-loader": {
      "version": "1.0.1",
      "resolved": "https://registry.npmmirror.com/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz",
      "integrity": "sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw=="
    },
    "@babel/code-frame": {
      "version": "7.12.13",
      "resolved": "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.12.13.tgz",
@@ -1886,6 +1891,63 @@
          "integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=",
          "dev": true
        },
        "ansi-styles": {
          "version": "4.3.0",
          "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz",
          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
          "dev": true,
          "optional": true,
          "requires": {
            "color-convert": "^2.0.1"
          }
        },
        "chalk": {
          "version": "4.1.2",
          "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
          "dev": true,
          "optional": true,
          "requires": {
            "ansi-styles": "^4.1.0",
            "supports-color": "^7.1.0"
          }
        },
        "color-convert": {
          "version": "2.0.1",
          "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
          "dev": true,
          "optional": true,
          "requires": {
            "color-name": "~1.1.4"
          }
        },
        "color-name": {
          "version": "1.1.4",
          "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
          "dev": true,
          "optional": true
        },
        "has-flag": {
          "version": "4.0.0",
          "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz",
          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
          "dev": true,
          "optional": true
        },
        "loader-utils": {
          "version": "2.0.4",
          "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.4.tgz",
          "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
          "dev": true,
          "optional": true,
          "requires": {
            "big.js": "^5.2.2",
            "emojis-list": "^3.0.0",
            "json5": "^2.1.2"
          }
        },
        "ssri": {
          "version": "8.0.1",
          "resolved": "https://registry.npm.taobao.org/ssri/download/ssri-8.0.1.tgz?cache=0&sync_timestamp=1617826515595&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fssri%2Fdownload%2Fssri-8.0.1.tgz",
@@ -1893,6 +1955,28 @@
          "dev": true,
          "requires": {
            "minipass": "^3.1.1"
          }
        },
        "supports-color": {
          "version": "7.2.0",
          "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz",
          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
          "dev": true,
          "optional": true,
          "requires": {
            "has-flag": "^4.0.0"
          }
        },
        "vue-loader-v16": {
          "version": "npm:vue-loader@16.8.3",
          "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-16.8.3.tgz",
          "integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
          "dev": true,
          "optional": true,
          "requires": {
            "chalk": "^4.1.0",
            "hash-sum": "^2.0.0",
            "loader-utils": "^2.0.0"
          }
        }
      }
@@ -14125,87 +14209,6 @@
          "resolved": "https://registry.npm.taobao.org/hash-sum/download/hash-sum-1.0.2.tgz",
          "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=",
          "dev": true
        }
      }
    },
    "vue-loader-v16": {
      "version": "npm:vue-loader@16.8.3",
      "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-16.8.3.tgz",
      "integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
      "dev": true,
      "optional": true,
      "requires": {
        "chalk": "^4.1.0",
        "hash-sum": "^2.0.0",
        "loader-utils": "^2.0.0"
      },
      "dependencies": {
        "ansi-styles": {
          "version": "4.3.0",
          "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz",
          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
          "dev": true,
          "optional": true,
          "requires": {
            "color-convert": "^2.0.1"
          }
        },
        "chalk": {
          "version": "4.1.2",
          "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
          "dev": true,
          "optional": true,
          "requires": {
            "ansi-styles": "^4.1.0",
            "supports-color": "^7.1.0"
          }
        },
        "color-convert": {
          "version": "2.0.1",
          "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
          "dev": true,
          "optional": true,
          "requires": {
            "color-name": "~1.1.4"
          }
        },
        "color-name": {
          "version": "1.1.4",
          "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
          "dev": true,
          "optional": true
        },
        "has-flag": {
          "version": "4.0.0",
          "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz",
          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
          "dev": true,
          "optional": true
        },
        "loader-utils": {
          "version": "2.0.4",
          "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.4.tgz",
          "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
          "dev": true,
          "optional": true,
          "requires": {
            "big.js": "^5.2.2",
            "emojis-list": "^3.0.0",
            "json5": "^2.1.2"
          }
        },
        "supports-color": {
          "version": "7.2.0",
          "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz",
          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
          "dev": true,
          "optional": true,
          "requires": {
            "has-flag": "^4.0.0"
          }
        }
      }
    },
admin/package.json
@@ -13,6 +13,7 @@
    "fix": "eslint --ext .js,.vue src --fix"
  },
  "dependencies": {
    "@amap/amap-jsapi-loader": "^1.0.1",
    "@riophae/vue-treeselect": "^0.4.0",
    "@wangeditor/editor": "^5.1.23",
    "@wangeditor/editor-for-vue": "^1.0.2",
admin/src/api/business/jkSketchCustomer.js
@@ -13,6 +13,11 @@
    trim: true
  })
}
export function allMapList (data) {
  return request.post('/visitsAdmin/cloudService/business/jkSketchCustomer/allMapList', data, {
    trim: true
  })
}
// å¯¼å‡ºExcel
export function exportExcel (data) {
admin/src/assets/icons/location-blue.png
admin/src/assets/icons/location-red.png
admin/src/components/business/OperaJkSketchLineListWindow.vue
@@ -17,7 +17,7 @@
      <div style="display: flex;margin-top: 20px" class="orange">
        <div style="flex: 1" >线路原始总路程:
          <span  v-if="(model.originDistance ||0) > 0 ||  (model.status||0) != 0" class="red" style="font-weight: bold"> {{((model.originDistance ||0)/1000).toFixed(2)}}</span>
          <span  v-if="(model.originDistance ||0) == 0 && (model.status||0) == 0"  class="blue" style="font-weight: bold;cursor: pointer" @click="initDistance"> ç‚¹å‡»èŽ·å– </span> å…¬é‡Œï¼Œ
          <span  v-if="(model.originDistance ||0) == 0 && (model.status||0) == 0"  class="blue" style="font-weight: bold;cursor: pointer" @click="initDistance"> ç‚¹å‡»èŽ·å– </span> å…¬é‡Œï¼›
          <span v-if="model.status ==2">优化后总路程:<span class="green" style="font-weight: bold"> {{((model.distance ||0)/1000).toFixed(2)}} </span> å…¬é‡Œ</span>
        </div>
      </div>
@@ -40,12 +40,13 @@
          </el-table-column>
          <el-table-column
              label="操作"
              min-width="120"
              min-width="160"
              align="center"
              fixed="right"
          >
            <template slot-scope="{row}">
              <el-button type="text" @click="$refs.operaJkSketchCustomerWindow.open('线路客户明细——', row)" icon="el-icon-view"  >查看客户</el-button>
              <el-button type="text" @click="$refs.operaJkSketchLineMapWindow.open('线路客户交通路线——', row)" icon="el-icon-view"  >交通路线</el-button>
            </template>
          </el-table-column>
        </el-table>
@@ -55,6 +56,7 @@
      <el-button @click="visible=false">返回</el-button>
    </template>
    <OperaJkSketchCustomerWindow ref="operaJkSketchCustomerWindow"  />
    <OperaJkSketchLineMapWindow ref="operaJkSketchLineMapWindow"  />
  </GlobalWindow>
</template>
@@ -62,11 +64,12 @@
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
import OperaJkSketchCustomerWindow from '@/components/business/OperaJkSketchCustomerWindow'
import OperaJkSketchLineMapWindow from '@/components/business/OperaJkSketchLineMapWindow'
import { initOriginDistance } from '@/api/business/jkSketch'
export default {
  name: 'OperaJkSketchLineWindow',
  extends: BaseOpera,
  components: { GlobalWindow, OperaJkSketchCustomerWindow },
  components: { GlobalWindow, OperaJkSketchCustomerWindow ,OperaJkSketchLineMapWindow},
  data () {
    return {
      // è¡¨å•数据
@@ -103,6 +106,7 @@
        if(res){
          that.model.originDistance = res.originDistance
          that.model.distance = res.distance
          that.loadList()
        }
      })
    },
admin/src/components/business/OperaJkSketchLineMapWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,176 @@
<template>
  <GlobalWindow
    :title="title"
    width="100%"
    :visible.sync="visible"
  >
    <div id="container"></div>
    <div id="panel" style='position: absolute; right: 10px;top: 10px;height: 480px;width: 300px;z-index: 100;overflow: auto;'></div>
    <template   v-slot:footer>
      <el-button @click="visible=false">返回</el-button>
    </template>
  </GlobalWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
import AMapLoader from '@amap/amap-jsapi-loader'
import blueIcon from '@/assets/icons/location-blue.png'
import redIcon from '@/assets/icons/location-red.png'
export default {
  name: 'OperaJkSketchMapWindow',
  extends: BaseOpera,
  components: { GlobalWindow },
  data () {
    return {
      // è¡¨å•数据
      visible: false,
      title: '',
      dataList: [],
      locations: [],
      map: null,
      model: {
      }
    }
  },
  created () {
    this.config({
      module: '交控-线路优化线路客户记录信息表',
      api: '/business/jkSketchCustomer',
      'field.id': 'id',
      'field.main': 'id'
    })
  },
  methods: {
    open (title, row) {
      this.title = title + (row.lineName)
      this.visible = true
      this.dataList = []
      this.model = row
      this.locations = []
      this.initAMap()
    },
    loadCustomer () {
      var that = this
      this.api.allMapList({
        sketchLineId: this.model.id
      }).then(res => {
        that.dataList = res || []
        that.locations = []
        that.dataList.forEach((item, index) => {
          var allsteps = []
          allsteps.push([item.startLogitude, item.startLatitude])
          const steps = (item.steps || '').split(';')
          if (index != that.dataList.length - 1 || true) {
            steps.forEach(item1 => {
              const ll = (item1 || '').split(',')
              allsteps.push(ll)
            })
            allsteps.push([item.endLogitude, item.endLatitude])
          }
          try {
            /*  console.log(item)
                var driving = new AMap.Driving({
                  map: that.map,
                  panel: 'panel'
                })
                driving.search(new AMap.LngLat(item.startLogitude, item.startLatitude), new AMap.LngLat(item.endLogitude, item.endLatitude), function (status, result) {
                  if (status === 'complete') {
                    console.log('绘制驾车路线完成')
                  } else {
                    console.error('获取驾车数据失败:' + result)
                  }
                }) */
          } catch (e) {
          }
          var color = index === that.dataList.length - 1 ? '#a10e0e' : '#157713'
          var polyline = new AMap.Polyline({
            path: [allsteps],
            isOutline: true,
            outlineColor: color || '#157713',
            borderWeight: 1,
            strokeColor: color || '#157713',
            strokeOpacity: 1,
            strokeWeight: 2,
            // æŠ˜çº¿æ ·å¼è¿˜æ”¯æŒ 'dashed'
            strokeStyle: 'solid',
            // strokeStyle是dashed时有效
            strokeDasharray: [10, 5],
            lineJoin: 'round',
            lineCap: 'round',
            zIndex: 100
          })
          that.map.add([polyline])
          that.map.setFitView()
          const icon = new AMap.Icon({
            size: new AMap.Size(30, 50), // å›¾æ ‡å°ºå¯¸
            image: index === 0 ? redIcon : blueIcon
          })
          var marker = new AMap.Marker({
            position: new AMap.LngLat(item.startLogitude, item.startLatitude),
            icon: index === 0 ? redIcon : blueIcon,
            anchor: 'bottom-center',
            offset: new AMap.Pixel(0, 0)
          })
          var title = (index == 0 ? '园区' : (index + '.' + item.name + (' ' + item.location || ''))) + ',' + (index != that.dataList.length - 1 ? '距下一站:' : '返回园区:') + ((item.distance || 0) / 1000) + '公里'
          marker.setTitle(title)
          var contnet = '<div>' + (index == 0 ? '园区' : (index + '.' + item.name)) + '</div>'
          marker.setLabel({
            direction: 'right',
            offset: new AMap.Pixel(0, 0),
            content: contnet
          })
          marker.setMap(that.map)
          // that.locations.push(allsteps)
        })
      })
    },
    initAMap () {
      var that = this
      AMapLoader.load({
        key: process.env.VUE_APP_AMAP_KEY,
        version: '2.0',
        plugins: ['AMap.ToolBar', 'AMap.Driving'],
        AMapUI: {
          version: '1.1',
          plugins: []
        },
        Loca: {
          version: '2.0' // æ•°æ®å¯è§†åŒ–
        }
      }).then((AMap) => {
        that.map = new AMap.Map('container', {
          viewMode: '2D', // é»˜è®¤ä½¿ç”¨ 2D æ¨¡å¼
          zoom: 20, // åˆå§‹åŒ–地图层级
          center: [118.39, 31.28] // åˆå§‹åŒ–地图中心点
        })
        this.loadCustomer()
      }).catch(e => {
        console.log(e)
      })
    },
    getRandomColor (index, total) {
      const r = 21
      // const g = 80 +(index*50/total);
      const g = 120
      const b = 19
      return `rgb(${r}, ${g}, ${b})`
    }
  }
}
</script>
<style>
#container {
  padding: 0px;
  margin: 0px;
  width: 100%;
  height: 90%;
  position: absolute;
}
</style>
admin/src/components/business/OperaJkSketchResultWindow.vue
@@ -28,12 +28,16 @@
          <el-table-column prop="dateInfo" label="送货日期" min-width="130px"></el-table-column>
          <el-table-column prop="lineName" label="送货线路" min-width="130px">  </el-table-column>
          <el-table-column prop="orderNum" label="客户数(户)" min-width="130px"> </el-table-column>
          <el-table-column prop="totalNum" label="送货量(条)" min-width="130px"></el-table-column>
          <el-table-column prop="totalNum" label="送货量/最大量(条)" min-width="130px">
            <template slot-scope="{row}">
             {{row.totalNum ||0}} / {{row.maxOrder || 0}}
            </template>
          </el-table-column>
          <el-table-column prop="carCode" label="车牌号" min-width="100px"></el-table-column>
          <el-table-column prop="memberName" label="送货司机" min-width="100px"></el-table-column>
          <el-table-column prop="distance" label="总路程(公里)" min-width="100px">
            <template slot-scope="{row}">
              {{((row.distance ||0)/1000).toFixed(2)}}
             {{((row.distance ||0)/1000).toFixed(2)}}(调整前)
            </template>
          </el-table-column>
          <el-table-column
@@ -42,11 +46,11 @@
              align="left"
              fixed="right"
          >
            <template slot-scope="{row}">
            <template slot-scope="{row}" v-if="dataList.length>1">
              <el-button type="text" @click="updateDo(row)" icon="el-icon-edit"   style="color: #0d68ff" v-if="!updating" >微调</el-button>
              <template v-else-if="updating &&  currentRow.id ===row.id" >
                <el-button type="text" style="color: #13ce66"  >本车</el-button>
                <el-button type="text" @click="cancelDo(row)"  icon="el-icon-delete"  style="color: red" >取消</el-button>
                <el-button type="text" @click="cancelDo(row)"  icon="el-icon-circle-close"  style="color: red" >取消</el-button>
              </template>
              <el-button type="text" @click="addDo(row)" icon="el-icon-plus"  style="color: red" v-else-if="updating &&  currentRow.id !==row.id" >加入</el-button>
            </template>
@@ -60,7 +64,8 @@
      <div>
        <p class="tip-warn"><i class="el-icon-warning"></i>操作说明:<br>
          1.请选择若干客户信息,点击上述其他线路后的<span class="red">【加入】</span>按钮,将选中的客户移加到对应线路中;<br>
            2.点击本车线路后的<span class="red">【取消】</span>按钮,可撤销本车微调操作;<br>
          2.点击本车线路后的<span class="red">【取消】</span>按钮,可撤销本车微调操作;<br>
          3.经过调整后的线路路程数请等待提交后查看;<br>
        </p>
        <el-table  :data="paginatedData" stripe  @selection-change="handleSelectionChange">>
          <el-table-column type="selection" width="55"></el-table-column>
@@ -87,6 +92,7 @@
    </div>
    <template   v-slot:footer>
      <el-button @click="confirmDo" type="primary" v-if="buttonName!==''">{{ buttonName||'确认' }}</el-button>
      <el-button @click="resetData" type="danger" v-if="buttonName!==''">撤销所有调整</el-button>
      <el-button @click="visible=false">返回</el-button>
    </template>
  </GlobalWindow>
@@ -96,6 +102,7 @@
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
import { allList as customerList } from '@/api/business/jkSketchCustomer'
import { updateSketchLine } from '@/api/business/jkSketch'
export default {
  name: 'OperaJkSketchLineWindow',
  extends: BaseOpera,
@@ -104,11 +111,13 @@
    return {
      // è¡¨å•数据
      updating: false,
      edited: false,
      currentRow: null,
      model: {
      },
      buttonName: '',
      dataList: [],
      originDataList: [],
      currentPage: 1,
      pageSize: 10,
      totalItems: 0, // æ€»æ•°æ®æ¡ç›®æ•°
@@ -131,8 +140,28 @@
    }
  },
  methods: {
    resetData () {
      this.buttonName = ''
      this.cancelDo()
      this.loadList()
    },
    confirmDo () {
      this.isWorking = true
      updateSketchLine({
        id: this.model.id,
        sketchLineList: this.dataList
      })
        .then(() => {
          this.visible = false
          this.$tip.apiSuccess('线路调整已完成!')
          this.$emit('success')
        })
        .catch(e => {
          // this.$tip.apiFailed(e)
        })
        .finally(() => {
          this.isWorking = false
        })
    },
    open (title, target) {
      this.title = title + target.categoryName
@@ -153,7 +182,7 @@
      this.selectRows = []
      this.updating = true
    },
    cancelDo (row) {
    cancelDo () {
      this.selectRows = []
      this.currentRow = null
      this.updating = false
@@ -177,22 +206,22 @@
          tarray.push(item)
        }
      })
      if(tarray.length === 0){
      if (tarray.length === 0) {
        this.$message.error('对不起,本车线路至少留存一个客户信息,无法全部清空!')
        return
      }
      var rArray =  row.customerList || []
      rArray = rArray.push(...this.selectRows)
      var rArray = [...row.customerList || []]
      rArray.push(...this.selectRows)
      let ttNum = 0
      rArray.forEach(item => {
        ttNum += (item.totalNum || 0)
      })
      if(tarray.length >= (row.maxCustomer||0)){
        this.$message.error('对不起,加入的线路最大支持'+ (row.maxOrderNum||0) + '客户!')
      if (tarray.length >= (row.maxCustomer || 0)) {
        this.$message.error('对不起,加入的线路最大支持' + (row.maxCustomer || 0) + '客户!')
        return
      }
      if(ttNum >= (row.maxOrder||0)){
        this.$message.error('对不起,加入的线路最大支持'+ (row.maxOrder||0) + '送货量!')
      if (ttNum >= (row.maxOrder || 0)) {
        this.$message.error('对不起,加入的线路最大支持' + (row.maxOrder || 0) + '送货量,当前方案:' + ttNum)
        return
      }
      this.currentRow.customerList = tarray
@@ -204,6 +233,9 @@
      this.currentRow = null
      this.updating = false
      this.buttonName = '保存调整开始优化'
      console.log(this.dataList)
      console.log(this.originDataList)
    },
    handleSelectionChange (rows) {
      this.selectRows = rows
@@ -229,7 +261,8 @@
      this.api.allList({
        sketchId: this.model.id
      }).then(res => {
        this.dataList = res
        this.dataList = [...(res || [])]
        this.originDataList = JSON.parse(JSON.stringify(res||[]));
        this.loadCustomerList()
      })
    },
admin/src/views/business/jkCustomer.vue
@@ -31,8 +31,9 @@
      </el-form-item>
      <el-form-item label="交通规划状态" prop="distanceStatus">
        <el-select v-model="searchForm.distanceStatus" clearable filterable placeholder="请选择交通规划状态"  @change="search">
          <el-option  :value="0" label="未完成"></el-option>
          <el-option  :value="1" label="已完成"></el-option>
          <el-option  :value="2" label="未定位"></el-option>
          <el-option  :value="0" label="未规划"></el-option>
          <el-option  :value="1" label="已规划"></el-option>
        </el-select>
      </el-form-item>
      <section>
@@ -68,8 +69,9 @@
        <el-table-column prop="sortno" label="序号" min-width="100px"></el-table-column>
        <el-table-column prop="distanceStatus" label="交通规划状态" min-width="100px" align="center">
          <template slot-scope="{row}">
            <span v-if="row.distanceStatus === 1" class="green">已完成</span>
            <span v-else class="blue">未完成</span>
            <span v-if="row.distanceStatus === 2" class="red">未定位</span>
            <span v-else-if="row.distanceStatus === 1" class="green">已规划</span>
            <span v-else class="blue">未规划</span>
          </template>
        </el-table-column>
        <el-table-column prop="editDate" label="更新时间" min-width="140px"></el-table-column>
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/JkSketchCloudController.java
@@ -75,6 +75,16 @@
        return ApiResponse.success(null);
    }
    @ApiOperation("根据ID修改")
    @PostMapping("/updateSketchLine")
    @CloudRequiredPermission("business:jksketch:update")
    public ApiResponse updateSketchLine(@RequestBody JkSketch jkSketch, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        jkSketch.setLoginUserInfo(this.getLoginUser(token));
        JkSketch model = jkSketchService.updateSketchLine(jkSketch);
        jkSketchService.startEditSketchLineAsync(model);//异步优化
        return ApiResponse.success(null);
    }
    @ApiOperation("根据ID重新计算当前线路的距离")
    @PostMapping("/initOriginDistance")
    @CloudRequiredPermission("business:jksketch:update")
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/admin/JkSketchCustomerCloudController.java
@@ -5,6 +5,7 @@
import com.doumee.core.annotation.excel.ExcelExporter;
import com.doumee.core.annotation.pr.PreventRepeat;
import com.doumee.core.utils.Constants;
import com.doumee.dao.business.model.JkCustomerNavigation;
import com.doumee.dao.business.model.JkSketchCustomer;
import com.doumee.service.business.JkSketchCustomerService;
import com.doumee.service.business.third.model.ApiResponse;
@@ -81,6 +82,12 @@
    public ApiResponse<List<JkSketchCustomer>> allList (@RequestBody JkSketchCustomer pageWrap) {
        return ApiResponse.success(jkSketchCustomerService.findList(pageWrap));
    }
    @ApiOperation("列表查询")
    @PostMapping("/allMapList")
    @CloudRequiredPermission("business:jksketchcustomer:query")
    public ApiResponse<List<JkCustomerNavigation> > allMapList (@RequestBody JkSketchCustomer pageWrap) {
        return ApiResponse.success(jkSketchCustomerService.allMapList(pageWrap));
    }
    @ApiOperation("导出Excel")
    @PostMapping("/exportExcel")
server/visits/dmvisit_service/src/main/java/com/doumee/core/tsp/DistanceCustomerSimpleModel.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package com.doumee.core.tsp;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
@Slf4j
@Data
public class DistanceCustomerSimpleModel {
     private long distance;
     private List<String> locations;
     private String polyline;
     private Integer startId;
     private Integer endId;
}
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/JkCustomer.java
@@ -89,7 +89,7 @@
    @ApiModelProperty(value = "状态 0正常 ç¦ç”¨", example = "1")
    //@ExcelColumn(name="状态 0正常 ç¦ç”¨")
    private Integer status;
    @ApiModelProperty(value = "距离计算状态 0未计算 1已计算", example = "1")
    @ApiModelProperty(value = "距离计算状态 0未计算 1已计算 2未定位", example = "1")
    //@ExcelColumn(name="状态 0正常 ç¦ç”¨")
    private Integer distanceStatus;
    @ApiModelProperty(value = "客户间距离集合", example = "1")
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/JkCustomerNavigation.java
@@ -1,5 +1,6 @@
package com.doumee.dao.business.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -68,24 +69,28 @@
    @ExcelColumn(name="途径经纬度集合,分号隔开")
    private String steps;
    @ApiModelProperty(value = "维度", example = "1")
    @ApiModelProperty(value = "起点纬度", example = "1")
    @ExcelColumn(name="维度")
    private BigDecimal startLatitude;
    @ApiModelProperty(value = "客户序号", example = "1")
    @ApiModelProperty(value = "终点纬度", example = "1")
    @ExcelColumn(name="客户序号")
    private BigDecimal endLatitude;
    @ApiModelProperty(value = "送货路线编码(关联jk_line)", example = "1")
    @ExcelColumn(name="送货路线编码(关联jk_line)")
    @ApiModelProperty(value = "起点经度", example = "1")
    private BigDecimal startLogitude;
    @ApiModelProperty(value = "状态 0正常 ç¦ç”¨", example = "1")
    @ExcelColumn(name="状态 0正常 ç¦ç”¨")
    @ApiModelProperty(value = "终点经度", example = "1")
    private BigDecimal endLogitude;
    @ApiModelProperty(value = "起止点ID组合(startId-endId)")
    @ExcelColumn(name="起止点ID组合(startId-endId)")
    private String idIndex;
    @ApiModelProperty(value = "客户名称")
    @TableField(exist = false)
    private String name;
    @ApiModelProperty(value = "客户地址")
    @TableField(exist = false)
    private String location;
}
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/JkSketch.java
@@ -118,6 +118,9 @@
    @ApiModelProperty(value = "线路集合", example = "1")
    @TableField(exist = false)
    List<JkLine> lineList;
    @ApiModelProperty(value = "线路集合(调整后)", example = "1")
    @TableField(exist = false)
    List<JkSketchLine> sketchLineList;
    @ApiModelProperty(value = "线路编码集合", example = "1")
    @TableField(exist = false)
    List<Integer> lineIdList;
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/JkSketchCustomer.java
@@ -146,4 +146,5 @@
    @ApiModelProperty(value = "同班组间客户位置距离数组,[{a:12,b:100},{a:13,b:200},...],a:客户编码,b:与客户a之间的距离")
    @TableField(exist = false)
    private List<DistanceMapParam> distanceMapParamList;
}
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/JkSketchLine.java
@@ -85,6 +85,8 @@
    private Date dateInfo;
    @ApiModelProperty(value = "交通规划明细(json数组集合)", example = "1")
    private String steps;
    @ApiModelProperty(value = "车牌号", example = "1")
    @TableField(exist = false)
    private String carCode;
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/JkSketchCustomerService.java
@@ -1,5 +1,6 @@
package com.doumee.service.business;
import com.doumee.dao.business.model.JkCustomerNavigation;
import com.doumee.service.business.third.model.PageData;
import com.doumee.service.business.third.model.PageWrap;
import com.doumee.dao.business.model.JkSketchCustomer;
@@ -78,7 +79,8 @@
     * @return List<JkSketchCustomer>
     */
    List<JkSketchCustomer> findList(JkSketchCustomer jkSketchCustomer);
    List<JkCustomerNavigation>  allMapList(JkSketchCustomer jkSketchCustomer);
    /**
     * åˆ†é¡µæŸ¥è¯¢
     *
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/JkSketchService.java
@@ -38,7 +38,7 @@
     * @param jkSketch å®žä½“对象
     */
    void delete(JkSketch jkSketch);
    void initAyncsJob();
    /**
     * æ‰¹é‡ä¸»é”®åˆ é™¤
     *
@@ -108,4 +108,8 @@
    void distanceCustomer(Category model );
    Category   checkDataValid(JkSketch model);
    JkSketch updateSketchLine(JkSketch jkSketch);
    void startEditSketchLineAsync(JkSketch model);
}
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/JkCustomerServiceImpl.java
@@ -111,6 +111,12 @@
                .set(JkCustomer::getLatitude,jkCustomer.getLatitude())
                .set(JkCustomer::getLongitude,jkCustomer.getLongitude())
                .set(JkCustomer::getEditor,jkCustomer.getLoginUserInfo().getId())
                .set(JkCustomer::getStartDistance,null)
                .set(JkCustomer::getEndDistance,null)
                .set(JkCustomer::getStartSteps,null)
                .set(JkCustomer::getEndSteps,null)
                .set(JkCustomer::getDistanceStatus,Constants.ZERO)
                .set(JkCustomer::getDistance,null)
                .set(JkCustomer::getEditDate,new Date())
                .eq(JkCustomer::getId,jkCustomer.getId())
        );
@@ -237,10 +243,10 @@
        try {
            LambdaQueryWrapper<JkCustomer> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.isNotNull(JkCustomer::getLocation);
            queryWrapper.isNotNull(JkCustomer::getLocation);
            queryWrapper.and(wrapper ->{
                wrapper.isNull(JkCustomer::getLatitude)
                        .or().isNull(JkCustomer::getLongitude); });
                        .or().isNull(JkCustomer::getLongitude)
                        .or().eq(JkCustomer::getDistanceStatus,Constants.TWO);});
            //查询全部有地址,但是没有经纬度的客户信息
            List<JkCustomer>  list = jkCustomerMapper.selectList(queryWrapper);
            if(list ==null || list.size()==0){
@@ -269,13 +275,18 @@
                            jkCustomerMapper.update(null,new UpdateWrapper<JkCustomer>().lambda()
                                    .set(JkCustomer::getLatitude,c.getLatitude())
                                    .set(JkCustomer::getLongitude,c.getLongitude())
                                    .set(JkCustomer::getStartDistance,null)
                                    .set(JkCustomer::getEndDistance,null)
                                    .set(JkCustomer::getStartSteps,null)
                                    .set(JkCustomer::getEndSteps,null)
                                    .set(JkCustomer::getDistanceStatus,Constants.ZERO)
                                    .set(JkCustomer::getDistance,null)
                                    .set(JkCustomer::getEditDate,new Date())
                                    .eq(JkCustomer::getId,c.getId())
                            );
                        }
                    }else{
                        log.error("更新交控中心客户经纬度信息=====获取json=========="+json);
                        log.error("更新交控中心客户经纬度信息=====获取失败=========="+urlStr+c.getName()+"-"+c.getLocation());
                        log.error("更新交控中心客户经纬度信息=====获取json=========="+urlStr+"\n"+c.getName()+"\n"+json);
                    }
                }catch (Exception e){
                    log.error("更新交控中心客户经纬度信息=====失败=========="+c.getName()+"-"+c.getLocation());
@@ -394,10 +405,17 @@
            tModel.setCreator(loginUserInfo.getId());
            tModel.setCreateDate(new Date());
            tModel.setIsnew(Constants.ONE);
            tModel.setDistanceStatus(Constants.TWO);//需要重新定位
            tModel.setStatus(Constants.ZERO);
            tModel.setDistanceStatus(Constants.ZERO);
            newList.add(tModel);
        }else{
            if(StringUtils.isBlank(model.getLocation()) ||
                    StringUtils.equals(tModel.getLocation().replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5]","")
                    ,model.getLocation().replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5]",""))){
                //如果位置信息发生变化
                tModel.setDistanceStatus(Constants.TWO);//需要重新定位
            }
            tModel.setIsnew(Constants.ZERO);
            updateList.add(tModel);
        }
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/JkSketchCustomerServiceImpl.java
@@ -1,6 +1,9 @@
package com.doumee.service.business.impl;
import com.alibaba.fastjson.JSONObject;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.core.utils.Constants;
import com.doumee.dao.business.JkCustomerNavigationMapper;
import com.doumee.dao.business.model.*;
import com.doumee.service.business.third.model.PageData;
import com.doumee.service.business.third.model.PageWrap;
@@ -17,7 +20,9 @@
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
/**
@@ -29,7 +34,11 @@
public class JkSketchCustomerServiceImpl implements JkSketchCustomerService {
    @Autowired
    private SystemDictDataBiz systemDictDataBiz;
    @Autowired
    private JkSketchCustomerMapper jkSketchCustomerMapper;
    @Autowired
    private JkCustomerNavigationMapper jkCustomerNavigationMapper;
    @Override
    public Integer create(JkSketchCustomer jkSketchCustomer) {
@@ -82,6 +91,100 @@
        return jkSketchCustomerMapper.selectOne(wrapper);
    }
    /**
     * æŸ¥è¯¢å…¨éƒ¨äº¤é€šè§„划路线
     * @param jkSketchCustomer
     * @return
     */
    @Override
    public List<JkCustomerNavigation>  allMapList(JkSketchCustomer jkSketchCustomer) {
        List<JkCustomerNavigation> list = new ArrayList<>();
        MPJLambdaWrapper<JkSketchCustomer> queryWrapper = new MPJLambdaWrapper<>();
        jkSketchCustomer.setIsdeleted(Constants.ZERO);
        queryWrapper.selectAll(JkSketchCustomer.class )
                .selectAs(JkCustomer::getName,JkSketchCustomer::getName)
                .selectAs(JkCustomer::getCode,JkSketchCustomer::getCode)
                .selectAs(JkCustomer::getStartDistance,JkSketchCustomer::getStartDistance)
                .selectAs(JkCustomer::getEndDistance,JkSketchCustomer::getEndDistance)
                .selectAs(JkCustomer::getLatitude,JkSketchCustomer::getLatitude)
                .selectAs(JkCustomer::getLongitude,JkSketchCustomer::getLongitude)
                .selectAs(JkCustomer::getStartSteps,JkSketchCustomer::getStartSteps)
                .selectAs(JkCustomer::getEndSteps,JkSketchCustomer::getEndSteps)
                .selectAs(JkCustomer::getLocation,JkSketchCustomer::getLocation)
                .leftJoin(JkCustomer.class,JkCustomer::getId,JkSketchCustomer::getCustomerId ) ;
        queryWrapper.eq( JkSketchCustomer::getSketchLineId,jkSketchCustomer.getSketchLineId())
                    .eq( JkSketchCustomer::getIsdeleted,Constants.ZERO);
        BigDecimal cLatitude =new BigDecimal(0);
        BigDecimal cLongitude =new BigDecimal(0);
        String comLocation = systemDictDataBiz.queryByCode(Constants.SYSTEM,Constants.COMPANY_LOCATION).getCode();
        try {
            String[] ss = comLocation.split(",");
            cLongitude = new BigDecimal(ss[0]);
            cLatitude =  new BigDecimal(ss[1]);
        }catch (Exception e){
        }
        List<JkSketchCustomer> allList =  jkSketchCustomerMapper.selectJoinList(JkSketchCustomer.class,queryWrapper);
        if(allList !=null && allList.size()>0){
            JkCustomerNavigation startmodel = new JkCustomerNavigation();
            startmodel.setStartId(-1);
            startmodel.setName("园区");
            startmodel.setStartLatitude(cLatitude);
            startmodel.setStartLogitude(cLongitude);
            startmodel.setEndLatitude(allList.get(0).getLatitude());
            startmodel.setEndLogitude(allList.get(0).getLongitude());
            startmodel.setDistance(allList.get(0).getStartDistance());
            startmodel.setSteps(allList.get(0).getStartSteps());
            if(StringUtils.isBlank(startmodel.getSteps())){
                startmodel.setSteps(comLocation +";"+allList.get(0).getLongitude()+","+allList.get(0).getLatitude());
            }
            list.add(startmodel);
            for (int i = 0; i < allList.size(); i++) {
                if(allList.size() == i+1){
                    JkCustomerNavigation endmodel = new JkCustomerNavigation();
                    endmodel.setStartId(-1);
                    endmodel.setLocation(allList.get(i).getLocation());
                    endmodel.setName(allList.get(i).getName());
                    endmodel.setSteps(allList.get(i).getEndSteps());
                    endmodel.setStartLatitude(allList.get(i).getLatitude());
                    endmodel.setStartLogitude(allList.get(i).getLongitude());
                    endmodel.setDistance(allList.get(0).getEndDistance());
                    endmodel.setEndLatitude(cLatitude);
                    endmodel.setEndLogitude(cLongitude);
                    if(StringUtils.isBlank(startmodel.getSteps())){
                        startmodel.setSteps(allList.get(i).getLongitude()+","+allList.get(i).getLatitude()+";"+comLocation);
                    }
                    list.add(endmodel);
                    break;
                }
                JkSketchCustomer start = allList.get(i);
                JkSketchCustomer end = allList.get(i+1);
                JkCustomerNavigation tt = jkCustomerNavigationMapper.selectOne(new QueryWrapper<JkCustomerNavigation>().lambda()
                        .eq(JkCustomerNavigation::getIsdeleted,Constants.ZERO)
                        .eq(JkCustomerNavigation::getIdIndex, allList.get(i).getCustomerId()+"-"+ allList.get(i+1).getCustomerId())
                        .orderByDesc(JkCustomerNavigation::getId)
                        .last("limit 1")
                );
                if(tt==null){
                    //只有起止点
                    tt = new JkCustomerNavigation();
                    tt.setStartLatitude(start.getLatitude());
                    tt.setStartLogitude(start.getLongitude());
                    tt.setEndLatitude(end.getLatitude());
                    tt.setEndLogitude(end.getLongitude());
                }
                tt.setLocation(allList.get(i).getLocation());
                tt.setName(allList.get(i).getName());
                if(StringUtils.isBlank(tt.getSteps())){
                    tt.setSteps(start.getLongitude()+","+end.getLatitude()+";"+end.getLongitude()+","+end.getLatitude());
                }
                list.add(tt);
            }
        }
        return list;
    }
    @Override
    public List<JkSketchCustomer> findList(JkSketchCustomer jkSketchCustomer) {
        MPJLambdaWrapper<JkSketchCustomer> queryWrapper = new MPJLambdaWrapper<>();
server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/JkSketchServiceImpl.java
@@ -33,6 +33,7 @@
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.*;
import java.util.Date;
@@ -85,6 +86,22 @@
    public void delete(JkSketch jkSketch) {
        UpdateWrapper<JkSketch> deleteWrapper = new UpdateWrapper<>(jkSketch);
        jkSketchMapper.delete(deleteWrapper);
    }
    @Override
    @PostConstruct
    public void initAyncsJob() {
        //重置交通规划和线路规划的异步任务状态
        jkSketchMapper.update(null,new UpdateWrapper<JkSketch>().lambda()
                .set(JkSketch::getStatus,Constants.THREE)
                .eq(JkSketch::getIsdeleted,Constants.ZERO)
                .eq(JkSketch::getStatus,Constants.ONE));
        categoryMapper.update(null,new UpdateWrapper<Category>().lambda()
                .set(Category::getStatus,Constants.ZERO)
                .eq(Category::getType,Constants.FOUR)
                .eq(Category::getIsdeleted,Constants.ZERO)
                .eq(Category::getStatus,Constants.TWO));
    }
    @Override
@@ -142,6 +159,77 @@
        jkSketchMapper.updateById(model);
        return model;
    }
    @Override
    public  JkSketch updateSketchLine(JkSketch jkSketch) {
        JkSketch model = jkSketchMapper.selectById(jkSketch.getId());
        if(model == null ||Constants.equalsInteger(model.getIsdeleted(),Constants.ONE)){
            throw  new BusinessException(ResponseStatus.DATA_EMPTY);
        }
        if(  jkSketch.getSketchLineList() ==null || jkSketch.getSketchLineList().size()==0 ){
            throw  new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"请按要求调整优化方案!");
        }
        if(Constants.equalsInteger(model.getStatus(),Constants.ONE)){
            throw  new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"当前线路正存在优化任务,请耐心等待优化完成再进行该调整操作!");
        }
        //当前所有线路(符合条件的线路)
        List<JkSketchLine> lineList =  jkSketchLineMapper.selectJoinList(JkSketchLine.class,new MPJLambdaWrapper<JkSketchLine>()
                .selectAll(JkSketchLine.class )
                .selectAs(JkLine::getName,JkSketchLine::getLineName)
                .selectAs(JkLine::getMaxOrder,JkSketchLine::getMaxOrder)
                .selectAs(JkLine::getMaxCustomer,JkSketchLine::getMaxCustomer)
                .leftJoin(JkLine.class,JkLine::getId,JkOrders::getLineId )
                .eq(JkSketchLine::getSketchId,jkSketch.getId())
                .eq(JkSketchLine::getIsdeleted,Constants.ZERO));
        if(lineList ==null ||lineList.size() ==0){
            throw  new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"当前线路不满足优化方案调整条件!");
        }
        for(JkSketchLine line :lineList){
            JkSketchLine lineParam =getLineParamById(line.getId(),jkSketch.getSketchLineList());
            if(lineParam == null){
                throw  new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"请基于现有线路进行方案调整,线路【"+line.getLineName()+"】线路配置不正确!");
            }
            if(lineParam.getCustomerList() == null || lineParam.getCustomerList().size() == 0 ){
                throw  new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"请基于现有线路进行方案调整,线路【"+line.getLineName()+"】客户信息不能为空!");
            }
            Integer totalCus = 0;
            BigDecimal totalNum =new BigDecimal(0);
            for(JkSketchCustomer customer :lineParam.getCustomerList()){
                 totalCus += 1;//总客户量
                 totalNum = totalNum.add(Constants.formatBigdecimal(customer.getTotalNum()));//总送货量
                 customer.setSketchLineId(line.getId());
            }
            if( totalCus > Constants.formatIntegerNum(line.getMaxCustomer()) ){
                throw  new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"线路【"+line.getLineName()+"】线路订单客户数量超过了线路总客户量限制,无法进行调整!");
            }
            if( totalNum.doubleValue() > Constants.formatIntegerNum(line.getMaxOrder())){
                throw  new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"线路【"+line.getLineName()+"】订单送货量超过了线路总送货量限制,无法进行调整!");
            }
            lineParam.setTotalNum(totalNum);
            lineParam.setOrderNum(totalCus);
        }
        model.setSketchLineList(jkSketch.getSketchLineList());//线路信息
        model.setStatus(Constants.ONE);
        model.setEditDate(new Date());
        model.setEditor(jkSketch.getLoginUserInfo().getId());
        model.setPlanLineDate(model.getEditDate());
        model.setPlanLineUserId(jkSketch.getLoginUserInfo().getId());
        model.setJobId(UUID.randomUUID().toString());
        redisTemplate.opsForValue().set(Constants.RedisKeys.JKLINE_JOB+model.getJobId(),true );//做异步处理
        jkSketchMapper.updateById(model);
        return model;
    }
    private JkSketchLine getLineParamById(Integer id, List<JkSketchLine> sketchLineList) {
        for(JkSketchLine line: sketchLineList){
            if(Constants.equalsInteger(line.getId(),id)){
                return line;
            }
        }
        return  null;
    }
    @Override
    public JkSketch initOriginDistance(JkSketch jkSketch ) {
        JkSketch model = jkSketchMapper.selectById(jkSketch.getId());
@@ -344,7 +432,7 @@
        }
        String errorMsg ="";
        for(JkCustomer c1 : customerList){
            if(c1.getLatitude()==null || c1.getLongitude() ==null){
            if(c1.getLatitude()==null || c1.getLongitude() ==null || Constants.equalsInteger(c1.getDistanceStatus(),Constants.TWO)){
                errorMsg += c.getName()+"-"+c.getName()+" | ";
            }
        }
@@ -367,13 +455,17 @@
            long[] vehicleCapacities1=new long[lineList.size()];//每辆车的最大订单量限制
            long[] demands1 = new long[customerList.size()+1]; //各个点的订单量
            long[][] distanceMatrix1 = new long[customerList.size()+1][customerList.size()+1];
            distanceMatrix1[0][0] = 0;
            demands1[0] =0;//原点
            for (int i = 0; i < customerList.size(); i++) {
                List<DistanceMapParam>  disList =  customerList.get(i).getDistanceMapParamList();
                distanceMatrix1[0][i] =  disList.get(0).getDistance();
                distanceMatrix1[i][0] = disList.get(disList.size() -1).getDistance();
                distanceMatrix1[0][i+1] =  disList.get(0).getDistance();
                distanceMatrix1[i+1][0] = disList.get(disList.size() -1).getDistance();
                demands1[i+1] = Constants.formatBigdecimal( customerList.get(i).getTotalNum()).longValue();  //各个点的订单量
                for (int j = 0; j< disList.size()-2; j++) {
                for (int j = 0; j < customerList.size(); j++) {
                    distanceMatrix1[i+1][j+1] =disList.get(j+1).getDistance() ;
                }
               /* for (int j = 0; j< disList.size()-2; j++) {
                    if(j+1 >=10){
                        break;
                    }
@@ -382,7 +474,7 @@
                    }else{
                        distanceMatrix1[i+1][j+1]  = 1l;
                    }
                }
                }*/
            }
            for (int i = 0; i < lineList.size(); i++) {
                vehicleCapacities1[i] = lineList.get(i).getMaxOrder();//每辆车的最大订单量限制
@@ -402,6 +494,149 @@
        }
    }
    @Override
    @Async
    public  void startEditSketchLineAsync(JkSketch model) {
        boolean success = true;
        int totalDistance = 0;
        List<JkSketchLine> lineList = model.getSketchLineList();
        try {
            MPJLambdaWrapper<JkSketchCustomer> queryWrapper = new MPJLambdaWrapper<>();
            queryWrapper.selectAll(JkSketchCustomer.class )
                    .selectAs(JkCustomer::getName,JkSketchCustomer::getName)
                    .selectAs(JkCustomer::getCode,JkSketchCustomer::getCode)
                    .selectAs(JkCustomer::getDistance,JkSketchCustomer::getDistanceJson)
                    .selectAs(JkCustomer::getLongitude,JkSketchCustomer::getLongitude)
                    .selectAs(JkCustomer::getLatitude,JkSketchCustomer::getLatitude)
                    .selectAs(JkCustomer::getStartDistance,JkSketchCustomer::getStartDistance)
                    .selectAs(JkCustomer::getEndDistance,JkSketchCustomer::getEndDistance)
                    .leftJoin(JkCustomer.class,JkCustomer::getId,JkSketchCustomer::getCustomerId )
                    .eq(JkSketchCustomer::getSketchId, model.getId())
                    .eq(JkSketchCustomer::getIsdeleted,Constants.ZERO)
                    .orderByAsc(JkSketchCustomer::getSortnum);
            List<JkSketchCustomer> customerList = jkSketchCustomerMapper.selectJoinList(JkSketchCustomer.class,queryWrapper);
            if(customerList == null ||customerList.size() ==0){
                throw  new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"该线路客户信息为空,不满足优化条件!");
            }
            int totalNum = 0;
            for(JkSketchLine line : lineList){
                //完善线路客户优化参数
                List<JkSketchCustomer> customerListParam =  line.getCustomerList() ;
                if(customerListParam ==null || customerListParam.size()==0){
                    throw  new BusinessException(ResponseStatus.BAD_REQUEST);
                }
                initSketchCustomerListParam(line.getCustomerList(),customerList) ;
                totalNum += customerListParam.size();
            }
            if(totalNum != Constants.formatIntegerNum(model.getOrderNum())){
                throw  new BusinessException(ResponseStatus.BAD_REQUEST);
            }
            for(JkSketchLine line : lineList){
                //逐个路线优化
                List<JkSketchCustomer> customerListParam =  line.getCustomerList() ;
                TspSolver.DataModel dataModel = new TspSolver.DataModel();
                int vehicleNumber1 = 1;//线路数量
                long[] vehicleCapacities1=new long[]{line.getMaxOrder()};//每辆车的最大订单量限制
                long[] demands1 = new long[customerListParam.size()+1]; //各个点的订单量
                long[][] distanceMatrix1 = new long[customerListParam.size()+1][customerListParam.size()+1];
                distanceMatrix1[0][0] = 0;
                demands1[0] =0;//原点
                for (int i = 0; i < customerListParam.size(); i++) {
                    List<DistanceMapParam>  disList =  customerListParam.get(i).getDistanceMapParamList();
                    distanceMatrix1[0][i+1] =  disList.get(0).getDistance();
                    distanceMatrix1[i+1][0] = disList.get(disList.size() -1).getDistance();
                    demands1[i+1] = Constants.formatBigdecimal( customerListParam.get(i).getTotalNum()).longValue();  //各个点的订单量
                    for (int j = 0; j < customerListParam.size(); j++) {
                        distanceMatrix1[i+1][j+1] =disList.get(j+1).getDistance() ;
                    }
                }
                //构造优化数据模型
                dataModel.initDataInfo(vehicleNumber1,demands1,vehicleCapacities1,distanceMatrix1);
                TspSolver.startSearch(dataModel);
                if(dataModel.getSolutions()==null || dataModel.getSolutions().size()==0){
                    throw  new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"线路【"+line.getLineName()+"】调整失败 ï¼ŒæœªèŽ·å¾—æœ€ä¼˜äº¤é€šè§„åˆ’æ–¹æ¡ˆï¼");
                }
                TspSolverSolutions so = dataModel.getSolutions().get(0);
                List<Integer> routes = so.getRouteIndex();
                totalDistance += so.getDistance();
                if(routes.size() <=2) {
                    throw  new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"线路【"+line.getLineName()+"】调整失败 ï¼ŒæœªèŽ·å¾—æœ€ä¼˜äº¤é€šè§„åˆ’æ–¹æ¡ˆï¼");
                }
                //有效路径
                for (Integer cIndex : routes){
                    if(cIndex ==0){
                        continue; //起始点不处理
                    }
                    JkSketchCustomer customer = customerListParam.get(cIndex-1);
                    customer.setSortnum(cIndex-1);
                }
                line.setDistance(so.getDistance());
            }
        }catch (Exception e){
            e.printStackTrace();
            success =false;
        }finally {
            if(success){
                List<JkSketchCustomer> allList = new ArrayList<>();
                for(JkSketchLine line : lineList){
                    allList.addAll(line.getCustomerList());
                }
                jkSketchLineMapper.updateById(lineList);
                jkSketchCustomerMapper.updateById(allList);
            }
            jkSketchMapper.update(null,new UpdateWrapper<JkSketch>().lambda()
                    .eq(JkSketch::getId,model.getId() )
                    .eq(JkSketch::getJobId,model.getJobId() )
                    .set(success,JkSketch::getDistance,totalDistance)
                    .set(JkSketch::getPlanLineInfo,success?"最近一次线路调整成功":"最近一次线路调整失败!")
                    .set(JkSketch::getStatus,success?Constants.TWO:Constants.THREE)
                    .set(JkSketch::getPlanLineEndDate,new Date()));
        }
    }
    private List<JkSketchCustomer> initSketchCustomerListParam(List<JkSketchCustomer> customerList, List<JkSketchCustomer> customerList1) {
        for(JkSketchCustomer param : customerList){
            for(JkSketchCustomer model : customerList1){
              if(Constants.equalsInteger(model.getId(),param.getId())){
                  param.setLatitude(model.getLatitude());
                  param.setLongitude(model.getLongitude());
                  param.setStartDistance(model.getStartDistance());
                  param.setEndDistance(model.getEndDistance());
                  param.setDistanceJson(model.getDistanceJson());
              }
            }
        }
        for(JkSketchCustomer c : customerList){
            List<DistanceMapParam> tmpList = new ArrayList<>();
            List<DistanceMapParam> distanceMapParamList  = getListFromJsonStr(c.getDistanceJson());
            DistanceMapParam t0 = new DistanceMapParam();
            t0.setId(-2);//表示返回园区
            t0.setDistance(Constants.formatLongNum(c.getStartDistance()) );
            tmpList.add(t0);
            for(JkSketchCustomer cm : customerList){
                //客户和客户之间的距离信息
                DistanceMapParam t = new DistanceMapParam();
                t.setId(cm.getCustomerId());
                t.setDistance(0);
                DistanceMapParam param = getParamByCustomerIds( cm.getCustomerId(),distanceMapParamList);
                if(param!=null){//如果之前已经获取过
                    t = param;
                }
                tmpList.add(t);
            }
            DistanceMapParam tt = new DistanceMapParam();
            tt.setId(-2);//表示返回园区
            tt.setDistance(Constants.formatLongNum(c.getEndDistance()));
            tmpList.add(tt);
            c.setDistanceMapParamList(tmpList);
        }
        return  customerList;
    }
    private void initCustomerDistance( List<JkSketchLine> lineList,JkSketch model,boolean updateLineDistance) {
        List<JkSketchCustomer> customerList = model.getCustomerList();
@@ -443,13 +678,22 @@
            for (JkSketchLine line :lineList){
                long lineDistance = 0;
                List<JkSketchCustomer> customers = getCustomerListByLineId(line.getId(),customerList);
                int index =0;
                for(JkSketchCustomer c : customers){
                    lineDistance+= Constants.formatLongNum(c.getStartDistance());
                    lineDistance+= Constants.formatLongNum(c.getEndDistance());
                    for(JkSketchCustomer cm : customers){
                    if(index ==0){
                        lineDistance+= Constants.formatLongNum(c.getStartDistance());
                    }
                    if(index == customers.size()-1){
                        lineDistance+= Constants.formatLongNum(c.getEndDistance());
                        break;
                    }
                    DistanceMapParam param = getParamByCustomerIds( customers.get(index+1).getCustomerId(),getListFromJsonStr(c.getDistanceJson()));
                    lineDistance += param.getDistance();
                    index++;
                  /*  for(JkSketchCustomer cm : customers){
                        DistanceMapParam param = getParamByCustomerIds( cm.getCustomerId(),getListFromJsonStr(c.getDistanceJson()));
                        lineDistance += param.getDistance();
                    }
                    }*/
                }
                if(updateLineDistance && Constants.equalsInteger(model.getStatus(),Constants.ZERO) ){
                    line.setDistance(lineDistance);
@@ -503,10 +747,11 @@
        if(solutions!=null && solutions.size()>0){
            for(TspSolverSolutions so : solutions){
                List<Integer> routes = so.getRouteIndex();
                totalDistance+= so.getDistance();
                if(routes.size() <=2) {
                    continue;//无客户的非有效路线
                }
                totalDistance+= so.getDistance();
//                totalDistance+= so.getDistance();
                JkLine  line =model.getLineList().get(so.getLineIndex());
                JkSketchLine tModel =  new JkSketchLine();
                tModel.setSketchId(model.getId());