zhangxin 1 tydzień temu
rodzic
commit
3de7571f79

+ 1 - 0
.env.development

@@ -1,3 +1,4 @@
1 1
 NODE_ENV = development
2 2
 VUE_APP_ENV = dev
3 3
 VITE_API_BASE_URL=https://crmtest.nanjingshiyu.com/prod-api
4
+#VITE_API_BASE_URL=https://crm.nanjingshiyu.com/prod-api

+ 2 - 2
src/manifest.json

@@ -2,8 +2,8 @@
2 2
     "name" : "小葫芦",
3 3
     "appid" : "__UNI__6259019",
4 4
     "description" : "",
5
-    "versionName" : "1.0.2",
6
-    "versionCode" : 102,
5
+    "versionName" : "1.0.3",
6
+    "versionCode" : 103,
7 7
     "transformPx" : false,
8 8
     /* 5+App特有相关 */
9 9
     "app-plus" : {

+ 2 - 2
src/pages/login/index.vue

@@ -124,14 +124,14 @@ const handleLogin = () => {
124 124
 			uni.removeStorageSync('password');
125 125
 		}
126 126
 		const res = await loginApi.login(form.value)
127
-		loading.value = false
128 127
 		uni.setStorageSync('token', res.data.access_token)
129 128
 		const infoRes = await loginApi.getInfo()
130 129
 		uni.setStorageSync('userInfo', infoRes.user)
130
+		loading.value = false
131 131
 		uni.showToast({ title: '登录成功', icon: 'success' })
132 132
 		setTimeout(() => {
133 133
 			uni.reLaunch({ url: '/pages/repair/index' })
134
-		}, 500)
134
+		}, 50)
135 135
 	}).catch((res: any) => {
136 136
 		uni.$u.toast(res[0].message);
137 137
 	})

+ 2 - 2
src/pages/repair/components/apply/index.vue

@@ -120,7 +120,7 @@
120 120
             <up-textarea v-model="formData.address" placeholder="请输入您的地址"></up-textarea>
121 121
           </up-form-item>
122 122
 
123
-          <up-form-item v-if="formData.serviceType === 'store'" prop="storeName" label="选择门店" required>
123
+          <up-form-item v-if="formData.serviceType === 'store'" prop="storeName" label="选择门店" required label-width="70">
124 124
             <up-select v-model="formData.storeName" :options="stores" label="请选择门店" @select="selectStoreItem">
125 125
               <template #text="{ label }">
126 126
                 <text>{{ formData.storeName }}</text>
@@ -128,7 +128,7 @@
128 128
             </up-select>
129 129
           </up-form-item>
130 130
 
131
-          <up-form-item v-if="formData.serviceType === 'home'" prop="delivery" label="上门时间" required
131
+          <up-form-item v-if="formData.serviceType === 'home'" prop="delivery" label="上门时间" required :label-width="70"
132 132
             @click="datetimerShow = true" labelPosition="top">
133 133
             <up-cate-tab height="300px" :tab-list="deliveryOptions" v-model:current="deliveryCurrent">
134 134
               <template v-slot:itemList="{ item }">

+ 119 - 3
src/pages/repair/components/orderList/index.vue

@@ -17,12 +17,15 @@
17 17
                     <up-swipe-action>
18 18
                         <up-swipe-action-item :threshold="100" v-model:show="swipeShow" :options="swipeOptions"
19 19
                             @click="(val: any) => handleSwipeAction(val, item)">
20
+                            <view class="more-btn" @tap.stop="openPopover(item, index)">
21
+                                <up-icon name="more-dot-fill" size="40rpx" color="#999"></up-icon>
22
+                            </view>
20 23
                             <view class="order-header">
21 24
                                 <view class="order-info">
22 25
                                     <text class="order-number">工单号:{{ item.orderId }}</text>
23 26
                                     <text class="order-time">{{ formatTime(item.createTime) }}</text>
24 27
                                 </view>
25
-                                <view class="order-status">
28
+                                <view class="order-right">
26 29
                                     <text :style="{ color: getStatusColor(item.status) }" class="status-text">{{
27 30
                                         item.status
28 31
                                     }}</text>
@@ -49,6 +52,28 @@
49 52
                             </view>
50 53
                         </up-swipe-action-item>
