Bladeren bron

套餐销售 - 购买套餐

chenrui 4 jaren geleden
bovenliggende
commit
0dac1fe1d8

+ 18 - 0
src/components/global.less

@@ -501,3 +501,21 @@ body {
     }
   }
 }
+
+/* 表格操作按钮样式 */
+  td .actionBtn {
+    font-size: 20px;
+    padding: 0 10px;
+  }
+  td .icon-blues {
+  	color: #1890FF;
+  }
+  td .icon-green {
+  	color: #16b50e;
+  }
+  td .icon-red {
+  	color: red;
+  }
+  td .icon-orange {
+  	color: #ffaa00;
+  }

+ 118 - 112
src/libs/tools.js

@@ -1,9 +1,9 @@
 export const forEach = (arr, fn) => {
   if (!arr.length || !fn) return
   let i = -1
-  let len = arr.length
+  const len = arr.length
   while (++i < len) {
-    let item = arr[i]
+    const item = arr[i]
     fn(item, i, arr)
   }
 }
@@ -14,9 +14,9 @@ export const forEach = (arr, fn) => {
  * @description 得到两个数组的交集, 两个数组的元素为数值或字符串
  */
 export const getIntersection = (arr1, arr2) => {
-  let len = Math.min(arr1.length, arr2.length)
+  const len = Math.min(arr1.length, arr2.length)
   let i = -1
-  let res = []
+  const res = []
   while (++i < len) {
     const item = arr2[i]
     if (arr1.indexOf(item) > -1) res.push(item)
@@ -108,17 +108,17 @@ const getDate = (timeStamp, startType) => {
 export const formtDate = (timeStamp, fmt) => {
   const d = new Date(timeStamp)
   var o = {
-        'M+': d.getMonth() + 1, // 月份
-        'd+': d.getDate(), // 日
-        'h+': d.getHours(), // 小时
-        'm+': d.getMinutes(), // 分
-        's+': d.getSeconds(), // 秒
-        'q+': Math.floor((d.getMonth() + 3) / 3), // 季度
-        'S': d.getMilliseconds() // 毫秒
-    }
-    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (d.getFullYear() + '').substr(4 - RegExp.$1.length))
-    for (var k in o) { if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length))) }
-    return fmt
+    'M+': d.getMonth() + 1, // 月份
+    'd+': d.getDate(), // 日
+    'h+': d.getHours(), // 小时
+    'm+': d.getMinutes(), // 分
+    's+': d.getSeconds(), // 秒
+    'q+': Math.floor((d.getMonth() + 3) / 3), // 季度
+    'S': d.getMilliseconds() // 毫秒
+  }
+  if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (d.getFullYear() + '').substr(4 - RegExp.$1.length))
+  for (var k in o) { if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length))) }
+  return fmt
 }
 /**
  * @param {String|Number} timeStamp 时间戳
@@ -160,13 +160,13 @@ export const formatSubmitDate = (val, type) => {
   if (val == null || val == '' || val == undefined) {
     return ''
   } else {
-    let _date = new Date(val)
-    let _year = _date.getFullYear()
-    let _montn = (_date.getMonth() + 1) < 10 ? '0' + (_date.getMonth() + 1) : (_date.getMonth() + 1)
-    let _day = _date.getDate() < 10 ? '0' + _date.getDate() : _date.getDate()
-    let _hour = _date.getHours() < 10 ? '0' + _date.getHours() : _date.getHours()
-    let _minutes = _date.getMinutes() < 10 ? '0' + _date.getMinutes() : _date.getMinutes()
-    let _seconds = _date.getSeconds() < 10 ? '0' + _date.getSeconds() : _date.getSeconds()
+    const _date = new Date(val)
+    const _year = _date.getFullYear()
+    const _montn = (_date.getMonth() + 1) < 10 ? '0' + (_date.getMonth() + 1) : (_date.getMonth() + 1)
+    const _day = _date.getDate() < 10 ? '0' + _date.getDate() : _date.getDate()
+    const _hour = _date.getHours() < 10 ? '0' + _date.getHours() : _date.getHours()
+    const _minutes = _date.getMinutes() < 10 ? '0' + _date.getMinutes() : _date.getMinutes()
+    const _seconds = _date.getSeconds() < 10 ? '0' + _date.getSeconds() : _date.getSeconds()
 
     if (type == 'minutes') return _year + '-' + _montn + '-' + _day + ' ' + _hour + ':' + _minutes
     else if (type == 'seconds') return _year + '-' + _montn + '-' + _day + ' ' + _hour + ':' + _minutes + ':' + _seconds
@@ -175,7 +175,7 @@ export const formatSubmitDate = (val, type) => {
 }
 // 正则验证车牌,验证通过返回true,不通过返回false
 export const isLicensePlate = function (str) {
-    return /^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$/.test(str)
+  return /^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$/.test(str)
 }
 // 车牌可输入字符
 export const isCarNumber = function (str) {
@@ -184,6 +184,12 @@ export const isCarNumber = function (str) {
 
   return _value
 }
+
+// 校验手机号
+export const isMobile = function (str) {
+  return /^[0-9]{11}$/.test(str)
+}
+
 // 小数点后两位
 export const numberToFixed = function (val, num) {
   let _value = val + ''
@@ -267,7 +273,7 @@ export const off = (function () {
 export const hasKey = (obj, key) => {
   if (key) return key in obj
   else {
-    let keysArr = Object.keys(obj)
+    const keysArr = Object.keys(obj)
     return keysArr.length
   }
 }
@@ -301,7 +307,7 @@ export const removeListById = (id, list) => {
  * @description 遍历赋值
 */
 export const objExtend = (obj1, obj2) => {
-  for (var a in obj1){
+  for (var a in obj1) {
     obj2[a] = obj1[a]
   }
   return obj2
@@ -311,8 +317,8 @@ export const objExtend = (obj1, obj2) => {
  * @description 浅拷贝
 */
 export const cloneObj = (obj) => {
-  let ret = {}
-  for (var a in obj){
+  const ret = {}
+  for (var a in obj) {
     ret[a] = obj[a]
   }
   return ret
@@ -322,98 +328,98 @@ export const cloneObj = (obj) => {
  * 校验身份证号合法性
  */
 export const checkIdNumberValid = (tex) => {
-    // var tip = '输入的身份证号有误,请检查后重新输入!'
-    let num = tex
-    num = num.toUpperCase()
+  // var tip = '输入的身份证号有误,请检查后重新输入!'
+  let num = tex
+  num = num.toUpperCase()
 
-    let len = num.length
-    let re
-    if (len == 0) return true
+  const len = num.length
+  let re
+  if (len == 0) return true
 
-    // 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X。
-    if (!(/(^\d{15}$)|(^\d{17}([0-9]|X)$)/.test(num))){
-        return false
-    }
+  // 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X。
+  if (!(/(^\d{15}$)|(^\d{17}([0-9]|X)$)/.test(num))) {
+    return false
+  }
 
-    // 验证前两位地区是否有效
-    let aCity = {11: '北京',
-12: '天津',
-13: '河北',
-14: '山西',
-15: '内蒙古',
-21: '辽宁',
-22: '吉林',
-23: '黑龙江',
-31: '上海',
-32: '江苏',
-33: '浙江',
-34: '安徽',
-35: '福建',
-36: '江西',
-37: '山东',
-41: '河南',
-42: '湖北',
-43: '湖南',
-44: '广东',
-45: '广西',
-46: '海南',
-50: '重庆',
-51: '四川',
-52: '贵州',
-53: '云南',
-54: '西藏',
-61: '陕西',
-62: '甘肃',
-63: '青海',
-64: '宁夏',
-65: '新疆',
-71: '台湾',
-81: '香港',
-82: '澳门',
-91: '国外'}
+  // 验证前两位地区是否有效
+  const aCity = { 11: '北京',
+    12: '天津',
+    13: '河北',
+    14: '山西',
+    15: '内蒙古',
+    21: '辽宁',
+    22: '吉林',
+    23: '黑龙江',
+    31: '上海',
+    32: '江苏',
+    33: '浙江',
+    34: '安徽',
+    35: '福建',
+    36: '江西',
+    37: '山东',
+    41: '河南',
+    42: '湖北',
+    43: '湖南',
+    44: '广东',
+    45: '广西',
+    46: '海南',
+    50: '重庆',
+    51: '四川',
+    52: '贵州',
+    53: '云南',
+    54: '西藏',
+    61: '陕西',
+    62: '甘肃',
+    63: '青海',
+    64: '宁夏',
+    65: '新疆',
+    71: '台湾',
+    81: '香港',
+    82: '澳门',
+    91: '国外' }
 
-    if (aCity[parseInt(num.substr(0, 2))] == null){
-        return false
-    }
+  if (aCity[parseInt(num.substr(0, 2))] == null) {
+    return false
+  }
 
-    // 当身份证为15位时的验证出生日期。
-    if (len == 15){
-        re = new RegExp(/^(\d{6})(\d{2})(\d{2})(\d{2})(\d{3})$/)
-        let arrSplit = num.match(re)
+  // 当身份证为15位时的验证出生日期。
+  if (len == 15) {
+    re = new RegExp(/^(\d{6})(\d{2})(\d{2})(\d{2})(\d{3})$/)
+    const arrSplit = num.match(re)
 
-        // 检查生日日期是否正确
-        let dtmBirth = new Date('19' + arrSplit[2] + '/' + arrSplit[3] + '/' + arrSplit[4])
-        let bGoodDay = (dtmBirth.getYear() == Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3])) && (dtmBirth.getDate() == Number(arrSplit[4]))
-        if (!bGoodDay){
-            return false
-        }
+    // 检查生日日期是否正确
+    const dtmBirth = new Date('19' + arrSplit[2] + '/' + arrSplit[3] + '/' + arrSplit[4])
+    const bGoodDay = (dtmBirth.getYear() == Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3])) && (dtmBirth.getDate() == Number(arrSplit[4]))
+    if (!bGoodDay) {
+      return false
     }
+  }
 
-    // 当身份证号为18位时,校验出生日期和校验位。
-    if (len == 18){
-        re = new RegExp(/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/)
-        let arrSplit = num.match(re)
-        // 检查生日日期是否正确
-        let dtmBirth = new Date(arrSplit[2] + '/' + arrSplit[3] + '/' + arrSplit[4])
-        let bGoodDay = (dtmBirth.getFullYear() == Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3])) && (dtmBirth.getDate() == Number(arrSplit[4]))
-        if (!bGoodDay){
-            return false
-        } else {
-            // 检验18位身份证的校验码是否正确。
-            // 校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
-            let valnum
-            let arrInt = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
-            let arrCh = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
-            let nTemp = 0
-            let i
-            for (i = 0; i < 17; i++){
-                nTemp += num.substr(i, 1) * arrInt[i]
-            }
-            valnum = arrCh[nTemp % 11]
-            if (valnum != num.substr(17, 1)){
-                return false
-            }
-        }
+  // 当身份证号为18位时,校验出生日期和校验位。
+  if (len == 18) {
+    re = new RegExp(/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/)
+    const arrSplit = num.match(re)
+    // 检查生日日期是否正确
+    const dtmBirth = new Date(arrSplit[2] + '/' + arrSplit[3] + '/' + arrSplit[4])
+    const bGoodDay = (dtmBirth.getFullYear() == Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3])) && (dtmBirth.getDate() == Number(arrSplit[4]))
+    if (!bGoodDay) {
+      return false
+    } else {
+      // 检验18位身份证的校验码是否正确。
+      // 校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
+      let valnum
+      const arrInt = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
+      const arrCh = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
+      let nTemp = 0
+      let i
+      for (i = 0; i < 17; i++) {
+        nTemp += num.substr(i, 1) * arrInt[i]
+      }
+      valnum = arrCh[nTemp % 11]
+      if (valnum != num.substr(17, 1)) {
+        return false
+      }
     }
-    return true
+  }
+  return true
 }

