复杂判断的优雅处理

实际业务场景及问题

场景1、在订单列表、订单详情中,不同状态(待付款/待发货/出库中/待收货/已完成)的订单,展示的操作按钮不同,而且列表中按钮展示的是一种形式,点击进去在该订单的详情中,展示的按钮又是另外一种形式;

场景2、商品详情、某些活动页面(其中涉及到了商品),或者是APP内嵌的H5页面,不同端/不同身份,展示的价格不同,价格文案也不同;

示例

处理方法与思路

  • 简单说明:2个场景不论怎么说,非常简单,不复杂,不同状态、场景显示不同的东西即可,最开始我记得场景很简单,页面内使用if判断,就可以完成需求,但是后来随着产品迭代,情况越来越复杂,这时候只能针对情况去单独抽出来做统一方法,方便后期继续增加和管理;

  • 思路:利用Map结构,将所涉及到的情况枚举,key-value清晰对应,一目了然;

先从场景1实际举例,按钮的文字不同、颜色样式不同、操作不同、列表页面的按钮与详情页的按钮展示又不同;
先上图说核心关键部分:
方法
Map结构
Map结构
get取值
其实就是做好对应的Map结构,最终遍历list列表,将符合的情况填进去,返回新的列表;

再以场景2实际举例,APP分为安卓与IOS,显示的价格与文案是一种,小程序显示的价格与文案是一种,公众号H5显示的价格与文案又是一种,上图说核心关键部分:
场景2

代码展示

场景1完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
import { Dialog } from 'vant'

/**
* @description: 按钮处理
* @param {*}
* 待付款:status=1
* 待发货:status=2
* 出库中 status=21 前端自定义 出库中 status=21 -> 21: 由于服务端定义的'出库中'status状态仍然为2(出库中状态是待发货状态的子集), 请求时新增了out_ware字段来区分,前端为了统一和方便, 自定义为21
* 待收货:status=3
* 已完成:status=5
* 已关闭:status=7
* 售后:status=6
* 已下架:goods_status=0
* 预上架:goods_status=1
* 已上架:goods_status=10
*/
export const BtnListHandle = function (itemObj, cameFrom = '', routerFrom = '') {
try {
if (!itemObj) return
const { out_ware, goods_status, type, pay_overtime, prescription_status, prescription_notice, show_edit_address } = itemObj
let status = +itemObj.status
if (+status === 2 && out_ware && +out_ware === 1) { // 出库中状态
status = 21 // 前端自定义 出库中 status=21 -> 设置21的原因: 由于服务端定义的'出库中'status状态仍然为2(出库中状态是待发货状态的子集), 请求时新增了out_ware字段来区分,前端为了统一和方便, 自定义为21
}
const show_pay = itemObj.credit_notice ? itemObj.credit_notice.show_pay : 0
const btnMap = new Map([
[101, { btn_name: '联系客服', btn_action: 'contact', sty: 'normal' }],
[102, { btn_name: '订单回执', btn_action: 'orderReturn', sty: 'normal' }],
[103, { btn_name: '取消订单', btn_action: 'cancel', sty: 'normal' }],
[104, { btn_name: '立即付款', btn_action: 'pay', sty: 'highLight' }], // 带有倒计时的付款
[105, +type === 15 && +show_pay === 1 ? { btn_name: '付款购买', btn_action: 'freeOrderPay', sty: 'highLight' } : null], // 先用后付订单的付款购买 (且要处于 退款退货 情况之外)
[106, { btn_name: '查看物流', btn_action: 'logistics', sty: 'normal' }],
[107, +type === 16 ? null : { btn_name: '申请售后', btn_action: 'applyAfter', sty: 'normal' }],
[108, +goods_status === 10 ? { btn_name: '再次购买', btn_action: 'reBuy', sty: 'normal' } : { btn_name: '申请复团', btn_action: 'applyBuy', sty: 'normal' }], // 再次购买/申请复团
[109, { btn_name: '确认收货', btn_action: 'confirm', sty: 'normal' }],
[110, { btn_name: '删除订单', btn_action: 'del', sty: 'normal' }], // 删除订单
[111, +show_edit_address === 1 ? { btn_name: '修改地址', btn_action: 'changeAddress', sty: 'normal' } : null] // 修改地址
])

const delBtnList = +type === 15 && +show_pay === 1 ? [] : [110] // 已完成&&先用后付&&未付款 的订单,不展示删除订单按钮
const btnListMap = new Map([
[1, [101, 102, 103, 104]], // 待付款 status=1
[2, [111, 101, 102, 103, 105]], // 待发货 status=2
[21, [101, 102]], // 前端自定义 出库中 status=21 -> 设置21的原因: 由于服务端定义的'出库中'status状态仍然为2(出库中状态是待发货状态的子集), 请求时新增了out_ware字段来区分,前端为了统一和方便, 自定义为21
[3, [101, 102, 106, 107, 105]], // 待收货 status=3
[5, [...delBtnList, 101, 107, 108, 105]], // 已完成 status=5
[7, [...delBtnList, 101, 108]], // 已关闭 status=7
[6, [101, 108, 105]] // 售后状态 status=6
])

if (cameFrom === 'orderDetail') {
const delBtnList = routerFrom === 'afterSale' || (+type === 15 && +show_pay === 1) ? [] : [110] // 特殊情况处理,针对 已完成/已关闭 状态的订单,需要显示 删除按钮,但是从 售后跳到订单详情的情况 || 先用后付订单,不显示 删除按钮
btnListMap.set(2, [111, 101, 102, 103, 105]) // 待发货 status=2
btnListMap.set(3, [101, 102, 106, 107, 109, 105])// 待收货 status=3 订单详情,新增'确认收货'
btnListMap.set(5, [...delBtnList, 101, 102, 107, 108, 105])// 已完成 status=5 订单详情,新增'订单回执'
btnListMap.set(7, [...delBtnList])// 已完成 status=5 订单详情,新增'订单回执'
}

const result = []
let _list = btnListMap.get(+status)

if (!_list) return result
_list.forEach(it => {
const item = btnMap.get(+it)
if (item) {
// 立即付款的情况
if (+it === 104) { item.btn_time = +pay_overtime * 1000 }
result.push(item)
}
})
return result
} catch (err) {
throw err
}
}