51 54
                     </up-swipe-action>
55
+
56
+                    <!-- 浮层蒙版(点击空白关闭) -->
57
+                    <view v-if="popoverIndex === index" class="popover-mask" @tap.stop="closePopover"></view>
58
+                    <!-- Popover 浮层 -->
59
+                    <view v-if="popoverIndex === index" class="popover-menu" @tap.stop>
60
+                        <view class="popover-item" @tap="handlePopoverAction({ index: 0 }, item)">
61
+                            <up-icon name="play-right-fill" size="32rpx" color="#42b983"></up-icon>
62
+                            <text class="popover-text">进度</text>
63
+                        </view>
64
+                        <view class="popover-divider"></view>
65
+                        <view class="popover-item" @tap="handlePopoverAction({ index: 1 }, item)">
66
+                            <up-icon name="list" size="32rpx" color="#2c94f6"></up-icon>
67
+                            <text class="popover-text">详情</text>
68
+                        </view>
69
+                        <view class="popover-divider"></view>
70
+                        <view class="popover-item" @tap="handlePopoverAction({ index: 2 }, item)">
71
+                            <up-icon name="rmb-circle" size="32rpx" color="#FF9900"></up-icon>
72
+                            <text class="popover-text">报价</text>
73
+                        </view>
74
+                        <!-- 小三角箭头 -->
75
+                        <view class="popover-arrow"></view>
76
+                    </view>
52 77
                 </view>
53 78
             </up-list-item>
54 79
             <up-empty v-if="filteredOrders.length === 0" image="empty" text="暂无订单数据"></up-empty>
@@ -156,6 +181,30 @@ const handleSwipeAction = (val: any, item: any) => {
156 181
     }
157 182
 }
158 183
 