+ 183 - 47
src/views/SetmealSales/BuySetmeal.vue

@@ -1,39 +1,81 @@
 <template>
-  <a-card :bordered="false" class="buySetmeal-wrap">
-    <a-row>
-      <a-col :span="5">选择套餐</a-col>
-      <a-col :span="19">
-        <a-input-search v-model="queryWord" placeholder="搜索套餐" enter-button @search="onSearch" />
-      </a-col>
-    </a-row>
-    <div class="draConts">
-      <!-- <div class="smenus">
-        <cSelect
-          ref="menus"
-          showType="menus"
-          v-model="clsId"
-          code="BUNDLE_CLS"
-          @on-change="menuChange">
-        </cSelect>
+  <div class="buySetmeal-wrap">
+    <a-card :bordered="false">
+      <a-row>
+        <a-col :span="5"><b class="buySetmeal-tit">选择套餐</b></a-col>
+        <a-col :span="19" class="search-con">
+          <a-input-search
+            v-model="queryWord"
+            placeholder="搜索套餐"
+            enter-button
+            class="search-inp"
+            id="buySetmeal-search"
+            @search="onSearch" />
+        </a-col>
+      </a-row>
+      <div class="draConts">
+        <!-- 分类 -->
+        <a-tabs v-model="clsId" tabPosition="left" class="smenus" @change="tabChange">
+          <a-tab-pane key="" tab="全部"></a-tab-pane>
+          <a-tab-pane v-for="item in setmealType" :key="item.id" :tab="item.dispName"></a-tab-pane>
+        </a-tabs>
+        <!-- 套餐数据列表 -->
+        <div class="itemBox" id="bundelScroll" :style="{height: winH - 356 + '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.remarks||'-' }}</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>
+        </div>
       </div>
