Bladeren bron

接口完善

冯诚 3 jaren geleden
bovenliggende
commit
8fd1d9d8c6

+ 2 - 0
src/env.d.ts

@@ -10,3 +10,5 @@ declare module '*.vue' {
 interface ImportMetaEnv {
   VITE_API_BASE: string
 }
+
+declare module 'nprogress'

+ 26 - 23
src/pages/benefits/index.vue

@@ -26,10 +26,10 @@
         >
           <p class="benefit-name">{{ item.title }}</p>
           <p class="benefit-desc">
-            {{ item.left_times ? `Available ${item.left_times}` : item.remark }}
+            {{ item.type === 1 ? `Available ${item.left_times}` : item.remark }}
           </p>
-          <p v-if="item.price || item.next_available_at" class="benefit-sup">
-            <template v-if="item.price">
+          <p v-if="item.type === 1" class="benefit-sup">
+            <template v-if="item.available">
               Member price:<span class="highlight">${{ item.price }}</span>
             </template>
             <template v-else
@@ -37,28 +37,21 @@
             >
           </p>
           <button
-            v-if="item.button_name"
+            v-if="
+              (item.type === 1 && item.available) || [2, 4].includes(item.type)
+            "
             class="ptc-button"
-            @click="onClickButton(item.button_link)"
+            @click="onClickButton(item)"
           >
-            {{ item.button_name }}
+            {{
+              item.type === 1
+                ? 'Apply'
+                : item.type === 2
+                ? item.button_name
+                : 'Send to me'
+            }}
           </button>
         </div>
-        <!-- <div class="benefit benefit-e">
-          <p class="benefit-name">Cleaning Kit</p>
-          <p class="benefit-desc">Give a gift of XX</p>
-          <button
-            class="ptc-button"
-            @click="
-              $router.push({
-                path: '/mailing',
-                query: { right_id: 6, right_name: 'Cleaning Kit' },
-              })
-            "
-          >
-            Send to me
-          </button>
-        </div> -->
       </div>
     </div>
   </div>
@@ -81,8 +74,18 @@ export default defineComponent({
     }
   },
   methods: {
-    onClickButton(link) {
-      location.href = link
+    onClickButton(right) {
+      right.type === 1
+        ? this.$router.push(`/repaire/appointment?right_id=${right.id}`)
+        : right.type === 2
+        ? (location.href = right.link)
+        : this.$router.push({
+            path: '/mailing',
+            query: {
+              right_id: right.id,
+              right_name: right.title,
+            },
+          })
     },
   },
 })

+ 6 - 1
src/pages/fill-order/StepTwo.vue

@@ -29,7 +29,12 @@
             class="device-item"
             :value="brand.id"
           >
-            <i :class="['device-img', `device-img-${brand.id}`]" />
+            <i
+              :class="[
+                'device-img',
+                [, 'd-iphone', 'd-ipag', 'd-samsung'][brand.id] || 'd-other',
+              ]"
+            />
             <p class="device-name">{{ brand.name }}</p>
           </PtcRadio>
         </PtcRadioGroup>

+ 2 - 3
src/pages/fill-order/index.vue

@@ -32,9 +32,8 @@ const { from, invitee } = useRoute().query as any
 state.form.from = from
 state.form.invitor = invitee
 
-onUnmounted(() => {
-  resetState()
-})
+// 此处不直接传入resetState是有必要的,否则resetState在整个应用生命周期只会执行一次
+onUnmounted(() => resetState())
 
 watch(step, () => window.scrollTo(0, 0))
 

+ 1 - 3
src/pages/repaire/appointment.vue

@@ -33,9 +33,7 @@ onBeforeRouteLeave((to, from) => {
   }
 })
 
