Explorar o código

Merge branch 'deploy_qbyc' of chelingzhu-web/zyyc_channe_html into master

lilei %!s(int64=4) %!d(string=hai) anos
pai
achega
d38c5c93b0
Modificáronse 51 ficheiros con 2361 adicións e 320 borrados
  1. 7 1
      .env
  2. 7 1
      .env.development
  3. 7 1
      .env.preview
  4. 11 0
      .env.qbdev
  5. 11 0
      .env.qbpre
  6. 11 0
      .env.qbpro
  7. 5 0
      package-lock.json
  8. 4 1
      package.json
  9. BIN=BIN
      public/clzlogo.png
  10. 1 1
      public/index.html
  11. BIN=BIN
      public/logo.png
  12. BIN=BIN
      public/qbyclogo.png
  13. 3 1
      src/App.vue
  14. 8 0
      src/api/FinancialManagement.js
  15. 20 0
      src/api/SetmealSales.js
  16. 37 0
      src/api/address.js
  17. 20 2
      src/api/customerBundle.js
  18. 7 0
      src/api/data.js
  19. BIN=BIN
      src/assets/logo.png
  20. BIN=BIN
      src/assets/logos.png
  21. 4 2
      src/components/GlobalFooter/GlobalFooter.vue
  22. 3 3
      src/components/global.less
  23. 3 2
      src/components/tools/Logo.vue
  24. 87 28
      src/config/router.config.js
  25. 7 4
      src/layouts/UserLayout.vue
  26. 10 0
      src/libs/getDate.js
  27. 2 2
      src/permission.js
  28. 1 0
      src/store/getters.js
  29. 8 1
      src/store/modules/user.js
  30. 1 1
      src/utils/request.js
  31. 7 0
      src/views/FinancialManagement/PaySettlementRecords.vue
  32. 4 5
      src/views/FinancialManagement/PaySettlementRecordsDetailsModal.vue
  33. 4 5
      src/views/FinancialManagement/WriteOffDetailsModal.vue
  34. 85 64
      src/views/Home.vue
  35. 366 0
      src/views/Service/PurchasedServiceDetail.vue
  36. 441 0
      src/views/Service/PurchasedServiceList.vue
  37. 159 0
      src/views/Service/yanQiModal.vue
  38. 74 38
      src/views/SetmealSales/BuySetmeal.vue
  39. 67 20
      src/views/SetmealSales/PurchasedSetmeal.vue
  40. 234 0
      src/views/SetmealSales/SetmealAttr.vue
  41. 78 17
      src/views/SetmealSales/SetmealDetailModal.vue
  42. 5 0
      src/views/SetmealSales/SetmealItemDetailModal.vue
  43. 43 5
      src/views/SetmealSales/SetmealPayMoney.vue
  44. 132 109
      src/views/SetmealSales/VerificationRecords.vue
  45. 209 0
      src/views/SetmealSales/attrModal.vue
  46. 157 0
      src/views/SetmealSales/delayModal.vue
  47. 1 1
      src/views/power/role/menuModal.vue
  48. 1 1
      src/views/power/role/roleModal.vue
  49. 0 2
      src/views/power/user/userModal.vue
  50. 6 0
      src/views/user/Login.vue
  51. 3 2
      vue.config.js

+ 7 - 1
.env

@@ -2,4 +2,10 @@ NODE_ENV=production
 VUE_APP_PREVIEW=false
 VUE_APP_API_BASE_URL=https://channel.zy-yc.cn/zyyc-channel/
 VUE_APP_VERSION=V1.0.1
-VUE_APP_PRO_NAME=合作商运营管理平台
+VUE_APP_PRO_NAME=合作商运营管理平台
+VUE_APP_ANOTHEN_NAME=章鱼养车
+VUE_APP_PINYIN=clz
+VUE_APP_LOGO=@/assets/logo.png
+VUE_APP_THEME_COLOR=#1890FF
+VUE_APP_COM_NAME=陕西山海高科信息技术有限公司
+VUE_APP_ICP=陕ICP备20006268号

+ 7 - 1
.env.development

@@ -2,4 +2,10 @@ NODE_ENV=development
 VUE_APP_PREVIEW=true
 VUE_APP_API_BASE_URL=/api
 VUE_APP_VERSION=V1.0.1
-VUE_APP_PRO_NAME=合作商运营管理平台-dev
+VUE_APP_PRO_NAME=合作商运营管理平台-dev
+VUE_APP_ANOTHEN_NAME=章鱼养车
+VUE_APP_PINYIN=clz
+VUE_APP_LOGO=@/assets/logo.png
+VUE_APP_THEME_COLOR=#1890FF
+VUE_APP_COM_NAME=陕西山海高科信息技术有限公司
+VUE_APP_ICP=陕ICP备20006268号

+ 7 - 1
.env.preview

@@ -2,4 +2,10 @@ NODE_ENV=production
 VUE_APP_PREVIEW=true
 VUE_APP_API_BASE_URL=https://channel.test.zyucgj.com/zyyc-channel/
 VUE_APP_VERSION=V1.0.1
-VUE_APP_PRO_NAME=合作商运营管理平台-pro
+VUE_APP_PRO_NAME=合作商运营管理平台-pro
+VUE_APP_ANOTHEN_NAME=章鱼养车
+VUE_APP_PINYIN=clz
+VUE_APP_LOGO=@/assets/logo.png
+VUE_APP_THEME_COLOR=#1890FF
+VUE_APP_COM_NAME=陕西山海高科信息技术有限公司
+VUE_APP_ICP=陕ICP备20006268号

+ 11 - 0
.env.qbdev

@@ -0,0 +1,11 @@
+NODE_ENV=development
+VUE_APP_PREVIEW=true
+VUE_APP_API_BASE_URL=/api
+VUE_APP_VERSION=V1.0.1
+VUE_APP_PRO_NAME=合作商运营管理平台-dev
+VUE_APP_ANOTHEN_NAME=丘比养车
+VUE_APP_PINYIN=qbyc
+VUE_APP_LOGO=@/assets/logos.png
+VUE_APP_THEME_COLOR=#eb6b2d
+VUE_APP_COM_NAME=成都丘比象科技有限公司
+VUE_APP_ICP=蜀ICP备2020036400号-2

+ 11 - 0
.env.qbpre

@@ -0,0 +1,11 @@
+NODE_ENV=production
+VUE_APP_PREVIEW=true
+VUE_APP_API_BASE_URL=https://channel.test.qiubcar.com/zyyc-channel/
+VUE_APP_VERSION=V1.0.1
+VUE_APP_PRO_NAME=合作商运营管理平台-pro
+VUE_APP_ANOTHEN_NAME=丘比养车
+VUE_APP_PINYIN=qbyc
+VUE_APP_LOGO=@/assets/logos.png
+VUE_APP_THEME_COLOR=#eb6b2d
+VUE_APP_COM_NAME=成都丘比象科技有限公司
+VUE_APP_ICP=蜀ICP备2020036400号-2

+ 11 - 0
.env.qbpro

@@ -0,0 +1,11 @@
+NODE_ENV=production
+VUE_APP_PREVIEW=false
+VUE_APP_API_BASE_URL=https://channel.qiubcar.com/zyyc-channel/
+VUE_APP_VERSION=V1.0.1
+VUE_APP_PRO_NAME=合作商运营管理平台
+VUE_APP_ANOTHEN_NAME=丘比养车
+VUE_APP_PINYIN=qbyc
+VUE_APP_LOGO=@/assets/logos.png
+VUE_APP_THEME_COLOR=#eb6b2d
+VUE_APP_COM_NAME=成都丘比象科技有限公司
+VUE_APP_ICP=蜀ICP备2020036400号-2

+ 5 - 0
package-lock.json

@@ -3639,6 +3639,11 @@
       "integrity": "sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ==",
       "dev": true
     },
+    "china-division": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/china-division/-/china-division-2.3.1.tgz",
+      "integrity": "sha512-mOfLagVRZ+lRmbIIZ0sci0+9Sr+uGyPCp9an4Orov2KxLf3DGSB/4qyao/jy3pegW4Weppvh0yzGfs+dAPJA7A=="
+    },
     "chokidar": {
       "version": "2.1.8",
       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",

+ 4 - 1
package.json

@@ -6,8 +6,10 @@
     "serve": "vue-cli-service serve",
     "dev": "vue-cli-service serve",
     "build": "vue-cli-service build",
-    "build:preview": "vue-cli-service build --mode preview",
     "uat": "vue-cli-service build --mode preview",
+    "dev:qbyc": "vue-cli-service serve --mode qbdev",
+    "uat:qbyc": "vue-cli-service build --mode qbpre",
+    "build:qbyc": "vue-cli-service build --mode qbpro",
     "lint": "vue-cli-service lint",
     "lint:nofix": "vue-cli-service lint --no-fix",
     "test:unit": "vue-cli-service test:unit",
@@ -17,6 +19,7 @@
     "@antv/data-set": "^0.10.2",
     "ant-design-vue": "^1.5.2",
     "axios": "^0.19.0",
+    "china-division": "^2.3.1",
     "core-js": "2.6.9",
     "echarts": "^4.9.0",
     "enquire.js": "^2.1.6",

BIN=BIN
public/clzlogo.png


+ 1 - 1
public/index.html

@@ -4,7 +4,7 @@
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
-    <link rel="icon" href="<%= BASE_URL %>logo.png">
+    <link rel="icon" href="<%= BASE_URL %><%= VUE_APP_PINYIN %>logo.png">
     <title>合作商运营管理平台</title>
     <style>#loading-mask{position:fixed;left:0;top:0;height:100%;width:100%;background:#fff;user-select:none;z-index:9999;overflow:hidden}.loading-wrapper{position:absolute;top:50%;left:50%;transform:translate(-50%,-100%)}.loading-dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:64px;width:64px;height:64px;box-sizing:border-box}.loading-dot i{width:22px;height:22px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.loading-dot i:nth-child(1){top:0;left:0}.loading-dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.loading-dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.loading-dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}</style>
     <!-- require cdn assets css -->

BIN=BIN
public/logo.png


BIN=BIN
public/qbyclogo.png


+ 3 - 1
src/App.vue

@@ -20,7 +20,9 @@ export default {
   created () {
     // 在页面加载时读取sessionStorage
     if (sessionStorage.getItem('store')) {
-      this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(sessionStorage.getItem('store'))))
+      const data = JSON.parse(sessionStorage.getItem('store'))
+      sessionStorage.setItem('Access-Token', data.user.token)
+      this.$store.replaceState(Object.assign({}, this.$store.state, data))
     }
     // 在页面刷新时将store保存到sessionStorage里
     window.addEventListener('beforeunload', () => {

+ 8 - 0
src/api/FinancialManagement.js

@@ -42,3 +42,11 @@ export const SettlementRecordsDetailsList = params => {
     method: 'post'
   })
 }
+
+export const salesChannelByBundleList = params => {
+  const url = `/salesChannel/queryByBundle/${params.id}`
+  return axios.request({
+    url: url,
+    method: 'get'
+  })
+}

+ 20 - 0
src/api/SetmealSales.js

@@ -44,3 +44,23 @@ export const settlementRecordsExport = (params) => {
     responseType: 'blob'
   })
 }
