Kaynağa Gözat

零售端-新增售后列表功能

ouyang 1 gün önce
ebeveyn
işleme
5bfc78143d

+ 3 - 3
mallApp/src/api/refund/index.js

@@ -1,6 +1,6 @@
 /**
  * 商城售后申请 API
- * 供 pages/order/refund、订单详情「申请售后」使用
+ * 供 pages/order/refund 申请页、pages/order/refund-list 列表与详情使用
  */
 import https from '@/plugins/luch-request_0.0.7/request'
 
@@ -14,12 +14,12 @@ export const createRefund = data => {
 	return https.post('/refund/create-order', data)
 }
 
-/** 顾客撤销待审核申请 */
+/** 顾客撤销待审核申请;列表「修改申请」会先撤销再重新填写 */
 export const cancelRefund = data => {
 	return https.post('/refund/cancel-order', data)
 }
 
-/** 顾客售后申请列表 */
+/** 顾客售后申请列表;status: all|0|1|closed */
 export const refundList = data => {
 	return https.get('/refund/list', data)
 }

+ 394 - 0
mallApp/src/components/refund/refund-card.vue

@@ -0,0 +1,394 @@
+<!--
+  商城售后列表/详情卡片
+  供 refund-list、refund-detail 使用;展示店铺、商品、退款类型与操作按钮
+-->
+<template>
+  <view class="refund-card" @click="onCardClick">
+    <!-- 店铺 + 状态 -->
+    <view class="card-header">
+      <view class="shop-row">
+        <!-- 店铺图标与订单列表 order-item 一致:dianpu-fill 雪碧图 -->
+        <sprite-icon name="dianpu-fill" :size="35" custom-class="member-crown-icon" />
+        <text class="shop-name">{{ info.hdName || '花店' }}</text>
+      </view>
+      <text class="status-text" :class="'tone-' + statusTone">{{ info.statusTitle || info.statusText }}</text>
+    </view>
+
+    <!-- 商品行:申请勾选快照;仅退款无明细时后端用原单首件兜底 -->
+    <view
+      v-for="(goods, index) in displayGoods"
+      :key="index"
+      class="goods-row"
+      :class="{ 'goods-row--first': index === 0 }"
+    >
+      <image class="goods-cover" :src="goodsCover(goods)" mode="aspectFill" />
+      <view class="goods-info">
+        <text class="goods-name">{{ goods.name || '商品' }}</text>
+        <text v-if="goods.spec" class="goods-spec">{{ goods.spec }}</text>
+        <text class="goods-price">¥{{ formatPrice(goods.price) }}</text>
+      </view>
+      <text class="goods-num">x{{ goods.num || 1 }}</text>
+    </view>
+
+    <!-- 退款摘要 -->
+    <view class="summary-row">
+      <view class="summary-left">
+        <text class="type-tag" :class="refundType == 1 ? 'type-tag--return' : 'type-tag--money'">
+          {{ info.refundTypeText || (refundType == 1 ? '退货退款' : '仅退款') }}
+        </text>
+        <text class="reason-text">{{ info.reasonText || '顾客申请售后' }}</text>
+      </view>
+      <text class="refund-price" :class="'tone-' + statusTone">¥{{ formatPrice(info.refundPrice) }}</text>
+    </view>
+
+    <!-- 状态提示 -->
+    <view v-if="info.statusTip" class="tip-row">
+      <view class="tip-dot" :class="'tone-bg-' + statusTone"></view>
+      <text class="tip-text" :class="'tone-' + statusTone">{{ info.statusTip }}</text>
+    </view>
+
+    <!-- 操作按钮:列表看详情,详情看原订单 -->
+    <view class="action-row" @click.stop>
+      <!-- 联系客服与订单列表 order-item 一致 -->
+      <view class="action-btn action-btn--ghost" @click.stop="onContact">联系客服</view>
+      <view
+        v-if="scene === 'list'"
+        class="action-btn"
+        :class="info.canModify ? 'action-btn--outline' : 'action-btn--primary'"
+        @click.stop="onDetail"
+      >查看详情</view>
+      <view
+        v-else
+        class="action-btn action-btn--outline"
+        @click.stop="onOrder"
+      >查看订单</view>
+      <view
+        v-if="info.canModify"
+        class="action-btn action-btn--primary"
+        @click.stop="onModify"
+      >修改申请</view>
+    </view>
+  </view>
+</template>
+
+<script>
+/**
+ * 售后卡片:列表点卡片/查看详情进详情页;处理中可撤销后重新申请
+ */
+export default {
+  name: 'RefundCard',
+  props: {
+    /** 列表/详情接口 formatCustomRow 后的申请行 */
+    info: {
+      type: Object,
+      default() {
+        return {}
+      }
+    },
+    /** list 展示「查看详情」;detail 展示「查看订单」 */
+    scene: {
+      type: String,
+      default: 'list'
+    }
+  },
+  computed: {
+    statusTone() {
+      return this.info.statusTone || 'pending'
+    },
+    refundType() {
+      return Number(this.info.refundType) || 2
+    },
+    displayGoods() {
+      if (this.info.goodsList && this.info.goodsList.length) {
+        return this.info.goodsList
+      }
+      if (this.info.goods && this.info.goods.name) {
+        return [this.info.goods]
+      }
+      return [{ name: '售后商品', cover: '', spec: '', price: this.info.refundPrice, num: 1 }]
+    }
+  },
+  methods: {
+    /** 金额保留两位,对齐设计稿 ¥188.00 */
+    formatPrice(val) {
+      const n = parseFloat(val)
+      if (isNaN(n)) {
+        return '0.00'
+      }
+      return n.toFixed(2)
+    },
+    goodsCover(goods) {
+      if (goods && goods.cover) {
+        return goods.cover
+      }
+      return `${this.$constant.imgUrl}/retail/default-img.png`
+    },
+    onCardClick() {
+      if (this.scene === 'list') {
+        this.$emit('detail', this.info)
+      }
+    },
+    onContact() {
+      this.$emit('contact', this.info)
+    },
+    onDetail() {
+      this.$emit('detail', this.info)
+    },
+    onOrder() {
+      this.$emit('order', this.info)
+    },
+    onModify() {
+      this.$emit('modify', this.info)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.refund-card {
+  margin: 0 24upx 20upx;
+  padding: 28upx 24upx 24upx;
+  background: #ffffff;
+  border-radius: 16upx;
+  box-sizing: border-box;
+}
+
+.card-header {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 24upx;
+}
+
+.shop-row {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  flex: 1;
+  min-width: 0;
+  margin-right: 16upx;
+}
+
+.shop-name {
+  margin-left: 12upx;
+  font-size: 30upx;
+  font-weight: 600;
+  color: $fontColorMain;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.status-text {
+  flex-shrink: 0;
+  margin-left: 16upx;
+  font-size: 26upx;
+  font-weight: 500;
+}
+
+.goods-row {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-top: 20upx;
+
+  &--first {
+    margin-top: 0;
+  }
+}
+
+.goods-cover {
+  width: 140upx;
+  height: 140upx;
+  border-radius: 12upx;
+  background: #f5f5f5;
+  flex-shrink: 0;
+}
+
+.goods-info {
+  flex: 1;
+  min-width: 0;
+  margin-left: 20upx;
+  display: flex;
+  flex-direction: column;
+}
+
+.goods-name {
+  font-size: 28upx;
+  color: #333333;
+  line-height: 1.4;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+}
+
+.goods-spec {
+  margin-top: 8upx;
+  font-size: 24upx;
+  color: #999999;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.goods-price {
+  margin-top: 12upx;
+  font-size: 26upx;
+  color: #333333;
+}
+
+.goods-num {
+  flex-shrink: 0;
+  margin-left: 16upx;
+  font-size: 24upx;
+  color: #999999;
+  align-self: center;
+}
+
+.summary-row {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  margin-top: 24upx;
+}
+
+.summary-left {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  flex: 1;
+  min-width: 0;
+}
+
+.type-tag {
+  flex-shrink: 0;
+  padding: 4upx 12upx;
+  border-radius: 6upx;
+  font-size: 22upx;
+  line-height: 1.3;
+}
+
+.type-tag--money {
+  color: #FA8C16;
+  background: #fff4e8;
+}
+
+.type-tag--return {
+  color: #07C160;
+  background: #eef8e8;
+}
+
+.reason-text {
+  margin-left: 12upx;
+  font-size: 24upx;
+  color: #666666;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.refund-price {
+  flex-shrink: 0;
+  margin-left: 16upx;
+  font-size: 32upx;
+  font-weight: 700;
+}
+
+.tip-row {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-top: 20upx;
+}
+
+.tip-dot {
+  width: 12upx;
+  height: 12upx;
+  border-radius: 50%;
+  flex-shrink: 0;
+}
+
+.tip-text {
+  margin-left: 10upx;
+  font-size: 24upx;
+  line-height: 1.4;
+  flex: 1;
+}
+
+.action-row {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: flex-end;
+  margin-top: 24upx;
+}
+
+.action-btn {
+  min-width: 140upx;
+  height: 56upx;
+  padding: 0 22upx;
+  margin-left: 12upx;
+  border-radius: 28upx;
+  font-size: 24upx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-sizing: border-box;
+
+  &:first-child {
+    margin-left: 0;
+  }
+}
+
+.action-btn--ghost {
+  min-width: 160upx;
+  height: 50upx;
+  padding: 0 28upx;
+  line-height: 50upx;
+  font-size: 26upx;
+  border-radius: 10upx;
+  color: $fontColorMain;
+  background: #ffffff;
+  border: 1upx solid #d9d9d9;
+}
+
+.action-btn--outline {
+  color: #07C160;
+  background: #ffffff;
+  border: 1upx solid #07C160;
+}
+
+.action-btn--primary {
+  color: #ffffff;
+  background: #07C160;
+  border: 1upx solid #07C160;
+}
+
+.tone-pending {
+  color: #FA8C16;
+}
+
+.tone-success {
+  color: #07C160;
+}
+
+.tone-closed {
+  color: #999999;
+}
+
+.tone-bg-pending {
+  background: #FA8C16;
+}
+
+.tone-bg-success {
+  background: #07C160;
+}
+
+.tone-bg-closed {
+  background: #999999;
+}
+</style>

+ 3 - 1
mallApp/src/pages.json

@@ -131,7 +131,9 @@
                 { "path": "list", "style": { "navigationBarTitleText": "订单列表" } },
                 { "path": "detail", "style": { "navigationBarTitleText": "订单详情" } },
                 { "path": "comment", "style": { "navigationBarTitleText": "评价" } },
-                { "path": "refund", "style": { "navigationBarTitleText": "申请售后" } }
+                { "path": "refund", "style": { "navigationBarTitleText": "申请售后" } },
+                { "path": "refund-list", "style": { "navigationBarTitleText": "退款售后", "enablePullDownRefresh": true } },
+                { "path": "refund-detail", "style": { "navigationBarTitleText": "售后详情" } }
             ]
         },
         {

+ 7 - 3
mallApp/src/pages/home/user.vue

@@ -124,12 +124,12 @@ export default {
     return {
       constant: this.$constant,
       navMetrics: getNavBarMetrics(),
-      /** 订单快捷入口,status 对应 order.vue tabs.key */
+      /** 订单快捷入口:status 对应订单 Tab;退款/售后走独立列表 url */
       orderShortcuts: [
         { key: "pay", name: "待付款", icon: "qianbao", iconSize: 48, status: "1", theme: "pink" },
         { key: "delivery", name: "待配送", icon: "huoche-da", iconSize: 48, status: "2", theme: "green" },
         { key: "receive", name: "待收货", icon: "baoguo", iconSize: 48, status: "3", theme: "green" },
-        { key: "refund", name: "退款/售后", icon: "fanghu-yuan", iconSize: 48, status: "0", theme: "pink" }
+        { key: "refund", name: "退款/售后", icon: "fanghu-yuan", iconSize: 48, url: "/pages/order/refund-list", theme: "pink" }
       ],
       /** 服务菜单 */
       serviceItems: [
@@ -219,11 +219,15 @@ export default {
         query: { status: "0" }
       });
     },
-    /** 按订单状态跳转订单 Tab */
+    /** 订单快捷入口:退款/售后进独立列表,其余进订单 Tab */
     goOrderStatus(item) {
       if (!this.requireLogin()) {
         return;
       }
+      if (item.url) {
+        this.pageTo({ url: item.url });
+        return;
+      }
       this.pageTo({
         url: "/pages/home/order",
         type: 4,

+ 228 - 0
mallApp/src/pages/order/refund-detail.vue

@@ -0,0 +1,228 @@
+<!--
+  商城售后详情
+  从退款售后列表「查看详情」进入;展示申请快照,处理中可修改申请
+-->
+<template>
+  <view class="refund-detail-page">
+    <block v-if="detail.id">
+      <refund-card
+        :info="detail"
+        scene="detail"
+        @contact="contactService"
+        @order="goOrder"
+        @modify="modifyApply"
+      />
+      <view class="extra-card">
+        <view class="extra-row extra-row--first">
+          <text class="extra-label">售后单号</text>
+          <text class="extra-value">{{ detail.orderSn || '--' }}</text>
+        </view>
+        <view class="extra-row">
+          <text class="extra-label">申请时间</text>
+          <text class="extra-value">{{ detail.addTime || '--' }}</text>
+        </view>
+        <view v-if="detail.auditTime && detail.auditTime !== '0000-00-00 00:00:00'" class="extra-row">
+          <text class="extra-label">审核时间</text>
+          <text class="extra-value">{{ detail.auditTime }}</text>
+        </view>
+        <view v-if="detail.remark" class="extra-row">
+          <text class="extra-label">申请说明</text>
+          <text class="extra-value">{{ detail.remark }}</text>
+        </view>
+        <view v-if="detail.status == 2 && detail.rejectReason" class="extra-row">
+          <text class="extra-label">驳回原因</text>
+          <text class="extra-value extra-value--reject">{{ detail.rejectReason }}</text>
+        </view>
+      </view>
+    </block>
+    <block v-else>
+      <app-wrapper-empty title="暂无售后详情" :is-empty="!detail.id && !loading" />
+    </block>
+  </view>
+</template>
+
+<script>
+/**
+ * 售后详情:读 /refund/detail;联系客服与订单列表 order-list-view 同一套会话参数
+ */
+import RefundCard from '@/components/refund/refund-card.vue'
+import AppWrapperEmpty from '@/components/app-wrapper-empty'
+import { refundDetail, cancelRefund } from '@/api/refund'
+import { currentInfo } from '@/api/user'
+
+export default {
+  name: 'refundDetail',
+  components: {
+    RefundCard,
+    AppWrapperEmpty
+  },
+  data() {
+    return {
+      applyId: 0,
+      loading: false,
+      inited: false,
+      detail: {},
+      user: { name: '', smallAvatar: '', id: 0 }
+    }
+  },
+  onLoad(option) {
+    this.applyId = Number((option && option.id) || 0)
+    this.loadUserInfo()
+    this.loadDetail().then(() => {
+      this.inited = true
+    }).catch(() => {
+      this.inited = true
+    })
+  },
+  onShow() {
+    if (!this.inited || this.applyId <= 0) {
+      return
+    }
+    this.loadDetail()
+  },
+  methods: {
+    loadUserInfo() {
+      currentInfo().then((res) => {
+        if (res.code == 1 && res.data && res.data.info) {
+          this.user = res.data.info
+        } else {
+          this.user = { name: '', smallAvatar: '', id: 0 }
+        }
+      })
+    },
+    /** 拉取单条申请,字段与列表卡片一致 */
+    loadDetail() {
+      if (this.applyId <= 0) {
+        this.$msg('缺少售后单')
+        return Promise.resolve()
+      }
+      this.loading = true
+      uni.showLoading({ mask: true, title: '加载中' })
+      return refundDetail({ id: this.applyId }).then((res) => {
+        uni.hideLoading()
+        this.loading = false
+        if (res.code == 1) {
+          this.detail = res.data || {}
+        } else {
+          this.$msg(res.msg || '获取售后详情失败')
+        }
+      }).catch(() => {
+        uni.hideLoading()
+        this.loading = false
+      })
+    },
+    /**
+     * 打开门店客服聊天,参数与订单列表联系客服一致
+     * customId 必须是该店 xhCustom.id;字符串 "0" 不能当有效值传给 chatPage
+     */
+    contactService() {
+      const item = this.detail
+      if (!item) {
+        return
+      }
+      const customId = Number(item.customId)
+      const shopId = Number(item.shopId)
+      if (!customId || customId <= 0) {
+        this.$msg('客户数据异常,请稍后再试')
+        return
+      }
+      uni.navigateTo({
+        url: '/pages/chat/chatPage',
+        success: (res) => {
+          res.eventChannel.emit('acceptDataFromOpenerPage', {
+            shopId: shopId,
+            customId: customId,
+            userId: (this.loginInfo && this.loginInfo.id) || this.user.id || '',
+            name: this.user.name || '',
+            avatar: this.user.smallAvatar || '',
+            chatPerson: item.hdName || ''
+          })
+        }
+      })
+    },
+    /** 回到原零售订单,方便核对购买信息 */
+    goOrder() {
+      const item = this.detail
+      if (!item || !item.orderId) {
+        return
+      }
+      this.pageTo({
+        url: '/pages/order/detail?id=' + item.orderId + '&account=' + (item.shopId || 0) + '&hdId=' + (item.hdId || 0)
+      })
+    },
+    modifyApply() {
+      const item = this.detail
+      if (!item || !item.id) {
+        return
+      }
+      uni.showModal({
+        title: '修改申请',
+        content: '修改需先撤销当前申请,再重新填写。是否继续?',
+        success: (res) => {
+          if (!res.confirm) {
+            return
+          }
+          uni.showLoading({ mask: true, title: '处理中' })
+          cancelRefund({ id: item.id }).then((resp) => {
+            uni.hideLoading()
+            if (resp.code == 1) {
+              this.pageTo({ url: '/pages/order/refund?id=' + item.orderId, type: 2 })
+            }
+          }).catch(() => {
+            uni.hideLoading()
+          })
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.refund-detail-page {
+  min-height: 100vh;
+  background: #f5f5f5;
+  padding-top: 20upx;
+  padding-bottom: 40upx;
+}
+
+.extra-card {
+  margin: 0 24upx;
+  padding: 8upx 24upx 16upx;
+  background: #ffffff;
+  border-radius: 16upx;
+}
+
+.extra-row {
+  display: flex;
+  flex-direction: row;
+  align-items: flex-start;
+  justify-content: space-between;
+  padding: 20upx 0;
+  border-top: 1upx solid #f3f4f6;
+  margin-top: 0;
+
+  &--first {
+    border-top: none;
+  }
+}
+
+.extra-label {
+  flex-shrink: 0;
+  font-size: 26upx;
+  color: #999999;
+}
+
+.extra-value {
+  flex: 1;
+  margin-left: 24upx;
+  font-size: 26upx;
+  color: #333333;
+  text-align: right;
+  word-break: break-all;
+}
+
+.extra-value--reject {
+  color: #ff4d4f;
+}
+</style>

+ 311 - 0
mallApp/src/pages/order/refund-list.vue

@@ -0,0 +1,311 @@
+<!--
+  商城「退款售后」列表
+  从「我的」退款/售后进入;按全部/处理中/已退款/已关闭筛选 xhMallRefundApply
+-->
+<template>
+  <view class="refund-list-page">
+    <view class="tab-bar">
+      <view
+        v-for="(tab, index) in tabs"
+        :key="tab.key"
+        class="tab-item"
+        @click="changeTab(index)"
+      >
+        <view class="tab-inner" :class="{ 'is-active': tabIndex === index }">
+          <text class="tab-text">{{ tab.name }}</text>
+          <view v-if="tab.key === '0' && pendingCount > 0" class="tab-badge">
+            <text class="tab-badge__num">{{ pendingCount > 99 ? '99+' : pendingCount }}</text>
+          </view>
+        </view>
+        <view class="tab-line" :class="{ 'is-active': tabIndex === index }"></view>
+      </view>
+    </view>
+
+    <view class="list-body">
+      <block v-if="!$util.isEmpty(list.data)">
+        <refund-card
+          v-for="item in list.data"
+          :key="item.id"
+          :info="item"
+          scene="list"
+          @detail="goDetail"
+          @contact="contactService"
+          @modify="modifyApply"
+        />
+        <view class="load-more">
+          <text v-if="list.loading">加载中...</text>
+          <text v-else-if="list.finished">没有更多了</text>
+        </view>
+      </block>
+      <block v-else>
+        <app-wrapper-empty title="暂无售后记录" :is-empty="$util.isEmpty(list.data)" />
+      </block>
+    </view>
+  </view>
+</template>
+
+<script>
+/**
+ * 退款售后列表:Tab 对应申请 status;处理中角标来自 pendingCount
+ */
+import RefundCard from '@/components/refund/refund-card.vue'
+import AppWrapperEmpty from '@/components/app-wrapper-empty'
+import { list } from '@/mixins'
+import { refundList, cancelRefund } from '@/api/refund'
+import { currentInfo } from '@/api/user'
+
+export default {
+  name: 'refundList',
+  components: {
+    RefundCard,
+    AppWrapperEmpty
+  },
+  mixins: [list],
+  data() {
+    return {
+      tabIndex: 0,
+      pendingCount: 0,
+      /** 首次 onLoad 完成前不在 onShow 里重拉,避免进页连打两次 */
+      inited: false,
+      user: { name: '', smallAvatar: '', id: 0 },
+      tabs: [
+        { name: '全部', key: 'all' },
+        { name: '处理中', key: '0' },
+        { name: '已退款', key: '1' },
+        { name: '已关闭', key: 'closed' }
+      ]
+    }
+  },
+  onLoad() {
+    this.loadUserInfo()
+    this.reload().then(() => {
+      this.inited = true
+    }).catch(() => {
+      this.inited = true
+    })
+  },
+  onShow() {
+    // 从详情/申请页返回后刷新,角标与状态及时更新
+    if (!this.inited) {
+      return
+    }
+    this.reload()
+  },
+  onReachBottom() {
+    if (!this.list.finished) {
+      this.fetchList()
+    }
+  },
+  onPullDownRefresh() {
+    this.reload().then(() => {
+      uni.stopPullDownRefresh()
+    })
+  },
+  methods: {
+    /** 重置到第一页再拉列表 */
+    reload() {
+      this.resetList()
+      return this.fetchList()
+    },
+    /**
+     * 按当前 Tab 拉取申请列表
+     * status=all 不筛选;closed 为驳回+取消
+     */
+    fetchList() {
+      const tab = this.tabs[this.tabIndex] || this.tabs[0]
+      return refundList({
+        status: tab.key,
+        page: this.list.page
+      }).then((res) => {
+        if (res.code == 1) {
+          if (!res.data) {
+            res.data = {}
+          }
+          if (!res.data.list) {
+            res.data.list = []
+          }
+          this.completes(res)
+          this.pendingCount = Number(res.data.pendingCount) || 0
+        } else {
+          this.list.loading = false
+          this.list.finished = true
+          this.$msg(res.msg || '获取售后列表失败')
+        }
+      }).catch(() => {
+        this.list.loading = false
+        this.list.finished = true
+      })
+    },
+    changeTab(index) {
+      if (this.tabIndex === index) {
+        return
+      }
+      uni.pageScrollTo({ scrollTop: 0, duration: 0 })
+      this.tabIndex = index
+      this.reload()
+    },
+    loadUserInfo() {
+      currentInfo().then((res) => {
+        if (res.code == 1 && res.data && res.data.info) {
+          this.user = res.data.info
+        } else {
+          this.user = { name: '', smallAvatar: '', id: 0 }
+        }
+      })
+    },
+    /** 进入售后详情 */
+    goDetail(item) {
+      if (!item || !item.id) {
+        return
+      }
+      this.pageTo({ url: '/pages/order/refund-detail?id=' + item.id })
+    },
+    /**
+     * 打开门店客服聊天,参数与订单列表联系客服一致
+     * customId 必须是该店 xhCustom.id;字符串 "0" 不能当有效值传给 chatPage
+     * @param {Object} item 售后申请行
+     */
+    contactService(item) {
+      if (!item) {
+        return
+      }
+      const customId = Number(item.customId)
+      const shopId = Number(item.shopId)
+      if (!customId || customId <= 0) {
+        this.$msg('客户数据异常,请稍后再试')
+        return
+      }
+      uni.navigateTo({
+        url: '/pages/chat/chatPage',
+        success: (res) => {
+          res.eventChannel.emit('acceptDataFromOpenerPage', {
+            shopId: shopId,
+            customId: customId,
+            userId: (this.loginInfo && this.loginInfo.id) || this.user.id || '',
+            name: this.user.name || '',
+            avatar: this.user.smallAvatar || '',
+            chatPerson: item.hdName || ''
+          })
+        }
+      })
+    },
+    /**
+     * 修改申请:待审核记录只能先撤销再重新提交,没有单独的改单接口
+     */
+    modifyApply(item) {
+      if (!item || !item.id) {
+        return
+      }
+      uni.showModal({
+        title: '修改申请',
+        content: '修改需先撤销当前申请,再重新填写。是否继续?',
+        success: (res) => {
+          if (!res.confirm) {
+            return
+          }
+          uni.showLoading({ mask: true, title: '处理中' })
+          cancelRefund({ id: item.id }).then((resp) => {
+            uni.hideLoading()
+            if (resp.code == 1) {
+              this.pageTo({ url: '/pages/order/refund?id=' + item.orderId })
+            }
+          }).catch(() => {
+            uni.hideLoading()
+          })
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.refund-list-page {
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+
+.tab-bar {
+  position: sticky;
+  top: 0;
+  z-index: 20;
+  display: flex;
+  flex-direction: row;
+  align-items: stretch;
+  height: 88upx;
+  background: #ffffff;
+  border-bottom: 1upx solid #eeeeee;
+}
+
+.tab-item {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+}
+
+.tab-inner {
+  position: relative;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: center;
+}
+
+.tab-text {
+  font-size: 28upx;
+  color: #666666;
+  line-height: 40upx;
+
+  .is-active & {
+    color: #1f7a3d;
+    font-weight: 600;
+  }
+}
+
+.tab-badge {
+  position: absolute;
+  top: -10upx;
+  right: -28upx;
+  min-width: 28upx;
+  height: 28upx;
+  padding: 0 6upx;
+  border-radius: 14upx;
+  background: #ff4d4f;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-sizing: border-box;
+}
+
+.tab-badge__num {
+  font-size: 18upx;
+  color: #ffffff;
+  line-height: 1;
+}
+
+.tab-line {
+  width: 48upx;
+  height: 6upx;
+  margin-top: 8upx;
+  border-radius: 6upx;
+  background: transparent;
+
+  &.is-active {
+    background: #1f7a3d;
+  }
+}
+
+.list-body {
+  padding-top: 20upx;
+  padding-bottom: 40upx;
+}
+
+.load-more {
+  padding: 16upx 0 40upx;
+  text-align: center;
+  font-size: 24upx;
+  color: #999999;
+}
+</style>