-onUnmounted(() => {
-  resetState()
-})
+onUnmounted(() => resetState())
 
 watch(
   () => state.step,

+ 6 - 3
src/pages/repaire/index.scss

@@ -44,9 +44,9 @@
     font-size: 32px;
     color: #1a1a1a;
     @include thin-border(bottom);
-    &:active {
-      background: #f2f5fb;
-    }
+    // &:active {
+    //   background: #f2f5fb;
+    // }
   }
 
   .tip {
@@ -341,6 +341,9 @@
     font-size: 32px;
     font-weight: 600;
     color: $primary-color;
+    &.hidden {
+      visibility: hidden;
+    }
   }
   .p1 {
     line-height: 56px;

+ 36 - 14
src/pages/repaire/steps/StepFive.vue

@@ -3,7 +3,7 @@
     <div class="ptc-inner">
       <div class="alert">
         <i class="alert-icon"></i>
-        <p class="alert-message">Monday, October 10 9:00 -9:30</p>
+        <p class="alert-message">{{ formattedTime }}</p>
       </div>
       <div class="action">
         <i class="icon-calendar"></i><strong>Add to calendar ></strong>
@@ -18,43 +18,41 @@
       <div class="detail">
         <div class="cell">
           <span class="cell-label">Store:</span>
-          <span class="cell-value">xxxxxxxxxx</span>
+          <span class="cell-value">{{ state.detail.shop_name }}</span>
         </div>
         <div class="cell">
-          <span class="cell-label">Phone Brand:</span>
-          <span class="cell-value">xxxxxxxxxx</span>
+          <strong class="primary">Navigation></strong>
         </div>
         <div class="cell">
-          <strong class="primary">Navigation></strong>
+          <span class="cell-label">Phone Brand:</span>
+          <span class="cell-value">{{ state.detail.phone_brand }}</span>
         </div>
         <div class="cell">
           <span class="cell-label">Phone Model:</span>
-          <span class="cell-value">xxxxxxxxxx</span>
+          <span class="cell-value">{{ state.detail.phone_model }}</span>
         </div>
         <div class="cell">
           <span class="cell-label">Phone Number:</span>
-          <span class="cell-value">xxxxxxxxxx</span>
+          <span class="cell-value">{{ state.detail.phone_number }}</span>
         </div>
         <div class="cell">
           <span class="cell-label">IMEI:</span>
-          <span class="cell-value">xxxxxxxxxx</span>
+          <span class="cell-value">{{ state.detail.phone_imei }}</span>
         </div>
         <div class="cell">
           <span class="cell-label">Service:</span>
-          <span class="cell-value">xxxxxxxxxx</span>
+          <span class="cell-value">{{ state.detail.fix_name }}</span>
         </div>
         <div class="cell">
           <span class="cell-label">Member Price:</span>
-          <span class="cell-value">$35</span>
+          <span class="cell-value">${{ state.detail.price }}</span>
         </div>
       </div>
     </div>
     <div class="ptc-button-group mg0">
       <div class="ptc-inner">
-        <button class="ptc-button" @click="state.step = 1">
-          Reselect time
-        </button>
-        <button class="ptc-button ptc-button--stroke">
+        <button class="ptc-button" @click="reselect">Reselect time</button>
+        <button class="ptc-button ptc-button--stroke" @click="applyCancel">
           Cancel appointment
         </button>
       </div>
@@ -63,6 +61,30 @@
 </template>
 
 <script setup lang="ts">
+import { useRouter } from 'vue-router'
 import { state } from '../store'
 import { cancelRepair } from '@/service/repair'
+import Toast from '@/components/toast'
+import dayjs from 'dayjs'
+
+const router = useRouter()
+
+const formattedTime = (() => {
+  const _ = dayjs(state.date, 'YYYY-MM-DD')
+  return `${_.format('dddd')},${_.format('MMMM')} ${_.format('DD')} ${
+    state.uiPeriod
+  }`
+})()
+
+function reselect() {
+  state.rightId
+    ? router.replace({ path: '', query: { id: state.repairId } })
+    : (state.step = 1)
+}
+
+async function applyCancel() {
+  const { message } = await cancelRepair(+state.repairId)
+  Toast(message)
+  setTimeout(() => router.push('/repaire/history'), 500)
+}
 </script>

+ 43 - 7
src/pages/repaire/steps/StepOne.vue

@@ -4,16 +4,27 @@
     <div class="ptc-inner-md pr">
       <form class="search-wrap" action="">
         <input
+          v-model="code"
           type="search"
           class="search-input ptc-input"
           placeholder="Search by zip code"
           @input="autocomplete"
+          @keydown="$event.keyCode === 13 && handleSearch()"
         />
-        <div role="button" class="search-btn ptc-button"></div>
+        <div
+          role="button"
+          class="search-btn ptc-button"
+          @click="handleSearch"
+        ></div>
       </form>
-      <div v-if="showSuggestions" class="search-suggestions">
-        <div class="suggestion">PTC Browns Plains Kiosk</div>
-        <div class="suggestion">PTC Browns Plains Kiosk</div>
+      <div v-if="suggestions.length" class="search-suggestions">
+        <div
+          v-for="(item, index) of suggestions"
+          :key="index"
+          class="suggestion"
+        >
+          {{ item.name }}
+        </div>
       </div>
       <div class="shop-wrap">
         <div class="tip">Nearby shops</div>
@@ -60,13 +71,17 @@ import { state } from '../store'
 import { getShopList } from '@/service/repair'
 import getLocation from '@/utils/getLocation'
 import InfiniteList from '@/components/infinite-list/index.vue'
+import { debounce } from 'lodash-es'
 
-const showSuggestions = ref(false)
 const loading = ref(false)
 const hasMore = ref(true)
 const list = ref<any[]>()
+const suggestions = ref<any[]>([])
+const code = ref('')
+
 let pageNo = 1
 let coords: GeolocationCoordinates | undefined
+let postCode = ''
 
 async function fetchData() {
   loading.value = true
@@ -81,6 +96,7 @@ async function fetchData() {
       size: 10,
       lat: coords?.latitude,
       lng: coords?.longitude,
+      post_code: postCode,
     })
     list.value.push(...results)
     pageNo++
@@ -89,8 +105,28 @@ async function fetchData() {
   loading.value = false
 }
 
-function autocomplete(e: any) {
-  showSuggestions.value = e.target.value.length > 0
+const autocomplete = debounce(async () => {
+  const value = code.value.trim()
+  if (!value) {
+    suggestions.value = []
+    return
+  }
+  const { results } = await getShopList({
+    page: 1,
+    size: 10,
+    post_code: value,
+  })
+  suggestions.value = results
+}, 300)
+
+function handleSearch() {
+  const value = code.value.trim()
+  if (value === postCode) return
+  postCode = value
+  pageNo = 1
+  list.value = []
+  suggestions.value = []
+  fetchData()
 }
 
 function selectShop(shop: any) {

+ 34 - 10
src/pages/repaire/steps/StepThree.vue

@@ -6,7 +6,7 @@
       <div class="shop-address">
         {{ state.shop.centre_name }},{{ state.shop.address }}
       </div>
-      <div class="shop-action">
+      <div v-if="!submitted" class="shop-action">
         <span class="modify" @click="state.step = 0">Modify ></span>
       </div>
     </div>
@@ -17,7 +17,9 @@
       <div class="flex-ac space-between">
         <strong class="p1">{{ state.uiDate }}</strong>
         <strong class="p2">{{ state.uiPeriod }}</strong>
-        <span class="modify" @click="state.step--">Modify ></span>
+        <span :class="['modify', { hidden: submitted }]" @click="state.step--"
+          >Modify ></span
+        >
       </div>
     </div>
   </div>
@@ -50,7 +52,7 @@
     </div>
     <div class="ptc-button-group">
       <div class="ptc-inner">
-        <button class="ptc-button ptc-button--loading" @click="submit">
+        <button class="ptc-button ptc-button--loading" @click="onSubmit">
           SUBMIT
         </button>
       </div>
@@ -59,18 +61,26 @@
 </template>
 
 <script setup lang="ts">
-import { onMounted } from 'vue'
+import { ref, onMounted } from 'vue'
 import { state } from '../store'
-import { getRepairPhone, applyRepair, rescheduleRepair } from '@/service/repair'
+import * as api from '@/service/repair'
 import Toast from '@/components/toast'
+import NProgress from 'nprogress'
 
 onMounted(async () => {
   if (state.repairId) {
-    state.phoneNumber = (await getRepairPhone()).results
+    state.phoneNumber = (await api.getRepairPhone()).results
   }
 })
 
+const submitted = ref(false)
+
+function onSubmit() {
+  submit().then(next)
+}
+
 async function submit() {
+  if (submitted.value) return
   if (!state.phoneNumber) return Toast('Please enter your phone number')
   const commonParams = {
     igeektek_id: state.shop.igeektek_id,
@@ -79,9 +89,23 @@ async function submit() {
     remark: state.remark || '',
   }
   const request = state.repairId
-    ? rescheduleRepair({ id: state.repairId, ...commonParams })
-    : applyRepair({ right_id: state.rightId, ...commonParams })
-  await request
-  state.step++
+    ? api.rescheduleRepair({ id: state.repairId, ...commonParams })
+    : api.applyRepair({ right_id: state.rightId, ...commonParams })
+  const { results } = await request
+  state.repairId = results
+  submitted.value = true
+}
+
+async function next() {
+  if (NProgress.status) return
+  try {
+    NProgress.start()
+    state.detail = (await api.getRepairInfo(+state.repairId)).results
+    state.step++
+    NProgress.done()
+  } catch {
+    NProgress.status = null
+    NProgress.remove()
+  }
 }
 </script>

+ 1 - 0
src/pages/repaire/store.ts

@@ -12,6 +12,7 @@ const initialState = {
   period: '',
   phoneNumber: '',
   remark: '',
+  detail: null as any,
 }
 export const state = reactive({ ...initialState })
 

+ 0 - 1
src/router.ts

@@ -1,6 +1,5 @@
 import { createRouter, createWebHistory } from 'vue-router'
 import { state } from './store'
-// @ts-ignore
 import NProgress from 'nprogress'
 
 NProgress.configure({ showSpinner: false })

+ 9 - 1
src/service/repair.ts

@@ -2,7 +2,11 @@ import request from './request'
 
 /** 获取零售店列表 */
 export function getShopList(params: any) {
-  return request.get('/shop/list', { params, baseURL: '/v2' })
+  return request.get('/shop/list', {
+    params,
+    baseURL: '/v2',
+    cancelable: true,
+  })
 }
 
 /** 获取店铺可预约的时间段 */
@@ -40,3 +44,7 @@ export function cancelRepair(id: number) {
 export function deleteRepair(id: number) {
   return request.post('/repair/delete', { id })
 }
+
+export function getRepairInfo(id: number) {
+  return request.get('/repair/detail?id=' + id)
+}

+ 1 - 1
src/style/components.scss

@@ -104,7 +104,7 @@
 
 .ptc-input {
   display: block;
-  padding-left: 28px;
+  padding: 0 28px;
   width: 100%;
   height: 100px;
   border-radius: 8px;