Kaynağa Gözat

feat: 工装、家装、跨区工程信息登录

zh 2 yıl önce
ebeveyn
işleme
6d1904bfc0
30 değiştirilmiş dosya ile 3583 ekleme ve 31 silme
  1. 11 7
      package-lock.json
  2. 1 1
      package.json
  3. 50 0
      src/api/crossDistrict.js
  4. 127 0
      src/api/frock.js
  5. 48 0
      src/api/homeDecoration.js
  6. 19 10
      src/components/Common/file-upload.vue
  7. 5 0
      src/components/template/template-page-1.vue
  8. 9 1
      src/main.js
  9. 4 3
      src/store/getters.js
  10. 14 9
      src/store/modules/user.js
  11. 136 0
      src/utils/lbs.js
  12. 609 0
      src/views/commercialEngineering/components/base.vue
  13. 135 0
      src/views/commercialEngineering/components/examine.vue
  14. 297 0
      src/views/commercialEngineering/components/geographicalPosi.vue
  15. 218 0
      src/views/commercialEngineering/components/model.vue
  16. 399 0
      src/views/commercialEngineering/components/operate.vue
  17. 97 0
      src/views/commercialEngineering/components/operationRecords.vue
  18. 60 0
      src/views/commercialEngineering/crossDistrict/crossDistrictForm.vue
  19. 251 0
      src/views/commercialEngineering/crossDistrict/crossDistrictkList.vue
  20. 45 0
      src/views/commercialEngineering/crossDistrict/detail.vue
  21. 46 0
      src/views/commercialEngineering/crossDistrict/examine.vue
  22. 44 0
      src/views/commercialEngineering/frock/detail.vue
  23. 47 0
      src/views/commercialEngineering/frock/examine.vue
  24. 57 0
      src/views/commercialEngineering/frock/frockForm.vue
  25. 248 0
      src/views/commercialEngineering/frock/frockList.vue
  26. 44 0
      src/views/commercialEngineering/homeDecoration/detail.vue
  27. 47 0
      src/views/commercialEngineering/homeDecoration/examine.vue
  28. 60 0
      src/views/commercialEngineering/homeDecoration/homeDecorationForm.vue
  29. 250 0
      src/views/commercialEngineering/homeDecoration/homeDecorationList.vue
  30. 205 0
      src/views/commercialEngineering/mixin/index.js

+ 11 - 7
package-lock.json