+//  套餐属性 列表
+export const salesChannelGoodsList = (params) => {
+  const url = `/salesChannelGoods/query/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}
+//  套餐属性  设置
+export const salesChannelGoodsConfig = (params) => {
+  const url = `/salesChannelGoods/setPropertiesConfig`
+  return axios({
+    url: url,
+    data: params,
+    method: 'post'
+  })
+}

+ 37 - 0
src/api/address.js

@@ -0,0 +1,37 @@
+import provinces from 'china-division/dist/provinces.json'
+import cities from 'china-division/dist/cities.json'
+import areas from 'china-division/dist/areas.json'
+
+areas.forEach((area) => {
+  const matchCity = cities.filter(city => city.code === area.cityCode)[0]
+  if (matchCity) {
+    matchCity.children = matchCity.children || []
+    matchCity.children.push({
+      label: area.name,
+      value: area.code
+    })
+  }
+})
+
+cities.forEach((city) => {
+  const matchProvince = provinces.filter(province => province.code === city.provinceCode)[0]
+  if (matchProvince) {
+    matchProvince.children = matchProvince.children || []
+    matchProvince.children.push({
+      label: city.name,
+      value: city.code,
+      children: city.children
+    })
+  }
+})
+
+const options = provinces.map(province => ({
+  label: province.name,
+  value: province.code,
+  children: province.children
+}))
+export const province = provinces
+export const city = cities
+export const area = areas
+
+export default options

+ 20 - 2
src/api/customerBundle.js

@@ -16,7 +16,7 @@ export const customerBundleDetail = (params) => {
   return axios.request({
     url: `customerBundle/detail/${params.id}`,
     method: 'get'
-  }).then(res => res)
+  })
 }
 
 // 已购套餐   使用记录
@@ -45,7 +45,9 @@ export const cancelBuy = (params) => {
 
 // 套餐列表
 export const getBundleList = params => {
-  const url = `bundle/query`
+  const url = `bundle/query/${params.pageNo}/${params.pageSize}`
+  delete params.pageNo
+  delete params.pageSize
   return axios.request({
     url: url,
     data: params,
@@ -95,3 +97,19 @@ export const countListBundle = params => {
     method: 'post'
   }).then(res => res)
 }
+//  已购套餐 套餐包含服务 延期
+export const customerBundleItemDelay = params => {
+  return axios.request({
+    url: `customerBundleItem/delay`,
+    data: params,
+    method: 'post'
+  }).then(res => res)
+}
+//  已购套餐 取消购买
+export const orderCancel = params => {
+  return axios.request({
+    url: `order/cancel/${params.id}`,
+    data: params,
+    method: 'get'
+  }).then(res => res)
+}

+ 7 - 0
src/api/data.js

@@ -25,6 +25,13 @@ export const listLookUp = params => {
   })
 }
 
+export const getLookUpDataBy = (params) => {
+  return axios.request({
+    url: `lookup/findByLookup/${params.type}`,
+    method: 'get'
+  })
+}
+
 export const getLookUpData = (params) => {
   const url = `/lookupItem/query/${params.pageNo}/${params.pageSize}`
   delete params.pageNo

BIN=BIN
src/assets/logo.png


BIN=BIN
src/assets/logos.png


+ 4 - 2
src/components/GlobalFooter/GlobalFooter.vue

@@ -16,7 +16,7 @@
     </div> -->
     <div class="copyright">
       Copyright
-      <a-icon type="copyright" /> 2020 <span> 陕西山海高科信息技术有限公司</span>
+      <a-icon type="copyright" /> {{new Date().getFullYear()}} <span> {{ company }}</span>
     </div>
   </div>
 </template>
@@ -25,7 +25,9 @@
 export default {
   name: 'GlobalFooter',
   data () {
-    return {}
+    return {
+      company: process.env.VUE_APP_COM_NAME //  公司
+    }
   }
 }
 </script>

+ 3 - 3
src/components/global.less

@@ -401,14 +401,14 @@ body {
 
     img,
     svg {
-      height: 32px;
-      width: 32px;
+      height: 40px;
+      width: 40px;
     }
 
     h1 {
       color: #fff;
       font-size: 16px;
-      margin: 0 0 0 12px;
+      margin: 0 0 0 6px;
       font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
       font-weight: 600;
       vertical-align: middle;

+ 3 - 2
src/components/tools/Logo.vue

@@ -2,7 +2,7 @@
   <div class="logo">
     <router-link :to="{name:'index'}">
       <!-- <LogoSvg alt="logo" /> -->
-      <img :src="LogoSvg" />
+      <img :src="logo" />
       <h1 v-if="showTitle">{{ title }}</h1>
     </router-link>
   </div>
@@ -30,7 +30,8 @@ export default {
   },
   data () {
     return {
-      LogoSvg: LogoSvg
+      LogoSvg: LogoSvg,
+      logo: require(process.env.VUE_APP_LOGO) //  logo
     }
   }
 }

+ 87 - 28
src/config/router.config.js

@@ -1,6 +1,7 @@
 import {
   UserLayout,
   BasicLayout,
+  RouteView,
   PageView
 } from '@/layouts'
 
@@ -54,36 +55,84 @@ export const asyncRouterMap = [{
       icon: 'snippets',
       permission: 'M_bundel_saller'
     },
-    children: [{
-      path: '/SetmealSales/VerificationRecords',
-      name: 'VerificationRecords',
-      component: () => import('@/views/SetmealSales/VerificationRecords.vue'),
-      meta: {
-        title: '核销记录',
-        icon: 'file-text',
-        permission: 'M_hxjl_list'
-      }
-    },
-    {
-      path: '/SetmealSales/BuySetmeal',
-      name: 'BuySetmeal',
-      component: () => import('@/views/SetmealSales/BuySetmeal.vue'),
-      meta: {
-        title: '购买套餐',
-        icon: 'file-text',
-        permission: 'M_buy_bundel'
+    children: [
+      {
+        path: '/SetmealSales/BuySetmeal',
+        name: 'BuySetmeal',
+        component: () => import('@/views/SetmealSales/BuySetmeal.vue'),
+        meta: {
+          title: '购买套餐',
+          icon: 'file-text',
+          permission: 'M_buy_bundel'
+        }
+      },
+      {
+        path: '/SetmealSales/PurchasedSetmeal',
+        name: 'PurchasedSetmeal',
+        component: () => import('@/views/SetmealSales/PurchasedSetmeal.vue'),
+        meta: {
+          title: '已购套餐',
+          icon: 'file-text',
+          permission: 'M_bundel_buyRecord'
+        }
+      },
+      {
+        path: '/SetmealSales/SetmealAttr',
+        name: 'SetmealAttr',
+        component: () => import('@/views/SetmealSales/SetmealAttr.vue'),
+        meta: {
+          title: '套餐属性',
+          icon: 'file-text',
+          permission: 'M_buy_attr'
+        }
       }
+    ]
+  },
+  // 服务
+  {
+    path: '/Service',
+    redirect: '/Service/PurchasedService',
+    component: PageView,
+    meta: {
+      title: '服务',
+      icon: 'profile',
+      permission: 'M_Service'
     },
-    {
-      path: '/SetmealSales/PurchasedSetmeal',
-      name: 'PurchasedSetmeal',
-      component: () => import('@/views/SetmealSales/PurchasedSetmeal.vue'),
-      meta: {
-        title: '已购套餐',
-        icon: 'file-text',
-        permission: 'M_bundel_buyRecord'
+    children: [
+      {
+        path: '/Service/PurchasedService',
+        redirect: '/Service/PurchasedService/list',
+        name: 'PurchasedService',
+        component: RouteView,
+        meta: {
+          title: '已购服务',
+          icon: 'profile',
+          permission: 'M_Service_list'
+        },
+        hideChildrenInMenu: true,
+        children: [
+          {
+            path: '/Service/PurchasedService/list',
+            name: 'PurchasedServiceList',
+            component: () => import(/* webpackChunkName: "order" */ '@/views/Service/PurchasedServiceList.vue'),
+            meta: {
+              title: '服务列表',
+              icon: 'shopping',
+              hidden: true
+            }
+          },
+          {
+            path: '/Service/PurchasedService/detail/:id',
+            name: 'PurchasedServiceDetail',
+            component: () => import(/* webpackChunkName: "order" */ '@/views/Service/PurchasedServiceDetail.vue'),
+            meta: {
+              title: '服务详情',
+              icon: 'profile',
+              hidden: true
+            }
+          }
+        ]
       }
-    }
     ]
   },
   {
@@ -92,11 +141,21 @@ export const asyncRouterMap = [{
 	  component: PageView,
 	  meta: { title: '财务管理', icon: 'account-book', permission: 'M_cwgn' },
 	  children: [
+      {
+			  path: '/SetmealSales/VerificationRecords',
+			  name: 'VerificationRecords',
+			  component: () => import('@/views/SetmealSales/VerificationRecords.vue'),
+			  meta: {
+			    title: '核销记录',
+			    icon: 'file-text',
+			    permission: 'M_hxjl_list'
+			  }
+      },
 	    {
 	      path: 'PaySettlementRecords/list',
 	      name: 'PaySettlementRecords',
 	      component: () => import(/* webpackChunkName: "writeOff" */ '@/views/FinancialManagement/PaySettlementRecords.vue'),
-	      meta: { title: '应付结算记录', icon: 'form', permission: 'M_yfjs_js_list' }
+	      meta: { title: '应付结算记录-套餐', icon: 'form', permission: 'M_yfjs_js_list' }
 	    }
 	  ]
   },

+ 7 - 4
src/layouts/UserLayout.vue

@@ -5,7 +5,7 @@
       <div class="top">
         <div class="header">
           <a href="/">
-            <img src="~@/assets/logo.png" class="logo" alt="logo">
+            <img :src="logo" class="logo" alt="logo">
             <!-- <span class="title">{{logo}}</span> -->
           </a>
         </div>
@@ -23,7 +23,7 @@
           <a href="_self">条款</a>
         </div> -->
         <div class="copyright">
-          Copyright &copy; 2020 陕西山海高科信息技术有限公司 <a href="http://beian.miit.gov.cn/" target="_blank">陕ICP备20006268号</a>
+          Copyright &copy; {{new Date().getFullYear()}} {{ company }} <a href="http://beian.miit.gov.cn/" target="_blank">{{ icp }}</a>
         </div>
       </div>
     </div>
@@ -41,7 +41,10 @@ export default {
   mixins: [mixinDevice],
   data () {
     return {
-      title: process.env.VUE_APP_PRO_NAME
+      title: process.env.VUE_APP_PRO_NAME,
+      company: process.env.VUE_APP_COM_NAME, //  公司
+      icp: process.env.VUE_APP_ICP, //  备案号
+      logo: require(process.env.VUE_APP_LOGO) //  logo
     }
   },
   mounted () {
@@ -98,7 +101,7 @@ export default {
           }
 
           .logo {
-            height: 64px;
+            height: 70px;
             vertical-align: top;
             margin-right: 16px;
             border-style: none;

+ 10 - 0
src/libs/getDate.js

@@ -12,6 +12,16 @@ export default {
     obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
     return obj
   },
+  //  近7天
+  getRecentday () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment().subtract('days', 6).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
   // 获取昨日的开始结束时间
   getYesterday () {
     const obj = {

+ 2 - 2
src/permission.js

@@ -17,8 +17,8 @@ router.beforeEach((to, from, next) => {
   NProgress.start() // start progress bar
   to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${to.meta.title} - ${domTitle}`))
   let token = store.state.user.token || sessionStorage.getItem(ACCESS_TOKEN)
