Browse Source

服务号套餐商城

lighter 6 tháng trước cách đây
mục cha
commit
0e8556d7b6

+ 40 - 0
src/api/package-mall.js

@@ -0,0 +1,40 @@
+import request from '../utils/request'
+
+export function getAllPackage() {
+  return request({
+    url: '/packageMall/getAllPackage',
+    method: 'get',
+  })
+}
+
+export function getPackageDetail(id) {
+  return request({
+    url: '/packageMall/getPackageDetail',
+    method: 'get',
+    params: {id}
+  })
+}
+
+export function getPurchasedPackage(patNo) {
+  return request({
+    url: '/packageMall/getPurchasedPackage',
+    method: 'get',
+    params: {patNo}
+  })
+}
+
+export function getPurchasedPackageItems(id) {
+  return request({
+    url: '/packageMall/getPurchasedPackageItems',
+    method: 'get',
+    params: {id}
+  })
+}
+
+export function refund(id, tradeNo) {
+  return request({
+    url: '/packageMall/refund',
+    method: 'get',
+    params: {id, tradeNo}
+  })
+}

+ 15 - 0
src/router/index.js

@@ -245,6 +245,21 @@ export const constantRoutes = [
     component: () => import('../views/hospital-service/self-service/health-cart/ResignOrRefund.vue'),
     meta: { title: '未成功的预约' },
   },