-      <div class="itemBox" id="bundelScroll">
-      </div> -->
-      <a-tabs v-model="clsId" tabPosition="left" class="smenus">
-        <a-tab-pane key="" tab="全部"></a-tab-pane>
-        <a-tab-pane v-for="item in setmealType" :key="item.id" :tab="item.dispName"></a-tab-pane>
-      </a-tabs>
-    </div>
-  </a-card>
+    </a-card>
+    <!-- 下单弹框 -->
+    <SetmealPayMoney :openModal="openSetmealPay" :setmealId="setmealId" @close="openSetmealPay=false" />
+    <!-- 套餐详细 -->
+    <SetmealItemDetailModal :openModal="openSetmealDetails" :setmealId="setmealId" @close="openSetmealDetails=false" />
+  </div>
+
 </template>
 
 <script>
-import { VSelect } from '@/components'
+import SetmealPayMoney from './SetmealPayMoney.vue'
+import SetmealItemDetailModal from './SetmealItemDetailModal.vue'
 export default {
   name: 'BuySetmeal',
-  components: { VSelect },
+  components: { SetmealPayMoney, SetmealItemDetailModal },
   data () {
     return {
-      listData: [], //  套餐数据
+      listData: [
+        { 'id': 10322, 'createDate': '2020-10-14 09:31:30', 'updateDate': '2020-10-19 10:36:34', 'tenantId': 0, 'companyId': 10000, 'beginDate': '2020-10-18T16:00:00.000+0000', 'name': '套餐1-养护', 'clsId': '3', 'originalPrice': 30.00, 'price': 55.00, 'expiryDate': '2099-12-30T16:00:00.000+0000', 'status': '1', 'scope': '车领主总部门店,llei测试门店,测试门店,wj_test,碑林更新街店,名京店', 'scopeNo': '10040,10283,10284,10285,10288,10289', 'salesNumber': 0 },
+        { 'id': 10304, 'createDate': '2020-08-25 18:45:49', 'updateDate': '2020-09-25 18:11:57', 'tenantId': 0, 'companyId': 10000, 'beginDate': '2020-08-24T16:00:00.000+0000', 'name': 'xinzeng ', 'clsId': '3', 'originalPrice': 0.00, 'price': 30.00, 'expiryDate': '2099-12-30T16:00:00.000+0000', 'status': '1', 'scopeNo': '0', 'salesNumber': 8 },
+        { 'id': 10300, 'remarks': '撒旦发生范德萨反对', 'createDate': '2020-08-25 15:31:29', 'updateDate': '2020-09-04 13:52:44', 'tenantId': 0, 'companyId': 10000, 'beginDate': '2020-08-24T16:00:00.000+0000', 'name': '测试套餐li', 'clsId': '2', 'originalPrice': 0.00, 'price': 100.00, 'expiryDate': '2099-12-30T16:00:00.000+0000', 'status': '1', 'scope': 'llei测试门店,测试门店,wj_test,车箱箱,碑林更新街店,名京店', 'scopeNo': '10289,10288,10285,10287,10284,10283', 'salesNumber': 7 },
+        { 'id': 10297, 'createDate': '2020-08-25 13:52:32', 'updateDate': '2020-09-29 16:35:49', 'tenantId': 0, 'companyId': 10000, 'beginDate': '2020-08-24T16:00:00.000+0000', 'name': '222', 'clsId': '1', 'originalPrice': 0.00, 'price': 0.00, 'expiryDate': '2099-12-30T16:00:00.000+0000', 'status': '1', 'scopeNo': '0', 'salesNumber': 5 },
+        { 'id': 10290, 'createDate': '2020-08-24 11:33:43', 'updateDate': '2020-09-30 14:52:51', 'tenantId': 0, 'companyId': 10000, 'beginDate': '2020-08-23T16:00:00.000+0000', 'name': '维修', 'clsId': '3', 'originalPrice': 120.00, 'price': 100.00, 'expiryDate': '2099-12-30T16:00:00.000+0000', 'status': '1', 'scopeNo': '0', 'salesNumber': 8, remarks: '-数据库个人福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵福建省快递费冀凯股份是点检见风使舵' }
+      ], //  套餐数据
       queryWord: '', //  关键词
       clsId: '',
       pageNo: 1,
@@ -44,7 +86,11 @@ export default {
         { 'id': 188, 'sort': 3, 'createDate': '2019-09-29 20:23:07', 'updateDate': '2019-09-29 20:23:07', 'lookupCode': 'BUNDLE_CLS', 'dispName': '系统养护套餐', 'code': '3', 'isEnable': '1' },
         { 'id': 190, 'sort': 5, 'createDate': '2019-09-29 20:23:07', 'updateDate': '2019-12-19 15:12:48', 'lookupCode': 'BUNDLE_CLS', 'dispName': '赠送套餐', 'code': '99', 'isEnable': '1' },
         { 'id': 189, 'sort': 98, 'createDate': '2019-09-29 20:23:07', 'updateDate': '2019-09-29 20:23:07', 'lookupCode': 'BUNDLE_CLS', 'dispName': '活动套餐', 'code': '98', 'isEnable': '1' }
-      ]
+      ],
+      openSetmealPay: false, //  下单弹框是否显示
+      openSetmealDetails: false, //  查看详细弹框是否显示
+      setmealId: null, //  套餐id
+      winH: 0 //  浏览器高度
     }
   },
   methods: {
@@ -53,35 +99,125 @@ export default {
       this.clsId = 'all'
       this.initData()
     },
+    pageInit () {
+      // 默认选择第一个类型
+      this.clsId = 'all'
+      this.queryWord = ''
+      this.initData()
+    },
     // 初始化数据
     initData () {
       const _this = this
-      getBundleList({
-        pageNo: this.pageNo,
-        pageSize: this.pageSize,
-        queryWord: this.queryWord,
-        clsId: this.clsId == 'all' ? '' : this.clsId
-      }).then(res => {
-        if (res.status == 200) {
-          _this.listData = res.data.data.list.map(item => {
-            this.$set(item, 'num', 1)
-            return item
-          })
-        }
-      })
+      // getBundleList({
+      //   pageNo: this.pageNo,
+      //   pageSize: this.pageSize,
+      //   queryWord: this.queryWord,
+      //   clsId: this.clsId == 'all' ? '' : this.clsId
+      // }).then(res => {
+      //   if (res.status == 200) {
+      //     _this.listData = res.data.data.list.map(item => {
+      //       this.$set(item, 'num', 1)
+      //       return item
+      //     })
+      //   }
+      // })
+    },
+    //  tab 切换
+    tabChange (v) {
+      console.log(v)
+      document.getElementById('bundelScroll').scrollTop = 0
+      this.clsId = v || 'all'
+      this.initData()
+    },
+    // 下单
+    openPay (data) {
+      this.setmealId = data.id
+      this.openSetmealPay = true
+    },
+    //  查看详细
+    openDetails (data) {
+      this.setmealId = data.id
+      this.openSetmealDetails = true
     }
+  },
+  mounted () {
+    this.winH = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight // 浏览器高度
   }
 }
 </script>
 
 <style lang="less">
   .buySetmeal-wrap{
-    .smenus{
-      .ant-tabs-tab-active.ant-tabs-tab{
-        padding: 12px 16px;
-        border-radius: 60px 0 0 60px;
-        color: #2d8cf0;
-        background: #f0faff;
+    .buySetmeal-tit{
+      line-height: 32px;
+    }
+    .search-con{
+      text-align: right;
+      .search-inp{
+        width: 60%;
+      }
+    }
+    .ant-tabs .ant-tabs-left-bar .ant-tabs-tab, .ant-tabs .ant-tabs-right-bar .ant-tabs-tab{
+      padding: 12px 55px;
+      margin: 0;
+    }
+    .draConts{
+      display: flex;
+      border-top: 1px solid #eee;
+      margin-top: 20px;
+      padding-top: 20px;
+      .smenus{
+        width: 20%;
+        .ant-tabs-nav .ant-tabs-tab:hover{
+          color: #1890FF;
+        }
+        .ant-tabs-ink-bar{
+          background: #1890FF;
+        }
+        .ant-tabs-tab-active.ant-tabs-tab{
+          border-radius: 60px 0 0 60px;
+          color: #1890FF;
+          background: #f0faff;
+        }
+        .ant-tabs-content.ant-tabs-content-animated.ant-tabs-left-content{
+          width: 0;
+          padding: 0;
+        }
+
+      }
+      .itemBox{
+        width: 80%;
+        overflow: auto;
+        .items-list{
+          display: flex;
+          align-items: middle;
+          justify-content: space-around;
+          border: 1px solid #eee;
+          border-radius: 10px;
+          margin: 10px 0;
+          padding: 15px 20px;
+          font-size: 14px;
+          overflow: hidden;
+          align-items: center;
+          h3{
+            margin: 0;
+          }
+          p{
+            color: #666;
+            padding: 5px 0 0 0;
+            margin: 0;
+            b{
+              font-weight: normal;
+              color: #333;
+            }
+          }
+          .handle-btn{
+            width: 90px;
+          }
+          .look-btn{
+            margin-top: 15px;
+          }
+        }
       }
     }
   }

+ 24 - 17
src/views/SetmealSales/PurchasedSetmeal.vue

@@ -7,6 +7,7 @@
           <a-col :span="6">
             <a-form-item label="下单时间" :label-col="{ span:7 }" :wrapper-col="{ span:17}">
               <a-range-picker
+                id="purchasedSetmeal-time"
                 v-model="time"
                 :format="dateFormat"
                 :placeholder="['开始时间','结束时间']"
@@ -17,34 +18,40 @@
           </a-col>
           <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 />
+              <a-input v-model.trim="searchForm.orderNo" id="purchasedSetmeal-orderNo" placeholder="请输入" allowClear />
             </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.customerMobile" placeholder="手机号/车牌号" allowClear />
+              <a-input v-model.trim="searchForm.customerMobile" id="purchasedSetmeal-info" placeholder="手机号/车牌号" allowClear />
             </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.customerMobile" placeholder="请输入" allowClear />
+              <a-input v-model.trim="searchForm.customerMobile" id="purchasedSetmeal-name" 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-model="searchForm.orderStatus" ref="orderStatus" code="ORDER_STATUS" placeholder="请选择" allowClear></v-select>
+              <v-select
+                v-model="searchForm.orderStatus"
+                ref="orderStatus"
+                id="purchasedSetmeal-status"
+                code="ORDER_STATUS"
+                placeholder="请选择"
+                allowClear></v-select>
             </a-form-item>
           </a-col>
           <a-col :span="12">
-            <a-button class="handle-btn serach-btn" type="primary" @click="handleSearch">查询</a-button>
-            <a-button class="handle-btn" type="" @click="handleReset">重置</a-button>
-            <a-button class="handle-btn export-btn" type="" :loading="loading" @click="handleExport">导出</a-button>
+            <a-button class="handle-btn serach-btn" id="purchasedSetmeal-serach" type="primary" @click="handleSearch">查询</a-button>
+            <a-button class="handle-btn" type="" id="purchasedSetmeal-reset" @click="handleReset">重置</a-button>
+            <a-button class="handle-btn export-btn" id="purchasedSetmeal-export" type="" :loading="loading" @click="handleExport">导出</a-button>
           </a-col>
         </a-row>
       </a-form>
     </div>
     <!-- 新建 -->
-    <div class="table-operator"><a-button type="primary" icon="plus" @click="goBuy()">购买套餐</a-button></div>
+    <div class="table-operator"><a-button type="primary" id="purchasedSetmeal-buy" icon="plus" @click="goBuy()">购买套餐</a-button></div>
     <!-- 合计 -->
     <div class="total">
       <a-icon type="info-circle" class="iconImg" />
@@ -67,7 +74,7 @@
       </span>
       <!-- 操作 -->
       <span slot="action" slot-scope="text, record">
-        <a-button type="primary" @click="seeDetail(record)">详情</a-button>
+        <a-button type="primary" id="purchasedSetmeal-look" @click="seeDetail(record)">详情</a-button>
       </span>
     </s-table>
     <!-- 查看详情弹窗 -->
@@ -116,14 +123,14 @@ export default {
       ],
       dateFormat: 'YYYY-MM-DD',
       columns: [
-        { title: '序号', dataIndex: 'no', width: '60', align: 'center' },
-        { title: '订单号', dataIndex: 'orderNo', width: '40', align: 'center' },
-        { title: '下单时间', dataIndex: 'orderTime', width: '40', align: 'center' },
-        { title: '套餐名称', dataIndex: 'storeName', width: '40', align: 'center' },
-        { title: '客户信息', dataIndex: 'customerMobile', width: '40', align: 'center' },
-        { title: '应收金额(¥)', dataIndex: 'payableAmount', width: '40', align: 'center' },
-        { title: '单据状态', scopedSlots: { customRender: 'orderStatus' }, width: '40', align: 'center' },
-        { title: '操作', scopedSlots: { customRender: 'action' }, width: '40', align: 'center' }
+        { title: '序号', dataIndex: 'no', width: 60, align: 'center' },
+        { title: '订单号', dataIndex: 'orderNo', width: 100, align: 'center' },
+        { title: '下单时间', dataIndex: 'orderTime', width: 100, align: 'center' },
+        { title: '套餐名称', dataIndex: 'storeName', width: 100, align: 'center' },
+        { title: '客户信息', dataIndex: 'customerMobile', width: 100, align: 'center' },
+        { title: '应收金额(¥)', dataIndex: 'payableAmount', width: 100, align: 'center' },
+        { title: '单据状态', scopedSlots: { customRender: 'orderStatus' }, width: 100, align: 'center' },
+        { title: '操作', scopedSlots: { customRender: 'action' }, width: 100, align: 'center' }
       ],
       // 加载数据方法 必须为 Promise 对象
       loadData: parameter => {

+ 1 - 1
src/views/SetmealSales/SetmealDetailModal.vue

@@ -87,7 +87,7 @@
         </a-tab-pane>
       </a-tabs>
       <div class="btn-cont">
-        <a-button @click="isShow=false">返回列表</a-button>
+        <a-button id="detailsSetmealModal-back" @click="isShow=false">返回列表</a-button>
       </div>
     </a-modal>
   </div>

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

@@ -0,0 +1,174 @@
+<template>
+  <a-modal
+    class="setmealItemDetailModal"
+    title="查看"
+    width="80%"
+    :footer="null"
+    :destroyOnClose="true"
+    @cancel="isShow=false"
+    v-model="isShow">
+    <div class="table-con">
+      <div class="table-main" v-if="bundleItemList">
+        <p class="table-tit">服务:</p>
+        <a-table
+          ref="table-item"
+          size="middle"
+          :rowKey="(record) => record.id"
+          :columns="columns_item"
+          :dataSource="bundleItemList"
+          :pagination="false"
+          bordered>
+          <!-- 工时费 -->
+          <template slot="priceL3" slot-scope="text, record">{{ record.priceL3 ? record.priceL3 : 0 }}元</template>
+          <!-- 优惠工时费 -->
+          <template slot="itemPrice" slot-scope="text, record">{{ record.itemPrice ? record.itemPrice : 0 }}元</template>
+          <!-- 次数 -->
+          <template slot="itemTimes" slot-scope="text, record">{{ record.itemTimes ? record.itemTimes : '--' }}</template>
+          <!-- 价值 -->
+          <template slot="worth" slot-scope="text, record">{{ (Number(record.priceL3 ? record.priceL3 : 0) - Number(record.itemPrice ? record.itemPrice : 0)) * (record.itemTimes ? record.itemTimes : 0) }}元</template>
+          <!-- 单次耗卡金额 -->
+          <template slot="allocationPrice" slot-scope="text, record">{{ record.allocationPrice ? record.allocationPrice : 0 }}元</template>
+        </a-table>
+      </div>
+      <div class="table-main" v-if="bundlePartList">
+        <p class="table-tit">配件:</p>
+        <a-table
+          ref="table-part"
+          size="middle"
+          :rowKey="(record) => record.id"
+          :columns="columns_part"
+          :dataSource="bundlePartList"
+          :pagination="false"
+          bordered>
+          <!-- 型号 -->
+          <template slot="type" slot-scope="text, record">{{ record.type ? record.type : '--' }}</template>
+          <!-- 规格 -->
+          <template slot="specNum" slot-scope="text, record">{{ record.specNum ? record.specNum : 0 }}{{ record.spec }}</template>
+          <!-- 价格 -->
+          <template slot="price" slot-scope="text, record">{{ record.price ? record.price : 0 }}元</template>
+          <!-- 数量 -->
+          <template slot="quantity" slot-scope="text, record">{{ record.quantity ? record.quantity : 1 }}</template>
+          <!-- 价值 -->
+          <template slot="worth" slot-scope="text, record">{{ (record.quantity ? record.quantity : 1) * (record.price ? record.price : 0) }}元</template>
+          <!-- 单次耗卡金额 -->
+          <template slot="allocationPrice" slot-scope="text, record">{{ record.allocationPrice ? record.allocationPrice : 0 }}元</template>
+        </a-table>
+      </div>
+      <div class="btn-cont">
+        <a-button id="setmealItemDetail-cancel" class="setmealItemDetail-cancel" @click="isShow=false">返回</a-button>
+      </div>
+    </div>
+  </a-modal>
+</template>
+
+<script>
+import { STable } from '@/components'
+export default {
+  name: 'SetmealItemDetailModal',
+  components: { STable },
+  props: {
+    openModal: {
+      //  弹框是否展示
+      type: Boolean,
+      default: false
+    },
+    setmealId: {
+      //  套餐id
+      type: Number || String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      isShow: this.openModal, //  弹框是否展示
+      columns_item: [
+        { title: '服务名称', dataIndex: 'itemName', width: 120, align: 'center' },
+        { title: '服务类别', dataIndex: 'itemClsName', width: 100, align: 'center' },
+        { title: '工时费', scopedSlots: { customRender: 'priceL3' }, width: 100, align: 'center' },
+        { title: '优惠工时费', scopedSlots: { customRender: 'itemPrice' }, width: 100, align: 'center' },
+        { title: '次数', scopedSlots: { customRender: 'itemTimes' }, width: 100, align: 'center' },
+        { title: '价值', scopedSlots: { customRender: 'worth' }, width: 100, align: 'center' },
+        { title: '单次耗卡金额', scopedSlots: { customRender: 'allocationPrice' }, width: 100, align: 'center' }
+      ],
+      bundleItemList: [],
+      columns_part: [
+        { title: '配件名称', dataIndex: 'partName', width: 120, align: 'center' },
+        { title: '型号', scopedSlots: { customRender: 'type' }, align: 'center', width: 100 },
+        { title: '规格', scopedSlots: { customRender: 'specNum' }, align: 'center', width: 100 },
+        { title: '价格', scopedSlots: { customRender: 'price' }, align: 'center', width: 100 },
+        { title: '数量', scopedSlots: { customRender: 'quantity' }, align: 'center', width: 100 },
+        { title: '价值', scopedSlots: { customRender: 'worth' }, align: 'center', width: 100 },
+        { title: '单次耗卡金额', scopedSlots: { customRender: 'allocationPrice' }, align: 'center', width: 150 }
+      ],
+      bundlePartList: []
+    }
+  },
+  methods: {
+    //  套餐信息
+    getSetmealInfo () {
+      const data = {
+        'id': 10322,
+        'createDate': '2020-10-14 09:31:30',
+        'updateDate': '2020-10-21 11:02:49',
+        'tenantId': 0,
+        'companyId': 10000,
+        'beginDate': '2020-10-18T16:00:00.000+0000',
+        'name': '套餐1-养护',
+        'clsId': '3',
+        'originalPrice': 30.00,
+        'price': 55.00,
+        'expiryDate': '2099-12-30T16:00:00.000+0000',
+        'status': '1',
+        'scope': '车领主总部门店,llei测试门店,测试门店,wj_test,碑林更新街店,名京店',
+        'scopeNo': '10040,10283,10284,10285,10288,10289',
+        'salesNumber': 1,
+        'bundleItemList': [
+          { 'id': 11250, 'createDate': '2020-10-19 10:36:34', 'updateDate': '2020-10-19 10:36:34', 'tenantId': 0, 'companyId': 10000, 'bundleId': 10322, 'itemId': 18373, 'itemName': '精致洗车', 'itemPrice': 0.00, 'allocationPrice': 2.00, 'itemClsName': '洗车', 'priceL3': 0.00, 'itemTimes': 6 },
+          { 'id': 11251, 'createDate': '2020-10-19 10:36:34', 'updateDate': '2020-10-19 10:36:34', 'tenantId': 0, 'companyId': 10000, 'bundleId': 10322, 'itemId': 18285, 'itemName': '精致洗车111', 'itemPrice': 0.00, 'allocationPrice': 3.00, 'itemClsName': '洗车', 'priceL3': 30.00, 'itemTimes': 1 }
+        ],
+        'bundlePartList': [
+          { 'id': 10200, 'createDate': '2020-10-19 10:36:34', 'updateDate': '2020-10-19 10:36:34', 'tenantId': 0, 'companyId': 10000, 'bundleId': 10322, 'partId': 41941, 'partName': '123123444', 'unit': '个', 'price': 0.00, 'allocationPrice': 7.00, 'quantity': 2 }
+        ]
+      }
+      this.bundleItemList = data.bundleItemList || []
+      this.bundlePartList = data.bundlePartList || []
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (val) {
+      if (!val) {
+        this.$emit('close')
+      }
+    },
+    setmealId (newValue, oldValue) {
+      if (newValue && this.isShow) {
+        this.getSetmealInfo(newValue)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .setmealItemDetailModal{
+    .table-con{
+      .table-main{
+        .table-tit{
+          margin: 0 0 10px;
+        }
+        margin: 0 0 30px;
+      }
+    }
+    .btn-cont{
+      text-align: center;
+      .setmealPayMoney-cancel{
+        margin-left: 30px;
+      }
+    }
+  }
+</style>

+ 153 - 0
src/views/SetmealSales/SetmealPayMoney.vue

@@ -0,0 +1,153 @@
+<template>
+  <a-modal
+    class="setmealPayMoneyModal"
+    title="套餐收款"
+    width="60%"
+    :footer="null"
+    :destroyOnClose="true"
+    @cancel="isShow=false"
+    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="customerMobile">
+        <a-input v-model.trim="form.customerMobile" :maxLength="11" placeholder="支持新增和搜索" />
+      </a-form-model-item>
+      <a-form-model-item label="车牌号" prop="vehicle">
+        <a-input v-model.trim="form.vehicle" :maxLength="8" placeholder="请输入车牌号(最多8个字符)" />
+      </a-form-model-item>
+      <a-form-model-item label="客户姓名" prop="name">
+        <a-input v-model.trim="form.name" :maxLength="30" placeholder="请输入客户姓名(最多30个字符)" />
+      </a-form-model-item>
+      <a-form-model-item label="应收金额" class="item-con">
+        <p class="item-main"><span class="item-price">399.00</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>
+        <a-button id="setmealPayMoney-cancel" class="setmealPayMoney-cancel" @click="cancel">取消</a-button>
+      </a-form-model-item>
+    </a-form-model>
+  </a-modal>
+</template>
+
+<script>
+import { isLicensePlate, isMobile } from '@/libs/tools'
+export default {
+  name: 'SetmealPayMoney',
+  props: {
+    openModal: {
+      //  弹框是否展示
+      type: Boolean,
+      default: false
+    },
+    setmealId: {
+      //  套餐id
+      type: Number || String,
+      default: ''
+    }
+  },
+  data () {
+    // 校验手机号
+    const isMobileValid = (rule, value, callback) => {
+      if (!value) {
+        callback(new Error('请输入手机号'))
+      } else {
+        if (!isMobile(value)) {
+          callback(new Error('请输入正确的手机号'))
+        } else {
+          callback()
+        }
+      }
+    }
+    // 校验车牌号
+    const isLicensePlateValid = (rule, value, callback) => {
+      if (!value) {
+        callback(new Error('请输入车牌号'))
+      } else {
+        if (!isLicensePlate(value)) {
+          callback(new Error('请输入正确的车牌号'))
+        } else {
+          callback()
+        }
+      }
+    }
+    return {
+      isShow: this.openModal, //  弹框是否展示
+      form: {
+        customerMobile: '',
+        vehicle: '',
+        name: ''
+      },
+      rules: {
+        customerMobile: [
+          { required: true, message: '请输入手机号', trigger: 'blur' },
+          { validator: isMobileValid, trigger: 'blur' }
+        ],
+        vehicle: [
+          { required: true, message: '请输入车牌号', trigger: 'blur' },
+          { validator: isLicensePlateValid, trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  methods: {
+    //  套餐信息
+    getSetmealInfo () {},
+    //  确认收款
+    onSubmit () {},
+    //  取消收款
+    cancel () {
+      this.resetForm() //  重置表单数据
+      this.isShow = false
+    },
+    // 重置表单
+    resetForm () {
+      this.form.customerMobile = ''
+      this.form.vehicle = ''
+      this.form.name = ''
+    }
+  },
+  watch: {
+    //  父页面传过来的弹框状态
+    openModal (newValue, oldValue) {
+      this.isShow = newValue
+    },
+    //  重定义的弹框状态
+    isShow (val) {
+      if (!val) {
+        this.$emit('close')
+      } else {
+        this.resetForm() //  重置表单数据
+      }
+    },
+    setmealId (newValue, oldValue) {
+      if (newValue && this.isShow) {
+        this.getSetmealInfo(newValue)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less">
+  .setmealPayMoneyModal{
+    .item-con{
+      .item-main{
+        margin: 0;
+        .item-price{
+          font-size: 24px;
+          color: red;
+          margin-right: 5px;
+        }
+      }
+    }
+    .btn-cont{
+      text-align: center;
+      .setmealPayMoney-cancel{
+        margin-left: 30px;
+      }
+    }
+  }
+</style>