@@ -9,7 +9,7 @@
       "version": "4.4.0",
       "license": "MIT",
       "dependencies": {
-        "@zjlib/element-plugins": "^2.5.6",
+        "@zjlib/element-plugins": "^2.6.4",
         "axios": "0.18.1",
         "clipboard": "^2.0.8",
         "concurrent-tasks": "^1.0.7",
@@ -5555,9 +5555,9 @@
       "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
     },
     "node_modules/@zjlib/element-plugins": {
-      "version": "2.5.6",
-      "resolved": "http://121.41.110.30:4873/@zjlib%2felement-plugins/-/element-plugins-2.5.6.tgz",
-      "integrity": "sha512-pu+HfYPQkzbyp/7BsDbjz0ZyM4RgZXpixb11NEMmm2reQ48sXLBKS69JoCVW5/AlFrM/aUANLnhQ6jZotJf2og==",
+      "version": "2.6.4",
+      "resolved": "http://121.41.110.30:4873/@zjlib%2felement-plugins/-/element-plugins-2.6.4.tgz",
+      "integrity": "sha512-OMt4pQo3qM6Yvtti1yMJnnjI6cPdGr6bLUF23j38r4KIyg3blcSTmGNnRGXJeQEiX839pFau5w7EZ7e6XGF39w==",
       "dependencies": {
         "@turf/turf": "^6.5.0",
         "@vuemap/vue-amap": "^0.1.12",
@@ -5597,6 +5597,10 @@
         "vuex": "3.1.0",
         "webpack": "^4.46.0",
         "yarn": "^1.22.18"
+      },
+      "engines": {
+        "node": ">=8.9",
+        "npm": ">= 3.0.0"
       }
     },
     "node_modules/@zjlib/element-plugins/node_modules/element-ui": {
@@ -31562,9 +31566,9 @@
       "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
     },
     "@zjlib/element-plugins": {
-      "version": "2.5.7",
-      "resolved": "http://121.41.110.30:4873/@zjlib%2felement-plugins/-/element-plugins-2.5.7.tgz",
-      "integrity": "sha512-MpSOIU/kDSbzDAcpAgXiuIkmEFz6kMqlVEP9UvAvI9Qot6CXRGKGdxecN6U6KOc6LhD5JM/lFlqpNydjW60FfA==",
+      "version": "2.6.4",
+      "resolved": "http://121.41.110.30:4873/@zjlib%2felement-plugins/-/element-plugins-2.6.4.tgz",
+      "integrity": "sha512-OMt4pQo3qM6Yvtti1yMJnnjI6cPdGr6bLUF23j38r4KIyg3blcSTmGNnRGXJeQEiX839pFau5w7EZ7e6XGF39w==",
       "requires": {
         "@turf/turf": "^6.5.0",
         "@vuemap/vue-amap": "^0.1.12",

+ 1 - 1
package.json

@@ -15,7 +15,7 @@
     "test:ci": "npm run lint && npm run test:unit"
   },
   "dependencies": {
-    "@zjlib/element-plugins": "^2.5.7",
+    "@zjlib/element-plugins": "^2.6.4",
     "axios": "0.18.1",
     "clipboard": "^2.0.8",
     "concurrent-tasks": "^1.0.7",

+ 50 - 0
src/api/crossDistrict.js

@@ -0,0 +1,50 @@
+import request, { postBlob } from '@/utils/request'
+
+export function getLoginCrossDistrictList(params) {
+  return request({
+    url: `/trade/login/order/span/list?moduleId=${params.moduleId}`,
+    method: 'post',
+    data: params
+  })
+}
+
+
+export function exportLoginCrossDistrict(data, name) {
+  return postBlob({
+    url: '/trade/login/order/span/list/export',
+    data,
+    name
+  })
+}
+
+export function addLoginHomeDecoration(params) {
+  return request({
+    url: `/trade/login/order/span-add`,
+    method: 'post',
+    data: params
+  })
+}
+
+export function editLoginHomeDecoration(params) {
+  return request({
+    url: `/trade/login/order/span-edit`,
+    method: 'post',
+    data: params
+  })
+}
+
+export function examineLoginHomeDecoration(params) {
+  return request({
+    url: `/trade/login/order/span-examine`,
+    method: 'post',
+    data: params
+  })
+}
+
+export function submitLoginHomeDecoration(params) {
+  return request({
+    url: `/trade/login/order/span-submit`,
+    method: 'post',
+    data: params
+  })
+}

+ 127 - 0
src/api/frock.js

@@ -0,0 +1,127 @@
+import request, { postBlob } from '@/utils/request'
+
+export function getLoginFrockList(params) {
+  return request({
+    url: `/trade/login/order/work/list?moduleId=${params.moduleId}`,
+    method: 'post',
+    data: params
+  })
+}
+
+export function exportLoginFrock(data, name) {
+  return postBlob({
+    url: '/trade/login/order/work/list/export',
+    data,
+    name
+  })
+}
+
+export function addLoginFrock(params) {
+  return request({
+    url: `/trade/login/order/work-add`,
+    method: 'post',
+    data: params
+  })
+}
+
+export function editLoginFrock(params) {
+  return request({
+    url: `/trade/login/order/work-edit`,
+    method: 'post',
+    data: params
+  })
+}
+
+export function examineLoginFrock(params) {
+  return request({
+    url: `/trade/login/order/work-examine`,
+    method: 'post',
+    data: params
+  })
+}
+
+export function submitLoginFrock(params) {
+  return request({
+    url: `/trade/login/order/work-submit`,
+    method: 'post',
+    data: params
+  })
+}
+
+export function getCommercialEngineeringDetail(params) {
+  return request({
+    url: `/trade/login/order/detail`,
+    method: 'post',
+    params
+  })
+}
+
+// 商用工程登录单-替换业务员
+export function replaceService(params) {
+  return request({
+    url: `/trade/login/order/replace-service`,
+    method: 'post',
+    data: params
+  })
+}
+// 商用工程登录单-一键更新
+export function batchUpdate(params) {
+  return request({
+    url: `/trade/login/order/batch-update`,
+    method: 'post',
+    data: params
+  })
+}
+//  商用工程登录单-申请修改
+export function applyUpdate(params) {
+  return request({
+    url: `/trade/login/order/apply-update`,
+    method: 'post',
+    data: params
+  })
+}
+
+// 商用工程登录单-申请修改查询
+export function applyUpdateQuery(params) {
+  return request({
+    url: `/trade/login/order/apply-update/query`,
+    method: 'post',
+    data: params
+  })
+}
+
+// 商用工程登录单-删除
+export function delOrder(params) {
+  return request({
+    url: `/trade/login/order/del`,
+    method: 'post',
+    data: params
+  })
+}
+
+// 商用工程登录单-审核确认
+export function examineUpdate(params) {
+  return request({
+    url: `/trade/login/order/examine-update`,
+    method: 'post',
+    data: params
+  })
+}
+
+// 商用工程登录单-操作记录
+export function getOperationRecord(params) {
+  return request({
+    url: `/trade/login/order/operation/record`,
+    method: 'post',
+    params
+  })
+}
+
+// 商用工程登录单-附近项目
+export function getPositionProject(params) {
+  return request({
+    url: `/trade/login/order/position/project`,
+    method: 'post',
+    params
+  })
+}

+ 48 - 0
src/api/homeDecoration.js

@@ -0,0 +1,48 @@
+import request, { postBlob } from '@/utils/request'
+
+export function getLoginHomeDecorationList(params) {
+  return request({
+    url: `/trade/login/order/home/list?moduleId=${params.moduleId}`,
+    method: 'post',
+    data: params
+  })
+}
+export function exportLoginHomeDecoration(data, name) {
+  return postBlob({
+    url: '/trade/login/order/home/list/export',
+    data,
+    name
+  })
+}
+
+export function addLoginHomeDecoration(params) {
+  return request({
+    url: `/trade/login/order/home-add`,
+    method: 'post',
+    data: params
+  })
+}
+
+export function editLoginHomeDecoration(params) {
+  return request({
+    url: `/trade/login/order/home-edit`,
+    method: 'post',
+    data: params
+  })
+}
+
+export function examineLoginHomeDecoration(params) {
+  return request({
+    url: `/trade/login/order/home-examine`,
+    method: 'post',
+    data: params
+  })
+}
+
+export function submitLoginHomeDecoration(params) {
+  return request({
+    url: `/trade/login/order/home-submit`,
+    method: 'post',
+    data: params
+  })
+}

+ 19 - 10
src/components/Common/file-upload.vue

@@ -6,11 +6,12 @@
       :multiple="multiple"
       :show-file-list="isShowFileList"
       :file-list="fileList"
+      :limit="limit"
       :before-upload="beforeUpload"
       :on-remove="handleRemove"
       :on-success="handleUploadSuccess"
     >
-      <el-button size="small" type="primary">{{
+      <el-button :size="size" type="primary">{{
         multiple ? '点击上传' : fileList.length == 0 ? '点击上传' : '重新上传'
       }}</el-button>
     </el-upload>
@@ -20,7 +21,7 @@
 import { getOssConfig } from '@/api/common'
 
 export default {
-  name: 'fileUpload',
+  name: 'FileUpload',
   props: {
     fileList: Array,
     multiple: {
@@ -30,6 +31,14 @@ export default {
     fileType: {
       type: Array,
       default: () => ['image', 'video', 'word', 'excel', 'ppt', 'pdf']
+    },
+    size: {
+      type: String,
+      default: 'small'
+    },
+    limit: {
+      type: Number,
+      default: null
     }
   },
   data() {
@@ -40,15 +49,9 @@ export default {
       flag: false
     }
   },
-  created() {
-    getOssConfig().then(res => {
-      this.oss_url = res.data.host
-      this.dataObj = res.data
-    })
-  },
   computed: {
     isShowFileList: {
-      get: function () {
+      get: function() {
         if (!this.multiple) {
           if (this.fileList.length > 0 && this.fileList[0].url) {
             return true
@@ -57,9 +60,15 @@ export default {
           }
         }
       },
-      set: function (newValue) {}
+      set: function(newValue) {}
     }
   },
+  created() {
+    getOssConfig().then(res => {
+      this.oss_url = res.data.host
+      this.dataObj = res.data
+    })
+  },
   methods: {
     getUUID() {
       return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {

+ 5 - 0
src/components/template/template-page-1.vue

@@ -22,6 +22,7 @@
       :defaultSearchData="defaultSearchData"
       :replaceOrNotMap="replaceOrNotMap"
       :moreParameters="moreParameters"
+      :pofx="pofx"
       @columnWidthChange="columnWidthChange"
       @columnListChange="columnListChange"
     >
@@ -146,6 +147,10 @@ export default {
     setModuleId: {
       type: [String, Number],
       default: null
+    },
+    pofx: {
+      type: Boolean,
+      default: false
     }
   },
   data() {

+ 9 - 1
src/main.js

@@ -33,9 +33,17 @@ import * as filters from './filters' // global filters
 import directives from './directives'
 
 import '@zjlib/element-plugins/dest/element-plugins.css'
-import ElementPlugins from '@zjlib/element-plugins'
+import ElementPlugins, { AMap } from '@zjlib/element-plugins'
 Vue.use(ElementPlugins)
 
+Vue.use(AMap)
+AMap.initAMapApiLoader({
+  // 高德的key
+  key: '5894bf90997454b0df3c3d60cab12f64',
+  version: '2.0',
+  plugins: ['AMap.Geocoder', 'AMap.AutoComplete', 'AMap.PlaceSearch', 'AMap.DistrictSearch']
+})
+
 // // 本地引用;
 // import ElementPlugins from '@packages'
 // Vue.use(ElementPlugins)

+ 4 - 3
src/store/getters.js

@@ -16,8 +16,9 @@ const getters = {
   showMessages: state => state.user.showMessages,
   code: state => state.sales.code,
   isCustomer: state => state.user.customerId && state.user.customerName && state.user.customerNumber,
-  userInfo :state =>state.user.userInfo,
-  isHongGe:state => state.user.userInfo.isHongGe,
-  autoChangeNum:state => state.user.changeNum
+  isTradeExaminer: state => state.user.isTradeExaminer,
+  userInfo: state => state.user.userInfo,
+  isHongGe: state => state.user.userInfo.isHongGe,
+  autoChangeNum: state => state.user.changeNum
 }
 export default getters

+ 14 - 9
src/store/modules/user.js

@@ -9,14 +9,15 @@ const getDefaultState = () => {
     name: '', // 用户名称
     phone: '', // 用户手机
     menus: '', // 菜单
-    customerId: '', //经销商ID
-    customerName: '', //经销商名称
-    customerNumber: '', //经销商编码
+    customerId: '', // 经销商ID
+    customerName: '', // 经销商名称
+    customerNumber: '', // 经销商编码
+    isTradeExaminer: '',
     showMessages: null, //
     isNotice: false,
     websitNumber: '',
     isCollapse: true,
-    changeNum:1,
+    changeNum: 1,
     userInfo: JSON.parse(localStorage.getItem('supply_user')) || {}
   }
 }
@@ -54,6 +55,7 @@ const mutations = {
   SET_CUSTOMERNUMBER: (state, customerNumber) => {
     state.customerNumber = customerNumber
   },
+
   SET_IS_COLLAPSE(state, bool) {
     state.isCollapse = !bool.isCollapse
   },
@@ -63,19 +65,21 @@ const mutations = {
   SET_USETINFO(state, data) {
     state.userInfo = data
   },
-  SET_CHANGEUNM(state, data){
-    state.changeNum = data  || 1
-
+  SET_CHANGEUNM(state, data) {
+    state.changeNum = data || 1
   },
   showMessage: (state, value) => {
     if (value == 'yes') {
       state.showMessages = true
-    }else{
+    } else {
       state.showMessages = false
     }
   },
   SET_MESSAGE(state, value) {
     state.isNotice = value
+  },
+  SET_TRADEEXAMINER: (state, isTradeExaminer) => {
+    state.isTradeExaminer = isTradeExaminer
   }
 }
 
@@ -119,7 +123,7 @@ const actions = {
           }
           console.log(data)
           let websitNumber
-          const { nickName, userName, customerId, customerName, customerNumber, changeNum, isFront } = data
+          const { nickName, userName, customerId, customerName, customerNumber, changeNum, isFront, isTradeExaminer } = data
 
           if (data.adminWebsit) {
             websitNumber = data.adminWebsit.websitNumber
@@ -155,6 +159,7 @@ const actions = {
           commit('SET_CUSTOMERID', customerId)
           commit('SET_CUSTOMERNAME', customerName)
           commit('SET_CUSTOMERNUMBER', customerNumber)
+          commit('SET_TRADEEXAMINER', isTradeExaminer)
           commit('SET_NAME', nickName)
           commit('SET_PHONE', userName)
           commit('SET_USETINFO', data)

+ 136 - 0
src/utils/lbs.js

@@ -0,0 +1,136 @@
+import axios from 'axios'
+
+export function supervisorChangeList(keyword) {
+  return new Promise(function (r, j) {
+    try {
+      new AMap.Autocomplete({
+        city: '全国'
+      }).search(keyword, function (status, result) {
+        if (status === 'complete') {
+          r(result)
+        } else {
+          console.error('根据地址查询位置失败')
+          j(result)
+        }
+      })
+    } catch (error) {
+      j(error)
+    }
+  })
+}
+
+/**
+ * 根据地址查坐标
+ * @param {*} address 例如:广东省广州市天河区邮通小区
+ * @returns Object
+ */
+export function getLocation(address) {
+  return new Promise(function (r, j) {
+    try {
+      new AMap.Geocoder().getLocation(address, function (status, result) {
+        if (status === 'complete' && result.geocodes?.length) {
+          r(result.geocodes)
+        } else {
+          console.error('根据地址查询位置失败')
+          j(result)
+        }
+      })
+    } catch (error) {
+      j(error)
+    }
+  })
+}
+
+/**
+ * 根据坐标查地址
+ * @param {*} location 例如:[113.36242, 23.1368425]
+ * @returns Object
+ */
+export function getAddress(location) {
+  return new Promise(function (r, j) {
+    try {
+      new AMap.Geocoder().getAddress(location, function (status, result) {
+        if (status === 'complete' && result.regeocode) {
+          r(result.regeocode)
+        } else {
+          console.error('根据地址查询位置失败')
+          j(result)
+        }
+      })
+    } catch (error) {
+      j(error)
+    }
+  })
+}
+
+export function axiosMapZb(params) {
+  return axios({
+    url: `https://restapi.amap.com/v3/place/around`,
+    method: 'get',
+    params: {
+      key: 'b772f8b0ace6bc96c04ae8e48f241e36',
+      ...params
+    }
+  })
+}
+
+// 获取ip定位地址
+export function getIPAdd() {
+  return new Promise(function (r, j) {
+    try {
+      getIPs(ip => {
+        axios
+          .get('https://restapi.amap.com/v3/ip?output=json&key=b772f8b0ace6bc96c04ae8e48f241e36&ip=' + ip)
+          .then(r)
+          .catch(j)
+      })
+    } catch (error) {
+      j(error)
+    }
+  })
+}
+
+// 获取当前ip
+function getIPs(callback) {
+  var ip_dups = {}
+  var RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection
+  var useWebKit = !!window.webkitRTCPeerConnection
+  var mediaConstraints = {
+    optional: [{ RtpDataChannels: true }]
+  }
+  var servers = {
+    iceServers: [{ urls: 'stun:stun.services.mozilla.com' }, { urls: 'stun:stun.l.google.com:19302' }]
+  }
+  var pc = new RTCPeerConnection(servers, mediaConstraints)
+  function handleCandidate(candidate) {
+    var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
+    var hasIp = ip_regex.exec(candidate)
+    if (hasIp) {
+      var ip_addr = ip_regex.exec(candidate)[1]
+      if (ip_dups[ip_addr] === undefined) callback(ip_addr)
+      ip_dups[ip_addr] = true
+    }
+  }
+  pc.onicecandidate = function (ice) {
+    if (ice.candidate) {
+      handleCandidate(ice.candidate.candidate)
+    }
+  }
+  pc.createDataChannel('')
+  pc.createOffer(
+    function (result) {
+      pc.setLocalDescription(
+        result,
+        function () {},
+        function () {}
+      )
+    },
+    function () {}
+  )
+  setTimeout(function () {
+    var lines = pc.localDescription.sdp.split('\n')
+    lines.forEach(function (line) {
+      if (line.indexOf('a=candidate:') === 0) handleCandidate(line)
+    })
+  }, 500)
+}

+ 609 - 0
src/views/commercialEngineering/components/base.vue

@@ -0,0 +1,609 @@
+<!-- eslint-disable vue/valid-v-on -->
+<template>
+  <div>
+    <h3 class="title">
+      <div>{{ title }}</div>
+      <div class="title-right">格力商用空调登录表提示:带*的为必填项</div>
+    </h3>
+    <el-divider />
+    <div class="diy-table-1">
+      <el-row :gutter="0">
+        <el-col v-if="['cross'].includes(pageType)" :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label">项目性质*:</div>
+          <div class="value">
+            <el-radio-group v-model="formData.orderType" style="width: 100%">
+              <el-radio
+                v-for="item in [
+                  { label: '工装', value: 'WORK' },
+                  { label: '家装', value: 'HOME' }
+                ]"
+                :key="item.value"
+                :label="item.label"
+              >
+                {{ item.label }}
+              </el-radio>
+            </el-radio-group>
+            <el-input
+              value="工程/家装  根据商家选择的登录表自动显示对应性质,跨区登录不显示"
+              placeholder="请填写"
+              size="mini"
+              clearable
+            />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="12" class="item">
+          <div class="label">销售公司名称:</div>
+          <div class="value">
+            <el-input v-model="formData.salesCompanyName" placeholder="请填写" size="mini" clearable />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="12" class="item">
+          <div class="label">{{ ['cross'].includes(pageType) ? '业务' : '项目' }}所在区域*:</div>
+          <div class="value">
+            <el-select v-model="formData.projectArea" placeholder="请选择" clearable filterable @change="handleService">
+              <el-option
+                v-for="item in commonData.dict['TRADE_PROJECT_AREA']"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="12" class="item">
+          <div class="label">跟进人*:</div>
+          <div class="value">
+            <el-select v-model="formData.serviceId" placeholder="请选择" clearable filterable @change="handleService">
+              <el-option
+                v-for="item in commonData.salesmanList"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </div>
+        </el-col>
+        <el-col v-if="['frock', 'cross'].includes(pageType)" :xs="24" :sm="12" :lg="12" class="item">
+          <div class="label">甲方名称*:</div>
+          <div class="value">
+            <el-select v-model="formData.partyAId" placeholder="请选择" clearable filterable @change="handlePartyA">
+              <el-option
+                v-for="item in commonData.PartyAList"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </div>
+        </el-col>
+        <el-col v-else :xs="24" :sm="12" :lg="12" class="item">
+          <div class="label" />
+          <div class="value" />
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="8" class="item">
+          <div class="label">经销商*:</div>
+          <div class="value">
+            <el-select v-model="formData.customerId" placeholder="请选择" clearable filterable @change="handleCustomer">
+              <el-option
+                v-for="item in commonData.customerList"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="8" class="item">
+          <div class="label">经销商联系人:</div>
+          <div class="value">
+            <el-input v-model="formData.customerLinkName" placeholder="请填写" size="mini" clearable />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="8" class="item">
+          <div class="label">经销商联系电话:</div>
+          <div class="value">
+            <el-input v-model="formData.customerLinkMobile" placeholder="请填写" size="mini" clearable />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="8" class="item">
+          <div class="label">经销商办公地址:</div>
+          <div class="value">
+            <el-input v-model="formData.customerAddress" placeholder="请填写" size="mini" clearable />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="8" class="item">
+          <div class="label">跟进经销商*:</div>
+          <div class="value">
+            <el-input v-model="formData.followCustomer" placeholder="请填写" size="mini" clearable />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="8" class="item">
+          <div class="label">跟进经销商电话*:</div>
+          <div class="value">
+            <el-input v-model="formData.followCustomerMobile" placeholder="请填写" size="mini" clearable />
+          </div>
+        </el-col>
+        <el-col v-if="['frock', 'cross'].includes(pageType)" :xs="24" :sm="24" :lg="8" class="item">
+          <div class="label">工程项目名称*:</div>
+          <div class="value">
+            <el-input v-model="formData.projectName" placeholder="请填写" size="mini" clearable />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="['home'].includes(pageType)? 12: 8" class="item">
+          <div class="label">工程联系人*:</div>
+          <div class="value">
+            <el-input v-model="formData.enginLinkName" placeholder="请填写" size="mini" clearable />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="['home'].includes(pageType)? 12: 8" class="item">
+          <div class="label">电话*:</div>
+          <div class="value">
+            <el-input v-model="formData.enginLinkMobile" placeholder="请填写" size="mini" clearable />
+          </div>
+        </el-col>
+        <el-col v-if="['home'].includes(pageType)" :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label" style="height: auto;">工程项目名称*:</div>
+          <div class="value" style="height: 100%;">
+            <el-radio-group v-model="formData.homeProjectNameRadio" @change="">
+              <el-radio label="AREA">
+                <el-input v-model="formData.homeProjectNameArea" class="my-width" placeholder="请填写" size="mini" clearable />小区
+                <el-input v-model="formData.homeProjectNameSeat" class="my-width" placeholder="请填写" size="mini" clearable />座
+                <el-input v-model="formData.homeProjectNameNumber" class="my-width" placeholder="请填写" size="mini" clearable />号
+              </el-radio>
+              <el-radio label="SELF">
+                <el-input v-model="formData.homeProjectNameArea" class="my-width" placeholder="请填写" size="mini" clearable />小区
+              </el-radio>
+              <el-radio label="VILLA">
+                <el-input v-model="formData.homeProjectNameArea" class="my-width" placeholder="请填写" size="mini" clearable />小区
+                <el-input v-model="formData.homeProjectNameNumber" class="my-width" placeholder="请填写" size="mini" clearable />号别墅
+              </el-radio>
+            </el-radio-group>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label">工程(建筑)地址*:</div>
+          <div class="value">
+            <el-select v-model="formData.provinceId" placeholder="请选择省" class="my-width" @change="changeProvince">
+              <el-option v-for="item in provinceList" :key="item.id" :label="item.name" :value="item.id" />
+            </el-select>
+            <el-select v-model="formData.cityId" placeholder="请选择市" class="my-width" @change="changeCity">
+              <el-option v-for="item in cityList" :key="item.id" :label="item.name" :value="item.id" />
+            </el-select>
+            <el-select v-model="formData.areaId" placeholder="请选择区" class="my-width" @change="changeArea">
+              <el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id" />
+            </el-select>
+            <el-select v-model="formData.streetId" placeholder="请选择街道" class="my-width" @change="changeStreet">
+              <el-option v-for="item in streetList" :key="item.id" :label="item.name" :value="item.id" />
+            </el-select>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label">详细地址</div>
+          <div class="value">
+            <el-input v-model="formData.address" placeholder="请填写" size="mini" clearable />
+            <geographicalPosi v-if="module !== 'detail'" :form-data="formData" @on-select-posi="handleSelectPosi" />
+          </div>
+        </el-col>
+        <!-- <el-col :xs="24" :sm="24" :lg="24" class="item" style="height: 400px">
+          <div class="label" style="height: auto">地图位置</div>
+          <div class="value" style="height: auto; padding: 0">
+            <zj-amap-polygon
+              eid="bMap"
+              :zoom="zoom"
+              :center="center"
+              :markers="markers"
+              :electronic-fence="electronicFence"
+              @getPolygons="getPolygons"
+            />
+          </div>
+        </el-col> -->
+        <el-col :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label">项目类别*:</div>
+          <div class="value">
+            <el-radio-group v-model="formData.projectCategory">
+              <el-radio v-for="item in commonData.dict['TRADE_LOGIN_CATEGORY']" :key="item.value" :label="item.value">
+                {{ item.label }}
+              </el-radio>
+            </el-radio-group>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="12" class="item">
+          <div class="label">图纸上传:</div>
+          <div class="value" style="justify-content: flex-end">
+            <FileUpload v-if="module !== 'detail'" :file-list="fileList" size="mini" :limit="1" class="file" />
+            <el-input v-model="formData.drawUpload" disabled size="mini" clearable />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="12" class="item">
+          <div class="label">类型</div>
+          <div class="value">
+            <el-radio-group v-model="formData.type">
+              <el-radio v-for="item in commonData.dict['TRADE_LOGIN_TYPE']" :key="item.value" :label="item.value">
+                {{ item.label }}
+              </el-radio>
+            </el-radio-group>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="12" class="item">
+          <div class="label">建筑面积㎡*:</div>
+          <div class="value">
+            <el-input v-model="formData.extent" placeholder="请填写" size="mini" clearable />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="12" class="item">
+          <div class="label">空调使用面积㎡*:</div>
+          <div class="value">
+            <el-input v-model="formData.useExtent" placeholder="请填写" size="mini" clearable />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="12" class="item">
+          <div class="label">项目所在行业分类*:</div>
+          <div class="value">
+            <el-select
+              v-model="formData.tradeParentId"
+              placeholder="请选择"
+              clearable
+              filterable
+              @change="handleTradeParent"
+            >
+              <el-option v-for="item in tradeParentList" :key="item.id" :label="item.name" :value="item.id" />
+            </el-select>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="12" class="item">
+          <div class="label">行业细分*:</div>
+          <div class="value">
+            <el-select v-model="formData.tradeId" placeholder="请选择" clearable filterable @change="handleTrade">
+              <el-option v-for="item in tradeList" :key="item.id" :label="item.name" :value="item.id" />
+            </el-select>
+          </div>
+        </el-col>
+        <el-col v-if="['frock', 'cross'].includes(pageType)" :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label">项目性质*:</div>
+          <div class="value">
+            <el-input
+              value="工程/家装  根据商家选择的登录表自动显示对应性质,跨区登录不显示"
+              placeholder="请填写"
+              size="mini"
+              clearable
+            />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label">机组类型*:</div>
+          <div class="value">
+            <el-select v-model="formData.machineType" placeholder="请选择" clearable filterable>
+              <el-option
+                v-for="item in commonData.dict['MACHINE_TYPE']"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label">成功机率*:</div>
+          <div class="value">
+            <el-radio-group v-model="formData.successRate">
+              <el-radio v-for="item in commonData.dict['SUCCESS_RATE']" :key="item.value" :label="item.value">
+                {{ item.label }}
+              </el-radio>
+            </el-radio-group>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="12" class="item">
+          <div class="label">预计签定合同日期*:</div>
+          <div class="value">
+            <el-date-picker
+              v-model="formData.preSignDate"
+              class="date"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              default-time="00:00:00"
+              style="width: 100%"
+              placeholder="选择日期"
+            />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :lg="12" class="item">
+          <div class="label">预计设备金额*:</div>
+          <div class="value">
+            <el-input v-model="formData.preDeviceAmount" placeholder="请填写" size="mini" clearable />万
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label">工程跟进状态*:</div>
+          <div class="value">
+            <el-radio-group v-model="formData.status">
+              <el-radio v-for="item in commonData.dict['FOLLOW_STATUS']" :key="item.value" :label="item.value">
+                {{ item.label }}
+              </el-radio>
+            </el-radio-group>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label" style="height: auto">备注:</div>
+          <div class="value" style="height: 100%">
+            <el-input
+              v-model="formData.remark"
+              style="margin: 5px 0"
+              type="textarea"
+              :rows="4"
+              placeholder="请输入备注"
+            />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label" style="height: auto">工程概况及此工程相关的社会关系以及其他相关信息:</div>
+          <div class="value" style="height: 100%">
+            <el-input
+              v-model="formData.otherInfo"
+              style="margin: 5px 0"
+              type="textarea"
+              :rows="3"
+              placeholder="请输入内容"
+            />
+          </div>
+        </el-col>
+      </el-row>
+    </div>
+  </div>
+</template>
+
+<script>
+import { findElem } from '@/utils/util'
+import { getRegion } from '@/api/sales'
+import { getTradeConfigList } from '@/api/basic_data/sectorAllocation'
+
+import GeographicalPosi from './geographicalPosi.vue'
+import FileUpload from '@/components/Common/file-upload.vue'
+export default {
+  components: {
+    FileUpload,
+    GeographicalPosi
+  },
+  props: {
+    // 标题
+    title: {
+      type: String,
+      default: '登录信息'
+    },
+    // 数据源
+    formData: {
+      type: Object,
+      default: () => ({})
+    },
+    // 页面类型
+    pageType: {
+      type: String,
+      default: 'frock'
+    },
+    // 功能类型
+    module: {
+      type: String,
+      default: 'add'
+    },
+    commonData: {
+      type: Object,
+      default: () => {}
+    }
+  },
+  data() {
+    return {
+      fileList: [],
+      // 地图缩放比例
+      zoom: 16,
+      // 地图默认中心
+      center: [113.36242, 23.1368425],
+      markers: [
+        {
+          id: '',
+          name: '',
+          center: ['', ''] // [row.workerLng, row.workerLat]
+        }
+      ],
+      // 是否启用电子围栏
+      electronicFence: false,
+      provinceList: [],
+      cityList: [],
+      areaList: [],
+      streetList: [],
+      tradeParentList: [],
+      tradeList: []
+    }
+  },
+  created() {
+    this.getRegion()
+    this.getTradeConfigList()
+  },
+  methods: {
+    // 获取省市区街道
+    getRegion(level = 0, id = 0) {
+      getRegion({ pid: id }).then(res => {
+        if (level === 0) {
+          this.provinceList = res.data
+        } else if (level === 1) {
+          this.cityList = res.data
+        } else if (level === 2) {
+          this.areaList = res.data
+        } else if (level === 3) {
+          this.streetList = res.data
+        }
+      })
+    },
+    handleArea(value, type) {
+      this.formData[type] = this[type + 'List'].find(k => k.id === value).name
+    },
+    // 切换省
+    changeProvince(value) {
+      this.formData.cityId = ''
+      this.formData.areaId = ''
+      this.formData.streetId = ''
+      this.cityList = []
+      this.areaList = []
+      this.streetList = []
+      this.getRegion(1, value)
+      this.handleArea(value, 'province')
+    },
+
+    // 切换市
+    changeCity(value) {
+      this.formData.areaId = ''
+      this.formData.streetId = ''
+      this.areaList = []
+      this.streetList = []
+      this.getRegion(2, value)
+      this.handleArea(value, 'city')
+    },
+
+    // 切换区
+    changeArea(value) {
+      this.areaValue = value
+      this.formData.streetId = ''
+      this.streetList = []
+      this.getRegion(3, value)
+      this.handleArea(value, 'area')
+    },
+
+    // 切换街道
+    changeStreet(value) {
+      this.getRegion(3, this.areaValue)
+      this.handleArea(value, 'street')
+    },
+
+    // 初始化省市区街道
+    initRegion(level, item, id = 0) {
+      const { province, city, area, street } = item
+      let nextId = null
+      getRegion({ pid: id }).then(res => {
+        if (level === 0) {
+          this.provinceList = res.data
+          nextId = this.formData.provinceId = this.provinceList[findElem(this.provinceList, 'name', province)].id
+        } else if (level === 1) {
+          this.cityList = res.data
+          nextId = this.formData.cityId = this.cityList[findElem(this.cityList, 'name', city)].id
+        } else if (level === 2) {
+          this.areaList = res.data
+          nextId = this.formData.areaId = this.areaList[findElem(this.areaList, 'name', area)].id
+        } else if (level === 3) {
+          this.streetList = res.data
+          nextId = this.formData.streetId = this.streetList[findElem(this.streetList, 'name', street)].id
+        }
+        if (level < 3) {
+          level = level + 1
+          this.initRegion(level, item, nextId)
+        }
+      })
+    },
+    handleTradeParent(e) {
+      if (e) {
+        const item = this.tradeParentList.find(k => k.id === e)
+        this.formData.tradeParentName = item.name
+        this.getTradeConfigList(e)
+        return
+      }
+      this.formData.tradeId = ''
+    },
+    handleTrade(e) {
+      if (e) {
+        const item = this.tradeList.find(k => k.id === e)
+        this.formData.tradeName = item.name
+      } else {
+        this.formData.tradeId = ''
+        this.formData.tradeName = ''
+      }
+    },
+    getTradeConfigList(parentId = '') {
+      getTradeConfigList({
+        pageNum: 1,
+        pageSize: -1,
+        parentId: parentId
+      }).then(res => {
+        if (parentId) {
+          this.tradeList = res.data.records
+          return
+        }
+        this.tradeParentList = res.data.records
+      })
+    },
+    handleService(e) {
+      if (e) {
+        const item = this.commonData.salesmanList.find(k => k.value === e)
+        this.formData.serviceName = item.label
+      } else {
+        this.formData.serviceName = ''
+      }
+    },
+    handlePartyA(e) {
+      if (e) {
+        const item = this.commonData.PartyAList.find(k => k.value === e)
+        this.formData.partyA = item.label
+      } else {
+        this.formData.partyA = ''
+      }
+    },
+    handleCustomer(e) {
+      if (e) {
+        const item = this.commonData.customerList.find(k => k.value === e)
+        this.formData.customerName = item.label
+        this.formData.customerNumber = item.number
+      } else {
+        this.formData.customerName = ''
+        this.formData.customerNumber = ''
+      }
+    },
+    onSbumit() {},
+    getPolygons(data) {
+      console.log(data)
+    },
+    handleSelectPosi(data) {
+      this.formData.lng = data.center[0]
+      this.formData.lat = data.center[1]
+      console.log(this.formData, 9999)
+
+      var { province, city, district, township } = data.data.addressComponent
+      var { lbsId, name } = this.sheng.find(item => item.name === province)
+      this.formData.provinceId = lbsId
+      this.formData.province = name
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.diy-table-1 .item .label {
+  width: 180px;
+  padding: 10px;
+}
+::v-deep .el-select {
+  width: 100% !important;
+}
+::v-deep .date .el-input__icon,
+::v-deep .date .el-input__prefix {
+  right: 50px !important;
+  left: auto;
+}
+::v-deep .el-textarea__inner {
+  padding: 0;
+  border: none;
+}
+::v-deep .file:first-child > div {
+  display: flex !important;
+  align-items: center;
+  flex-direction: row-reverse;
+}
+::v-deep .file .is-success {
+  margin-top: 0;
+}
+.my-width{
+  width: 150px;
+}
+.title{
+  display: flex;
+    justify-content: space-between;
+    .title-right{
+      font-size: 16px;
+      font-weight: 300;
+    }
+}
+</style>

+ 135 - 0
src/views/commercialEngineering/components/examine.vue

@@ -0,0 +1,135 @@
+<template>
+  <div>
+    <h3>{{ title }}</h3>
+    <el-divider />
+    <div class="diy-table-1">
+      <el-row :gutter="0">
+        <el-col :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label">登录状态</div>
+          <div class="value">
+            <el-radio-group v-model="formData.loginStatus">
+              <el-radio v-for="item in engType" :key="item.value" :label="item.value">
+                {{ item.label }}
+              </el-radio>
+            </el-radio-group>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label" style="height: auto">选择登录成功项目</div>
+          <div class="value" style="height: 100%; display: block">
+            <el-col :span="7" class="flex-box">
+              <div class="flex-box-title">项目编号</div>
+              <el-input v-model="formData.projectNo" class="my-input" placeholder="请填写" size="mini" clearable />
+            </el-col>
+            <el-col :span="7" class="flex-box">
+              <div class="flex-box-title">经销商编号</div>
+              <el-input v-model="formData.customerNumber" class="my-input" placeholder="请填写" size="mini" clearable />
+            </el-col>
+            <el-col :span="7" class="flex-box">
+              <div class="flex-box-title">经销商名称</div>
+              <el-input v-model="formData.customerName" class="my-input" placeholder="请填写" size="mini" clearable />
+            </el-col>
+            <el-col :span="7" class="flex-box">
+              <div class="flex-box-title">业务员编号</div>
+              <el-input v-model="formData.serviceNumber" class="my-input" placeholder="请填写" size="mini" clearable />
+            </el-col>
+            <el-col :span="7" class="flex-box">
+              <div class="flex-box-title">业务员名称</div>
+              <el-input v-model="formData.serviceName" class="my-input" placeholder="请填写" size="mini" clearable />
+            </el-col>
+          </div>
+        </el-col>
+        <el-col :xs="12" :sm="12" :lg="12" class="item">
+          <div class="label">审核备注</div>
+          <div class="value">
+            <el-select v-model="formData.note" placeholder="请选择" size="mini" clearable style="width: 100%">
+              <el-option v-for="item in []" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+          </div>
+        </el-col>
+        <el-col :xs="12" :sm="12" :lg="12" class="item">
+          <div class="label">共同跟进项目编号</div>
+          <div class="value">
+            <el-input v-model="formData.commonFollowProject" placeholder="请填写" size="mini" clearable />
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="24" :lg="24" class="item">
+          <div class="label" style="height: auto">审核上传</div>
+          <div class="value" style="height: auto">
+            <ImageUpload class="mg-b" :file-list="formData.files" />
+            <div style="margin-left: 20px">注:可上传文件、附件</div>
+          </div>
+        </el-col>
+      </el-row>
+    </div>
+  </div>
+</template>
+
+<script>
+import ImageUpload from '@/components/Common/image-upload.vue'
+export default {
+  components: {
+    ImageUpload
+  },
+  props: {
+    title: {
+      type: String,
+      default: '审核信息'
+    },
+    formData: {
+      type: Object,
+      default: () => ({})
+    },
+    // 页面类型
+    pageType: {
+      type: String,
+      default: 'frock'
+    },
+    // 功能类型
+    module: {
+      type: String,
+      default: 'add'
+    },
+    commonData: {
+      type: Object,
+      default: () => {}
+    }
+  },
+  data() {
+    return {
+      engType: [
+        { label: '登录成功', value: 1 },
+        { label: '登录不成功', value: 2 },
+        { label: '驳回', value: 3 }
+      ]
+    }
+  },
+  methods: {
+    onSbumit() {}
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.diy-table-1 .item .label {
+  width: 150px;
+}
+::v-deep .el-radio {
+  margin-right: 120px;
+}
+.flex-box {
+  display: flex;
+  align-items: center;
+  margin: 5px 20px;
+  &-title {
+    width: 100px;
+  }
+}
+::v-deep .my-input > input {
+  padding-left: 10px !important;
+  border: 1px solid #dcdfe6 !important;
+}
+.mg-b {
+  margin: 10px 0;
+}
+</style>

+ 297 - 0
src/views/commercialEngineering/components/geographicalPosi.vue

@@ -0,0 +1,297 @@
+<template>
+  <div class="withinLine">
+    <el-button type="primary" size="mini" @click="open">地理定位</el-button>
+    <el-dialog
+      title="地理定位"
+      :visible.sync="dialogVisible"
+      :append-to-body="true"
+      width="1000px"
+      :before-close="handleClose"
+    >
+      <template v-if="dialogVisible">
+        <div>
+          <el-row :gutter="20">
+            <el-col :xs="24" :sm="24" :lg="24">
+              <div class="teshubuju">
+                <el-autocomplete
+                  v-model="queryString"
+                  style="width: 100%; margin-right: 10px"
+                  placeholder="请输入内容"
+                  :fetch-suggestions="querySearchAsync"
+                  @select="handleSelect"
+                />
+                <el-button
+                  size="mini"
+                  type="primary"
+                  @click="
+                    () => {
+                      querySearchAsync(queryString)
+                    }
+                  "
+                >查询</el-button>
+              </div>
+            </el-col>
+          </el-row>
+        </div>
+        <br>
+        <div style="height: 60vh; position: relative">
+          <zj-amap-polygon
+            :markers="markers"
+            :zoom="zoom"
+            :center="center"
+            :electronic-fence="false"
+            @getGeocoder="getGeocoder"
+          >
+            <template #marker="{ marker }">
+              <i class="el-icon-location-outline IP_font" />
+              <div class="IP">
+                <div>地址:{{ marker.name }}</div>
+                <div>经度:{{ marker.center[0] }}</div>
+                <div>维度:{{ marker.center[1] }}</div>
+              </div>
+            </template>
+          </zj-amap-polygon>
+          <!-- 周边数据 -->
+          <div class="zhoubian">
+            <div v-for="(item, index) in mapzhoubian" :key="index" class="zhoubianItem" @click="zhoubiandw(item)">
+              <div class="zhoubianItemview">
+                <i class="el-icon-location-outline" />
+                <div>
+                  <div style="font-weight: bold; margin-bottom: 8px; box-sizing: border-box; padding: 0px 5px">
+                    {{ item.pname }}{{ item.cityname }}{{ item.adname }}{{ item.address }}
+                  </div>
+                  <div>地址:{{ item.name }}</div>
+                </div>
+                <div>
+                  <img
+                    v-for="(p, i) in item.photos || []"
+                    v-if="i === 0"
+                    :key="i"
+                    :src="seturl(p.url)"
+                    alt=""
+                    srcset=""
+                  >
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+        <span slot="footer" class="dialog-footer">
+          <el-button size="mini" @click="handleClose">取 消</el-button>
+          <el-button size="mini" type="primary" @click="sub">提交</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getLocation, getAddress, supervisorChangeList, axiosMapZb } from '@/utils/lbs'
+export default {
+  props: { formData: { type: Object, default: () => ({}) }},
+  data() {
+    return {
+      dialogVisible: false,
+      loading: false,
+      center: [113.36242, 23.1368425],
+      zoom: 16.7,
+      markers: [],
+      mapSearchList: [],
+      mapzhoubian: [],
+      queryString: ''
+    }
+  },
+  watch: {
+    'formData.gpsAddress'() {
+      if (this.markers[0] && this.markers[0].name !== this.formData.gpsAddress) {
+        Object.assign(this.$data, this.$options.data())
+      }
+    }
+  },
+  methods: {
+    seturl(url) {
+      if (~url.indexOf('https://')) {
+        return url
+      } else {
+        return url.replace('http://', 'https://')
+      }
+    },
+    async open() {
+      this.dialogVisible = true
+      if (this.formData.lng && this.formData.lat && this.formData.gpsAddress) {
+        this.changeSearchMapFn(`${this.formData.lng}//${this.formData.lat}//${this.formData.gpsAddress}`)
+      } else {
+        var str = ''
+        if (!~(this.formData.gpsAddress || '').indexOf(this.formData.province)) {
+          str += this.formData.province || ''
+        }
+        if (!~(this.formData.gpsAddress || '').indexOf(this.formData.city)) {
+          str += this.formData.city || ''
+        }
+        if (!~(this.formData.gpsAddress || '').indexOf(this.formData.area)) {
+          str += this.formData.area || ''
+        }
+        if (!~(this.formData.gpsAddress || '').indexOf(this.formData.street)) {
+          str += this.formData.street || ''
+        }
+        str += this.formData.gpsAddress || ''
+        await this.remoteMethod(str)
+        if (this.mapSearchList.length) {
+          var v = this.mapSearchList[0]
+          this.changeSearchMapFn(`${v.location.KL}//${v.location.kT}//${v.formattedAddress}`)
+        }
+      }
+    },
+    async querySearchAsync(queryString, cb) {
+      if (!queryString) {
+        cb && cb([])
+      } else {
+        var res = await supervisorChangeList(queryString)
+        var list = res.tips.map(item => {
+          return {
+            ...item,
+            value: item.district + item.name + item.address
+          }
+        })
+        if (cb) {
+          cb(list)
+        } else if (list.length) {
+          this.handleSelect(list[0])
+        }
+      }
+    },
+    async handleSelect(item) {
+      this.center = [item.location.lng, item.location.lat]
+      var data = await getAddress(this.center)
+      this.markers = [
+        {
+          id: '',
+          name: item.value,
+          center: [item.location.lng, item.location.lat],
+          data: {
+            ...data,
+            formattedAddress: item.value
+          }
+        }
+      ]
+      this.getAxiosMapZb(this.center)
+    },
+    zhoubiandw(item) {
+      this.changeSearchMapFn(
+        `${item.location.split(',').join('//')}//${
+          item.pname + item.cityname + item.adname + item.name + item.address
+        }`,
+        false
+      )
+    },
+    async changeSearchMapFn(value, bool = true) {
+      const res = value.split('//')
+      var data = await getAddress([Number(res[0]), Number(res[1])])
+      this.queryString = res[2]
+      this.markers = [
+        {
+          id: '',
+          name: res[2],
+          center: [res[0], res[1]],
+          data
+        }
+      ]
+      this.center = [res[0], res[1]]
+      if (bool) {
+        this.getAxiosMapZb(this.center)
+      }
+    },
+    async remoteMethod(query) {
+      if (query !== '') {
+        this.loading = true
+        this.mapSearchList = await getLocation(query)
+        this.loading = false
+      } else {
+        this.workerList = []
+      }
+    },
+    async getAxiosMapZb(center = []) {
+      axiosMapZb({
+        location: center.join(',')
+      })
+        .then(res => {
+          this.mapzhoubian = res.data.pois
+        })
+        .catch(err => {
+          console.log(err)
+        })
+    },
+    getGeocoder(data) {
+      this.markers = [
+        {
+          id: '',
+          name: data.formattedAddress,
+          center: data.center,
+          data
+        }
+      ]
+      this.changeSearchMapFn(`${data.center[0]}//${data.center[1]}//${data.formattedAddress}`)
+    },
+    handleClose(done) {
+      this.dialogVisible = false
+    },
+    sub() {
+      this.$emit('selectPosi', this.markers[0])
+      this.handleClose()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+::v-deep .address_map {
+  .el-dialog__body {
+    padding: 0 20px;
+  }
+}
+.IP_font {
+  font-size: 28px;
+  color: #409eff;
+  position: absolute;
+  left: -13px;
+  top: -25px;
+}
+.IP {
+  width: 15vw;
+  background-color: #fff;
+  padding: 6px 0 6px 6px;
+}
+.withinLine {
+  display: inline-block;
+  ::v-deep .el-button {
+    margin-left: 10px;
+  }
+}
+.teshubuju {
+  display: flex;
+}
+.zhoubian {
+  width: 320px;
+  max-height: 100%;
+  position: absolute;
+  right: 0;
+  top: 0;
+  overflow-y: auto;
+  .zhoubianItem {
+    width: 100%;
+    height: auto;
+    box-sizing: border-box;
+    padding: 16px 8px;
+    border-bottom: 1px solid #aaa;
+    background: #fff;
+    cursor: pointer;
+    .zhoubianItemview {
+      display: flex;
+      justify-content: space-between;
+      img {
+        width: 100px;
+      }
+    }
+  }
+}
+</style>

+ 218 - 0
src/views/commercialEngineering/components/model.vue

@@ -0,0 +1,218 @@
+<template>
+  <div>
+    <h3>{{ title }}</h3>
+    <el-divider />
+    <zj-table
+      ref="tableEl"
+      :is-drop="true"
+      :columns="columns"
+      :table-data="formData.items"
+      :table-attributes="{
+        border: true
+      }"
+    />
+    <el-button v-if="module !=='detail'" style="width: 100%" type="primary" size="small" @click="handleAdd">添加</el-button>
+  </div>
+</template>
+
+<script>
+import { getMaterialListV2 } from '@/api/basic_data/material'
+
+export default {
+  props: {
+    title: {
+      type: String,
+      default: '机型信息'
+    },
+    formData: {
+      type: Object,
+      default: () => ({})
+    },
+    // 页面类型
+    pageType: {
+      type: String,
+      default: 'frock'
+    },
+    // 功能类型
+    module: {
+      type: String,
+      default: 'add'
+    },
+    commonData: {
+      type: Object,
+      default: () => {}
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      k3List: []
+    }
+  },
+  computed: {
+    columns() {
+      return [
+        ...(() => {
+          return this.module !== 'detail' ? [{
+            hidden: '',
+            columnAttributes: {
+              fixed: 'left',
+              label: '操作',
+              prop: ''
+            },
+            render: (h, { row, column, index }) => {
+              return (
+                <div>
+                  <el-button
+                    size='mini'
+                    type='text'
+                    onClick={() => {
+                      this.formData.items.splice(index, 1)
+                    }}
+                  >
+                  删除
+                  </el-button>
+                </div>
+              )
+            }
+          }] : []
+        })(),
+        {
+          columnAttributes: {
+            label: '物料名称',
+            prop: 'materialName'
+          },
+          render: (h, { row, column, index }) => {
+            return (
+              <el-select
+                value={row.materialName}
+                clearable
+                style='width: 100%;padding: 5px;'
+                onInput={e => (row.materialName = e)}
+                onChange={e => this.setCheckeData(e, row)}
+                filterable
+                size='mini'
+                remote
+                reserve-keyword
+                placeholder='请输入规格型号'
+                remote-method={e => this.remoteMethod(e, 'name')}
+                loading={this.loading}
+              >
+                {this.k3List.map(k => {
+                  return <el-option key={k.id} label={k.name} value={k.id}></el-option>
+                })}
+              </el-select>
+            )
+          }
+        },
+        {
+          columnAttributes: {
+            label: '规格型号',
+            prop: 'specification'
+          },
+          render: (h, { row, column, index }) => {
+            return (
+              <el-select
+                value={row.specification}
+                clearable
+                style='width: 100%;padding: 5px;'
+                onInput={e => (row.specification = e)}
+                onChange={e => this.setCheckeData(e, row)}
+                filterable
+                size='mini'
+                remote
+                reserve-keyword
+                placeholder='请输入规格型号'
+                remote-method={e => this.remoteMethod(e, 'specification')}
+                loading={this.loading}
+              >
+                {this.k3List.map(k => {
+                  return <el-option key={k.id} label={k.specification} value={k.id}></el-option>
+                })}
+              </el-select>
+            )
+          }
+        },
+        {
+          columnAttributes: {
+            label: '备注',
+            prop: 'itemRemark'
+          },
+          render: (h, { row, column, index }) => {
+            return (
+              <el-input style='padding: 5px;' value={row.itemRemark} onInput={e => (row.itemRemark = e)}
+                size='mini' clearable ></el-input>
+            )
+          }
+        },
+        {
+          columnAttributes: {
+            label: '数量',
+            prop: 'qty'
+          },
+          render: (h, { row, column, index }) => {
+            return (
+              <el-input style='padding: 5px;' value={row.qty} onInput={e => (row.qty = e)}
+                size='mini' clearable ></el-input>
+            )
+          }
+        }
+      ]
+    }
+  },
+  methods: {
+    remoteMethod(query, type, name) {
+      if (query !== '') {
+        this.loading = true
+        getMaterialListV2({
+          pageNum: 1,
+          pageSize: 100,
+          params: [
+            {
+              'param': `a.${type}`,
+              'compare': 'like',
+              'value': query
+            }
+          ]
+        }).then(res => {
+          this.k3List = res.data.records
+          this.loading = false
+        })
+      } else {
+        this.k3List = []
+      }
+    },
+    setCheckeData(e, row) {
+      if (e) {
+        const item = this.k3List.find(k => k.id === e)
+        row.specification = item.specification
+        row.materialName = item.name
+        row.materialId = item.id
+        row.materialOldNumber = item.oldNumber
+      } else {
+        row.specification = ''
+        row.materialName = ''
+        row.materialId = ''
+        row.materialOldNumber = ''
+      }
+    },
+    handleAdd() {
+      this.formData.items.push({
+        id: '',
+        itemRemark: '',
+        materialId: '',
+        materialName: '',
+        materialNumber: '',
+        materialOldNumber: '',
+        orderId: '',
+        projectNo: '',
+        qty: 0,
+        specification: '',
+        unit: ''
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 399 - 0
src/views/commercialEngineering/components/operate.vue

@@ -0,0 +1,399 @@
+<template>
+  <el-dialog
+    :title="operateTitle"
+    :visible.sync="visible"
+    :width="operateType === 'delete' ? '30%' : '50%'"
+    :append-to-body="true"
+    :close-on-click-modal="false"
+    @close="onClose"
+  >
+    <div v-if="['update', 'replace'].includes(operateType)">
+      <div>
+        <div v-if="operateType === 'update'">
+          <div class="flex-box">
+            <div class="flex-box-title">工单跟进状态</div>
+            <el-select v-model="formData.status" placeholder="请选择" clearable size="mini">
+              <el-option v-for="item in followType" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+          </div>
+          <div class="flex-box">
+            <div class="flex-box-title">工程登录信息</div>
+            <div>已选择{{ tableData.length || 0 }}个工程登录</div>
+          </div>
+        </div>
+      </div>
+      <div v-if="operateType === 'replace'">
+        <div class="flex-box">
+          <div class="flex-box-title">业务员</div>
+          <el-select v-model="formData.serviceId" placeholder="请选择" clearable size="mini">
+            <el-option v-for="item in salesmanList" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </div>
+        <div class="flex-box">
+          <div class="flex-box-title">备注</div>
+          <el-input
+            v-model="formData.remark"
+            type="textarea"
+            :rows="4"
+            placeholder="请输入"
+            :maxlength="-1"
+            :show-word-limit="false"
+            :autosize="{ minRows: 2, maxRows: 4 }"
+          />
+        </div>
+        <div class="flex-box">
+          <div class="flex-box-title">工程登录信息</div>
+          <div>已选择{{ tableData.length || 0 }}个工程登录</div>
+        </div>
+      </div>
+      <div>
+        <zj-table
+          ref="tableEl"
+          style="margin-bottom: 20px"
+          :is-drop="true"
+          :columns="columns"
+          :table-data="tableData"
+          :table-attributes="{
+            border: true,
+            selectColumn: true
+          }"
+          :table-events="tableEvents"
+        />
+        <div class="fr">
+          <el-pagination
+            :current-page="currentPage"
+            :page-sizes="[10, 20, 30, 50]"
+            :page-size="10"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="listTotal"
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"
+          />
+        </div>
+      </div>
+    </div>
+    <div v-if="operateType === 'delete'">
+      <div class="mg">请确认是否需要删除该项目?经删除后不可恢复</div>
+      <div>请确认是否需要删除已选择的项目?经删除后不可恢复</div>
+    </div>
+    <div v-if="operateType === 'apply'">
+      <div class="mg">请确认是否需要申请修改项目跟进状态?</div>
+      <div class="mg">申请原因</div>
+      <div>
+        <el-input
+          v-model="formData.remark"
+          type="textarea"
+          :rows="4"
+          placeholder="请输入"
+          :maxlength="-1"
+          :show-word-limit="false"
+          :autosize="{ minRows: 2, maxRows: 4 }"
+        />
+      </div>
+    </div>
+    <div v-if="operateType === 'examine'">
+      <el-row :gutter="20">
+        <el-col :span="12" :offset="0"> 申请人: {{ formData.applyBy }}</el-col>
+        <el-col :span="12" :offset="0"> 所属公司: {{ formData.applyCompany }} </el-col>
+      </el-row>
+      <div class="mg">申请原因</div>
+      <div>
+        <el-input
+          v-model="formData.applyReason"
+          type="textarea"
+          :rows="4"
+          placeholder="请输入"
+          :maxlength="-1"
+          :show-word-limit="false"
+          :autosize="{ minRows: 2, maxRows: 4 }"
+        />
+      </div>
+      <div class="mg">审核确认</div>
+      <div>
+        <el-radio-group v-model="formData.remark">
+          <el-radio
+            v-for="item in [
+              { label: '同意', value: 'YES' },
+              { label: '拒绝', value: 'NO' }
+            ]"
+            :key="item.value"
+            :label="item.value"
+          >
+            {{ item.label }}
+          </el-radio>
+        </el-radio-group>
+      </div>
+      <div class="mg">备注</div>
+      <div>
+        <el-input
+          v-model="formData.remark"
+          type="textarea"
+          :rows="4"
+          placeholder="请输入"
+          :maxlength="-1"
+          :show-word-limit="false"
+          :autosize="{ minRows: 2, maxRows: 4 }"
+        />
+      </div>
+    </div>
+    <span slot="footer">
+      <el-button @click="onClose">取消</el-button>
+      <el-button type="primary" @click="onConfirm">确定</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { getDictList, getSalesmanList } from '@/api/common'
+import { replaceService, batchUpdate, applyUpdate, delOrder, examineUpdate, applyUpdateQuery } from '@/api/frock'
+
+export default {
+  props: {
+    operateVisible: {
+      type: Boolean,
+      default: false
+    },
+    operateType: {
+      type: String,
+      default: 'update'
+    },
+    operateTitle: {
+      type: String,
+      default: '更新'
+    },
+    recordSelected: {
+      type: Array,
+      default: () => []
+    },
+    detailId: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      show: false,
+      visible: true,
+      formData: {
+        applyBy: '',
+        applyCompany: '',
+        applyReason: '',
+        ids: [],
+        isSuccess: '',
+        remark: '',
+        serviceId: '',
+        serviceName: '',
+        status: ''
+      },
+      tableData: [],
+      currentPage: 1,
+      listTotal: 0,
+      followType: [],
+      salesmanList: [],
+      machineList: [],
+      tableEvents: {
+        'selection-change': this.selectionChange
+      },
+      selectedData: []
+      // operateConfig: ['update', 'delete', 'apply', 'replace', 'examine']
+    }
+  },
+  computed: {
+    columns() {
+      return [
+        {
+          columnAttributes: {
+            label: '工程编号',
+            prop: 'projectNo',
+            width: 150
+          }
+        },
+        {
+          columnAttributes: {
+            label: '项目名称',
+            prop: 'projectName',
+            width: 200
+          }
+        },
+        {
+          columnAttributes: {
+            label: '登录日期',
+            prop: 'createTime',
+            width: 150
+          }
+        },
+        {
+          columnAttributes: {
+            label: '经销商名称',
+            prop: 'customerName',
+            width: 200
+          }
+        },
+        {
+          columnAttributes: {
+            label: '业务员',
+            prop: 'serviceName',
+            width: 100
+          }
+        },
+        {
+          columnAttributes: {
+            label: '机组类型',
+            prop: 'machineType'
+          }
+        },
+        {
+          columnAttributes: {
+            label: '工程地址',
+            prop: 'address',
+            width: 200
+          }
+        },
+        {
+          columnAttributes: {
+            label: '跟进状态',
+            prop: 'status'
+          }
+        }
+      ]
+    }
+  },
+  created() {
+    this.visible = this.operateVisible
+    this.tableData = this.recordSelected
+    if (['update', 'replace'].includes(this.operateType)) {
+      this.getDictList()
+      this.operateType === 'replace' && this.getSalesmanList()
+    }
+    if (this.operateType === 'examine' && this.detailId) {
+      this.getApplyUpdateQuery()
+    }
+  },
+  methods: {
+    getDictList() {
+      getDictList({
+        sysDictEnum: 'FOLLOW_STATUS'
+      }).then(res => {
+        this.followType = res.data.map(k => {
+          return {
+            label: k.dictValue,
+            value: k.dictCode
+          }
+        })
+      })
+    },
+    getSalesmanList() {
+      getSalesmanList({
+        pageNum: 1,
+        pageSize: -1,
+        isCustomer: 0,
+        status: true
+      }).then(res => {
+        this.salesmanList = res.data.records.map(k => {
+          return {
+            label: k.nickName,
+            value: k.adminUserId
+          }
+        })
+      })
+    },
+    getApplyUpdateQuery() {
+      applyUpdateQuery({ id: this.detailId }).then(res => {
+        this.formData = {
+          ...res.data
+        }
+      })
+    },
+    selectionChange(data) {
+      this.selectedData = data
+    },
+    handleInterface(fn, tip) {
+      fn.then(() => {
+        this.$successMsg(tip)
+        this.onClose()
+      })
+    },
+    onConfirm() {
+      let params
+      const fnEnum = {
+        update: () => {
+          if (!this.formData.status) {
+            this.$errorMsg('工单跟进状态不能为空')
+            return
+          }
+          if (!this.selectedData.length) {
+            this.$errorMsg('工程登录信息不能为空')
+            return
+          }
+          const ids = this.selectedData.map(k => k.id)
+          params = {
+            status: this.formData.status,
+            ids
+          }
+          this.handleInterface(batchUpdate(params), '更新成功')
+        },
+        replace: () => {
+          if (!this.formData.serviceId) {
+            this.$errorMsg('业务员不能为空')
+            return
+          }
+          if (!this.selectedData.length) {
+            this.$errorMsg('工程登录信息不能为空')
+            return
+          }
+          const ids = this.selectedData.map(k => k.id)
+          const serviceName = this.salesmanList.find(k => k.value === this.formData.serviceId).label
+          params = {
+            serviceId: this.formData.serviceId,
+            serviceName,
+            ids
+          }
+          this.handleInterface(replaceService(params), '替换成功')
+        },
+        apply: () => {
+          if (!this.formData.remark) {
+            this.$errorMsg('申请原因不能为空')
+            return
+          }
+          params = {
+            remark: this.formData.remark,
+            ids: [this.detailId]
+          }
+          this.handleInterface(applyUpdate(params), '申请成功')
+        },
+        examine: () => {
+          params = {
+            remark: this.formData.remark,
+            ids: [this.detailId]
+          }
+          this.handleInterface(examineUpdate)
+        },
+        delete: () => {
+          const ids = this.tableData.map(k => k.id)
+          this.handleInterface(delOrder(ids), '删除成功')
+        }
+      }
+      fnEnum[this.operateType]()
+    },
+    onClose() {
+      this.$emit('close')
+    },
+    handleSizeChange() {},
+    handleCurrentChange() {}
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.flex-box {
+  display: flex;
+  align-items: center;
+  margin: 20px 0;
+  &-title {
+    flex: 0 0 100px;
+  }
+}
+.mg {
+  margin: 20px 0;
+}
+</style>

+ 97 - 0
src/views/commercialEngineering/components/operationRecords.vue

@@ -0,0 +1,97 @@
+<template>
+  <div>
+    <zj-table
+      ref="tableEl"
+      style="margin: 20px 0"
+      :is-drop="true"
+      :columns="columns"
+      :table-data="tableData"
+      :table-attributes="{
+        border: true,
+        maxHeight: '600px'
+      }"
+    />
+    <!-- <div class="fr">
+      <el-pagination
+        :current-page="currentPage"
+        :page-sizes="[10, 20, 30, 50]"
+        :page-size="10"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="listTotal"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+      />
+    </div> -->
+  </div>
+</template>
+
+<script>
+import { getOperationRecord } from '@/api/frock'
+export default {
+  props: {
+    detailId: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      target: 1,
+      tableData: [],
+      currentPage: 1,
+      listTotal: 0
+    }
+  },
+  computed: {
+    columns() {
+      return [
+        {
+          columnAttributes: {
+            label: '操作类型',
+            prop: 'operType'
+          }
+        },
+        {
+          columnAttributes: {
+            label: '操作内容',
+            prop: 'operContent',
+            width: 400
+          }
+        },
+        {
+          columnAttributes: {
+            label: '备注',
+            prop: 'remark'
+          }
+        },
+        {
+          columnAttributes: {
+            label: '操作人',
+            prop: 'createBy'
+          }
+        },
+        {
+          columnAttributes: {
+            label: '操作时间',
+            prop: 'createTime'
+          }
+        }
+      ]
+    }
+  },
+  created() {
+    this.getOperationRecord()
+  },
+  methods: {
+    getOperationRecord() {
+      getOperationRecord({ id: this.detailId }).then(res => {
+        this.tableData = res.data
+      })
+    },
+    handleSizeChange() {},
+    handleCurrentChange() {}
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 60 - 0
src/views/commercialEngineering/crossDistrict/crossDistrictForm.vue

@@ -0,0 +1,60 @@
+<template>
+  <div>
+    <Base :form-data="formData" page-type="cross" :module="module" :common-data="commonData" />
+    <Model :form-data="formData" page-type="cross" :module="module" :common-data="commonData" />
+    <div style="margin: 20px 0">
+      <el-button type="primary" size="small" @click="onSbumit(1)">提交</el-button>
+      <el-button type="primary" size="small" @click="onSbumit(2)">暂存-草稿箱</el-button>
+      <el-button size="small" @click="onReset">重置</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import Base from '../components/base.vue'
+import Model from '../components/model.vue'
+import Mixin from '../mixin'
+import { addLoginHomeDecoration, editLoginHomeDecoration, submitLoginHomeDecoration } from '@/api/crossDistrict'
+export default {
+  components: {
+    Base,
+    Model
+  },
+  mixins: [Mixin],
+  methods: {
+    onSbumit(type) {
+      const params = {
+        ...this.formData
+      }
+      params.address = params.projectName
+      params.positionAddress = params.address
+      const item = [113.36242, 23.1368425]
+      params.lat = item[0]
+      params.lnt = item[1]
+      params.isSpan = true
+
+      if (type === 1) {
+        submitLoginHomeDecoration(params).then(res => {
+          this.commonFn('提交成功')
+        })
+      } else {
+        if (!this.detailId) {
+          addLoginHomeDecoration(params).then(res => {
+            this.commonFn('新增成功')
+          })
+          return
+        }
+        editLoginHomeDecoration(params).then(res => {
+          this.commonFn('编辑成功')
+        })
+      }
+    },
+    commonFn(name) {
+      this.$successMsg(name)
+      this.$emit('updateList')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 251 - 0
src/views/commercialEngineering/crossDistrict/crossDistrictkList.vue

@@ -0,0 +1,251 @@
+<template>
+  <template-page
+    ref="pageRef"
+    :get-list="getList"
+    :export-list="exportList"
+    :operation="operation()"
+    :pofx="true"
+    :column-parsing="columnParsing"
+    :operation-column-width="200"
+    :options-evens-group="optionsEvensGroup"
+    :table-attributes="tableAttributes"
+    :table-events="tableEvents"
+  >
+    <Popu v-if="visible">
+      <el-page-header slot="head" :content="content" @back="handleClose" />
+      <CrossDistrictForm
+        v-if="['add', 'edit','apply'].includes(module)"
+        :detail-id="detailId"
+        :module="module"
+        @updateList="handleClose"
+      />
+      <Detail v-if="['detail'].includes(module)" :detail-id="detailId" :module="module" @updateList="handleClose" />
+      <Examine v-if="['examine'].includes(module)" :detail-id="detailId" :module="module" @updateList="handleClose" />
+    </Popu>
+    <Operate v-if="operateVisible" :operate-visible="operateVisible" :operate-type="operateType" :operate-title="operateTitle" :detail-id="detailId" :record-selected="recordSelected" @close="handleClose" />
+
+  </template-page>
+</template>
+
+<script>
+import TemplatePage from '@/components/template/template-page-1.vue'
+import import_mixin from '@/components/template/import_mixin.js'
+import add_callback_mixin from '@/components/template/add_callback_mixin.js'
+import Popu from '@/components/template/popu.vue'
+import CrossDistrictForm from './crossDistrictForm.vue'
+import Detail from './detail.vue'
+import Examine from './examine.vue'
+import Operate from '../components/operate.vue'
+import { mapGetters } from 'vuex'
+
+import { getLoginCrossDistrictList, exportLoginCrossDistrict } from '@/api/crossDistrict'
+export default {
+  components: { TemplatePage, Popu, CrossDistrictForm, Detail, Examine, Operate },
+  mixins: [import_mixin, add_callback_mixin],
+  data() {
+    return {
+      visible: false,
+      // 事件组合
+      optionsEvensGroup: [
+        [
+          [
+            {
+              name: '添加记录',
+              click: this.addOn(() => {
+                this.visible = true
+              })
+            }
+          ]
+        ],
+        ...(() => {
+          return !this.isTradeExaminer
+            ? [
+              [
+                [
+                  {
+                    name: '更新',
+                    click: () => {
+                      if (this.recordSelected.length === 0) {
+                        this.$message.error('请选择需要更新的数据')
+                        return
+                      }
+                      this.operateType = 'update'
+                      this.operateTitle = '更新'
+                      this.operateVisible = true
+                    }
+                  }
+                ]
+              ],
+              [
+                [
+                  {
+                    name: '替换业务员',
+                    click: () => {
+                      if (this.recordSelected.length === 0) {
+                        this.$message.error('请选择需要替换业务员的数据')
+                        return
+                      }
+                      this.operateType = 'replace'
+                      this.operateTitle = '替换业务员'
+                      this.operateVisible = true
+                    }
+                  }
+                ]
+              ],
+              [
+                [
+                  {
+                    name: '删除',
+                    click: () => {
+                      if (this.recordSelected.length === 0) {
+                        this.$message.error('请选择需要删除的数据')
+                        return
+                      }
+                      this.operateType = 'delete'
+                      this.operateTitle = '删除'
+                      this.operateVisible = true
+                    }
+                  }
+                ]
+              ]
+            ]
+            : []
+        })()
+      ],
+      // 表格属性
+      tableAttributes: {
+        // 启用勾选列
+        selectColumn: true
+      }, // 关闭新增弹窗
+
+      // 表格事件
+      tableEvents: {
+        'selection-change': this.selectionChange
+      },
+      recordSelected: [],
+      content: '新增',
+      detailId: '',
+      module: 'add', // ['add', 'edit', 'detail', 'examine']
+      operateVisible: false,
+      operateType: null,
+      operateTitle: null
+    }
+  },
+  computed: {
+    ...mapGetters(['isTradeExaminer'])
+  },
+  methods: {
+    // 列表请求函数
+    getList(...p) {
+      this.recordSelected = []
+      return getLoginCrossDistrictList(...p)
+    },
+    // 列表导出函数
+    exportList: exportLoginCrossDistrict,
+    // 表格列解析渲染数据更改
+    columnParsing(item, defaultData) {
+      return defaultData
+    },
+    // 监听勾选变化
+    selectionChange(data) {
+      this.recordSelected = data
+    },
+    operation() {
+      return (h, { row, index, column }) => {
+        return (
+          <div class='operation-btns'>
+            {this.isTradeExaminer ? (
+              <el-button
+                size='mini'
+                type='text'
+                onClick={() => {
+                  this.content = '审核'
+                  this.module = 'examine'
+                  this.detailId = row.id
+                  this.visible = true
+                }}
+              >
+                审核
+              </el-button>
+            ) : null}
+            <el-button
+              size='mini'
+              type='text'
+              onClick={() => {
+                this.content = '详情'
+                this.module = 'detail'
+                this.detailId = row.id
+                this.visible = true
+              }}
+            >
+              详情
+            </el-button>
+            <el-button
+              size='mini'
+              type='text'
+              onClick={() => {
+                this.content = '编辑'
+                this.module = 'edit'
+                this.detailId = row.id
+                this.visible = true
+              }}
+            >
+              编辑
+            </el-button>
+            <el-button size='mini' type='text' onClick={() => {
+              this.operateType = 'update'
+              this.operateTitle = '更新'
+              this.recordSelected = [row]
+              this.operateVisible = true
+            }}>
+              更新
+            </el-button>
+            {!this.isTradeExaminer ? (
+              <el-button
+                size='mini'
+                type='text'
+                onClick={() => {
+                  this.detailId = row.id
+                  this.operateType = 'apply'
+                  this.operateTitle = '申请修改'
+                  this.operateVisible = true
+                }}
+              >
+                申请修改
+              </el-button>
+            ) : null}
+            {this.isTradeExaminer ? (
+              <el-button
+                size='mini'
+                type='text'
+                onClick={() => {
+                  this.detailId = row.id
+                  this.operateType = 'examine'
+                  this.operateTitle = '审核修改'
+                  this.operateVisible = true
+                }}
+              >
+                审核修改
+              </el-button>
+            ) : null}
+          </div>
+        )
+      }
+    },
+    handleClose() {
+      this.addOff(() => {
+        this.content = '新增'
+        this.module = 'add'
+        this.operateVisible = false
+        this.operateTitle = null
+        this.operateType = null
+        this.detailId = ''
+        this.visible = false
+        this.$refs.pageRef.refreshList()
+      })()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 45 - 0
src/views/commercialEngineering/crossDistrict/detail.vue

@@ -0,0 +1,45 @@
+<template>
+  <div>
+    <el-radio-group v-model="current" size="mini">
+      <el-radio-button class="my-width" label="detail">详情</el-radio-button>
+      <el-radio-button class="my-width" label="record">操作记录</el-radio-button>
+    </el-radio-group>
+    <el-form v-if="current === 'detail'" disabled>
+      <Base :form-data="formData" page-type="cross" :module="module" :common-data="commonData" />
+      <Model :form-data="formData" page-type="cross" :module="module" :common-data="commonData" />
+      <Examine v-if="formData.confirmBy && formData.confirmTime" :form-data="formData" page-type="cross" :module="module" :common-data="commonData" />
+    </el-form>
+    <template v-else>
+      <OperationRecords :detail-id="detailId" />
+    </template>
+  </div>
+</template>
+
+<script>
+import Base from '../components/base.vue'
+import Model from '../components/model.vue'
+import Examine from '../components/examine.vue'
+import OperationRecords from '../components/operationRecords.vue'
+
+import Mixin from '../mixin'
+export default {
+  components: {
+    Base,
+    Model,
+    Examine,
+    OperationRecords
+  },
+  mixins: [Mixin],
+  data() {
+    return {
+      current: 'detail'
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.my-width ::v-deep .el-radio-button__inner {
+  width: 100px;
+}
+</style>

+ 46 - 0
src/views/commercialEngineering/crossDistrict/examine.vue

@@ -0,0 +1,46 @@
+<template>
+  <div>
+    <Base :form-data="formData" page-type="cross" :module="module" :common-data="commonData" />
+    <Model :form-data="formData" page-type="cross" :module="module" :common-data="commonData" />
+    <div style="margin: 20px 0">
+      <el-button type="primary" size="small" @click="onSbumit(1)">提交</el-button>
+      <el-button size="small">返回</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import Base from '../components/base.vue'
+import Model from '../components/model.vue'
+import Mixin from '../mixin'
+import { examineLoginHomeDecoration } from '@/api/crossDistrict'
+export default {
+  components: {
+    Base,
+    Model
+  },
+  mixins: [Mixin],
+  methods: {
+    onSbumit(type) {
+      const item = [113.36242, 23.1368425]
+      const params = {
+        ...this.formData,
+        lat: item[0],
+        lnt: item[1],
+        positionAddress: this.formData.address,
+        orderStatus: 'OK'
+      }
+
+      examineLoginHomeDecoration(params).then(res => {
+        this.commonFn('审核成功')
+      })
+    },
+    commonFn(name) {
+      this.$successMsg(name)
+      this.$emit('updateList')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 44 - 0
src/views/commercialEngineering/frock/detail.vue

@@ -0,0 +1,44 @@
+<template>
+  <div>
+    <el-radio-group v-model="current" size="mini">
+      <el-radio-button class="my-width" label="detail">详情</el-radio-button>
+      <el-radio-button class="my-width" label="record">操作记录</el-radio-button>
+    </el-radio-group>
+    <el-form v-if="current === 'detail'" disabled>
+      <Base :form-data="formData" page-type="frock" :module="module" :common-data="commonData" />
+      <Model :form-data="formData" page-type="frock" :module="module" :common-data="commonData" />
+      <Examine v-if="formData.confirmBy && formData.confirmTime" :form-data="formData" page-type="frock" :module="module" :common-data="commonData" />
+    </el-form>
+    <template v-else>
+      <OperationRecords :detail-id="detailId" />
+    </template>
+  </div>
+</template>
+
+<script>
+import Base from '../components/base.vue'
+import Model from '../components/model.vue'
+import Examine from '../components/examine.vue'
+import OperationRecords from '../components/operationRecords.vue'
+import Mixin from '../mixin'
+export default {
+  components: {
+    Base,
+    Model,
+    Examine,
+    OperationRecords
+  },
+  mixins: [Mixin],
+  data() {
+    return {
+      current: 'detail'
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.my-width ::v-deep .el-radio-button__inner {
+  width: 100px;
+}
+</style>

+ 47 - 0
src/views/commercialEngineering/frock/examine.vue

@@ -0,0 +1,47 @@
+<template>
+  <div>
+    <Base :form-data="formData" page-type="frock" :module="module" :common-data="commonData" />
+    <Model :form-data="formData" page-type="frock" :module="module" :common-data="commonData" />
+    <div style="margin: 20px 0">
+      <el-button type="primary" size="small" @click="onSbumit">提交</el-button>
+      <el-button size="small">返回</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import Base from '../components/base.vue'
+import Model from '../components/model.vue'
+import Mixin from '../mixin'
+import { examineLoginFrock } from '@/api/frock'
+export default {
+  components: {
+    Base,
+    Model
+  },
+  mixins: [Mixin],
+  methods: {
+    onSbumit() {
+      const item = [113.36242, 23.1368425]
+      const params = {
+        ...this.formData,
+        lat: item[0],
+        lnt: item[1],
+        positionAddress: this.formData.address,
+        orderStatus: 'OK'
+
+      }
+
+      examineLoginFrock(params).then(res => {
+        this.commonFn('审核成功')
+      })
+    },
+    commonFn(name) {
+      this.$successMsg(name)
+      this.$emit('updateList')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 57 - 0
src/views/commercialEngineering/frock/frockForm.vue

@@ -0,0 +1,57 @@
+<template>
+  <div>
+    <Base :form-data="formData" page-type="frock" :module="module" :common-data="commonData" />
+    <Model :form-data="formData" page-type="frock" :module="module" :common-data="commonData" />
+    <div style="margin: 20px 0">
+      <el-button type="primary" size="small" @click="onSbumit(1)">提交</el-button>
+      <el-button type="primary" size="small" @click="onSbumit(2)">暂存-草稿箱</el-button>
+      <el-button size="small" @click="onReset">重置</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import Base from '../components/base.vue'
+import Model from '../components/model.vue'
+import Mixin from '../mixin'
+import { addLoginFrock, editLoginFrock, submitLoginFrock } from '@/api/frock'
+export default {
+  components: {
+    Base,
+    Model
+  },
+  mixins: [Mixin],
+  methods: {
+    onSbumit(type) {
+      const params = {
+        ...this.formData
+      }
+      params.positionAddress = this.formData.address
+      const item = [113.36242, 23.1368425]
+      params.lat = item[0]
+      params.lnt = item[1]
+      if (type === 1) {
+        submitLoginFrock(params).then(res => {
+          this.commonFn('提交成功')
+        })
+      } else {
+        if (!this.detailId) {
+          addLoginFrock(params).then(res => {
+            this.commonFn('新增成功')
+          })
+          return
+        }
+        editLoginFrock(params).then(res => {
+          this.commonFn('编辑成功')
+        })
+      }
+    },
+    commonFn(name) {
+      this.$successMsg(name)
+      this.$emit('updateList')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 248 - 0
src/views/commercialEngineering/frock/frockList.vue

@@ -0,0 +1,248 @@
+<template>
+  <template-page
+    ref="pageRef"
+    :get-list="getList"
+    :export-list="exportList"
+    :pofx="true"
+    :operation="operation()"
+    :column-parsing="columnParsing"
+    :operation-column-width="200"
+    :options-evens-group="optionsEvensGroup"
+    :table-attributes="tableAttributes"
+    :table-events="tableEvents"
+  >
+    <Popu v-if="visible">
+      <el-page-header slot="head" :content="content" @back="handleClose" />
+      <FrockForm
+        v-if="['add', 'edit','apply'].includes(module)"
+        :detail-id="detailId"
+        :module="module"
+        @updateList="handleClose"
+      />
+      <Detail v-if="['detail'].includes(module)" :detail-id="detailId" :module="module" @updateList="handleClose" />
+      <Examine v-if="['examine'].includes(module)" :detail-id="detailId" :module="module" @updateList="handleClose" />
+    </Popu>
+    <Operate v-if="operateVisible" :operate-visible="operateVisible" :operate-type="operateType" :operate-title="operateTitle" :detail-id="detailId" :record-selected="recordSelected" @close="handleClose" />
+  </template-page>
+</template>
+
+<script>
+import TemplatePage from '@/components/template/template-page-1.vue'
+import import_mixin from '@/components/template/import_mixin.js'
+import add_callback_mixin from '@/components/template/add_callback_mixin.js'
+import Popu from '@/components/template/popu.vue'
+import FrockForm from './frockForm.vue'
+import Detail from './detail.vue'
+import Examine from './examine.vue'
+import Operate from '../components/operate.vue'
+import { getLoginFrockList, exportLoginFrock } from '@/api/frock'
+import { mapGetters } from 'vuex'
+export default {
+  components: { TemplatePage, Popu, FrockForm, Detail, Examine, Operate },
+  mixins: [import_mixin, add_callback_mixin],
+  data() {
+    return {
+      visible: false,
+      optionsEvensGroup: [
+        [
+          [
+            {
+              name: '添加记录',
+              click: this.addOn(() => {
+                this.visible = true
+              })
+            }
+          ]
+        ],
+        ...(() => {
+          return !this.isTradeExaminer
+            ? [
+              [
+                [
+                  {
+                    name: '更新',
+                    click: () => {
+                      if (this.recordSelected.length === 0) {
+                        this.$message.error('请选择需要更新的数据')
+                        return
+                      }
+                      this.operateType = 'update'
+                      this.operateTitle = '更新'
+                      this.operateVisible = true
+                    }
+                  }
+                ]
+              ],
+              [
+                [
+                  {
+                    name: '替换业务员',
+                    click: () => {
+                      if (this.recordSelected.length === 0) {
+                        this.$message.error('请选择需要替换业务员的数据')
+                        return
+                      }
+                      this.operateType = 'replace'
+                      this.operateTitle = '替换业务员'
+                      this.operateVisible = true
+                    }
+                  }
+                ]
+              ],
+              [
+                [
+                  {
+                    name: '删除',
+                    click: () => {
+                      if (this.recordSelected.length === 0) {
+                        this.$message.error('请选择需要删除的数据')
+                        return
+                      }
+                      this.operateType = 'delete'
+                      this.operateTitle = '删除'
+                      this.operateVisible = true
+                    }
+                  }
+                ]
+              ]
+            ]
+            : []
+        })()
+      ],
+      // 表格属性
+      tableAttributes: {
+        // 启用勾选列
+        selectColumn: true
+      }, // 关闭新增弹窗
+
+      // 表格事件
+      tableEvents: {
+        'selection-change': this.selectionChange
+      },
+      recordSelected: [],
+      content: '新增',
+      detailId: '',
+      module: 'add',
+      operateVisible: false,
+      operateType: null,
+      operateTitle: null
+    }
+  },
+  computed: {
+    ...mapGetters(['isTradeExaminer'])
+  },
+  methods: {
+    // 列表请求函数
+    getList(...p) {
+      this.recordSelected = []
+      return getLoginFrockList(...p)
+    },
+    // 列表导出函数
+    exportList: exportLoginFrock,
+    // 表格列解析渲染数据更改
+    columnParsing(item, defaultData) {
+      return defaultData
+    },
+    // 监听勾选变化
+    selectionChange(data) {
+      this.recordSelected = data
+    },
+    operation() {
+      return (h, { row, index, column }) => {
+        return (
+          <div class='operation-btns'>
+            {this.isTradeExaminer ? (
+              <el-button
+                size='mini'
+                type='text'
+                onClick={() => {
+                  this.content = '审核'
+                  this.module = 'examine'
+                  this.detailId = row.id
+                  this.visible = true
+                }}
+              >
+                审核
+              </el-button>
+            ) : null}
+            <el-button
+              size='mini'
+              type='text'
+              onClick={() => {
+                this.content = '详情'
+                this.module = 'detail'
+                this.detailId = row.id
+                this.visible = true
+              }}
+            >
+              详情
+            </el-button>
+            <el-button
+              size='mini'
+              type='text'
+              onClick={() => {
+                this.content = '编辑'
+                this.module = 'edit'
+                this.detailId = row.id
+                this.visible = true
+              }}
+            >
+              编辑
+            </el-button>
+            <el-button size='mini' type='text' onClick={() => {
+              this.operateType = 'update'
+              this.operateTitle = '更新'
+              this.recordSelected = [row]
+              this.operateVisible = true
+            }}>
+              更新
+            </el-button>
+            {!this.isTradeExaminer ? (
+              <el-button
+                size='mini'
+                type='text'
+                onClick={() => {
+                  this.detailId = row.id
+                  this.operateType = 'apply'
+                  this.operateTitle = '申请修改'
+                  this.operateVisible = true
+                }}
+              >
+                申请修改
+              </el-button>
+            ) : null}
+            {this.isTradeExaminer ? (
+              <el-button
+                size='mini'
+                type='text'
+                onClick={() => {
+                  this.detailId = row.id
+                  this.operateType = 'examine'
+                  this.operateTitle = '审核修改'
+                  this.operateVisible = true
+                }}
+              >
+                审核修改
+              </el-button>
+            ) : null}
+          </div>
+        )
+      }
+    },
+    handleClose() {
+      this.addOff(() => {
+        this.content = '新增'
+        this.module = 'add'
+        this.detailId = ''
+        this.operateVisible = false
+        this.operateTitle = null
+        this.operateType = null
+        this.visible = false
+        this.$refs.pageRef.refreshList()
+      })()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 44 - 0
src/views/commercialEngineering/homeDecoration/detail.vue

@@ -0,0 +1,44 @@
+<template>
+  <div>
+    <el-radio-group v-model="current" size="mini">
+      <el-radio-button class="my-width" label="detail">详情</el-radio-button>
+      <el-radio-button class="my-width" label="record">操作记录</el-radio-button>
+    </el-radio-group>
+    <el-form v-if="current === 'detail'" disabled>
+      <Base :form-data="formData" page-type="home" :module="module" :common-data="commonData" />
+      <Model :form-data="formData" page-type="home" :module="module" :common-data="commonData" />
+      <Examine v-if="formData.confirmBy && formData.confirmTime" :form-data="formData" page-type="home" :module="module" :common-data="commonData" />
+    </el-form>
+    <template v-else>
+      <OperationRecords :detail-id="detailId" />
+    </template>
+  </div>
+</template>
+
+<script>
+import Base from '../components/base.vue'
+import Model from '../components/model.vue'
+import Examine from '../components/examine.vue'
+import OperationRecords from '../components/operationRecords.vue'
+import Mixin from '../mixin'
+export default {
+  components: {
+    Base,
+    Model,
+    Examine,
+    OperationRecords
+  },
+  mixins: [Mixin],
+  data() {
+    return {
+      current: 'detail'
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.my-width ::v-deep .el-radio-button__inner {
+  width: 100px;
+}
+</style>

+ 47 - 0
src/views/commercialEngineering/homeDecoration/examine.vue

@@ -0,0 +1,47 @@
+<template>
+  <div>
+    <Base :form-data="formData" page-type="home" :module="module" :common-data="commonData" />
+    <Model :form-data="formData" page-type="home" :module="module" :common-data="commonData" />
+    <div style="margin: 20px 0">
+      <el-button type="primary" size="small" @click="onSbumit(1)">提交</el-button>
+      <el-button size="small">返回</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import Base from '../components/base.vue'
+import Model from '../components/model.vue'
+import Mixin from '../mixin'
+import { examineLoginFrock } from '@/api/homeDecoration'
+export default {
+  components: {
+    Base,
+    Model
+  },
+  mixins: [Mixin],
+  methods: {
+    onSbumit(type) {
+      const item = [113.36242, 23.1368425]
+      const params = {
+        ...this.formData,
+        lat: item[0],
+        lnt: item[1],
+        positionAddress: this.formData.address,
+        orderStatus: 'OK'
+
+      }
+
+      examineLoginFrock(params).then(res => {
+        this.commonFn('审核成功')
+      })
+    },
+    commonFn(name) {
+      this.$successMsg(name)
+      this.$emit('updateList')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 60 - 0
src/views/commercialEngineering/homeDecoration/homeDecorationForm.vue

@@ -0,0 +1,60 @@
+<template>
+  <div>
+    <Base :form-data="formData" page-type="home" :module="module" :common-data="commonData" />
+    <Model :form-data="formData" page-type="home" :module="module" :common-data="commonData" />
+    <div style="margin: 20px 0">
+      <el-button type="primary" size="small" @click="onSbumit(1)">提交</el-button>
+      <el-button type="primary" size="small" @click="onSbumit(2)">暂存-草稿箱</el-button>
+      <el-button size="small" @click="onReset">重置</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import Base from '../components/base.vue'
+import Model from '../components/model.vue'
+import Mixin from '../mixin'
+import { addLoginHomeDecoration, editLoginHomeDecoration, submitLoginHomeDecoration } from '@/api/homeDecoration'
+export default {
+  components: {
+    Base,
+    Model
+  },
+  mixins: [Mixin],
+  methods: {
+    onSbumit(type) {
+      const params = {
+        ...this.formData
+      }
+      params.projectName = params.homeProjectNameArea + params.homeProjectNameSeat + params.homeProjectNameNumber
+      params.address = params.projectName
+      params.positionAddress = params.address
+      const item = [113.36242, 23.1368425]
+      params.lat = item[0]
+      params.lnt = item[1]
+
+      if (type === 1) {
+        submitLoginHomeDecoration(params).then(res => {
+          this.commonFn('提交成功')
+        })
+      } else {
+        if (!this.detailId) {
+          addLoginHomeDecoration(params).then(res => {
+            this.commonFn('新增成功')
+          })
+          return
+        }
+        editLoginHomeDecoration(params).then(res => {
+          this.commonFn('编辑成功')
+        })
+      }
+    },
+    commonFn(name) {
+      this.$successMsg(name)
+      this.$emit('updateList')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 250 - 0
src/views/commercialEngineering/homeDecoration/homeDecorationList.vue

@@ -0,0 +1,250 @@
+<template>
+  <template-page
+    ref="pageRef"
+    :get-list="getList"
+    :export-list="exportList"
+    :pofx="true"
+    :operation="operation()"
+    :column-parsing="columnParsing"
+    :operation-column-width="200"
+    :options-evens-group="optionsEvensGroup"
+    :table-attributes="tableAttributes"
+    :table-events="tableEvents"
+  >
+    <Popu v-if="visible">
+      <el-page-header slot="head" :content="content" @back="handleClose" />
+      <HomeDecorationForm
+        v-if="['add', 'edit','apply'].includes(module)"
+        :detail-id="detailId"
+        :module="module"
+        @updateList="handleClose"
+      />
+      <Detail v-if="['detail'].includes(module)" :detail-id="detailId" :module="module" @updateList="handleClose" />
+      <Examine v-if="['examine'].includes(module)" :detail-id="detailId" :module="module" @updateList="handleClose" />
+    </Popu>
+    <Operate v-if="operateVisible" :operate-visible="operateVisible" :operate-type="operateType" :operate-title="operateTitle" :detail-id="detailId" :record-selected="recordSelected" @close="handleClose" />
+  </template-page>
+</template>
+
+<script>
+import TemplatePage from '@/components/template/template-page-1.vue'
+import import_mixin from '@/components/template/import_mixin.js'
+import add_callback_mixin from '@/components/template/add_callback_mixin.js'
+import Popu from '@/components/template/popu.vue'
+import HomeDecorationForm from './homeDecorationForm.vue'
+import Detail from './detail.vue'
+import Examine from './examine.vue'
+import Operate from '../components/operate.vue'
+import { getLoginHomeDecorationList, exportLoginHomeDecoration } from '@/api/homeDecoration'
+import { mapGetters } from 'vuex'
+
+export default {
+  components: { TemplatePage, Popu, HomeDecorationForm, Detail, Examine, Operate },
+  mixins: [import_mixin, add_callback_mixin],
+  data() {
+    return {
+      visible: false,
+      // 事件组合
+      optionsEvensGroup: [
+        [
+          [
+            {
+              name: '添加记录',
+              click: this.addOn(() => {
+                this.visible = true
+              })
+            }
+          ]
+        ],
+        ...(() => {
+          return !this.isTradeExaminer
+            ? [
+              [
+                [
+                  {
+                    name: '更新',
+                    click: () => {
+                      if (this.recordSelected.length === 0) {
+                        this.$message.error('请选择需要更新的数据')
+                        return
+                      }
+                      this.operateType = 'update'
+                      this.operateTitle = '更新'
+                      this.operateVisible = true
+                    }
+                  }
+                ]
+              ],
+              [
+                [
+                  {
+                    name: '替换业务员',
+                    click: () => {
+                      if (this.recordSelected.length === 0) {
+                        this.$message.error('请选择需要替换业务员的数据')
+                        return
+                      }
+                      this.operateType = 'replace'
+                      this.operateTitle = '替换业务员'
+                      this.operateVisible = true
+                    }
+                  }
+                ]
+              ],
+              [
+                [
+                  {
+                    name: '删除',
+                    click: () => {
+                      if (this.recordSelected.length === 0) {
+                        this.$message.error('请选择需要删除的数据')
+                        return
+                      }
+                      this.operateType = 'delete'
+                      this.operateTitle = '删除'
+                      this.operateVisible = true
+                    }
+                  }
+                ]
+              ]
+            ]
+            : []
+        })()
+      ],
+      // 表格属性
+      tableAttributes: {
+        // 启用勾选列
+        selectColumn: true
+      }, // 关闭新增弹窗
+
+      // 表格事件
+      tableEvents: {
+        'selection-change': this.selectionChange
+      },
+      recordSelected: [],
+      content: '新增',
+      module: 'add',
+      detailId: '',
+      operateVisible: false,
+      operateType: null,
+      operateTitle: null
+    }
+  },
+  computed: {
+    ...mapGetters(['isTradeExaminer'])
+  },
+  methods: {
+    // 列表请求函数
+    getList(...p) {
+      this.recordSelected = []
+      return getLoginHomeDecorationList(...p)
+    },
+    // 列表导出函数
+    exportList: exportLoginHomeDecoration,
+    // 表格列解析渲染数据更改
+    columnParsing(item, defaultData) {
+      return defaultData
+    },
+    // 监听勾选变化
+    selectionChange(data) {
+      this.recordSelected = data
+    },
+    operation() {
+      return (h, { row, index, column }) => {
+        return (
+          <div class='operation-btns'>
+            {this.isTradeExaminer ? (
+              <el-button
+                size='mini'
+                type='text'
+                onClick={() => {
+                  this.content = '审核'
+                  this.module = 'examine'
+                  this.detailId = row.id
+                  this.visible = true
+                }}
+              >
+                审核
+              </el-button>
+            ) : null}
+            <el-button
+              size='mini'
+              type='text'
+              onClick={() => {
+                this.content = '详情'
+                this.module = 'detail'
+                this.detailId = row.id
+                this.visible = true
+              }}
+            >
+              详情
+            </el-button>
+            <el-button
+              size='mini'
+              type='text'
+              onClick={() => {
+                this.content = '编辑'
+                this.module = 'edit'
+                this.detailId = row.id
+                this.visible = true
+              }}
+            >
+              编辑
+            </el-button>
+            <el-button size='mini' type='text' onClick={() => {
+              this.operateType = 'update'
+              this.operateTitle = '更新'
+              this.recordSelected = [row]
+              this.operateVisible = true
+            }}>
+              更新
+            </el-button>
+            {!this.isTradeExaminer ? (
+              <el-button
+                size='mini'
+                type='text'
+                onClick={() => {
+                  this.detailId = row.id
+                  this.operateType = 'apply'
+                  this.operateTitle = '申请修改'
+                  this.operateVisible = true
+                }}
+              >
+                申请修改
+              </el-button>
+            ) : null}
+            {this.isTradeExaminer ? (
+              <el-button
+                size='mini'
+                type='text'
+                onClick={() => {
+                  this.detailId = row.id
+                  this.operateType = 'examine'
+                  this.operateTitle = '审核修改'
+                  this.operateVisible = true
+                }}
+              >
+                审核修改
+              </el-button>
+            ) : null}
+          </div>
+        )
+      }
+    },
+    handleClose() {
+      this.addOff(() => {
+        this.content = '新增'
+        this.module = 'add'
+        this.detailId = ''
+        this.operateVisible = false
+        this.operateTitle = null
+        this.operateType = null
+        this.visible = false
+        this.$refs.pageRef.refreshList()
+      })()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 205 - 0
src/views/commercialEngineering/mixin/index.js

@@ -0,0 +1,205 @@
+import { getCommercialEngineeringDetail, getPositionProject } from '@/api/frock'
+import { getDictList, getSalesmanList } from '@/api/common'
+import { getDealerListV2 } from '@/api/basic_data/dealer'
+import {
+  getFirstPartyCustomerManagementList
+} from '@/api/basic_data/partya'
+export default {
+  props: {
+    detailId: {
+      type: String,
+      default: ''
+    },
+    module: {
+      type: String,
+      default: 'add'
+    }
+  },
+  data() {
+    return {
+      resetData: {},
+      formData: {
+        address: '',
+        adminCompanyId: '',
+        adminUserId: '',
+        adminWebsitId: '',
+        applyUpdateBy: '',
+        applyUpdateCompanyId: '',
+        applyUpdateCompanyName: '',
+        applyUpdateName: '',
+        areaId: '',
+        cityId: '',
+        commonFollowProject: '',
+        confirmBy: '',
+        confirmName: '',
+        confirmTime: '',
+        customerAddress: '',
+        customerId: '',
+        customerLinkMobile: '',
+        customerLinkName: '',
+        customerName: '',
+        customerNumber: '',
+        del: null,
+        drawUpload: '',
+        enginLinkMobile: '',
+        enginLinkName: '',
+        examineNote: '',
+        tradeName: '',
+        tradeParentName: '',
+        extent: '',
+        files: [],
+        followCustomer: '',
+        followCustomerMobile: '',
+        homeProjectNameArea: '',
+        homeProjectNameNumber: '',
+        homeProjectNameRadio: '',
+        homeProjectNameSeat: '',
+        id: '',
+        isApplyUpdate: null,
+        isSpan: null,
+        items: [],
+        lat: '',
+        lnt: '',
+        loginStatus: '',
+        machineType: '',
+        note: '',
+        orderStatus: '',
+        orderType: '',
+        otherInfo: '',
+        partyA: '',
+        partyAId: '',
+        positionAddress: '',
+        preDeviceAmount: 0,
+        preSignDate: '',
+        projectArea: '',
+        projectCategory: '',
+        projectMent: '',
+        projectName: '',
+        projectNo: '',
+        provinceId: '',
+        refCustomerId: '',
+        remark: '',
+        salesCompanyName: '',
+        serviceId: '',
+        serviceName: '',
+        status: '',
+        streetId: '',
+        submitBy: '',
+        submitName: '',
+        submitTime: '',
+        successLoginProject: '',
+        successRate: '',
+        tradeId: '',
+        tradeParentId: '',
+        type: '',
+        useExtent: ''
+      },
+      commonData: {
+        dict: {
+          TRADE_LOGIN_CATEGORY: [], // 项目类别
+          TRADE_LOGIN_TYPE: [], // 类型
+          SUCCESS_RATE: [], // 成功机率
+          FOLLOW_STATUS: [], // 工程跟进状态
+          MACHINE_TYPE: [], // 机组类型
+          TRADE_EXAMINE_NOTE: [], // 审核备注
+          TRADE_PROJECT_AREA: [] // 项目所在区域
+        },
+        salesmanList: [],
+        customerList: [],
+        PartyAList: [],
+        vicinityMarkers: []
+      }
+    }
+  },
+  created() {
+    this.resetData = {
+      ...this.formData
+    }
+    this.getDictList()
+    this.getDealerListV2()
+    this.getSalesmanList()
+    this.getFirstPartyCustomerManagementList()
+    if (this.detailId) {
+      this.getCommercialEngineeringDetail()
+      this.getPositionProject()
+    }
+  },
+  methods: {
+    getDictList() {
+      Object.keys(this.commonData.dict).forEach(async k => {
+        const { data } = await getDictList({ sysDictEnum: k })
+        this.commonData.dict[k] = data.map(l => {
+          return {
+            label: l.dictValue,
+            value: l.dictCode
+          }
+        })
+      })
+    },
+    getSalesmanList() {
+      getSalesmanList({
+        pageNum: 1,
+        pageSize: -1,
+        isCustomer: 0,
+        status: true
+      }).then(res => {
+        this.commonData.salesmanList = res.data.records.map(k => {
+          return {
+            label: k.nickName,
+            value: k.adminUserId
+          }
+        })
+      })
+    },
+    getFirstPartyCustomerManagementList() {
+      getFirstPartyCustomerManagementList({ pageNum: 1,
+        pageSize: -1 }).then(res => {
+        this.commonData.PartyAList = res.data.records.map(k => {
+          return {
+            label: k.name,
+            value: k.id
+          }
+        })
+      })
+    },
+    getDealerListV2() {
+      getDealerListV2({
+        pageNum: 1,
+        pageSize: -1,
+        params: [
+          {
+            param: 'a.jiaxian_type',
+            compare: '=',
+            value: 'KING'
+          }
+        ]
+      }).then(res => {
+        this.commonData.customerList = res.data.records.map(k => {
+          return {
+            number: k.number,
+            label: k.name,
+            value: k.id
+          }
+        })
+      })
+    },
+    getCommercialEngineeringDetail() {
+      getCommercialEngineeringDetail({ id: this.detailId }).then(res => {
+        this.formData = {
+          ...res.data
+        }
+      })
+    },
+    getPositionProject() {
+      getPositionProject({ id: this.detailId }).then(res => {
+        this.commonData.vicinityMarkers = res.data
+      })
+    },
+    onReset() {
+      this.formData = {
+        ...this.resetData,
+        id: this.detailId
+      }
+    }
+  }
+}