+  {
+    path: '/selectPackageMallPatient',
+    component: () => import('../views/hospital-service/self-service/package-mall/SelectPatientCard.vue'),
+    meta: { title: '选择就诊人' },
+  },
+  {
+    path: '/mallPackage/:patientId',
+    component: () => import('../views/hospital-service/self-service/package-mall/MallPackage.vue'),
+    meta: { title: '套餐商城' },
+  },
+  {
+    path: '/packageDetail/:patientId/:id/:from',
+    component: () => import('../views/hospital-service/self-service/package-mall/PackageDetail.vue'),
+    meta: { title: '套餐内容' },
+  },
   {
     path: '/importDrugPurchase',
     component: () => import('../views/hospital-service/medicine-consult/import-drug/ImportDrugPurchase.vue'),

+ 10 - 0
src/store/index.js

@@ -26,6 +26,7 @@ export default createStore({
     physicalExamListFinished: false,
     physicalExamIndexes: [],
     appointmentManagementActiveTab: 'unpaid',
+    packageMallActiveTab: 0,
     createOrderRequest: {},
   },
 
@@ -84,6 +85,10 @@ export default createStore({
 
     getCurrentElectroIndex(state) {
       return state.currentElectroIndex
+    },
+
+    getPackageMallActiveTab(state) {
+      return state.packageMallActiveTab
     }
   },
   
@@ -108,6 +113,7 @@ export default createStore({
     SET_PHYSICAL_EXAM_INDEXES: (state, payload) => (state.physicalExamIndexes = payload),
     SET_APPOINTMENT_MANAGEMENT_ACTIVE_TAB: (state, payload) => {state.appointmentManagementActiveTab = payload},
     CREATE_ORDER_REQUEST: (state, payload) => (state.createOrderRequest = payload),
+    SET_PACKAGE_MALL_ACTIVE_TAB: (state, payload) => (state.packageMallActiveTab = payload),
   },
 
 
@@ -201,5 +207,9 @@ export default createStore({
     storeAppointmentManagementActiveTab({commit}, payload) {
       commit('SET_APPOINTMENT_MANAGEMENT_ACTIVE_TAB', payload['appointmentManagementActiveTab'])
     },
+
+    storePackageMallActiveTab({commit}, payload) {
+      commit('SET_PACKAGE_MALL_ACTIVE_TAB', payload['packageMallActiveTab'])
+    }
   },
 })

+ 7 - 0
src/views/hospital-service/self-service/SelfService.vue

@@ -7,6 +7,13 @@
         center
         @click="simpleRoute('/healthCartCategory/', '/selectHealthCartPatient')">
     </van-cell>
+    <van-cell
+        title="套餐购买"
+        label="购买优惠的套餐项目"
+        is-link
+        center
+        @click="simpleRoute('/mallPackage/', '/selectPackageMallPatient')">
+    </van-cell>
   </window-size>
 </template>
 

+ 145 - 0
src/views/hospital-service/self-service/package-mall/MallPackage.vue

@@ -0,0 +1,145 @@
+<template>
+  <window-size class="mall-package">
+    <van-tabs v-model:active="active" @change="onTabChange">
+      <van-tab title="套餐选购">
+        <van-empty v-if="showEmpty" :image="empty" description="暂无数据"></van-empty>
+        <div v-else class="package-card-box">
+          <van-card
+              v-for="item in allPackages"
+              :desc="item.description"
+              :title="item.name"
+              :thumb="item.thumbPath"
+              @click="toPackageDetail(item)"
+          >
+            <template #price>
+              ¥ {{item.price.toFixed(2)}}
+            </template>
+          </van-card>
+        </div>
+      </van-tab>
+      <van-tab title="已购套餐">
+        <van-empty v-if="showEmpty2" :image="empty" description="暂无数据"></van-empty>
+        <div v-else class="package-card-box">
+          <van-card
+              v-for="item in purchasedPackages"
+              :desc="item.description"
+              :title="item.packageName"
+              :thumb="item.thumbPath"
+              @click="toPackageDetail(item)"
+          >
+            <template #desc>
+              <div class="van-card__desc van-ellipsis">
+                {{item.description}}
+              </div>
+              <div class="p-time">
+                购买时间:{{item.purchaseTime}}
+              </div>
+            </template>
+            <template #price>
+              ¥ {{item.purchasePrice.toFixed(2)}}
+              <span class="real-pay">
+                实付金额:
+                <span>
+                  ¥ {{item.cashpayAmt.toFixed(2)}}
+                </span>
+              </span>
+              <span v-if="item.state === 'REFUND'" class="refund-mark">
+                已退款
+              </span>
+            </template>
+          </van-card>
+        </div>
+      </van-tab>
+    </van-tabs>
+  </window-size>
+</template>
+
+<script setup>
+import {computed, onMounted, ref} from "vue";
+import {getAllPackage, getPurchasedPackage} from "@/api/package-mall";
+import empty from "@/assets/empty.png";
+import router from "@/router";
+import store from "@/store";
+
+const patientId = router.currentRoute.value.params.patientId
+
+const active = ref(store.getters.getPackageMallActiveTab)
+
+const allPackages = ref([])
+const showEmpty = computed(() => {
+  return allPackages.value.length === 0
+})
+
+function toPackageDetail(pkg) {
+  router.push(`/packageDetail/${patientId}/${pkg.id}/${active.value}`);
+}
+
+const purchasedPackages = ref([])
+const showEmpty2 = computed(() => {
+  return purchasedPackages.value.length === 0
+})
+function onTabChange(val) {
+  store.dispatch({
+    type: 'storePackageMallActiveTab',
+    packageMallActiveTab: val,
+  }).then(() => {
+    fetchPackageData()
+  })
+}
+
+function fetchPackageData() {
+  if (active.value === 0) {
+    getAllPackage().then(res => {
+      allPackages.value = res;
+    })
+  } else {
+    getPurchasedPackage(patientId).then(res => {
+      purchasedPackages.value = res
+    });
+  }
+}
+
+onMounted(() => {
+  fetchPackageData()
+})
+
+</script>
+
+<style lang="scss">
+.mall-package {
+  .package-card-box {
+    margin-top: 8px;
+    height: calc(100vh - 100px);
+    overflow-y: auto;
+    .p-time {
+      color: #6e6e6e;
+      margin: 2px 0;
+    }
+  }
+  .real-pay {
+    border: 1px solid gray;
+    padding: 2px;
+    margin-left: 12px;
+    font-weight: normal;
+    > span {
+      margin-left: -6px;
+      color: orangered;
+    }
+  }
+  .refund-mark {
+    display: block;
+    position: absolute;
+    bottom: 0;
+    right: 0;
+    padding: 2px 6px;
+    background-color: #acacac;
+    color: white;
+    border-radius: 4px;
+    font-style: italic;
+    font-size: 12px;
+  }
+  .purchased-footer {
+    font-size: 12px;
+  }
+}
+</style>

+ 229 - 0
src/views/hospital-service/self-service/package-mall/PackageDetail.vue

@@ -0,0 +1,229 @@
+<template>
+  <window-size class="package-item">
+    <van-card
+        :title="detail.name || detail.packageName"
+        :thumb="detail.thumbPath"
+        @click="showDesc"
+    >
+      <template #desc>
+        <div class="van-card__desc van-ellipsis">
+          {{ detail.description }}
+        </div>
+        <div v-if="from === '1'" class="p-time">
+          购买时间:{{ detail.purchaseTime }}
+        </div>
+      </template>
+      <template #price>
+        <span v-if="from === '0'">
+          ¥ {{ detail.price?.toFixed(2) }}
+        </span>
+        <span v-else>
+          ¥ {{ detail.purchasePrice?.toFixed(2) }}
+          <span class="real-pay">
+            实付金额:
+            <span>
+              ¥ {{ detail.cashpayAmt?.toFixed(2) }}
+            </span>
+          </span>
+          <span v-if="detail.state === 'REFUND'" class="refund-mark">
+            已退款
+          </span>
+          <span v-else-if="detail.state === 'NOT_USED'" class="refund-btn">
+            <button @click.prevent.stop="beforeRefund">退款</button>
+          </span>
+        </span>
+      </template>
+    </van-card>
+    <van-tag style="margin-top: 12px">套餐详情</van-tag>
+    <div class="item-wrapper">
+      <div v-for="item in detail.items">
+        <div class="item-box">
+          <div class="item-name">{{ item.hisName }}</div>
+          <div v-if="from === '0'" class="item-price-quantity">
+            <div class="price">¥ {{ item.price?.toFixed(2) }}</div>
+            <div class="quantity">x{{ item.quantity }}</div>
+          </div>
+          <div v-else class="item-price-quantity">
+            <div class="used">已用数量:{{ item.usedQuantity }}</div>
+            <div class="usable">可用数量:{{ item.usableQuantity }}</div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div v-if="from === '0'" class="buy-box">
+      <van-button block type="success" @click="toCashier">购买</van-button>
+    </div>
+  </window-size>
+</template>
+
+<script setup>
+import router from "@/router";
+import {onMounted, ref} from "vue";
+import {getPackageDetail, getPurchasedPackageItems, refund} from "@/api/package-mall";
+import store from "@/store";
+import {showConfirmDialog, showDialog} from "vant";
+
+const routeParams = router.currentRoute.value.params
+const from = ref('0')
+const detail = ref({})
+
+onMounted(() => {
+  from.value = routeParams.from
+  const id = routeParams.id
+  if (from.value === '0') {
+    getPackageDetail(id).then(res => {
+      detail.value = res;
+    })
+  } else {
+    getPurchasedPackageItems(id).then(res => {
+      detail.value = res;
+    })
+  }
+})
+
+function showDesc() {
+  showDialog({
+    title: '套餐描述',
+    message: detail.value.description
+  })
+}
+
+function toCashier() {
+  const createOrderRequest = {
+    body: `医院套餐(${detail.value.name})`,
+    orderType: 10,
+    wxmallPackageId: detail.value.id,
+    totalFee: detail.value.price,
+    patientId: routeParams.patientId,
+    fundpayAmt: 0,
+    acctpayAmt: 0,
+    cashpayAmt: detail.value.price,
+    couponAmt: 0,
+  }
+  store.dispatch({
+    type: 'storeCreateOrderRequest',
+    createOrderRequest,
+  }).then(() => {
+    router.push('/cashier')
+  })
+}
+
+function beforeRefund() {
+  showConfirmDialog({
+    title: '提示',
+    message: '退款无法返还已使用的代金券,是否确认退款?',
+  }).then(() => {
+    refund(detail.value.id, detail.value.wxTradeNo).then(res => {
+      detail.value.state = 'REFUND'
+      detail.value.items = res
+      showDialog({
+        title: '退款成功',
+        message: '已为您退款,请留意到账信息。',
+      })
+    })
+  }).catch(() => {
+  })
+}
+</script>
+
+<style lang="scss">
+.package-item {
+  .item-wrapper {
+    margin-top: 4px;
+    height: calc(100vh - 230px);
+    overflow-y: auto;
+
+    .item-box {
+      background: #f4f4f4;
+      margin: 8px 12px;
+      padding: 4px 12px;
+      border-radius: 4px;
+
+      .item-name {
+        font-size: 14px;
+        font-weight: bold;
+        color: #454545;
+      }
+
+      .item-price-quantity {
+        display: flex;
+        align-items: center;
+        font-size: 12px;
+        margin-top: 8px;
+
+        .price {
+          color: orangered;
+          width: 90%;
+        }
+
+        .quantity {
+          width: 10%;
+          text-align: right;
+        }
+
+        .used, .usable {
+          width: auto;
+        }
+
+        .usable {
+          color: orangered;
+          margin-left: 24px;
+        }
+      }
+    }
+  }
+
+  .real-pay {
+    border: 1px solid gray;
+    padding: 2px;
+    margin-left: 12px;
+    font-weight: normal;
+
+    > span {
+      margin-left: -6px;
+      color: orangered;
+    }
+  }
+
+  .refund-mark {
+    display: block;
+    position: absolute;
+    bottom: 0;
+    right: 0;
+    padding: 2px 6px;
+    background-color: #acacac;
+    color: white;
+    border-radius: 4px;
+    font-style: italic;
+    font-size: 12px;
+  }
+
+  .refund-btn {
+    display: block;
+    position: absolute;
+    right: 8px;
+    bottom: 0;
+
+    > button {
+      padding: 1px 8px;
+      border: none;
+      background-color: #004e45;
+      color: #fff;
+      border-radius: 2px;
+    }
+  }
+
+  .buy-box {
+    height: 44px;
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+  }
+
+  .p-time {
+    margin: 2px 0;
+    color: #6e6e6e;
+  }
+}
+</style>

+ 9 - 0
src/views/hospital-service/self-service/package-mall/SelectPatientCard.vue

@@ -0,0 +1,9 @@
+<template>
+  <window-size>
+    <SelectCard to="mallPackage" />
+  </window-size>
+</template>
+
+<script setup>
+import SelectCard from "@/components/select-card";
+</script>

+ 0 - 1
src/views/public-pages/Cashier.vue

@@ -120,7 +120,6 @@ function makeMoneyStyle(m) {
 }
 
 function weChatPay() {
-  console.log(createOrderRequest)
   createPayOrder(createOrderRequest).then((order) => {
     createOrderRequest.tradeNo = order.tradeNo
     store.dispatch({