-  token = token != 'undefined' ? token : ''
-  // console.log(token)
+  token = token != 'null' && token != 'undefined' && token ? token : ''
+  // console.log(token,'token')
   // 已登录
   if (token) {
     /* has token */

+ 1 - 0
src/store/getters.js

@@ -10,6 +10,7 @@ const getters = {
   welcome: state => state.user.welcome,
   roles: state => state.user.roles,
   userInfo: state => state.user.info,
+  authUserInfo: state => state.user.authUserInfo,
   addRouters: state => state.permission.addRouters,
   multiTab: state => state.app.multiTab,
   lang: state => state.i18n.lang

+ 8 - 1
src/store/modules/user.js

@@ -12,7 +12,8 @@ const user = {
     welcome: '',
     avatar: '',
     roles: { permissionList: [] },
-    info: {}
+    info: {},
+    authUserInfo: {}
   },
 
   mutations: {
@@ -39,6 +40,9 @@ const user = {
     },
     SET_INFO: (state, info) => {
       state.info = info
+    },
+    SET_AUTH_USER_INFO: (state, authUserInfo) => {
+      state.authUserInfo = authUserInfo
     }
   },
 
@@ -57,6 +61,8 @@ const user = {
               commit('SET_TOKEN', res.access_token)
               commit('SET_NAME', { name: users.userNameCN, welcome: welcome() })
               commit('SET_CHANNELNAME', users.extInfo.channel.salesChannelName)
+              console.log('登陆成功user数据', users)
+              commit('SET_AUTH_USER_INFO', users)
               commit('SET_MUSTCHANGEPWD', users.mustChangePwd)
               Vue.ls.set('rolesAccess', { permissionList: users.permCodes }, 7 * 24 * 60 * 60 * 1000)
               commit('SET_AVATAR', res.avatar ? res.avatar : '')
@@ -99,6 +105,7 @@ const user = {
         }).finally(() => {
           commit('SET_NAME', { name: '', welcome: '' })
           commit('SET_CHANNELNAME', '')
+          commit('SET_AUTH_USER_INFO', {})
           commit('SET_MUSTCHANGEPWD', '')
           commit('SET_AVATAR', '')
           commit('SET_TOKEN', '')

+ 1 - 1
src/utils/request.js

@@ -49,7 +49,7 @@ service.interceptors.request.use(config => {
 service.interceptors.response.use((response) => {
   console.log(response, 'response.data.status')
   if (window.location.pathname != '/user/login') {
-    if (response.data.status == '500') {
+    if (response.data.status == '900' || response.data.status == '500') {
       notification.destroy()
       notification.error({
         message: '提示',

+ 7 - 0
src/views/FinancialManagement/PaySettlementRecords.vue

@@ -118,6 +118,13 @@ export default {
         width: '150px',
         align: 'center'
       },
+	{
+	  title: '销售合作商',
+	  dataIndex: 'salesChannelName',
+	  width: '150px',
+	  align: 'center'
+	},
+			
       {
         title: '结算时间',
         dataIndex: 'settleDate',

+ 4 - 5
src/views/FinancialManagement/PaySettlementRecordsDetailsModal.vue

@@ -41,11 +41,10 @@ export default {
   data () {
     return {
       loadData: parameter => {
-        return SettlementRecordsDetailsList({
-          settleNo: this.itemId,
-          pageNo: 1,
-          pageSize: 10
-        }).then(res => {
+        let params = Object.assign(parameter, {
+          settleNo: this.itemId
+         })
+        return SettlementRecordsDetailsList(params).then(res => {
           const no = (res.data.pageNo - 1) * res.data.pageSize
           for (let i = 0; i < res.data.list.length; i++) {
             const _item = res.data.list[i]

+ 4 - 5
src/views/FinancialManagement/WriteOffDetailsModal.vue

@@ -42,11 +42,10 @@ export default {
   data () {
     return {
       loadData: parameter => {
-        return SettlementRecordsDetailsList({
-          settleNo: this.itemId,
-          pageNo: 1,
-          pageSize: 10
-        }).then(res => {
+        let params = Object.assign(parameter, {
+          settleNo: this.itemId
+         })
+        return SettlementRecordsDetailsList(params).then(res => {
           const no = (res.data.pageNo - 1) * res.data.pageSize
           for (let i = 0; i < res.data.list.length; i++) {
             const _item = res.data.list[i]

+ 85 - 64
src/views/Home.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="home">
-    <a-alert message="欢迎登录合作商运营管理平台系统" type="info" showIcon />
+    <a-alert :message="alertMessage" type="info" showIcon />
     <div class="report-page">
       <!-- 查询条件 -->
       <a-row>
@@ -35,7 +35,7 @@
         <chart-line
           style="height: 350px;"
           color="#6C6FBE"
-          :yMax="200"
+          :yMax="yMax"
           yUnit="单"
           :xAxisRotate="resize"
           :xAxisData="XdaysData"
@@ -84,7 +84,7 @@
               style="height: 350px;"
               color="#6C6FBE"
               :xAxisRotate="resize"
-              :yMax="200"
+              :yMax="yMax1"
               yUnit="单"
               :xAxisData="XdaysData"
               :seriesData="washTypeBarData"
@@ -97,7 +97,7 @@
               ref="ChartLine"
               style="height: 350px;"
               color="#6C6FBE"
-              :yMax="200"
+              :yMax="yMax1"
               yUnit="单"
               :xAxisRotate="resize"
               :xAxisData="XdaysData"
@@ -166,6 +166,7 @@ import _ from 'lodash'
 import getDate from '@/libs/getDate'
 import moment from 'moment'
 import { getOrderstatistics } from '@/api/report-charts.js'
+import { salesChannelList } from '@/api/FinancialManagement'
 export default {
   name: 'Home',
   components: {
@@ -190,7 +191,7 @@ export default {
     }
   },
   computed: {
-    ...mapGetters(['mustChangePwd']),
+    ...mapGetters(['mustChangePwd', 'authUserInfo']),
     resize () {
       console.log(this.screenWidth, 'this.screenWidth')
       if (this.screenWidth < 1640) {
@@ -244,75 +245,69 @@ export default {
         bundleNum: 0 //  套餐销售量
       },
       // 快速删选tab
-      tabList: [{
-        name: '今天',
-        type: 'today'
-      },
-      {
-        name: '本周',
-        type: 'thisWeek'
-      },
-      {
-        name: '上周',
-        type: 'lastWeek'
-      },
-      {
-        name: '本月',
-        type: 'thisMonth'
-      }
+      tabList: [
+        { name: '今天', type: 'today' },
+        { name: '本周', type: 'thisWeek' },
+        { name: '上周', type: 'lastWeek' },
+        { name: '本月', type: 'thisMonth' }
       ],
       curentType: 'thisWeek', // 当前所选时间查询类型
       beginDate: null, // 开始时间
       endDate: null, // 结束时间
+      yMax: 250,
       // 套餐量图表数据
-      washCarsChartData: [{
-        name: '当日套餐销售量',
-        type: 'line',
-        data: []
-      },
-      {
-        name: '当日套餐使用量',
-        type: 'line',
-        data: []
-      }
+      washCarsChartData: [
+        {
+          name: '当日套餐销售量',
+          type: 'line',
+          data: []
+        },
+        {
+          name: '当日套餐使用量',
+          type: 'line',
+          data: []
+        }
       ],
       couponColor: ['#d48265', '#ff55ff'],
       // 套餐类型数据
       currentTabChart: 'tab1', // 套餐类型详情数据与变化趋势的tab 默认展示详情数据
       XdaysData: [], // 图表X轴时间集合
+      yMax1: 250,
       // 套餐类型柱状图表数据
-      washTypeBarData: [{
-        name: '洗美套餐',
-        type: 'bar',
-        data: []
-      },
-      {
-        name: '保养套餐',
-        type: 'bar',
-        data: []
-      },
-      {
-        name: '系统养护套餐',
-        type: 'bar',
-        data: []
-      }
+      washTypeBarData: [
+        {
+          name: '洗美套餐',
+          type: 'bar',
+          data: []
+        },
+        {
+          name: '保养套餐',
+          type: 'bar',
+          data: []
+        },
+        {
+          name: '系统养护套餐',
+          type: 'bar',
+          data: []
+        }
       ],
       // 套餐类型折线图表数据
-      washTypeLineData: [{
-        name: '洗美套餐',
-        type: 'line',
-        data: []
-      },
-      {
-        name: '保养套餐',
-        type: 'line',
-        data: []
-      },
-      {
-        name: '系统养护套餐',
-        type: 'line',
-        data: []
-      }
+      washTypeLineData: [
+        {
+          name: '洗美套餐',
+          type: 'line',
+          data: []
+        },
+        {
+          name: '保养套餐',
+          type: 'line',
+          data: []
+        },
+        {
+          name: '系统养护套餐',
+          type: 'line',
+          data: []
+        }
       ],
       // 各类型占比
       washTypePieColor: ['#ffaa00', '#00ff00', '#00aaff', '#ff55ff', '#1dc5d4', '#8465c7', '#00ffff'],
@@ -321,7 +316,8 @@ export default {
         washTypePieData: [],
         chartData: {}
       },
-      openResetPwd: false //  重置密码是否显示
+      openResetPwd: false, //  重置密码是否显示
+      alertMessage: '欢迎登录合作商运营管理平台系统' //  系统提示语
     }
   },
   methods: {
@@ -426,7 +422,8 @@ export default {
       })
       this.XdaysData = days
       const washTypeData = [kxData, jxData, dlxData]
-      console.log(washTypeData, 'washTypeData')
+      console.log(kxData.concat(jxData).concat(dlxData), 'washTypeData')
+      this.yMax1 = Math.max.apply(null, kxData.concat(jxData).concat(dlxData))
       // 套餐类型柱状图表数据
       this.washTypeBarData.map((item, index) => {
         item.data = washTypeData[index]
@@ -438,6 +435,21 @@ export default {
       // 套餐量图表数据赋值
       this.washCarsChartData[0].data = totalData
       this.washCarsChartData[1].data = useCouponData
+      this.yMax = Math.max.apply(null, totalData.concat(useCouponData))
+    },
+    //  获取渠道商下的合作商信息
+    getSalesChannel () {
+      salesChannelList().then(res => {
+        if (res.status == 200) {
+          let msg = '以下统计来源于'
+          res.data.map((item, index) => {
+            if (index < 3) {
+              msg += item.salesChannelName + '、'
+            }
+          })
+          this.alertMessage = msg.substr(0, msg.length - 1) + '等多家合作商的数据汇总'
+        }
+      })
     }
   },
   beforeRouteEnter (to, from, next) {
@@ -448,7 +460,16 @@ export default {
       } else {
         vm.openResetPwd = true
       }
-      console.log(vm.mustChangePwd, '-------是否需要重置密码')
+      console.log(vm.mustChangePwd, 'vm.mustChangePwd')
+      if (vm.authUserInfo.hasOwnProperty('extInfo')) {
+        if (vm.authUserInfo.extInfo.channel.salesChannelType == 'CHANNEL') { //  渠道商
+          vm.getSalesChannel()
+        }
+      } else {
+        vm.$store.dispatch('Logout')
+      }
+
+      // console.log(vm.mustChangePwd, '-------是否需要重置密码', vm.authUserInfo)
       vm.pageInit()
       vm.curentType = 'thisWeek'
       vm.getCurentSearchTime()

+ 366 - 0
src/views/Service/PurchasedServiceDetail.vue

@@ -0,0 +1,366 @@
+<template>
+  <a-card>
+    <a-spin :spinning="loading">
+      <a-card class="detail-card" :bordered="false" title="基本信息">
+        <detail-list>
+          <detail-list-item term="订单编号">{{ orderBundle.number ? orderBundle.number : '--' }}</detail-list-item>
+          <detail-list-item term="订单来源">{{ dataSourceName ? dataSourceName : '--' }}</detail-list-item>
+          <detail-list-item term="下单时间">{{ orderBundle.orderDate ? orderBundle.orderDate : '--' }}</detail-list-item>
+          <detail-list-item term="订单状态">{{ palyStatus ? palyStatus :'--' }}</detail-list-item>
+          <detail-list-item term="客户信息">{{ custInfo ? custInfo : '--' }}</detail-list-item>
+          <detail-list-item term="应付金额">¥{{ orderBundle.totalAmount ? orderBundle.totalAmount :0 }}</detail-list-item>
+          <detail-list-item term="支付时间" v-if="isPay">{{ payDate ? payDate : '--' }}</detail-list-item>
+          <detail-list-item term="支付金额" v-if="isPay">¥{{ orderBundle.payedAmount ? orderBundle.payedAmount : 0 }}</detail-list-item>
+        </detail-list>
+      </a-card>
+      <a-card class="detail-card" :bordered="false" title="服务内容">
+        <a-table
+          :columns="columns"
+          rowKey="id"
+          :dataSource="customerBundleItemList"
+          bordered
+          :pagination="false">
+          <span slot="no" slot-scope="text, record, index">
+            <template>
+              {{ index + 1 }}
+            </template>
+          </span>
+          <span slot="hexiao" slot-scope="text, record, index">
+            <template>
+              <a-button type="primary" v-if="!isRund && record.isDelay " @click="yanQi(record)" id="PurchasedServiceDetail-yanQi">延期</a-button>
+              <span v-else>--</span>
+            </template>
+          </span>
+        </a-table>
+      </a-card>
+      <!-- 使用记录 -->
+      <a-card class="detail-card" :bordered="false" title="使用记录">
+        <a-table
+          :columns="usedColumns"
+          rowKey="id"
+          :dataSource="verificationList"
+          bordered
+          v-if="verificationList && verificationList.length > 0"
+          :pagination="false">
+          <span slot="no" slot-scope="text, record, index">
+            <template>
+              {{ index + 1 }}
+            </template>
+          </span>
+        </a-table>
+        <div class="detail-card-info" v-else>
+          此订单没有使用记录
+        </div>
+      </a-card>
+      <!-- 取消购买 -->
+      <a-card class="detail-card" :bordered="false" style="text-align: center;">
+        <a-button v-if="!verificationList && salesChannelSettleStatus== 'NOT_SETTLE' && palyStatus =='已支付' " type="primary" @click="canselBuy" id="PurchasedServiceDetail-canselBuy">取消购买</a-button>
+        <a-button style="margin-left: 20px;" @click="toList">返回列表</a-button>
+      </a-card>
+      <!-- 延期弹窗 -->
+      <yanQi-modal :yanQiData="yanQiData" :yanqiModal="yanqiModal" @close="canselYq"></yanQi-modal>
+    </a-spin>
+  </a-card>
+</template>
+
+<script>
+import { customerBundleDetail, orderCancel } from '@/api/customerBundle'
+import { getLookUpDataBy } from '@/api/data'
+import { PageView } from '@/layouts'
+import { STable } from '@/components'
+import yanQiModal from './yanQiModal.vue'
+import DetailList from '@/components/tools/DetailList'
+import _ from 'lodash'
+import moment from 'moment'
+const DetailListItem = DetailList.Item
+export default {
+  name: 'OrderAdd',
+  components: {
+    PageView,
+    DetailList,
+    DetailListItem,
+    STable,
+    yanQiModal
+  },
+  computed: {
+    palyStatus () {
+      const _playStatus = _.find(this.palyStatusList, ['code', this.orderBundle.orderFlag])
+      if (_playStatus) {
+        if (_playStatus.code === 'CAEL' || _playStatus.code === 'SYCA') {
+          return '已取消'
+        }
+        return _playStatus.dispName
+      }
+      return ''
+    },
+    palyStatusStr () {
+      const _playStatus = _.find(this.palyStatusList, ['code', this.orderBundle.orderFlag])
+      if (_playStatus) {
+        if (_playStatus.code === 'SYCA') {
+          return '超时未支付自动取消'
+        }
+        return _playStatus.dispName
+      }
+      return ''
+    },
+    isPay () {
+      return this.orderBundle.orderFlag === 'PAED'
+    },
+		isRund(){
+			return this.orderBundle.orderFlag === 'RUND'
+		},
+    isCancel () {
+      return this.orderBundle.orderFlag === 'CAEL' || this.orderBundle.orderFlag === 'SYCA'
+    },
+    payDate () {
+      return _.get(this, 'paymentDetailList.payDate')
+    },
+    custInfo () {
+      let info = null
+      if (this.customer) {
+        info = this.customer.name
+        if (info) {
+          info = info + '-' + this.customer.mobile
+        } else {
+          info = this.customer.mobile
+        }
+      } else {
+        info = this.orderBundle.custMobile
+        if (this.orderBundle.vehicleNumber) {
+          info += '(' + this.orderBundle.vehicleNumber + ')'
+        }
+      }
+      return info
+    }
+
+  },
+  data () {
+    return {
+      form: this.$form.createForm(this),
+      loading: false,
+      // showBackNum:true,
+      customerCoupon: {},
+      palyStatusList: [],
+      yanqiModal: false,
+      hexiaoModal: false,
+      buyModal: false,
+      orderBundleId: '',
+      yanQiData: null,
+      hxCustomerBundleItemId: '',
+      dataSourceName: '',
+      salesChannelSettleStatus: '', // 结算状态
+      customer: null,
+      orderBundle: {},
+      payDetail: {},
+      verificationList: [],
+      customerBundleItemList: [],
+      coupon: {},
+      columns: [
+        {
+          title: '服务名称',
+          dataIndex: 'itemName',
+          width: 100,
+          align: 'center'
+        },
+        {
+          title: '到期时间',
+          dataIndex: 'expiryDate',
+          width: 100,
+          align: 'center'
+        },
+        {
+          title: '购买数量',
+          dataIndex: 'times',
+          width: 100,
+          align: 'center'
+        },
+        {
+          title: '剩余次数',
+          dataIndex: 'remainTimes',
+          width: 100,
+          align: 'center'
+        },
+        {
+          title: '已用次数',
+          dataIndex: 'usedTimes',
+          width: 100,
+          align: 'center'
+        },
+        {
+          title: '过期次数',
+          dataIndex: 'expiryTimes',
+          width: 100,
+          align: 'center'
+        },
+        {
+          title: '退款次数',
+          dataIndex: 'refundTimes',
+          width: 100,
+          align: 'center'
+        },
+        {
+          title: '操作',
+          width: 100,
+          align: 'center',
+          scopedSlots: {
+            customRender: 'hexiao'
+          }
+        }
+      ],
+      usedColumns: [{
+        title: '序号',
+        scopedSlots: {
+          customRender: 'no'
+        },
+        width: 60,
+        align: 'center'
+      },
+      {
+        title: '服务名称',
+        dataIndex: 'itemName',
+        width: 100,
+        align: 'center'
+      },
+      {
+        title: '使用时间',
+        dataIndex: 'usedTime',
+        width: 100,
+        align: 'center'
+      },
+      {
+        title: '使用门店',
+        dataIndex: 'usedStoreName',
+        width: 100,
+        align: 'center'
+      },
+      {
+        title: '核销单号',
+        dataIndex: 'bizNum',
+        width: 200,
+        align: 'center'
+      },
+      {
+        title: '门店结算金额',
+        dataIndex: 'accountPrice',
+        width: 100,
+        align: 'center'
+      }
+      ]
+
+    }
+  },
+  created () {
+    this.initPage()
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      console.log(vm.$route.params.id)
+      // vm.clear()
+      if (to.query.id) {
+        vm.initPage()
+      }
+    })
+  },
+  methods: {
+    moment,
+    // 不可选日期
+    disabledDate (current) {
+      return current && current < moment().subtract(1, 'days')
+    },
+    initPage () {
+      const _this = this
+      this.loading = true
+      getLookUpDataBy({
+        type: 'PAY_STATUS'
+      }).then(res => {
+        if (res.status === '200') {
+          _this.palyStatusList = res.data
+        }
+        return customerBundleDetail({
+          id: _this.$route.params.id
+        })
+      }).then(res => {
+        if (res.status + '' === '200') {
+          const _data = res.data
+          _this.orderBundleId = _data.orderBundleId
+          _this.customer = _data.customer
+          _this.dataSourceName = _data.dataSourceName
+          _this.salesChannelSettleStatus = _data.salesChannelSettleStatus
+          _this.orderBundle = _data.orderBundle
+          if (_data.paymentDetailList && _data.paymentDetailList.length) {
+            _this.paymentDetailList = _data.paymentDetailList[0]
+          }
+          _this.coupon = _data.coupon
+          if (_data.customerCoupon) {
+            _this.customerCoupon = _data.customerCoupon
+          }
+          _this.customerBundleItemList = _data.customerBundleItemList
+          _this.customerBundleItemList.map((item, index) => {
+            // item.no = index + 1
+            item.isDelay = item.expiryDate ? item.expiryDate.substr(0, 10) != '2099-01-01' : false
+          })
+          _this.verificationList = _data.verificationList
+        }
+        this.loading = false
+      })
+    },
+    // 延期
+    yanQi (row) {
+      this.yanQiData = row
+      this.yanqiModal = true
+    },
+    // 关闭延期弹窗
+    canselYq () {
+      this.initPage()
+      this.yanQiData = null
+      this.yanqiModal = false
+    },
+    // 取消购买
+    canselBuy () {
+      this.$confirm({
+        title: '取消购买',
+        content: '取消购买后,套餐内所有服务的剩余次数变为0,用户无法再使用套餐。确认取消购买吗?',
+        onOk: () => {
+          orderCancel({
+            id: this.$route.params.id
+          }).then(res => {
+            if (res.status == 200) {
+              this.$message.info(res.message)
+              this.$router.push({ name: 'PurchasedServiceList' })
+            }
+          })
+        },
+        onCancel () {}
+      })
+    },
+    toList () {
+      this.$router.push({ name: 'PurchasedServiceList' })
+    },
+    // quxiao
+    canselGM () {
+      this.buyModal = false
+      this.hxCustomerBundleItemId = ''
+    }
+  }
+}
+</script>
+
+<style scoped>
+	.detail-card+.detail-card {
+		margin-top: 10px;
+	}
+
+	.detail-card-info {
+		text-align: center;
+		font-size: 1.1em;
+	}
+
+	.button-row {
+		padding-top: 20px;
+		text-align: center;
+	}
+
+	.button-row .ant-btn {
+		margin-left: 20px;
+	}
+</style>

+ 441 - 0
src/views/Service/PurchasedServiceList.vue

@@ -0,0 +1,441 @@
+<template>
+  <a-card :bordered="false">
+    <v-select v-show="false" ref="orderFlag" code="PAY_STATUS" placeholder="请选择订单状态" allowClear></v-select>
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline" :form="form" @keyup.enter.native="refresh">
+        <a-row :gutter="48">
+          <a-col :lg="6" :sm="12">
+            <a-form-item label="订单编号:" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
+              <a-input class="full-width" id="PurchasedServiceList-number" v-model.trim="queryParam.number" placeholder="订单编号" allowClear />
+            </a-form-item>
+          </a-col>
+          <a-col :lg="6" :sm="12">
+            <a-form-item label="下单时间:" :label-col="{ span: 7 }" :wrapper-col="{ span: 17}">
+              <a-range-picker
+                style="width:100%"
+                id="PurchasedServiceList-queryOrderDate"
+                :disabledDate="disabledDate"
+                v-model="queryOrderDate"
+                :format="dateFormat"
+                :placeholder="['开始时间', '结束时间']" />
+            </a-form-item>
+          </a-col>
+          <a-col :lg="6" :sm="12">
+            <a-form-item label="结算状态:" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
+              <v-select
+                code="SETTLE_STATUS_ALL"
+                id="PurchasedServiceList-salesChannelSettleStatus"
+                ref="salesChannelSettleStatus"
+                v-model="queryParam.salesChannelSettleStatus"
+                allowClear></v-select>
+            </a-form-item>
+          </a-col>
+          <a-col :lg="6" :sm="12">
+            <a-form-item label="销售合作商" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
+              <a-select
+                id="PurchasedServiceList-dataSourceNo"
+                allowClear
+                option-filter-prop="children"
+                placeholder="请选择销售合作商"
+                v-model="queryParam.dataSourceNo">
+                <a-select-option v-for="(item,index) in dataSourceNoList" :key="index" :value="item.salesChannelNo">{{ item.salesChannelName }}</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+        </a-row>
+        <a-row :gutter="48">
+          <a-col :lg="6" :sm="12">
+            <a-form-item label="客户信息" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
+              <a-input
+                class="full-width"
+                id="PurchasedServiceList-custMobile"
+                v-model.trim="queryParam.custMobile"
+                :maxLength="11"
+                placeholder="客户信息"
+                allowClear />
+            </a-form-item>
+          </a-col>
+          <a-col :lg="6" :sm="12">
+            <a-form-item label="服务名称" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
+              <a-input class="full-width" id="PurchasedServiceList-bundleName" v-model.trim="queryParam.bundleName" placeholder="服务名称" allowClear />
+            </a-form-item>
+          </a-col>
+          <a-col :lg="6" :sm="12">
+            <a-button type="primary" @click="refresh" :disabled="disabled" id="PurchasedServiceList-search">查询</a-button>
+            <a-button style="margin-left: 8px" :disabled="disabled" @click="resetSearchForm" id="PurchasedServiceList-resetSearchForm">重置</a-button>
+            <a-button style="margin-left: 8px" class="export-btn" @click="handleExport" id="PurchasedServiceList-handleExport">导出</a-button>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 合计 -->
+    <a-alert type="info" showIcon style="margin-bottom:15px">
+      <div class="ftext" slot="message">共<span>{{ orderTotal || 0 }}</span>单,收款金额<span>¥{{ totalAmounts || 0 }}</span>元</div>
+    </a-alert>
+    <div class="card-container">
+      <s-table
+        ref="table"
+        size="default"
+        rowKey="id"
+        bordered
+        :columns="columns"
+        :data="loadData">
+        <span slot="orderFlag" slot-scope="text, record">{{ $refs.orderFlag.getNameByCode(record.orderFlag) }}</span>
+        <!-- 结算状态 -->
+        <span slot="salesChannelSettleStatus" slot-scope="text, record">{{ $refs.salesChannelSettleStatus.getNameByCode(record.salesChannelSettleStatus) }}</span>
+        <!-- 操作 -->
+        <span slot="action" slot-scope="text, record">
+          <a-button type="primary" style="margin: 5px;" @click="handleDetail(record)" id="PurchasedServiceList-handleDetail">详情</a-button>
+          </a-button>
+        </span>
+        <template slot="userInfo" slot-scope="text, record">
+          <p>{{ text }}<br>{{ record.vehicleNumber ? record.vehicleNumber : '--' }}</p>
+        </template>
+      </s-table>
+    </div>
+  </a-card>
+</template>
+<script>
+import moment from 'moment'
+import getDate from '@/libs/getDate.js'
+import {
+  STable,
+  VSelect
+} from '@/components'
+import {
+  salesChannelList
+} from '@/api/FinancialManagement'
+import {
+  listCustomerBundle,
+  queryBankPayStatus,
+  countListBundle,
+  exportBundle
+} from '@/api/customerBundle'
+export default {
+  name: 'OrderList',
+  components: {
+    VSelect,
+    STable
+  },
+  data () {
+    return {
+      disabled: false,
+      loadData: parameter => {
+        const searchData = Object.assign(parameter, this.queryParam, {
+          freeChoiceFlag: 1
+        })
+        console.log(this.queryOrderDate, 'this.queryOrderDate')
+        if (this.queryOrderDate && this.queryOrderDate.length) {
+          searchData.beginDate = moment(this.queryOrderDate[0]).format('YYYY-MM-DD')
+          searchData.endDate = moment(this.queryOrderDate[1]).format('YYYY-MM-DD')
+        } else {
+          searchData.beginDate = ''
+          searchData.endDate = ''
+        }
+        this.disabled = true
+        return listCustomerBundle(searchData).then(res => {
+          const no = (res.data.pageNo - 1) * res.data.pageSize
+          for (let i = 0; i < res.data.list.length; i++) {
+            const _item = res.data.list[i]
+            _item.no = no + i + 1
+          }
+          this.disabled = false
+          return res.data
+        })
+      },
+      form: this.$form.createForm(this, {
+        name: 'CustomerBundleList'
+      }),
+      // 将默认时间日期回显在时间选择框中
+      queryOrderDate: [
+        moment(getDate.getRecentday().starttime, this.dateFormat),
+        moment(getDate.getRecentday().endtime, this.dateFormat)
+      ],
+      dateFormat: 'YYYY-MM-DD',
+      queryParam: {
+        number: '', // 订单编号
+        bundleName: '', // 服务名称
+        beginDate: null,
+        endDate: null,
+        custMobile: '', // 用户信息
+        dataSourceNo: undefined, // 合作商
+        salesChannelSettleStatus: '' // 结算状态
+      },
+      dataSourceNoList: [],
+      orderTotal: '', // 订单总数
+      totalAmounts: '',
+      columns: [{
+        title: '序号',
+        dataIndex: 'no',
+        width: 60,
+        align: 'center'
+      },
+      {
+        title: '订单编号',
+        dataIndex: 'number',
+        width: 150,
+        align: 'center'
+      },
+      {
+        title: '销售合作商',
+        dataIndex: 'salesChannelName',
+        width: 150,
+        align: 'center',
+        customRender: function (text) {
+          return (text || '--')
+        }
+      },
+      {
+        title: '下单时间',
+        dataIndex: 'orderDate',
+        width: 150,
+        align: 'center'
+      },
+      {
+        title: '客户信息',
+        dataIndex: 'custMobile',
+        width: 150,
+        align: 'center',
+        scopedSlots: {
+          customRender: 'userInfo'
+        }
+      },
+      {
+        title: '服务名称',
+        dataIndex: 'bundleName',
+        align: 'center',
+        width: 100,
+        customRender: function (text) {
+          return (text || '--')
+        }
+      },
+      {
+        title: '购买数量',
+        dataIndex: 'cnt',
+        align: 'center',
+        width: 100,
+        customRender: function (text) {
+          return (text || '--')
+        }
+      },
+      {
+        title: '收款金额',
+        dataIndex: 'payedAmount',
+        width: 100,
+        align: 'center'
+      },
+      {
+        title: '订单状态',
+        dataIndex: 'orderFlag',
+        width: 100,
+        align: 'center',
+        scopedSlots: {
+          customRender: 'orderFlag'
+        }
+      },
+      {
+        title: '结算状态',
+        dataIndex: '',
+        width: 100,
+        align: 'center',
+        scopedSlots: {
+          customRender: 'salesChannelSettleStatus'
+        }
+      },
+      {
+        title: '操作',
+        width: 100,
+        align: 'center',
+        scopedSlots: {
+          customRender: 'action'
+        }
+      }
+      ]
+    }
+  },
+  methods: {
+    // 禁止不可选日期
+    disabledDate (current) {
+      return current && current > moment().endOf('day')
+    },
+    // 创建时间change
+    onChange (dates, dateStrings) {
+      if ((dates, dateStrings)) {
+        this.queryParam.beginDate = dateStrings[0]
+        this.queryParam.endDate = dateStrings[1]
+      }
+    },
+    //  获取渠道商下的合作商信息
+    getSalesChannel () {
+      salesChannelList().then(res => {
+        if (res.status == 200) {
+          this.dataSourceNoList = res.data
+        } else {
+          this.dataSourceNoList = []
+        }
+      })
+    },
+    handleChange (value) {
+      console.log(`selected ${value}`)
+    },
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    },
+    // 合计
+    getTotal () {
+      const params = {
+        beginDate: this.queryParam.beginDate,
+        endDate: this.queryParam.endDate,
+        bundleName: this.queryParam.bundleName,
+        number: this.queryParam.number,
+        custMobile: this.queryParam.custMobile,
+        dataSourceNo: this.queryParam.dataSourceNo,
+        salesChannelSettleStatus: this.queryParam.salesChannelSettleStatus,
+        freeChoiceFlag: 1
+      }
+      params.beginDate == null ? params.beginDate = getDate.getRecentday().starttime : null
+      params.endDate == null ? params.endDate = getDate.getRecentday().endtime : null
+      countListBundle(params).then(res => {
+        if (res.status == 200) {
+          if (res.data) {
+            this.orderTotal = res.data.cnt || 0
+            this.totalAmounts = res.data.totalAmounts || 0
+          } else {
+            this.orderTotal = 0
+            this.totalAmounts = 0
+          }
+        } else {
+          this.orderTotal = 0
+          this.totalAmounts = 0
+        }
+      })
+    },
+    // 查看详情、
+    handleDetail (row) {
+      this.$router.push({
+        path: `/Service/PurchasedService/detail/${row.id}`
+      })
+    },
+    reloadRow (row) {
+      queryBankPayStatus({
+        tradeNo: row.tradeNo
+      }).then(res => {
+        console.log(res)
+        if (res.status == 200) {
+          this.$refs.table.refresh(true)
+        }
+      })
+    },
+    // 查询
+    refresh () {
+      this.$refs.table.refresh(true)
+      this.getTotal()
+    },
+    // 重置
+    resetSearchForm () {
+      this.queryParam.beginDate = getDate.getRecentday().starttime
+      this.queryParam.endDate = getDate.getRecentday().endtime
+      this.queryOrderDate = [
+        moment(getDate.getRecentday().starttime, this.dateFormat),
+        moment(getDate.getRecentday().endtime, this.dateFormat)
+      ]
+      this.queryParam = {
+        dataSourceNo: '',
+        custMobile: '',
+        bundleName: '',
+        dataSourceNo: undefined,
+        salesChannelSettleStatus: '',
+        freeChoiceFlag: 1
+      }
+      this.refresh()
+    },
+    // 导出
+    handleExport () {
+      const params = {
+        bundleName: this.queryParam.bundleName,
+        number: this.queryParam.number,
+        custMobile: this.queryParam.custMobile,
+        dataSourceNo: this.queryParam.dataSourceNo,
+        salesChannelSettleStatus: this.queryParam.salesChannelSettleStatus,
+        freeChoiceFlag: 1
+      }
+      if (this.queryOrderDate && this.queryOrderDate.length) {
+        params.beginDate = moment(this.queryOrderDate[0]).format('YYYY-MM-DD')
+        params.endDate = moment(this.queryOrderDate[1]).format('YYYY-MM-DD')
+      } else {
+        params.beginDate = ''
+        params.endDate = ''
+      }
+      if (!params.beginDate && !params.endDate) {
+        this.$message.error('请先选择需要导出的下单时间区间再进行导出!')
+        return
+      }
+      // 判断两个时间段是否相差1个月  第二个参数指相差单位,第三个参数指是否返回浮点形式(小数)
+      if (moment(params.endDate).diff(moment(params.beginDate), 'months', true) > 1) {
+        this.$message.error('单次最多只能导出1个月的数据,请缩小查询区间后再进行导出!')
+        return
+      }
+      this.loading = true
+      exportBundle(params).then(res => {
+        this.loading = false
+        this.download(res)
+      })
+    },
+    download (data) {
+      if (!data) {
+        return
+      }
+      const url = window.URL.createObjectURL(new Blob([data]))
+      const link = document.createElement('a')
+      link.style.display = 'none'
+      link.href = url
+      const a = moment().format('YYYYMMDDhhmmss')
+      const fname = '已购服务记录-' + a
+      link.setAttribute('download', fname + '.xlsx')
+      document.body.appendChild(link)
+      link.click()
+    }
+  },
+  mounted () {
+    this.getSalesChannel()
+	this.getTotal()
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.queryParam.beginDate = getDate.getRecentday().starttime
+      vm.queryParam.endDate = getDate.getRecentday().endtime
+      vm.queryOrderDate = [
+        moment(getDate.getRecentday().starttime, this.dateFormat),
+        moment(getDate.getRecentday().endtime, this.dateFormat)
+      ]
+      vm.queryParam = {
+        dataSourceNo: '',
+        custMobile: '',
+        bundleName: '',
+        dataSourceNo: undefined,
+        salesChannelSettleStatus: '',
+        freeChoiceFlag: 1
+      }
+    })
+  }
+}
+</script>
+
+<style lang="less">
+	.table-page-search-wrapper {
+		.export-btn {
+			background-color: #ff9900;
+			border-color: #ff9900;
+			color: #fff;
+			margin-left: 10px;
+		}
+
+		.export-btn.ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger),
+		.export-btn.ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger) {
+			color: #fff;
+			border-color: #ff9900;
+		}
+	}
+</style>

+ 159 - 0
src/views/Service/yanQiModal.vue

@@ -0,0 +1,159 @@
+<template>
+	<!-- 延期弹窗 -->
+	<a-modal title="服务延期" :footer="null" v-model="isShow" @cancel="canselYq" @ok="handleYanqiOk" width="50%" :centered='true'>
+		<a-form :form="form" ref="form">
+			<a-col :span="24">
+				<!-- 服务名称 -->
+				<a-form-item label="服务名称" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }">
+					<span>{{this.yanQiData ? this.yanQiData.itemName : '--'}}</span>
+				</a-form-item>
+			</a-col>
+			<a-col :span="24">
+				<!-- 到期时间 -->
+				<a-form-item label="到期时间" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }">
+					<span>{{this.yanQiData ? this.yanQiData.expiryDate : '--'}}</span>
+				</a-form-item>
+			</a-col>
+			<a-col :span="24">
+				<!-- 剩余次数 -->
+				<a-form-item label="剩余次数" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }">
+					<span>{{this.yanQiData ? this.yanQiData.remainTimes : '--'}}</span>
+				</a-form-item>
+			</a-col>
+			<a-col :span="24">
+				<!-- 过期次数 -->
+				<a-form-item label="过期次数" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }">
+					<span>{{this.yanQiData ? this.yanQiData.expiryTimes : '--'}}</span>
+				</a-form-item>
+			</a-col>
+			<a-col :span="24">
+				<a-form-item label="新到期时间" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }">
+					<a-date-picker style="width: 60%;"
+				        format="YYYY-MM-DD"
+						placeholder="请选择新的到期时间"
+				        :disabled-date="disabledDate"
+						v-decorator="[
+						  'formData.expiryDate',
+						  {
+						    initialValue: formData.expiryDate,
+						    rules: [{ required: true, message: '请选择新的到期时间!' }] },
+						]"
+				      />
+				</a-form-item>
+			</a-col>
+			<a-col :span="24">
+				<a-form-item label="返还次数" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }">
+					<a-input-number id="inputNumber" :disabled="isDisabled" :min="0" :max="this.yanQiData ? this.yanQiData.expiryTimes : this.formData.returnTimes" :precision="0"  placeholder="请输入返还次数" style="width: 60%;" v-decorator="['formData.returnTimes',{initialValue: formData.returnTimes,rules: []}]"/>
+				</a-form-item>
+			</a-col>
+			<div class="button-row">
+				<a-button key="back" @click="canselYq">取消</a-button>
+				<a-button key="submit" type="primary"  @click="handleYanqiOk">确定</a-button>
+			</div>
+	    </a-form-item>
+	  </a-form>
+	</a-modal>
+</template>
+<script>
+	import moment from 'moment'
+	import { customerBundleItemDelay } from '@/api/customerBundle.js'
+	export default{
+		name:'yanQiModal',
+		props:{
+			yanqiModal:{
+				type:Boolean,
+				default:false
+			},
+			yanQiData: {
+			  //  服务数据
+			  type: Object,
+			  default: () => {
+			    return {}
+			  }
+			}
+		},
+		data(){
+			return{
+				form: this.$form.createForm(this),
+				isShow:this.yanqiModal,
+				formData:{
+					returnTimes:'',
+					expiryDate:''
+				},
+				isDisabled:false
+			}
+		},
+		methods:{
+			moment,
+			 // 不可选日期
+			disabledDate(current) {
+				return current < moment().subtract(1, 'days') ||  current > moment('2038-01-01')
+			},
+			// 重置表单
+			resetForm(){
+				this.formData.returnTimes=''
+				this.formData.expiryDate=''
+			},
+			// 取消
+			canselYq(){
+				this.resetForm() //  重置表单数据
+				this.isShow = false
+			},
+			// 保存
+			handleYanqiOk () {
+				this.form.validateFields((err, values) => {
+					if (!err) {
+						const formData = values.formData
+						const params={
+							expiryDate: moment(formData.expiryDate).format('YYYY-MM-DD'),
+							returnTimes: formData.returnTimes == '' ? 0 : formData.returnTimes,
+							id: this.yanQiData.id  
+						}
+						console.log(params,this.formData)
+						customerBundleItemDelay(params).then(res => {
+						  console.log(res)
+						  if (res.status == 200) {
+						    this.$message.info(res.message)
+						    this.canselYq()
+						  }
+						})
+					}
+				})
+			},
+		},
+		watch: {
+		  //  父页面传过来的弹框状态
+		  yanqiModal (newValue, oldValue) {
+		    this.isShow = newValue
+			console.log(this.yanQiData)
+			if(this.yanQiData){
+				if(this.yanQiData.expiryTimes == 0){
+					 this.isDisabled=true 
+				}
+			}
+		  },
+		  //  重定义的弹框状态
+		  isShow (val) {
+		    if (!val) {
+		      this.$emit('close')
+		    } else {
+				//  重置表单数据
+		      this.resetForm()
+		    }
+		  },
+		  yanQiData (val) {
+		    console.log(val)
+		  }
+		}
+	}
+</script>
+
+<style lang="less">
+	.button-row{
+	  padding-top: 20px;
+	  text-align: center;
+	  button{
+		  margin: 0 10px;
+	  }
+	}
+</style>

+ 74 - 38
src/views/SetmealSales/BuySetmeal.vue

@@ -21,37 +21,51 @@
           <a-tab-pane v-for="item in setmealType" :key="item.code" :tab="item.dispName"></a-tab-pane>
         </a-tabs>
         <!-- 套餐数据列表 -->
-        <div class="itemBox" id="bundelScroll" :style="{height: winH - 358 + 'px'}">
-          <a-row class="items-list" v-for="(item, index) in listData" :key="index">
-            <a-col :span="15">
-              <h3>{{ item.name }} </h3>
-              <p>
-                <span><b>原价:</b><em style="text-decoration: line-through;">¥{{ item.originalPrice }}</em> </span>
-                <span style="margin-left: 15px;margin-right: 15px;color: red;"><b>现价:</b>¥{{ item.price }} </span>
-              </p>
-              <p>
-                <span><b>套餐说明:</b>{{ item.summary || '-' }}</span>
-              </p>
-            </a-col>
-            <a-col :span="1"></a-col>
-            <a-col :span="4">
-              <!-- <span>1 套</span> -->
-            </a-col>
-            <a-col :span="4">
-              <a-button
-                class="handle-btn buy-btn"
-                id="buySetmeal-buy"
-                type="primary"
-                @click="openPay(item)"
-                shape="round">下单</a-button>
-              <a-button
-                class="handle-btn look-btn"
-                id="buySetmeal-look"
-                @click="openDetails(item)"
-                shape="round">查看详细</a-button>
-            </a-col>
-          </a-row>
-          <a-empty v-if="listData.length == 0" class="noData" />
+        <div class="itemBox" id="bundelScroll">
+          <a-spin :spinning="loading" tip="Loading...">
+            <a-row class="items-list" v-for="(item, index) in listData" :key="index">
+              <a-col :span="15">
+                <h3>{{ item.name }} </h3>
+                <p>
+                  <span><b>原价:</b><em style="text-decoration: line-through;">¥{{ item.originalPrice }}</em> </span>
+                  <span style="margin-left: 15px;margin-right: 15px;color: red;"><b>现价:</b>¥{{ item.price }} </span>
+                  <span style="margin-left: 15px;margin-right: 15px;">
+                    有效期:{{ item.validityTermType == 'PERMANENT_VALIDITY' ? '永久有效' : item.validityTermType == 'FIXED_TIME' ? item.validityTermValue+'过期' : item.validityTermType == 'FIXED_DAYS' ? '购买后'+item.validityTermValue+'天过期' : '' }}
+                  </span>
+                </p>
+                <p>
+                  <span><b>套餐说明:</b>{{ item.summary || '-' }}</span>
+                </p>
+              </a-col>
+              <a-col :span="1"></a-col>
+              <a-col :span="4">
+                <!-- <span>1 套</span> -->
+              </a-col>
+              <a-col :span="4">
+                <a-button
+                  class="handle-btn buy-btn"
+                  id="buySetmeal-buy"
+                  type="primary"
+                  @click="openPay(item)"
+                  shape="round">下单</a-button>
+                <a-button
+                  class="handle-btn look-btn"
+                  id="buySetmeal-look"
+                  @click="openDetails(item)"
+                  shape="round">查看详细</a-button>
+              </a-col>
+            </a-row>
+            <!-- 分页 -->
+            <a-pagination
+              v-if="listData.length != 0"
+              class="pagination"
+              show-size-changer
+              :total="total"
+              @showSizeChange="onShowSizeChange"
+              @change="onChange" />
+            <!-- 暂无数据 -->
+            <a-empty v-if="listData.length == 0" class="noData" />
+          </a-spin>
         </div>
       </div>
     </a-card>
@@ -77,13 +91,14 @@ export default {
       queryWord: '', //  关键词
       clsId: '',
       pageNo: 1,
-      pageSize: 1000,
+      pageSize: 10,
+      total: 0,
       setmealType: [], //  套餐类型
       openSetmealPay: false, //  下单弹框是否显示
       openSetmealDetails: false, //  查看详细弹框是否显示
       setmealId: null, //  套餐id
       setmealInfo: null, //  套餐信息
-      winH: 0 //  浏览器高度
+      loading: false //  加载中状态
     }
   },
   methods: {
@@ -98,23 +113,41 @@ export default {
       this.queryWord = ''
       this.initData()
     },
+    //  分页查询  每页多少条
+    onShowSizeChange (current, pageSize) {
+      this.pageNo = current
+      this.pageSize = pageSize
+      this.initData()
+    },
+    //  分页查询  页码
+    onChange (page, pageSize) {
+      this.pageNo = page
+      this.pageSize = pageSize
+      this.initData()
+    },
     // 初始化数据
     initData () {
+      this.loading = true
       getBundleList({
         queryWord: this.queryWord,
-        clsId: this.clsId == 'all' ? '' : this.clsId
+        clsId: this.clsId == 'all' ? '' : this.clsId,
+        pageNo: this.pageNo,
+        pageSize: this.pageSize
       }).then(res => {
         if (res.status == 200) {
-          this.listData = res.data
+          this.listData = res.data.list || []
+          this.total = res.data.count || 0
         } else {
           this.listData = []
+          this.total = 0
         }
+        this.loading = false
       })
     },
     //  tab 切换
     tabChange (v) {
       this.listData = []
-      document.getElementById('bundelScroll').scrollTop = 0
+      this.pageNo = 1
       this.clsId = v
       if (this.clsId == 'all') {
         this.queryWord = this.queryWord
@@ -152,7 +185,6 @@ export default {
     }
   },
   mounted () {
-    this.winH = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight // 浏览器高度
     this.getBundleClsDatas()//  套餐分类  数据字典
     this.pageInit()
   }
@@ -239,10 +271,14 @@ export default {
           }
         }
         .noData{
-          margin: 150px 0 0;
+          margin: 150px 0 295px;
           text-align: center;
         }
       }
     }
+    .pagination{
+      text-align: right;
+      margin: 16px 0;
+    }
   }
 </style>

+ 67 - 20
src/views/SetmealSales/PurchasedSetmeal.vue

@@ -22,7 +22,7 @@
           </a-col>
           <a-col :span="6">
             <a-form-item label="客户信息" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
-              <a-input v-model.trim="searchForm.queryWord" id="purchasedSetmeal-queryWord" placeholder="请输入手机号" allowClear />
+              <a-input v-model.trim="searchForm.custMobile" id="purchasedSetmeal-custMobile" placeholder="请输入手机号" allowClear />
             </a-form-item>
           </a-col>
           <a-col :span="6">
@@ -30,8 +30,6 @@
               <a-input v-model.trim="searchForm.bundleName" id="purchasedSetmeal-bundleName" placeholder="请输入套餐名称" allowClear />
             </a-form-item>
           </a-col>
-          <!-- <a-col :span="6">
-            <a-form-item label="订单状态" :label-col="{ span:7 }" :wrapper-col="{ span:17}"> -->
           <v-select
             v-show="false"
             v-model="searchForm.orderFlag"
@@ -40,8 +38,6 @@
             code="PAY_STATUS"
             placeholder="请选择订单状态"
             allowClear></v-select>
-          <!-- </a-form-item>
-          </a-col> -->
           <a-col :span="6">
             <a-form-item label="结算状态" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
               <v-select
@@ -53,6 +49,18 @@
                 allowClear></v-select>
             </a-form-item>
           </a-col>
+          <a-col :span="6">
+            <a-form-item label="销售合作商" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
+              <a-select
+                id="purchasedSetmeal-dataSourceNo"
+                allowClear
+                option-filter-prop="children"
+                placeholder="请选择销售合作商"
+                v-model="searchForm.dataSourceNo">
+                <a-select-option v-for="(item,index) in dataSourceNoList" :key="index" :value="item.salesChannelNo">{{ item.salesChannelName }}</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
           <a-col :span="12">
             <a-button class="handle-btn serach-btn" id="purchasedSetmeal-serach" type="primary" @click="$refs.table.refresh(true)">查询</a-button>
             <a-button class="handle-btn" type="" id="purchasedSetmeal-reset" @click="handleReset">重置</a-button>
@@ -92,16 +100,16 @@
       </span>
     </s-table>
     <!-- 查看详情弹窗 -->
-    <setmeal-detail-modal :openModal="openDetailModal" :setmealId="detailId" @close="openDetailModal=false" />
+    <setmeal-detail-modal :openModal="openDetailModal" :setmealId="detailId" @refrresh="refrreshDetail" @close="closeModal" />
   </a-card>
 </template>
 
 <script>
 import { STable, VSelect } from '@/components'
 import getDate from '@/libs/getDate.js'
-import { completeDate } from '@/libs/tools.js'
 import moment from 'moment'
 import SetmealDetailModal from './SetmealDetailModal.vue'
+import { salesChannelList } from '@/api/FinancialManagement'
 import { listCustomerBundle, exportBundle, countListBundle } from '@/api/customerBundle.js'
 export default {
   name: 'PurchasedSetmeal',
@@ -114,9 +122,11 @@ export default {
         endDate: null, // 结束时间
         bundleName: '', // 套餐名称
         number: '', // 订单号
-        queryWord: '', // 客户信息
+        custMobile: '', // 客户信息
         orderFlag: '', // 订单状态
-        salesChannelSettleStatus: '' // 结算状态
+        salesChannelSettleStatus: '', // 结算状态
+        dataSourceNo: undefined, //  销售合作商
+        freeChoiceFlag: 0 //  套餐传0,服务传1
       },
       loading: false, // 导出loading
       orderTotal: '', // 合计开单数量
@@ -133,6 +143,7 @@ export default {
         { title: '序号', dataIndex: 'no', width: 60, align: 'center' },
         { title: '订单号', dataIndex: 'number', width: 100, align: 'center' },
         { title: '下单时间', dataIndex: 'orderDate', width: 100, align: 'center' },
+        { title: '销售合作商', dataIndex: 'salesChannelName', width: 100, align: 'center' },
         { title: '套餐名称', dataIndex: 'bundleName', width: 100, align: 'center' },
         { title: '客户信息', scopedSlots: { customRender: 'custInfo' }, width: 100, align: 'center' },
         { title: '收款金额(¥)', dataIndex: 'payedAmount', width: 80, align: 'center' },
@@ -155,7 +166,8 @@ export default {
             return res.data
           }
         })
-      }
+      },
+      dataSourceNoList: [] //  销售合作商  下拉数据
     }
   },
   methods: {
@@ -164,6 +176,16 @@ export default {
     disabledDate (date, dateStrings) {
       return date && date.valueOf() > Date.now()
     },
+    //  获取渠道商下的合作商信息
+    getSalesChannel () {
+      salesChannelList().then(res => {
+        if (res.status == 200) {
+          this.dataSourceNoList = res.data
+        } else {
+          this.dataSourceNoList = []
+        }
+      })
+    },
     //  购买套餐
     goBuy () {
       this.$router.push({ path: '/SetmealSales/BuySetmeal' })
@@ -182,9 +204,11 @@ export default {
         endDate: this.searchForm.endDate,
         bundleName: this.searchForm.bundleName,
         number: this.searchForm.number,
-        queryWord: this.searchForm.queryWord,
+        custMobile: this.searchForm.custMobile,
         orderFlag: this.searchForm.orderFlag,
-        salesChannelSettleStatus: this.searchForm.salesChannelSettleStatus
+        salesChannelSettleStatus: this.searchForm.salesChannelSettleStatus,
+        dataSourceNo: this.searchForm.dataSourceNo,
+        freeChoiceFlag: 0
       }
       params.beginDate == null ? params.beginDate = getDate.getToday().starttime : null
       params.endDate == null ? params.endDate = getDate.getToday().endtime : null
@@ -209,6 +233,11 @@ export default {
       this.detailId = String(record.id)
       this.openDetailModal = true
     },
+    //  关闭查看详情弹框
+    closeModal () {
+      this.detailId = ''
+      this.openDetailModal = false
+    },
     // 重置
     handleReset () {
       this.searchForm.beginDate = getDate.getToday().starttime
@@ -219,29 +248,44 @@ export default {
       ]
       this.searchForm.bundleName = ''
       this.searchForm.number = ''
-      this.searchForm.queryWord = ''
+      this.searchForm.custMobile = ''
       this.searchForm.orderFlag = null
       this.searchForm.salesChannelSettleStatus = null
+      this.searchForm.dataSourceNo = undefined
+      this.searchForm.freeChoiceFlag = 0
       this.$refs.table.refresh(true)
     },
+    //  刷新数据
+    refrreshDetail () {
+      this.openDetailModal = false
+      this.detailId = null
+      this.$refs.table.refresh()
+    },
     // 导出
     handleExport () {
       const params = {
-        beginDate: this.searchForm.beginDate == null ? getDate.getToday().starttime : this.searchForm.beginDate,
-        endDate: this.searchForm.endDate == null ? getDate.getToday().endtime : this.searchForm.endDate,
         bundleName: this.searchForm.bundleName,
         number: this.searchForm.number,
-        queryWord: this.searchForm.queryWord,
+        custMobile: this.searchForm.custMobile,
         orderFlag: this.searchForm.orderFlag,
-        salesChannelSettleStatus: this.searchForm.salesChannelSettleStatus
+        salesChannelSettleStatus: this.searchForm.salesChannelSettleStatus,
+        dataSourceNo: this.searchForm.dataSourceNo,
+        freeChoiceFlag: 0
+      }
+      if (this.time && this.time.length) {
+        params.beginDate = moment(this.time[0]).format('YYYY-MM-DD')
+        params.endDate = moment(this.time[1]).format('YYYY-MM-DD')
+      } else {
+        params.beginDate = ''
+        params.endDate = ''
       }
       if (!params.beginDate && !params.endDate) {
         this.$message.error('请先选择需要导出的下单时间区间再进行导出!')
         return
       }
-      // 判断两个时间段是否相差m个月
-      if (!completeDate(params.beginDate, params.endDate, 3)) {
-        this.$message.error('单次最多只能导出3个月的数据,请缩小查询区间后再进行导出!')
+      // 判断两个时间段是否相差1个月  第二个参数指相差单位,第三个参数指是否返回浮点形式(小数)
+      if (moment(params.endDate).diff(moment(params.beginDate), 'months', true) > 1) {
+        this.$message.error('单次最多只能导出1个月的数据,请缩小查询区间后再进行导出!')
         return
       }
       this.loading = true
@@ -262,6 +306,9 @@ export default {
       document.body.appendChild(link)
       link.click()
     }
+  },
+  mounted () {
+    this.getSalesChannel()
   }
 }
 </script>

+ 234 - 0
src/views/SetmealSales/SetmealAttr.vue

@@ -0,0 +1,234 @@
+<template>
+  <a-card :bordered="false" class="setmealAttr-wrap">
+    <v-select v-show="false" code="BELONG_COMPANY" ref="belongCompany" ></v-select>
+    <!-- 搜索条件 -->
+    <div class="setmealAttr-searchForm">
+      <a-form ref="searchForm" @keyup.enter.native="searchFun">
+        <a-row :gutter="48">
+          <a-col :span="6">
+            <a-form-item label="合作商" required :label-col="{ span: 7 }" :wrapper-col="{ span: 17 }">
+              <a-select
+                id="setmealAttr-partner"
+                allowClear
+                show-search
+                option-filter-prop="children"
+                placeholder="请选择合作商"
+                v-model="searchForm.salesChannelNo">
+                <a-select-option v-for="(item, index) in partnerList" :key="index" :value="item.salesChannelNo">{{ item.salesChannelName }}</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+          <a-col :span="6">
+            <a-form-item label="套餐名称" :label-col="{ span: 7 }" :wrapper-col="{ span: 17 }">
+              <a-input v-model.trim="searchForm.bundle.name" id="setmealAttr-bundleName" placeholder="请输入套餐名称" allowClear />
+            </a-form-item>
+          </a-col>
+          <a-col :span="12">
+            <a-button class="handle-btn serach-btn" id="setmealAttr-serach" type="primary" @click="searchFun">查询</a-button>
+            <a-button class="handle-btn" type="" id="setmealAttr-reset" @click="handleReset">重置</a-button>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 未选择合作商 -->
+    <div class="unChoose" v-if="!isSearch">
+      <a-icon type="exclamation-circle" theme="filled" :style="{ fontSize: '18px', color: '#ff9900', verticalAlign: 'sub', marginRight: '5px' }" />
+      <span>请先选择合作商</span>
+    </div>
+    <!-- 列表 -->
+    <a-table
+      v-if="isSearch"
+      class="table"
+      ref="table"
+      size="default"
+      :rowKey="record => record.id"
+      :columns="columns"
+      :dataSource="loadData"
+      :pagination="paginationProps"
+      bordered>
+      <!-- 所属地区 -->
+      <p slot="areas" slot-scope="text, record">
+        <span v-if="record.addrProvinceName">{{ record.addrProvinceName }}{{ record.addrCityName }}{{ record.addrDistrictName }}</span>
+        <span v-else>--</span>
+      </p>
+      <!-- 分公司名称 -->
+      <p slot="belongCompany" slot-scope="text, record">
+        <!-- <span v-if="record.belongCompany">{{ $refs.belongCompany.getNameByCode(record.belongCompany) }}</span> -->
+        <span>{{ record.belongCompany || '--' }}</span>
+      </p>
+      <!-- 操作 -->
+      <span slot="action" slot-scope="text, record"><a-button type="primary" id="setmealAttr-set" @click="setAttr(record)">设置套餐属性</a-button></span>
+    </a-table>
+    <!-- 设置套餐属性 -->
+    <attr-modal :openModal="openModal" :setmealId="setmealId" :setmealData="setmealData" @close="closeModal" />
+  </a-card>
+</template>
+
+<script>
+import { STable, VSelect } from '@/components'
+import AttrModal from './attrModal.vue'
+import { mapGetters } from 'vuex'
+import { salesChannelList } from '@/api/FinancialManagement'
+import { salesChannelGoodsList } from '@/api/SetmealSales'
+export default {
+  components: { STable, VSelect, AttrModal },
+  data () {
+    return {
+      // 查询参数
+      searchForm: {
+        bundle: { name: '' }, // 套餐名称
+        salesChannelNo: undefined //  合作商
+      },
+      partnerList: [], //  合作商  下拉数据
+      columns: [
+        { title: '序号', dataIndex: 'no', width: 60, align: 'center' },
+        { title: '合作商名称', dataIndex: 'salesChannelName', width: 100, align: 'center' },
+        { title: '套餐名称', dataIndex: 'bundle.name', width: 100, align: 'center' },
+        { title: '套餐别名', width: 100, align: 'center', customRender: (record, text) => { return record ? (record.goodsAlias ? record.goodsAlias : '--') : '--' } },
+        { title: '所属地区', scopedSlots: { customRender: 'areas' }, width: 100, align: 'center' },
+        { title: '所属项目名称', width: 100, align: 'center', customRender: (record, text) => { return record ? (record.belongProject ? record.belongProject : '--') : '--' } },
+        { title: '分公司名称', scopedSlots: { customRender: 'belongCompany' }, width: 100, align: 'center' },
+        { title: '折扣比例', width: 80, align: 'center', customRender: (record, text) => { return record ? (record.useDiscountRate ? record.useDiscountRate + '%' : '--') : '--' } },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 100, align: 'center' }
+      ],
+      loadData: [], //  表格数据
+      setmealId: '', //  套餐id
+      openModal: false, //  设置套餐属性弹框
+      pageNo: 1, //  分页页码
+      pageSize: 10, //  分页 每页多少条
+      paginationProps: {
+        showSizeChanger: true, //  是否可以改变 pageSize
+        total: 0, //  分页总条数
+        current: 1,
+        onShowSizeChange: (current, pageSize) => this.changePageSize(current, pageSize),
+        onChange: (current) => this.changePage(current)
+      },
+      setmealData: null, //  套餐属性数据
+      isSearch: false //  是否点击查询
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserInfo'])
+  },
+  methods: {
+    searchFun () {
+      this.isSearch = !!this.searchForm.salesChannelNo
+      this.pageInit(1)
+    },
+    //  页面初始化
+    pageInit (pageNo, pageSize) {
+      if (this.searchForm.salesChannelNo) {
+        this.pageNo = pageNo || this.pageNo
+        this.pageSize = pageSize || this.pageSize
+        //  请求列表数据
+        salesChannelGoodsList({
+          salesChannelNo: this.searchForm.salesChannelNo,
+          bundle: { name: this.searchForm.bundle.name },
+          pageNo: this.pageNo,
+          pageSize: this.pageSize
+        }).then(res => {
+          if (res.status == 200) {
+            const data = res.data
+            this.paginationProps.total = res.data.count || 0
+            this.paginationProps.current = this.pageNo
+            const no = (data.pageNo - 1) * data.pageSize
+            for (var i = 0; i < data.list.length; i++) {
+              data.list[i].no = no + i + 1
+            }
+            this.loadData = data.list
+          } else {
+            this.loadData = []
+          }
+        })
+      } else {
+        this.isSearch = false
+      }
+    },
+    //  分页  一页多少条change
+    changePageSize (current, pageSize) {
+      this.pageNo = current
+      this.pageSize = pageSize
+      this.pageInit()
+    },
+    //  分页 页码change
+    changePage (current) {
+      this.pageNo = current
+      this.pageInit()
+    },
+    //  设置套餐属性
+    setAttr (row) {
+      this.setmealId = row.id
+      this.setmealData = row
+      this.openModal = true
+    },
+    // 重置
+    handleReset () {
+      this.searchForm.bundle.name = ''
+      const salesChannelType = this.authUserInfo.extInfo.channel.salesChannelType
+      if (salesChannelType == 'SALLER') { //  合作商
+        this.searchForm.salesChannelNo = this.partnerList.length > 0 ? this.partnerList[0].salesChannelNo : undefined
+        this.isSearch = true
+      } else {
+        this.searchForm.salesChannelNo = undefined
+        this.isSearch = false
+      }
+      this.pageInit(1)
+    },
+    //  关闭
+    closeModal () {
+      this.openModal = false
+      this.setmealData = null
+      this.pageInit()
+    },
+    //  获取渠道商下的合作商信息
+    getSalesChannel () {
+      salesChannelList().then(res => {
+        if (res.status == 200) {
+          this.partnerList = res.data
+          const salesChannelType = this.authUserInfo.extInfo.channel.salesChannelType
+          if (salesChannelType == 'SALLER') { //  合作商
+            this.searchForm.salesChannelNo = res.data.length > 0 ? res.data[0].salesChannelNo : undefined
+            this.isSearch = true
+          }
+          this.pageInit(1)
+        } else {
+          this.partnerList = []
+          this.searchForm.salesChannelNo = undefined
+        }
+      })
+    }
+  },
+  beforeRouteEnter (to, from, next) {
+    next(vm => {
+      vm.isSearch = false
+      vm.handleReset()
+      vm.getSalesChannel()
+    })
+  }
+}
+</script>
+
+<style lang="less">
+.setmealAttr-wrap {
+  .setmealAttr-searchForm {
+    // 搜索框的下间距
+    .ant-form-item {
+      margin-bottom: 10px;
+    }
+    .handle-btn {
+      margin-top: 4px;
+    }
+    .serach-btn {
+      margin-right: 10px;
+    }
+  }
+  .table {
+    margin-top: 25px;
+  }
+  .unChoose {
+    text-align: center;
+    margin: 240px 0 300px;
+    font-size: 16px;
+  }
+}
+</style>

+ 78 - 17
src/views/SetmealSales/SetmealDetailModal.vue

@@ -43,7 +43,7 @@
       <a-row :gutter="20" v-if="detailsData">
         <a-col :span="8" class="item-cont">
           <p class="item-label">套餐价格:</p>
-          <p class="item-main">{{ detailsData.orderBundle.totalAmount ? detailsData.orderBundle.totalAmount + '元' : '--' }}</p>
+          <p class="item-main">{{ detailsData.orderBundle.totalAmount ? detailsData.orderBundle.totalAmount + '元' : 0 }}</p>
         </a-col>
         <a-col :span="8" class="item-cont">
           <p class="item-label">销售人员:</p>
@@ -51,7 +51,7 @@
         </a-col>
         <a-col :span="8" class="item-cont">
           <p class="item-label">收款金额:</p>
-          <p class="item-main">{{ detailsData.orderBundle.payedAmount ? detailsData.orderBundle.payedAmount + '元' : '--' }}</p>
+          <p class="item-main">{{ detailsData.orderBundle.payedAmount ? detailsData.orderBundle.payedAmount + '元' : 0 }}</p>
         </a-col>
       </a-row>
       <a-row :gutter="20" v-if="detailsData">
@@ -70,7 +70,19 @@
             :columns="setMealColumns"
             :dataSource="setMealData"
             :pagination="false"
-            bordered></a-table>
+            :loading="loading"
+            bordered>
+            <!-- 到期时间 -->
+            <span slot="expiryDate" slot-scope="text, record">
+              <span v-if="record.cycleFlag==0">{{ record.expiryDate }}</span>
+              <span v-else>--</span>
+            </span>
+            <!-- 操作 -->
+            <span slot="action" slot-scope="text, record">
+              <a-button v-if="record.isDelay" type="link" @click="openSetDelay(record)">延期</a-button>
+              <span v-else>--</span>
+            </span>
+          </a-table>
         </a-tab-pane>
         <a-tab-pane key="2" tab="使用记录">
           <!-- 使用记录列表 -->
@@ -89,17 +101,23 @@
           </a-table>
         </a-tab-pane>
       </a-tabs>
-      <div class="btn-cont"><a-button id="detailsSetmealModal-back" @click="isShow = false">返回列表</a-button></div>
+      <div class="btn-cont" v-if="detailsData">
+        <a-button id="detailsSetmealModal-back" @click="isShow = false">返回列表</a-button>
+        <a-button v-if="detailsData.orderBundle.orderFlag=='PAED'&&detailsData.salesChannelSettleStatus=='NOT_SETTLE'&&recordData.length==0" id="detailsSetmealModal-cancel" type="primary" @click="cancelBuy">取消购买</a-button>
+      </div>
     </a-modal>
+    <!-- 延期 -->
+    <delay-modal :openModal="setDelay" :serverData="serverData" @close="closeSetDelay" />
   </div>
 </template>
 
 <script>
 import { STable, VSelect } from '@/components'
-import { customerBundleDetail, customerBundleUseHistory } from '@/api/customerBundle.js'
+import { customerBundleDetail, customerBundleUseHistory, orderCancel } from '@/api/customerBundle.js'
+import DelayModal from './delayModal.vue'
 export default {
   name: 'SetmealDetailModal',
-  components: { STable, VSelect },
+  components: { STable, VSelect, DelayModal },
   props: {
     openModal: {
       //  弹框是否展示
@@ -117,32 +135,42 @@ export default {
       isShow: this.openModal, //  弹框是否展示
       setMealColumns: [
         { title: '序号', dataIndex: 'no', width: 60, align: 'center' },
-        { title: '内容', dataIndex: 'itemName', width: 200, align: 'center' },
-        { title: '剩余数量', dataIndex: 'remainTimes', width: 100, align: 'center' }
+        { title: '服务名称', dataIndex: 'itemName', width: 200, align: 'center' },
+        { title: '到期时间', scopedSlots: { customRender: 'expiryDate' }, width: 100, align: 'center' },
+        { title: '总次数', dataIndex: 'times', width: 100, align: 'center' },
+        { title: '剩余次数', dataIndex: 'remainTimes', width: 100, align: 'center' },
+        { title: '已用次数', dataIndex: 'usedTimes', width: 100, align: 'center' },
+        { title: '过期次数', dataIndex: 'expiryTimes', width: 100, align: 'center' },
+        { title: '退款次数', dataIndex: 'refundTimes', width: 100, align: 'center' },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 100, align: 'center' }
       ],
       recordColumns: [
         { title: '序号', dataIndex: 'no', width: 60, align: 'center' },
         { title: '使用时间', dataIndex: 'usedTime', width: 100, align: 'center' },
-        { title: '服务内容', dataIndex: 'bundItemName', width: 100, align: 'center' },
+        { title: '服务内容', dataIndex: 'itemName', width: 100, align: 'center' },
         { title: '服务门店', scopedSlots: { customRender: 'usedStoreName' }, width: 100, align: 'center' },
         { title: '核销单号', dataIndex: 'bizNum', width: 100, align: 'center' }
       ],
       setMealData: [], //  套餐内容
       recordData: [], //  使用记录
-      detailsData: null //  套餐数据
+      detailsData: null, //  套餐数据
+      setDelay: false, //  延期设置
+      serverData: null, //  套餐包含服务 数据
+      loading: false
     }
   },
   methods: {
     // 套餐详情
-    getSetmealInfo (id) {
+    getSetmealInfo () {
+      this.loading = true
       //  套餐详情
-      customerBundleDetail({ id: id }).then(res => {
-        console.log(res)
+      customerBundleDetail({ id: this.setmealId }).then(res => {
         if (res.status == 200) {
           this.detailsData = res.data
           if (res.data && res.data.customerBundleItemList && res.data.customerBundleItemList.length > 0) {
             res.data.customerBundleItemList.map((item, index) => {
               item.no = index + 1
+              item.isDelay = (item.expiryDate ? item.expiryDate.substr(0, 10) != '2099-01-01' : false) && (item.cycleFlag == 0)
             })
             this.setMealData = res.data.customerBundleItemList
           } else {
@@ -152,10 +180,10 @@ export default {
           this.detailsData = null
           this.setMealData = []
         }
+        this.loading = false
       })
       //  使用记录
-      customerBundleUseHistory({ id: id }).then(res => {
-        console.log(res)
+      customerBundleUseHistory({ id: this.setmealId }).then(res => {
         if (res.status == 200) {
           if (res.data && res.data.length > 0) {
             res.data.map((item, index) => {
@@ -169,6 +197,33 @@ export default {
           this.recordData = []
         }
       })
+    },
+    //  取消购买
+    cancelBuy () {
+      const _this = this
+      this.$confirm({
+        title: '取消购买',
+        content: '取消购买后,套餐内所有服务的剩余次数变为0,用户无法再使用套餐。确认取消购买吗?',
+        onOk: () => {
+          orderCancel({ id: _this.setmealId }).then(res => {
+            if (res.status == 200) {
+              _this.$emit('refrresh')
+            }
+          })
+        },
+        onCancel () {}
+      })
+    },
+    //  延期
+    openSetDelay (row) {
+      this.serverData = row
+      this.setDelay = true
+    },
+    //  关闭延期
+    closeSetDelay () {
+      this.getSetmealInfo()
+      this.serverData = null
+      this.setDelay = false
     }
   },
   watch: {
@@ -180,11 +235,14 @@ export default {
     isShow (val) {
       if (!val) {
         this.$emit('close')
+        this.setMealData = []
+        this.recordData = []
+        this.detailsData = null
       }
     },
     setmealId (newValue, oldValue) {
       if (newValue && this.isShow) {
-        this.getSetmealInfo(newValue)
+        this.getSetmealInfo()
       }
     }
   }
@@ -242,7 +300,10 @@ export default {
 	}
 	.btn-cont {
 		text-align: center;
-		margin: 35px 0 10px;
+		margin: 50px 0 10px;
+    button{
+      margin: 0 20px;
+    }
 	}
 }
 </style>

+ 5 - 0
src/views/SetmealSales/SetmealItemDetailModal.vue

@@ -19,6 +19,7 @@
           :columns="columns_item"
           :dataSource="bundleItemList"
           :pagination="false"
+          :loading="loading"
           bordered>
           <!-- 服务价格 -->
           <template slot="itemPrice" slot-scope="text, record">{{ record.itemPrice ? record.itemPrice : 0 }}元</template>
@@ -55,6 +56,7 @@ export default {
   },
   data () {
     return {
+      loading: false, //  加载中状态
       isShow: this.openModal, //  弹框是否展示
       columns_item: [
         { title: '服务名称', dataIndex: 'itemName', width: 120, align: 'center' },
@@ -69,6 +71,7 @@ export default {
   methods: {
     //  套餐信息
     getSetmealInfo (id) {
+      this.loading = true
       getBundleDetails({ id: id }).then(res => {
         console.log(res)
         if (res.status == 200) {
@@ -76,6 +79,7 @@ export default {
         } else {
           this.bundleItemList = []
         }
+        this.loading = false
       })
     }
   },
@@ -88,6 +92,7 @@ export default {
     isShow (val) {
       if (!val) {
         this.$emit('close')
+        this.bundleItemList = []
       }
     },
     setmealId (newValue, oldValue) {

+ 43 - 5
src/views/SetmealSales/SetmealPayMoney.vue

@@ -11,16 +11,28 @@
     v-model="isShow">
     <!-- 表单 -->
     <a-form-model ref="ruleForm" :model="form" :rules="rules" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
+      <!-- 手机号 -->
       <a-form-model-item label="手机号" prop="custMobile">
-        <a-input v-model.trim="form.custMobile" @input="mobileInput" :maxLength="11" placeholder="请输入手机号" />
+        <a-input id="setmealPayMoney-custMobile" v-model.trim="form.custMobile" @input="mobileInput" :maxLength="11" placeholder="请输入手机号" />
       </a-form-model-item>
-      <a-form-model-item label="客户姓名" prop="custName"><a-input v-model.trim="form.custName" :maxLength="30" placeholder="请输入客户姓名(最多30个字符)" /></a-form-model-item>
+      <!-- 销售合作商 -->
+      <a-form-model-item label="销售合作商" prop="dataSourceNo">
+        <a-select id="setmealPayMoney-dataSourceNo" v-model="form.dataSourceNo" placeholder="请选择该套餐是由哪个合作商售出">
+          <a-select-option v-for="(item, index) in partnerList" :key="index" :value="item.salesChannelNo">{{ item.salesChannelName }}</a-select-option>
+        </a-select>
+      </a-form-model-item>
+      <!-- 客户姓名 -->
+      <a-form-model-item label="客户姓名" prop="custName">
+        <a-input id="setmealPayMoney-custName" v-model.trim="form.custName" :maxLength="30" placeholder="请输入客户姓名(最多30个字符)" />
+      </a-form-model-item>
+      <!-- 应收金额 -->
       <a-form-model-item label="应收金额" class="item-con">
         <p class="item-main">
           <span class="item-price" v-if="setmealData">{{ setmealData.price || 0 }}</span>
         </p>
       </a-form-model-item>
+      <!-- 收款方式 -->
       <a-form-model-item label="收款方式" class="item-con"><p class="item-main">现金</p></a-form-model-item>
       <a-form-model-item label="" class="btn-cont" :label-col="{ span: 0 }" :wrapper-col="{ span: 24 }">
         <a-button type="primary" id="setmealPayMoney-submit" @click="onSubmit">确认收款</a-button>
@@ -33,7 +45,9 @@
 
 <script>
 import { isMobile } from '@/libs/tools'
+import { mapGetters } from 'vuex'
 import { bundleFindByMobile, bundleBuy } from '@/api/customerBundle.js'
+import { salesChannelByBundleList } from '@/api/FinancialManagement'
 export default {
   name: 'SetmealPayMoney',
   props: {
@@ -68,14 +82,20 @@ export default {
       form: {
         custMobile: '',
         custName: '',
-        custId: null
+        custId: null,
+        dataSourceNo: undefined //  销售合作商
       },
       rules: {
-        custMobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }, { validator: isMobileValid, trigger: 'blur' }]
+        custMobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }, { validator: isMobileValid, trigger: 'blur' }],
+        dataSourceNo: [{ required: true, message: '请选择销售合作商', trigger: 'change' }]
       },
-      setmealData: null //  套餐数据
+      setmealData: null, //  套餐数据
+      partnerList: [] //  合作商  下拉数据
     }
   },
+  computed: {
+    ...mapGetters(['authUserInfo'])
+  },
   methods: {
     //  手机号输入监听
     mobileInput () {
@@ -108,6 +128,7 @@ export default {
             custId: this.form.custId,
             custName: this.form.custName,
             custMobile: this.form.custMobile,
+            dataSourceNo: this.form.dataSourceNo,
             totalAmount: this.setmealData.price,
             paymentDetail: { payType: 10001 }
           }
@@ -136,6 +157,22 @@ export default {
       this.form.custMobile = ''
       this.form.custName = ''
       this.form.custId = null
+      this.form.dataSourceNo = undefined
+    },
+    //  获取渠道商下的合作商信息
+    getSalesChannel () {
+      salesChannelByBundleList({ id: this.setmealData.id }).then(res => {
+        if (res.status == 200) {
+          this.partnerList = res.data
+          const salesChannelType = this.authUserInfo.extInfo.channel.salesChannelType
+          if (salesChannelType == 'SALLER') { //  合作商
+            this.form.dataSourceNo = res.data.length > 0 ? res.data[0].salesChannelNo : undefined
+          }
+        } else {
+          this.partnerList = []
+          this.form.dataSourceNo = undefined
+        }
+      })
     }
   },
   watch: {
@@ -154,6 +191,7 @@ export default {
     setmealInfo (newValue, oldValue) {
       if (newValue && this.isShow) {
         this.setmealData = newValue
+        this.getSalesChannel()
       } else {
         this.setmealData = null
       }

+ 132 - 109
src/views/SetmealSales/VerificationRecords.vue

@@ -5,38 +5,45 @@
       <a-form ref="searchForm" @keyup.enter.native="handleSearch">
         <a-row :gutter="48">
           <a-col :span="6">
-            <a-form-item label="核销时间" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
+            <a-form-item label="核销时间" :label-col="{ span: 7 }" :wrapper-col="{ span: 17 }">
               <a-range-picker
                 v-model="time"
                 id="VerificationRecords-time"
                 :format="dateFormat"
-                :placeholder="['开始时间','结束时间']"
+                :placeholder="['开始时间', '结束时间']"
                 :disabledDate="disabledDate"
-                @change="onChange" />
+                @change="onChange"
+              />
             </a-form-item>
           </a-col>
           <a-col :span="6">
-            <a-form-item label="核销门店" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
-              <a-select placeholder="请选择" allowClear v-model="searchForm.usedStoreId" id="VerificationRecords-usedStoreId">
+            <a-form-item label="核销门店" :label-col="{ span: 7 }" :wrapper-col="{ span: 17 }">
+              <a-select
+                placeholder="请选择"
+                showSearch
+                allowClear
+                :filter-option="filterOption"
+                v-model="searchForm.usedStoreId"
+                id="VerificationRecords-usedStoreId">
                 <a-select-option v-for="item in storeOptionData" :key="item.id" :value="item.id">{{ item.name }}</a-select-option>
               </a-select>
             </a-form-item>
           </a-col>
           <a-col :span="6">
-            <a-form-item label="客户信息" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
-              <a-input v-model.trim="searchForm.queryWord" placeholder="请输入手机号" allowClear id="VerificationRecords-queryWord"/>
+            <a-form-item label="客户信息" :label-col="{ span: 7 }" :wrapper-col="{ span: 17 }">
+              <a-input v-model.trim="searchForm.queryWord" placeholder="请输入手机号" allowClear id="VerificationRecords-queryWord" />
             </a-form-item>
           </a-col>
           <a-col :span="6">
-            <a-form-item label="套餐名称" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
-              <a-input v-model.trim="searchForm.bundName" placeholder="请输入" allowClear id="VerificationRecords-bundName"/>
+            <a-form-item label="套餐名称" :label-col="{ span: 7 }" :wrapper-col="{ span: 17 }">
+              <a-input v-model.trim="searchForm.bundName" placeholder="请输入" allowClear id="VerificationRecords-bundName" />
             </a-form-item>
           </a-col>
         </a-row>
         <a-row :gutter="48">
           <a-col :span="6">
-            <a-form-item label="关联订单号" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
-              <a-input v-model.trim="searchForm.orderNo" placeholder="请输入" allowClear id="VerificationRecords-orderNo"/>
+            <a-form-item label="关联订单号" :label-col="{ span: 7 }" :wrapper-col="{ span: 17 }">
+              <a-input v-model.trim="searchForm.orderNo" placeholder="请输入" allowClear id="VerificationRecords-orderNo" />
             </a-form-item>
           </a-col>
           <a-col :span="18">
@@ -49,13 +56,19 @@
     </div>
     <!-- 合计 -->
     <a-alert type="info" showIcon style="margin-bottom:15px">
-      <div class="ftext" slot="message">总计:<span>{{ orderTotal || 0 }}</span>单,结算金额:<span>¥{{ paymentAmountTotal || 0 }}</span>元</div>
+      <div class="ftext" slot="message">
+        总计:
+        <span>{{ orderTotal || 0 }}</span>
+        单,结算金额:
+        <span>¥{{ paymentAmountTotal || 0 }}</span>
+        元
+      </div>
     </a-alert>
     <!-- 列表 -->
     <s-table
       ref="table"
       size="default"
-      :rowKey="(record) => record.id"
+      :rowKey="record => record.id"
       :columns="columns"
       :data="loadData"
       bordered>
@@ -71,21 +84,15 @@
           <span v-if="record.custMobile">{{ record.custMobile }}</span>
           <span v-if="record.vehicleNum">{{ record.vehicleNum }}</span>
         </div>
-        <span v-if="!record.custMobile && !record.vehicleNum">--</span>
+        <span v-if="!(record.custMobile && record.vehicleNum)">--</span>
       </template>
     </s-table>
   </a-card>
 </template>
 <script>
-import {
-  STable,
-  VSelect
-} from '@/components'
+import { STable, VSelect } from '@/components'
 import getDate from '@/libs/getDate.js'
-import { completeDate } from '@/libs/tools.js'
-import {
-  getVerificationRecordsList, getVerificationRecordsListTotal, settlementRecordsExport, getStoreList
-} from '@/api/SetmealSales.js'
+import { getVerificationRecordsList, getVerificationRecordsListTotal, settlementRecordsExport, getStoreList } from '@/api/SetmealSales.js'
 import moment from 'moment'
 export default {
   name: 'OrderCenter',
@@ -109,63 +116,69 @@ export default {
       paymentAmountTotal: '', // 合计实收金额
       storeOptionData: [], // 门店数据
       // 将默认当天时间日期回显在时间选择框中
-      time: [
-        moment(getDate.getToday().starttime, this.dateFormat),
-        moment(getDate.getToday().endtime, this.dateFormat)
-      ],
+      time: [moment(getDate.getToday().starttime, this.dateFormat), moment(getDate.getToday().endtime, this.dateFormat)],
       dateFormat: 'YYYY-MM-DD',
-      nowBeginDate: '',
-      columns: [{
-        title: '序号',
-        dataIndex: 'no',
-        width: 60,
-        align: 'center'
-      },
-      {
-        title: '核销时间',
-        dataIndex: 'usedTime',
-        width: 100,
-        align: 'center'
-      },
-      {
-        title: '核销单号/关联订单号',
-        scopedSlots: { customRender: 'num' },
-        width: 150,
-        align: 'center'
-      },
-      {
-        title: '核销服务名称',
-        dataIndex: 'bundItemName',
-        width: 150,
-        align: 'center'
-      },
-      {
-        title: '客户信息',
-        scopedSlots: { customRender: 'userInfo' },
-        width: 150,
-        align: 'center'
-      },
-      {
-        title: '套餐名称',
-        dataIndex: 'bundName',
-        width: 150,
-        align: 'center'
-      },
-      {
-        title: '结算金额(¥)',
-        dataIndex: 'salesChannelSettleAmount',
-        width: 100,
-        align: 'center',
-        customRender: function (text) {
-		  return (text || 0) + '元'
+      columns: [
+        {
+          title: '序号',
+          dataIndex: 'no',
+          width: 60,
+          align: 'center'
+        },
+        {
+          title: '核销时间',
+          dataIndex: 'usedTime',
+          width: 100,
+          align: 'center'
+        },
+        {
+          title: '核销单号/关联订单号',
+          scopedSlots: { customRender: 'num' },
+          width: 150,
+          align: 'center'
+        },
+        {
+          title: '销售合作商',
+          dataIndex: 'salesChannelName',
+          width: 150,
+          align: 'center'
+        },
+        {
+          title: '核销服务名称',
+          dataIndex: 'itemName',
+          width: 150,
+          align: 'center'
+        },
+        {
+          title: '客户信息',
+          scopedSlots: { customRender: 'userInfo' },
+          width: 150,
+          align: 'center'
+        },
+        {
+          title: '套餐名称',
+          dataIndex: 'bundName',
+          width: 150,
+          align: 'center',
+          customRender: function (text) {
+            return text || '--'
+          }
+        },
+        {
+          title: '结算金额(¥)',
+          dataIndex: 'salesChannelSettleAmount',
+          width: 100,
+          align: 'center',
+          customRender: function (text) {
+            return (text || 0) + '元'
+          }
         }
-      }
       ],
       // 加载数据方法 必须为 Promise 对象
       loadData: parameter => {
-		  const _this = this
-        _this.searchForm.beginDate == null ? this.searchForm.beginDate = getDate.getToday().starttime : null
-        _this.searchForm.endDate == null ? this.searchForm.endDate = getDate.getToday().endtime : null
+        const _this = this
+        _this.searchForm.beginDate == null ? (this.searchForm.beginDate = getDate.getToday().starttime) : null
+        _this.searchForm.endDate == null ? (this.searchForm.endDate = getDate.getToday().endtime) : null
         return getVerificationRecordsList(Object.assign(parameter, _this.searchForm)).then(res => {
           if (res.status == 200) {
             _this.orderTotal = res.data.count
@@ -182,6 +195,11 @@ export default {
   },
   methods: {
     moment,
+    filterOption (input, option) {
+      return (
+        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      )
+    },
     // 不可选日期
     disabledDate (date, dateStrings) {
       return date && date.valueOf() > Date.now()
@@ -214,8 +232,8 @@ export default {
         queryWord: this.searchForm.queryWord,
         bundName: this.searchForm.bundName
       }
-      params.beginDate == null ? params.beginDate = getDate.getToday().starttime : null
-      params.endDate == null ? params.endDate = getDate.getToday().endtime : null
+      params.beginDate == null ? (params.beginDate = getDate.getToday().starttime) : null
+      params.endDate == null ? (params.endDate = getDate.getToday().endtime) : null
       getVerificationRecordsListTotal(params).then(res => {
         console.log(res, '--------')
         if (res.status == 200) {
@@ -230,44 +248,50 @@ export default {
     },
     // 重置
     handleRest () {
-      this.nowBeginDate = getDate.getToday().starttime
       this.searchForm.beginDate = getDate.getToday().starttime
       this.searchForm.endDate = getDate.getToday().endtime
-      this.time = [
-        moment(getDate.getToday().starttime, this.dateFormat),
-        moment(getDate.getToday().endtime, this.dateFormat)
-      ]
+      this.time = [moment(getDate.getToday().starttime, this.dateFormat), moment(getDate.getToday().endtime, this.dateFormat)]
       this.searchForm.usedStoreId = undefined
       this.searchForm.orderNo = ''
-      this.$refs.table.refresh()
+      this.searchForm.queryWord = ''
+      this.searchForm.bundName = ''
+      this.$refs.table.refresh(true)
       this.getTotal()
     },
     // 导出
     handleExport () {
       const params = {
-        beginDate: this.searchForm.beginDate == null ? getDate.getToday().starttime : this.searchForm.beginDate,
-        endDate: this.searchForm.endDate == null ? getDate.getToday().endtime : this.searchForm.endDate,
         usedStoreId: this.searchForm.usedStoreId,
         orderNo: this.searchForm.orderNo,
         queryWord: this.searchForm.queryWord,
         bundName: this.searchForm.bundName
       }
-	  if (!params.beginDate && !params.endDate) {
-		 this.$message.error('请先选择需要导出的核销时间段再进行导出!')
-		  return
-	  }
-      if (!completeDate(params.beginDate, params.endDate, 3)) {
-        this.$message.error('单次最多只能导出3个月的数据,请缩小查询区间后再进行导出!')
+      if (this.time && this.time.length) {
+        params.beginDate = moment(this.time[0]).format('YYYY-MM-DD')
+        params.endDate = moment(this.time[1]).format('YYYY-MM-DD')
+      } else {
+        params.beginDate = ''
+        params.endDate = ''
+      }
+      if (!params.beginDate && !params.endDate) {
+        this.$message.error('请先选择需要导出的核销时间段再进行导出!')
+        return
+      }
+      // 判断两个时间段是否相差1个月  第二个参数指相差单位,第三个参数指是否返回浮点形式(小数)
+      if (moment(params.endDate).diff(moment(params.beginDate), 'months', true) > 1) {
+        this.$message.error('单次最多只能导出1个月的数据,请缩小查询区间后再进行导出!')
         return
       }
-	  this.loading = true
+      this.loading = true
       settlementRecordsExport(params).then(res => {
         this.loading = false
         this.download(res)
       })
     },
     download (data) {
-      if (!data) { return }
+      if (!data) {
+        return
+      }
       const url = window.URL.createObjectURL(new Blob([data]))
       const link = document.createElement('a')
       link.style.display = 'none'
@@ -289,22 +313,21 @@ export default {
 }
 </script>
 <style lang="less">
-	.orderCenter-searchForm {
-
-		// 搜索框的下间距
-		.ant-form-item {
-			margin-bottom: 10px;
-		}
-	}
-  .export-btn{
-    background-color: #ff9900;
-    border-color: #ff9900;
-    color: #fff;
-    margin-left: 10px;
+.orderCenter-searchForm {
+  // 搜索框的下间距
+  .ant-form-item {
+    margin-bottom: 10px;
   }
-	// 合计
-	.ftext span {
-		color: #fa8c16;
-		font-weight: bold;
-	}
+}
+.export-btn {
+  background-color: #ff9900;
+  border-color: #ff9900;
+  color: #fff;
+  margin-left: 10px;
+}
+// 合计
+.ftext span {
+  color: #fa8c16;
+  font-weight: bold;
+}
 </style>

+ 209 - 0
src/views/SetmealSales/attrModal.vue

@@ -0,0 +1,209 @@
+<template>
+  <a-modal
+    class="attrModal"
+    title="设置属性"
+    width="60%"
+    centered
+    :footer="null"
+    :maskClosable="false"
+    :destroyOnClose="true"
+    @cancel="isShow = false"
+    v-model="isShow">
+    <!-- 表单 -->
+    <a-form-model
+      ref="ruleForm"
+      :model="form"
+      :rules="rules"
+      :label-col="{ span: 6 }"
+      :wrapper-col="{ span: 18 }"
+      v-if="setmealData">
+      <!-- 合作商名称 -->
+      <a-form-model-item label="合作商名称" class="item-con"><p class="item-main">{{ setmealData.salesChannelName }}</p></a-form-model-item>
+      <!-- 套餐名称 -->
+      <a-form-model-item label="套餐名称" class="item-con"><p class="item-main">{{ setmealData.bundle.name || '--' }}</p></a-form-model-item>
+      <!-- 套餐别名 -->
+      <a-form-model-item label="套餐别名" class="item-con">
+        <a-input id="attr-goodsAlias" v-model.trim="form.goodsAlias" :maxLength="30" placeholder="请输入套餐别名" />
+      </a-form-model-item>
+      <!-- 所属地区 -->
+      <a-form-model-item label="所属地区" class="item-con" v-if="propertiesConfig.indexOf('BELONG_AREA')!=-1">
+        <a-cascader id="attr-areas" v-model="areas" :options="options" placeholder="请选择省市区" />
+      </a-form-model-item>
+      <!-- 所属项目名称 -->
+      <a-form-model-item label="所属项目名称" class="item-con" prop="belongProject" v-if="propertiesConfig.indexOf('BELONG_PROJECT')!=-1">
+        <a-input id="attr-belongProject" v-model.trim="form.belongProject" :maxLength="30" placeholder="请输入所属项目名称" />
+      </a-form-model-item>
+      <!-- 分公司名称 -->
+      <a-form-model-item label="分公司名称" class="item-con" prop="belongCompany" v-if="propertiesConfig.indexOf('BELONG_COMPANY')!=-1">
+        <!-- <v-select
+          code="BELONG_COMPANY"
+          ref="belongCompany"
+          v-model="form.belongCompany"
+          id="attr-belongCompany"
+          allowClear
+          placeholder="请选择分公司名称" ></v-select> -->
+        <a-input id="attr-belongCompany" v-model.trim="form.belongCompany" :maxLength="300" placeholder="请输入分公司名称" />
+      </a-form-model-item>
+      <!-- 折扣比例 -->
+      <a-form-model-item label="折扣比例" class="item-con" prop="useDiscountRate" v-if="propertiesConfig.indexOf('USE_DISCOUNT_RATE')!=-1">
+        <a-input-number
+          id="attr-useDiscountRate"
+          v-model="form.useDiscountRate"
+          :min="0"
+          :max="100"
+          :precision="2"
+          placeholder="请输入折扣比例"
+          style="width: 80%;margin-right: 10px;" />%
+      </a-form-model-item>
+      <a-form-model-item label="" class="btn-cont" :label-col="{ span: 0 }" :wrapper-col="{ span: 24 }">
+        <a-button id="attr-cancel" class="attr-cancel" @click="cancel">取消</a-button>
+        <a-button type="primary" id="attr-submit" @click="onSubmit">提交</a-button>
+      </a-form-model-item>
+    </a-form-model>
+  </a-modal>
+</template>
+
+<script>
+import { VSelect } from '@/components'
+import addrData, { province, city, area } from '@/api/address'
+import { salesChannelGoodsConfig } from '@/api/SetmealSales'
+import _ from 'lodash'
+export default {
+  name: 'AttrModal',
+  components: { VSelect },
+  props: {
+    openModal: {
+      //  弹框是否展示
+      type: Boolean,
+      default: false
+    },
+    setmealId: {
+      //  套餐id
+      type: [String, Number],
+      default: ''
+    },
+    setmealData: { //  套餐数据
+      type: Object,
+      default: () => { return {} }
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  弹框是否展示
+      form: {
+        goodsAlias: '', //  套餐别名
+        addrProvince: undefined, //  省
+        addrProvinceName: '',
+        addrCity: undefined, // 市
+        addrCityName: '',
+        addrDistrict: undefined, // 区
+        addrDistrictName: '',
+        belongProject: '', //  所属项目名称
+        belongCompany: undefined, //  分公司名称
+        useDiscountRate: '' //  折扣比例
+      },
+      rules: {},
+      options: addrData,
+      areas: [],
+      propertiesConfig: [] //  套餐属性
+    }
+  },
+  methods: {
+    //  取消
+    cancel () {
+      this.resetForm() //  重置表单数据
+      this.isShow = false
+    },
+    // 重置表单
+    resetForm () {
+      this.form.goodsAlias = ''
+      this.form.addrProvince = undefined
+      this.form.addrProvinceName = ''
+      this.form.addrCity = undefined
+      this.form.addrCityName = ''
+      this.form.addrDistrict = undefined
+      this.form.addrDistrictName = ''
+      this.areas = []
+      this.form.belongProject = ''
+      this.form.belongCompany = undefined
+      this.form.useDiscountRate = ''
+    },
+    //  提交
+    onSubmit () {
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          if (this.areas.length) {
+            this.form.addrProvince = this.areas[0]
+            this.form.addrProvinceName = _.find(province, ['code', this.areas[0]]).name
+            this.form.addrCity = this.areas[1]
+            this.form.addrCityName = _.find(city, ['code', this.areas[1]]).name
+            this.form.addrDistrict = this.areas[2]
+            this.form.addrDistrictName = _.find(area, ['code', this.areas[2]]).name
+          }
+          const params = {
+            id: this.setmealId,
+            goodsAlias: this.form.goodsAlias,
+            addrProvince: this.form.addrProvince,
+            addrProvinceName: this.form.addrProvinceName,
+            addrCity: this.form.addrCity,
+            addrCityName: this.form.addrCityName,
+            addrDistrict: this.form.addrDistrict,
+            addrDistrictName: this.form.addrDistrictName,
+            belongProject: this.form.belongProject,
+            belongCompany: this.form.belongCompany,
+            useDiscountRate: this.form.useDiscountRate
+          }
+          salesChannelGoodsConfig(params).then(res => {
+            if (res.status == 200) {
+              this.cancel()
+            }
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (val) {
+      if (!val) {
+        this.$emit('close')
+      } else {
+        this.resetForm() //  重置表单数据
+      }
+    },
+    setmealData: {
+      handler: function (obj) {
+        if (obj) {
+          this.propertiesConfig = obj.salesChannel.propertiesConfig ? obj.salesChannel.propertiesConfig.split(',') : []
+          this.form.goodsAlias = obj.goodsAlias
+          //  省市区
+          this.areas = obj.addrProvince ? [obj.addrProvince + '', obj.addrCity + '', obj.addrDistrict + ''] : []
+          this.form.belongProject = obj.belongProject || ''
+          this.form.belongCompany = obj.belongCompany || undefined
+          this.form.useDiscountRate = obj.useDiscountRate || ''
+        }
+      },
+      deep: true
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .attrModal{
+    .btn-cont {
+    	text-align: center;
+    	margin: 50px 0 10px;
+      button{
+        margin: 0 20px;
+      }
+    }
+  }
+</style>

+ 157 - 0
src/views/SetmealSales/delayModal.vue

@@ -0,0 +1,157 @@
+<template>
+  <a-modal
+    class="delayModal"
+    title="套餐服务延期"
+    width="60%"
+    centered
+    :footer="null"
+    :maskClosable="false"
+    :destroyOnClose="true"
+    @cancel="isShow = false"
+    v-model="isShow">
+    <!-- 表单 -->
+    <a-form-model
+      ref="ruleForm"
+      :model="form"
+      :rules="rules"
+      :label-col="{ span: 6 }"
+      :wrapper-col="{ span: 18 }"
+      v-if="serverData">
+      <!-- 服务名称 -->
+      <a-form-model-item label="服务名称" class="item-con"><p class="item-main">{{ serverData.itemName }}</p></a-form-model-item>
+      <!-- 到期时间 -->
+      <a-form-model-item label="到期时间" class="item-con"><p class="item-main">{{ serverData.expiryDate }}</p></a-form-model-item>
+      <!-- 剩余次数 -->
+      <a-form-model-item label="剩余次数" class="item-con"><p class="item-main">{{ serverData.remainTimes }}次</p></a-form-model-item>
+      <!-- 过期次数 -->
+      <a-form-model-item label="过期次数" class="item-con"><p class="item-main">{{ serverData.expiryTimes }}次</p></a-form-model-item>
+      <!-- 新的到期时间 -->
+      <a-form-model-item label="新的到期时间" prop="expiryDate">
+        <a-date-picker
+          type="date"
+          v-model="form.expiryDate"
+          id="delay-expiryDate"
+          placeholder="请选择到期时间,超过该时间,用户将无法再使用套餐"
+          :disabled-date="disabledDate"
+          style="width: 80%;" />
+      </a-form-model-item>
+      <!-- 返还次数 -->
+      <a-form-model-item label="返还次数" prop="returnTimes">
+        <a-input-number
+          id="delay-returnTimes"
+          v-model="form.returnTimes"
+          :precision="0"
+          :min="0"
+          :max="serverData.expiryTimes"
+          :disabled="serverData.expiryTimes==0"
+          placeholder="请输入返还次数"
+          style="width: 80%;margin-right: 10px;" />次
+      </a-form-model-item>
+      <a-form-model-item label="" class="btn-cont" :label-col="{ span: 0 }" :wrapper-col="{ span: 24 }">
+        <a-button id="delay-cancel" class="delay-cancel" @click="cancel">取消</a-button>
+        <a-button type="primary" id="delay-submit" @click="onSubmit">提交</a-button>
+      </a-form-model-item>
+    </a-form-model>
+  </a-modal>
+</template>
+
+<script>
+import moment from 'moment'
+import { customerBundleItemDelay } from '@/api/customerBundle.js'
+export default {
+  name: 'DelayModal',
+  props: {
+    openModal: {
+      //  弹框是否展示
+      type: Boolean,
+      default: false
+    },
+    serverData: {
+      //  服务数据
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  弹框是否展示
+      form: {
+        expiryDate: null, //  新的到期时间
+        returnTimes: null //  返还次数
+      },
+      rules: {
+        expiryDate: [{ required: true, message: '请选择新的到期时间', trigger: 'change' }]
+      }
+    }
+  },
+  methods: {
+    disabledDate (current) {
+      //  到期时间范围为:当前日期 <= date < 2038-01-01
+      const minDate = current.valueOf() < moment().subtract(1, 'days').valueOf() //  包含当天
+      const maxDate = current.valueOf() > moment('2038-01-01').valueOf()
+      return minDate || maxDate
+    },
+    //  取消
+    cancel () {
+      this.resetForm() //  重置表单数据
+      this.isShow = false
+    },
+    // 重置表单
+    resetForm () {
+      this.form.returnTimes = null
+      this.form.expiryDate = null
+    },
+    //  提交
+    onSubmit () {
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          const params = {
+            id: this.serverData.id,
+            returnTimes: this.form.returnTimes || 0,
+            expiryDate: moment(this.form.expiryDate).format('YYYY-MM-DD')
+          }
+          customerBundleItemDelay(params).then(res => {
+            if (res.status == 200) {
+              this.cancel()
+            }
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (val) {
+      if (!val) {
+        this.$emit('close')
+      } else {
+        this.resetForm() //  重置表单数据
+      }
+    },
+    serverData (val) {
+
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .delayModal{
+    .btn-cont {
+    	text-align: center;
+    	margin: 50px 0 10px;
+      button{
+        margin: 0 20px;
+      }
+    }
+  }
+</style>

+ 1 - 1
src/views/power/role/menuModal.vue

@@ -93,7 +93,7 @@ export default {
                 _this.cancel()
               }, 300)
             } else {
-              this.$message.error(res.message)
+              // this.$message.error(res.message)
             }
           })
         }

+ 1 - 1
src/views/power/role/roleModal.vue

@@ -109,7 +109,7 @@ export default {
                 _this.cancel()
               }, 300)
             } else {
-              this.$message.error(res.message)
+              // this.$message.error(res.message)
             }
           })
         }

+ 0 - 2
src/views/power/user/userModal.vue

@@ -175,8 +175,6 @@ export default {
               setTimeout(function () {
                 _this.cancel()
               }, 300)
-            } else {
-              this.$message.error(res.message)
             }
           })
         }

+ 6 - 0
src/views/user/Login.vue

@@ -121,6 +121,7 @@ import TwoStepCaptcha from '@/components/tools/TwoStepCaptcha'
 import { mapActions } from 'vuex'
 import { timeFix } from '@/utils/util'
 import { getSmsCaptcha, get2step } from '@/api/login'
+import { updateTheme } from '@/components/SettingDrawer/settingConfig'
 
 export default {
   components: {
@@ -164,6 +165,11 @@ export default {
       this.password = rem.password
       this.rememberMe = rem.rememberMe
     }
+    //  设置主题色
+    if (process.env.VUE_APP_THEME_COLOR) {
+      this.$store.dispatch('ToggleColor', process.env.VUE_APP_THEME_COLOR)
+      updateTheme(process.env.VUE_APP_THEME_COLOR)
+    }
   },
   methods: {
     ...mapActions(['Login', 'Logout']),

+ 3 - 2
vue.config.js

@@ -108,8 +108,9 @@ const vueConfig = {
     // If you want to turn on the proxy, please remove the mockjs /src/main.jsL11
     proxy: {
       '/api': {
-        target: 'https://channel.test.zyucgj.com/zyyc-channel/',
-        // target: 'http://192.168.16.104:8081/zyyc-channel/',
+        // target: 'https://channel.test.zyucgj.com/zyyc-channel/',
+        // target: 'http://192.168.16.103:7103/zyyc-channel/',
+        target: 'https://channel.qiubcar.com/zyyc-channel/',
         ws: false,
         changeOrigin: true,
         pathRewrite: {