/**
* @description: 按钮点击事件
* @param {*} action
* @param {*} itemObj
*/
export const BtnClickHandle = function (action, itemObj) {
console.log('BtnClickJump')
console.log(action)
console.log(itemObj)
if (!action || !itemObj || Object.keys(itemObj).length === 0) return

// 医药 - 补充信息/问诊开方
const midicine = async () => {
try {
const { prescription_status, prescription_notice } = itemObj
if (+prescription_status !== 2 || !prescription_notice || Object.keys(prescription_notice).length === 0) return
const { step, url } = prescription_notice
switch (+step) {
case 1: // 补充信息
this.$router.push({ name: "medicineBaseInfoIndex" })
break;

case 2: // 问诊开方
console.log('问诊开方')
break;
}
} catch (err) {
throw err
}
}

// 修改地址
const changeAddress = async () => {
try {
const { id } = itemObj
await this.$api.order.checkOrderExport({ order_id: id }, { loading: true })
this.$router.push({ name: 'changeAddress', query: { order_id: +id } })
} catch (err) {
console.log(err)
}
}

// 联系客服
const contact = () => { this.$emit('showContact', itemObj) }

// 订单回执
const orderReturn = async () => {
const { id, is_child, status } = itemObj

console.log(`id:${id} , is_child:${is_child}, status:${status}`)

if (+status === 1) { // 待付款状态, 不管是不是多商品情况, 直接显示canvas
if (Object.keys(this.orderReturnDetail).length === 0) {
const { data } = await this.$api.order.getReturnDetail({ id: +id }, { loading: true, loadingDesc: "数据获取中" })
this.orderReturnDetail = data
}
this.showCanvas = true
return
}

if (+is_child === 0) { // 跳转到订单列表
// this.$emit('changeMenu', 2)
this.$router.push({ name: 'orderList' })
return
}

if (Object.keys(this.orderReturnDetail).length === 0) {
const { data } = await this.$api.order.getReturnDetail({ id: +id }, { loading: true, loadingDesc: "数据获取中" })
this.orderReturnDetail = data
}
this.showCanvas = true
}

// 取消订单
const cancel = async () => {
const { id, is_award } = itemObj
if (is_award) { // 中奖订单的情况
Dialog.confirm({
title: "提示",
message: "亲爱的小主,本订单为已中奖订单。【取消订单】后,系统将对本单所中奖品做回收处理,是否确认继续?",
closeOnPopstate: true, // 是否在页面回退时自动关闭
confirmButtonText: "继续",
cancelButtonText: "关闭",
confirmButtonColor: "#FC0D5E"
}).then(async () => {
const { data } = await this.$api.order.judgeCancelOrder({ id: +id }, { loading: true })
if (data.is_can) {
this.orderId = +id
this.cancelVisible = true
} else {
this.$toast(data.message)
}
})
return
}

// 其它情况
const { data } = await this.$api.order.judgeCancelOrder({ id: +id }, { loading: true })
if (data.is_can) {
this.orderId = +id
this.cancelVisible = true
} else {
this.$toast(data.message)
}
}

// 删除订单
const del = async () => {
const { id } = itemObj
Dialog.confirm({
title: '确定删除订单?',
message: '删除后可联系平台客服进行恢复',
closeOnPopstate: true, // 是否在页面回退时自动关闭
confirmButtonText: "确定",
cancelButtonText: "取消",
confirmButtonColor: "#FC0D5E"
}).then(async () => {
const { message } = await this.$api.order.delOrder({ order_id: id }, { loading: true, loadingDesc: '删除中' })
message && this.$toast(message)
this.delSuccess()
})
}

// 立即付款(带有倒计时)
const pay = async () => {
const { id, status, pay_overtime } = itemObj
if (+status === 1 && +pay_overtime <= 0) {
Dialog.alert({
message: "订单已超时,请重新下单",
closeOnPopstate: true // 是否在页面回退时自动关闭
})
return
}
this.$router.push({ name: "orderPay", query: { order_id: +id } })
}

// 付款购买(先用后买的情况)
const freeOrderPay = async () => {
const { id, type } = itemObj
this.$router.push({ name: "orderPay", query: { order_id: +id, type } })
}

// 查看物流
const logistics = async () => {
const { logistics_sn, express_code, id } = itemObj
this.$router.push({ name: "logistics", query: { logistics_sn, express_code, order_id: id } })
}

// 申请售后
const applyAfter = async () => {
try {
const { is_sale_over_day, sale_over_day_name, id, type, sales_id } = itemObj
if (+is_sale_over_day === 1) {
this.$toast(sale_over_day_name)
return
}
if (+type === 15) { // 先用后付
const { data } = await this.$api.order.freeOrderBeforeSalesApply({ order_id: id, sales_id: sales_id || '' }, { loading: true })
if (!data) {
this.$router.push({ name: "createAfterSale2", query: { order_id: +id } })
return
}
const { credit_notice_words, isToast } = data
if (data && credit_notice_words && isToast) {
this.$toast(credit_notice_words)
return
}
this.$router.push({ name: "createAfterSale2", query: { order_id: +id } })
} else {
await this.$api.order.getAfterSaleOrderInfo({ order_id: id }, { loading: true })
this.$router.push({ name: "createAfterSale2", query: { order_id: +id } })
}
} catch (err) {
console.log(err)
}
}

// 确认收货
const confirm = async () => {
const { id, is_review } = itemObj
Dialog.confirm({
title: "确认收货",
message: "请确定您已经收到商品,是否继续?",
closeOnPopstate: true, // 是否在页面回退时自动关闭
confirmButtonText: "确认",
cancelButtonText: "关闭",
confirmButtonColor: "#F9150F"
}).then(async () => {
await this.$api.order.confirmReceipt({ id }, { loading: true })

// 该订单已被评价过
if (+is_review === 1) {
this.$autoToast("success", "收货成功", 1500, -1)
return
}

// 该订单还没有评价,跳转至评价页面 evaluationDetail order_id=5020982&is_review=0
this.$toast('收货成功')
Dialog.confirm({
title: "订单评价",
message: "亲,您当前订单已完成,请进行评价~",
closeOnPopstate: true, // 是否在页面回退时自动关闭
confirmButtonText: "去评价",
cancelButtonText: "关闭",
confirmButtonColor: "#F9150F"
}).then(() => {
this.$router.push({ name: 'evaluationDetail', query: { order_id: id, is_review } })
}).catch(() => {
this.$router.go(-1)
})
})
}

// 再次购买
const reBuy = async () => {
const { goods_id, sku_id } = itemObj
this.$router.push({ name: 'goodsDetail', query: { id: goods_id, sku_id } })
}

// 申请复团
const applyBuy = async () => {
const { goods_id, id } = itemObj
this.recGoodsId = goods_id
this.showGoodsRec = true
await this.$api.order.applyBuy({ goods_id, order_id: id }, { loading: true })
}

const ActionMap = new Map([
['midicine', () => midicine()],
['contact', () => contact()],
['orderReturn', () => orderReturn()],
['cancel', () => cancel()],
['del', () => del()],
['pay', () => pay()],
['freeOrderPay', () => freeOrderPay()],
['logistics', () => logistics()],
['applyAfter', () => applyAfter()],
['confirm', () => confirm()],
['reBuy', () => reBuy()],
['applyBuy', () => applyBuy()],
['changeAddress', () => changeAddress()]
])

const handle = ActionMap.get(action)
if (!handle) return
handle.call(this)
}