184
+// Popover 相关
185
+const popoverIndex = ref<number | null>(null)
186
+const currentPopoverItem = ref<OrderListItem_Result | null>(null)
187
+
188
+const openPopover = (item: OrderListItem_Result, index: number) => {
189
+    if (popoverIndex.value === index) {
190
+        popoverIndex.value = null
191
+        currentPopoverItem.value = null
192
+    } else {
193
+        popoverIndex.value = index
194
+        currentPopoverItem.value = item
195
+    }
196
+}
197
+
198
+const closePopover = () => {
199
+    popoverIndex.value = null
200
+    currentPopoverItem.value = null
201
+}
202
+
203
+const handlePopoverAction = (val:object, item: OrderListItem_Result) => {
204
+    closePopover()
205
+    handleSwipeAction(val, item)
206
+}
207
+
159 208
 const loadMore = () => {
160 209
     if (loading.value) return
161 210
 
@@ -231,7 +280,13 @@ onMounted(() => {
231 280
         box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
232 281
         border-radius: 20rpx;
233 282
         margin: 20rpx 20rpx;
234
-
283
+        position: relative;
284
+        .more-btn {
285
+            display: flex;
286
+            align-items: center;
287
+            justify-content: flex-end;
288
+            border-radius: 50%;
289
+        }
235 290
         .order-header {
236 291
             display: flex;
237 292
             justify-content: space-between;
@@ -255,11 +310,17 @@ onMounted(() => {
255 310
                 }
256 311
             }
257 312
 
258
-            .order-status {
313
+            .order-right {
314
+                display: flex;
315
+                align-items: center;
316
+                gap: 16rpx;
317
+
259 318
                 .status-text {
260 319
                     font-size: 28rpx;
261 320
                     font-weight: bold;
262 321
                 }
322
+
323
+                
263 324
             }
264 325
         }
265 326
 
@@ -330,6 +391,61 @@ onMounted(() => {
330 391
         }
331 392
     }
332 393
 
394
+    /* Popover 浮层 */
395
+    .popover-mask {
396
+        position: fixed;
397
+        top: 0;
398
+        left: 0;
399
+        right: 0;
400
+        bottom: 0;
401
+        z-index: 998;
402
+    }
403
+
404
+    .popover-menu {
405
+        position: absolute;
406
+        top: 80rpx;
407
+        right: 10rpx;
408
+        z-index: 999;
409
+        background: #fff;
410
+        border-radius: 16rpx;
411
+        box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.16);
412
+        padding: 8rpx 0;
413
+        min-width: 180rpx;
414
+
415
+        .popover-item {
416
+            display: flex;
417
+            align-items: center;
418
+            gap: 16rpx;
419
+            padding: 20rpx 32rpx;
420
+            &:active {
421
+                background: #f5f7fa;
422
+            }
423
+
424
+            .popover-text {
425
+                font-size: 28rpx;
426
+                color: #333;
427
+            }
428
+        }
429
+
430
+        .popover-divider {
431
+            height: 1rpx;
432
+            background: #f0f0f0;
433
+            margin: 0 16rpx;
434
+        }
435
+
436
+        .popover-arrow {
437
+            position: absolute;
438
+            top: -16rpx;
439
+            right: 32rpx;
440
+            width: 0;
441
+            height: 0;
442
+            border-left: 16rpx solid transparent;
443
+            border-right: 16rpx solid transparent;
444
+            border-bottom: 16rpx solid #fff;
445
+            filter: drop-shadow(0 -2rpx 2rpx rgba(0, 0, 0, 0.08));
446
+        }
447
+    }
448
+
333 449
     /* 空状态 */
334 450
     .empty {
335 451
         padding: 80rpx 0;

+ 19 - 17
src/pages/repair/components/price/index.vue

@@ -49,8 +49,8 @@
49 49
         <view class="cost-list">
50 50
           <view v-for="(cost, index) in formData.costs" :key="index" class="cost-item">
51 51
             <view class="cost-header">
52
-              <up-select v-model="cost.type" @select="handleCostTypeSelect(cost, index)" :options="costTypeOptions"
53
-                :label="cost.type ? '' : '费用类型'">
52
+              <up-select v-model="cost.type" @select="(e:any) => handleCostTypeSelect(e,index)" :options="costTypeOptions"
53
+                :label="cost.type ? '' : '费用类型'" showOptionsLabel>
54 54
                 <template v-slot:text="{ value }">
55 55
                   <text>{{ cost.type }}</text>
56 56
                 </template>
@@ -93,11 +93,9 @@
93 93
       <view class="form-section">
94 94
         <view class="section-title">其他信息</view>
95 95
         <up-form-item label="预计完成日期" prop="estimatedCompletionDate" required :label-width="100" @click="showDatePicker">
96
-          <template #right>
97 96
             <up-datetime-picker hasInput :show="datePickerShow" v-model="formData.estimatedCompletionDate" mode="date"
98
-              @cancel="datePickerShow = false" @confirm="datePickerShow = false"
97
+              @cancel="handleDateCancel" @confirm="handleDateConfirm($event)"
99 98
               placeholder="请选择预计完成日期"></up-datetime-picker>
100
-          </template>
101 99
         </up-form-item>
102 100
         <up-form-item label="质保期" prop="warrantyPeriod" :label-width="70">
103 101
           <up-select v-model="formData.warrantyPeriod" :options="warrantyPeriodOptions" label="请选择质保期"
@@ -132,6 +130,8 @@ import {
132 130
   warrantyPeriodOptions
133 131
 } from '../public'
134 132
 import type { RepairQuoteForm_Params } from '@/types/repair'
133
+import dayjs from 'dayjs'
134
+
135 135
 const formRef = ref()
136 136
 const datePickerShow = ref(false)
137 137
 // 表单数据
@@ -140,7 +140,7 @@ const formData = ref<RepairQuoteForm_Params>({
140 140
   repairItems: [],
141 141
   laborHours: '2小时',
142 142
   costs: [
143
-    { type: 'PARTS', amount: 0, description: '' },
143
+    { type: '', amount: 0, description: '' },
144 144
   ],
145 145
   totalAmount: 0,
146 146
   remarks: '',
@@ -201,28 +201,20 @@ const removeCost = (index: number) => {
201 201
 
202 202
 const handleSubmit = () => {
203 203
   formRef.value.validate().then(() => {
204
-    // 更新表单数据
205 204
     formData.value.totalAmount = totalAmount.value
206 205
     formData.value.discountAmount = discountAmount.value
207 206
     formData.value.finalAmount = finalAmount.value
208 207
 
209
-    console.log('提交报价', formData.value)
210 208
     uni.showToast({
211 209
       title: '报价提交成功',
212 210
       icon: 'success'
213 211
     })
214 212
 
215
-    // 跳转到订单详情页
216 213
     setTimeout(() => {
217 214
       uni.navigateTo({
218 215
         url: '/pages/repair/components/orderDetail/index?orderId=' + formData.value.orderId,
219 216
       })
220 217
     }, 1500)
221
-  }).catch(() => {
222
-    uni.showToast({
223
-      title: '请完善表单信息',
224
-      icon: 'none'
225
-    })
226 218
   })
227 219
 }
228 220
 
@@ -242,10 +234,10 @@ const handleLaborHoursSelect = (value: any) => {
242 234
   formData.value.laborHours = value.name
243 235
 }
244 236
 
245
-const handleCostTypeSelect = (value: any, index: number) => {
237
+const handleCostTypeSelect = (val:any,index:number) => {
246 238
   formData.value.costs.forEach((cost, i) => {
247
-    if (index === i) {
248
-      cost.type = value.type
239
+    if (index == i) {
240
+      cost.type = val.name
249 241
     }
250 242
   })
251 243
 }
@@ -258,6 +250,16 @@ const showDatePicker = () => {
258 250
   datePickerShow.value = true
259 251
 }
260 252
 
253
+const handleDateCancel = () => {
254
+  datePickerShow.value = false
255
+}
256
+
257
+const handleDateConfirm = (value: any) => {
258
+  datePickerShow.value = false
259
+  formData.value.estimatedCompletionDate = dayjs(value.value).format('YYYY-MM-DD')
260
+  formRef.value?.validateField('estimatedCompletionDate')
261
+}
262
+
261 263
 
262 264
 
263 265
 // 生命周期

+ 3 - 18
src/pages/repair/index.vue

@@ -60,27 +60,12 @@ import { ref } from 'vue'
60 60
 import type { Repair_Result } from '@/types/repair'
61 61
 import { gridList,processSteps} from './components/public'
62 62
 import LineChart from './components/charts/line.vue'
63
-import { hasRole } from '@/utils/utils'
64 63
 import { loginApi } from '@/apis/login'
65 64
 const searchKeyword = ref<string>('')
66 65
 const handleGridClick = (item: Repair_Result) => {
67
-  if(item.label == 'apply'){
68
-    if(hasRole('REPAIRMAN',false)){
69
-      uni.showToast({
70
-        title: '您没有权限访问该功能',
71
-        icon: 'none'
72
-      })
73
-      return false
74
-    }else{
75
-      uni.navigateTo({
76
-        url: item.path,
77
-      })
78
-    }
79
-  }else if(item.label == 'order'){
80
-    uni.navigateTo({
81
-      url: item.path,
82
-    })
83
-  }
66
+  uni.navigateTo({
67
+    url: item.path,
68
+  })
84 69
 }
85 70
 const handleLogout = () => {
86 71
   uni.removeStorageSync('userInfo')

+ 1 - 1
src/types/repair.d.ts

@@ -51,7 +51,7 @@ export interface RepairQuoteForm_Params {
51 51
   totalAmount: number
52 52
   remarks: string
53 53
   technician: string
54
-  estimatedCompletionDate: string
54
+  estimatedCompletionDate: string | Date
55 55
   warrantyPeriod: string
56 56
   urgency: 'normal' | 'urgent' | 'emergency'
57 57
   discountRate: number

+ 2 - 3
src/utils/http.ts

@@ -13,7 +13,6 @@ interface RequestOptions {
13 13
   toastError?: boolean
14 14
 }
15 15
 
16
-// 扩展 Headers 类型,添加 Authorization
17 16
 interface CustomHeaders {
18 17
   'Content-Type': string
19 18
   Authorization?: string
@@ -35,7 +34,7 @@ class HttpRequest {
35 34
       'Content-Type': 'application/json'
36 35
     }
37 36
     if (token) {
38
-      headers.Authorization = token
37
+      headers.Authorization = 'Bearer ' + token
39 38
     }
40 39
     return headers
41 40
   }
@@ -328,4 +327,4 @@ const http = new HttpRequest({})
328 327
 export { http }
329 328
 export const createHttp = (config?: { timeout?: number }) => {
330 329
   return new HttpRequest(config || {})
331
-}
330
+}