场景2完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

import { mapGetters } from 'vuex'

/**
* @description: 价格处理
* @param {Object} dataObj:需要处理的数据
*/
export const PriceHandle = function(dataObj) {
// diff_fee diffFee 差价
// shop_price 普通会员价/团购价
// store_price 店主价
// market_price 市场价/原价
try {
let curSystem = null
if (this.$inApp) {
curSystem = 'App'
} else if (this.$isMiniProgram) {
curSystem = 'MiniProgram'
} else {
curSystem = 'H5'
}

const userInfo = mapGetters(['userInfo']).userInfo.call(this)

const { type } = userInfo.member

const { diff_fee, diffFee, shop_price, store_price, market_price } = dataObj
const _diffFee = diff_fee || diffFee || 0

const MemberTypeMap = new Map([
[1, 'general'], // 会员
[3, 'store'], // 店主
[5, 'store'] // 店主
])

const DisplayMap = new Map([
['H5-general', { oneText: '团购', oneNum: +shop_price, twoText: '原价', twoNum: +market_price, showCart: true, diff: { text: null, num: null } }], // H5-普通会员
['H5-store', { oneText: '团购', oneNum: +shop_price, twoText: '原价', twoNum: +market_price, showCart: true, diff: { text: null, num: null } }], // H5-店主级别
['App-general', { oneText: '团购', oneNum: +shop_price, twoText: '原价', twoNum: +market_price, showCart: true, diff: { text: null, num: null } }], // APP-普通会员
['App-store', { oneText: '店主', oneNum: +store_price, twoText: '团购', twoNum: +shop_price, showCart: false, diff: { text: '赚', num: +_diffFee } }], // H5-店主级别
['MiniProgram-general', { oneText: '团购', oneNum: +shop_price, twoText: '原价', twoNum: +market_price, showCart: true, diff: { text: null, num: null } }], // 小程序-普通会员
['MiniProgram-store', { oneText: '店主', oneNum: +store_price, twoText: '团购', twoNum: +shop_price, showCart: false, diff: { text: '省', num: +_diffFee } }] // 小程序-店主级别
])

const curMemberType = MemberTypeMap.get(+type || 1)
const result = DisplayMap.get(`${curSystem}-${curMemberType}`)
return result
} catch (err) {
console.log(err)
}
}

总结

可以看出实际业务场景中使用Map结构,会优雅很多,逻辑清晰便于维护,否则随着业务量增加,if里面无限嵌套if,代码会非常难读;
给自己挖坑不要紧,后面接手你代码的人心里问候你18遍,这才是作为一个开发者最失败和最悲哀的地方。


复杂判断的优雅处理
https://liujiaweb.cn/posts/6426.html
作者
Liu Jia
发布于
2021年12月8日
许可协议