ソースを参照

feat[litemall-admin, litemall-admin-api]: 支持售后管理页面

Junling Bu 5 年 前
コミット
09f8cf73c6

+ 60 - 0
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminAftersaleController.java

@@ -0,0 +1,60 @@
+package org.linlinjava.litemall.admin.web;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.linlinjava.litemall.admin.annotation.RequiresPermissionsDesc;
+import org.linlinjava.litemall.core.util.JacksonUtil;
+import org.linlinjava.litemall.core.util.ResponseUtil;
+import org.linlinjava.litemall.core.validator.Order;
+import org.linlinjava.litemall.core.validator.Sort;
+import org.linlinjava.litemall.db.domain.LitemallAftersale;
+import org.linlinjava.litemall.db.service.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import java.util.List;
+
+@RestController
+@RequestMapping("/admin/aftersale")
+@Validated
+public class AdminAftersaleController {
+    private final Log logger = LogFactory.getLog(AdminAftersaleController.class);
+
+    @Autowired
+    private LitemallAftersaleService aftersaleService;
+    @Autowired
+    private LitemallOrderService orderService;
+    @Autowired
+    private LitemallOrderGoodsService orderGoodsService;
+
+    @RequiresPermissions("admin:aftersale:list")
+    @RequiresPermissionsDesc(menu = {"商城管理", "售后管理"}, button = "查询")
+    @GetMapping("/list")
+    public Object list(Integer orderId, String aftersaleSn,
+                       @RequestParam(defaultValue = "1") Integer page,
+                       @RequestParam(defaultValue = "10") Integer limit,
+                       @Sort @RequestParam(defaultValue = "add_time") String sort,
+                       @Order @RequestParam(defaultValue = "desc") String order) {
+        List<LitemallAftersale> aftersaleList = aftersaleService.querySelective(orderId, aftersaleSn, page, limit, sort, order);
+        return ResponseUtil.okList(aftersaleList);
+    }
+
+
+    @RequiresPermissions("admin:aftersale:delete")
+    @RequiresPermissionsDesc(menu = {"商城管理", "售后管理"}, button = "删除")
+    @PostMapping("/delete")
+    public Object delete(@RequestBody LitemallAftersale aftersale) {
+        aftersaleService.deleteById(aftersale.getId());
+        return ResponseUtil.ok();
+    }
+
+    @RequiresPermissions("admin:aftersale:batch-delete")
+    @RequiresPermissionsDesc(menu = {"商城管理", "售后管理"}, button = "批量删除")
+    @PostMapping("/batch-delete")
+    public Object batchDelete(@RequestBody String body) {
+        List<Integer> ids = JacksonUtil.parseIntegerList(body, "ids");
+        aftersaleService.deleteByIds(ids);
+        return ResponseUtil.ok();
+    }
+}

+ 25 - 0
litemall-admin/src/api/aftersale.js

@@ -0,0 +1,25 @@
+import request from '@/utils/request'
+
+export function listAftersale(query) {
+  return request({
+    url: '/aftersale/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function deleteAftersale(data) {
+  return request({
+    url: '/aftersale/delete',
+    method: 'post',
+    data
+  })
+}
+
+export function batchDeleteAftersale(data) {
+  return request({
+    url: '/aftersale/batch-delete',
+    method: 'post',
+    data
+  })
+}

+ 10 - 0
litemall-admin/src/router/index.js

@@ -203,6 +203,16 @@ export const asyncRouterMap = [
         }
       },
       {
+        path: 'aftersale',
+        component: () => import('@/views/mall/aftersale'),
+        name: 'aftersale',
+        meta: {
+          perms: ['GET /admin/aftersale/list', 'GET /admin/aftersale/detail', 'POST /admin/order/receive', 'POST /admin/aftersale/complete', 'POST /admin/aftersale/reject'],
+          title: '售后管理',
+          noCache: true
+        }
+      },
+      {
         path: 'issue',
         component: () => import('@/views/mall/issue'),
         name: 'issue',

+ 184 - 0
litemall-admin/src/views/mall/aftersale.vue

@@ -0,0 +1,184 @@
+<template>
+  <div class="app-container">
+
+    <!-- 查询和其他操作 -->
+    <div class="filter-container">
+      <el-input v-model="listQuery.aftersaleSn" clearable class="filter-item" style="width: 200px;" placeholder="请输入服务编号" />
+      <el-input v-model="listQuery.orderId" clearable class="filter-item" style="width: 200px;" placeholder="请输入订单ID" />
+      <el-button v-permission="['GET /admin/aftersale/list']" class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
+      <el-button :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload">导出</el-button>
+    </div>
+
+    <div class="operator-container">
+      <el-button v-permission="['GET /admin/aftersale/batch-delete']" class="filter-item" type="danger" icon="el-icon-delete" @click="handleBatchDelete">批量删除</el-button>
+    </div>
+
+    <!-- 查询结果 -->
+    <el-table v-loading="listLoading" :data="list" element-loading-text="正在查询中。。。" border fit highlight-current-row @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" />
+
+      <el-table-column align="center" label="服务编号" prop="aftersaleSn" />
+      <el-table-column align="center" label="订单ID" prop="orderId" />
+      <el-table-column align="center" label="用户ID" prop="userId" />
+      <el-table-column align="center" label="售后类型" prop="type">
+        <template slot-scope="scope">
+          <el-tag :type="typeTag[scope.row.type]">{{ typeDesc[scope.row.type] }}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="退款原因" prop="reason" />
+      <el-table-column align="center" label="退款价格" prop="amount" />
+      <el-table-column align="center" label="申请时间" prop="addTime" />
+
+      <el-table-column align="center" label="操作" min-width="100" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button type="primary" size="mini" @click="handleRead(scope.row)">详情</el-button>
+          <el-button v-permission="['POST /admin/aftersale/delete']" type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
+
+    <el-tooltip placement="top" content="返回顶部">
+      <back-to-top :visibility-height="100" />
+    </el-tooltip>
+
+  </div>
+</template>
+
+<script>
+import { listAftersale, deleteAftersale, batchDeleteAftersale } from '@/api/aftersale'
+import BackToTop from '@/components/BackToTop'
+import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
+import _ from 'lodash'
+
+export default {
+  name: 'Topic',
+  components: { BackToTop, Pagination },
+  data() {
+    return {
+      list: [],
+      total: 0,
+      listLoading: true,
+      listQuery: {
+        page: 1,
+        limit: 20,
+        aftersaleSn: undefined,
+        orderId: undefined,
+        sort: 'add_time',
+        order: 'desc'
+      },
+      typeTag: [
+        '',
+        'success',
+        'warning'
+      ],
+      typeDesc: [
+        '未收货退款',
+        '不退货退款',
+        '退货退款'
+      ],
+      multipleSelection: [],
+      contentDetail: '',
+      contentDialogVisible: false,
+      downloadLoading: false
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    getList() {
+      this.listLoading = true
+      listAftersale(this.listQuery)
+        .then(response => {
+          this.list = response.data.data.list
+          this.total = response.data.data.total
+          this.listLoading = false
+        })
+        .catch(() => {
+          this.list = []
+          this.total = 0
+          this.listLoading = false
+        })
+    },
+    handleFilter() {
+      this.listQuery.page = 1
+      this.getList()
+    },
+    handleDelete(row) {
+      deleteAftersale(row)
+        .then(response => {
+          this.$notify.success({
+            title: '成功',
+            message: '删除专题成功'
+          })
+          const index = this.list.indexOf(row)
+          this.list.splice(index, 1)
+        })
+        .catch(response => {
+          this.$notify.error({
+            title: '失败',
+            message: response.data.errmsg
+          })
+        })
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val
+    },
+    showContent(content) {
+      this.contentDetail = content
+      this.contentDialogVisible = true
+    },
+    handleBatchDelete() {
+      if (this.multipleSelection.length === 0) {
+        this.$message.error('请选择至少一条记录')
+        return
+      }
+      const ids = []
+      _.forEach(this.multipleSelection, function(item) {
+        ids.push(item.id)
+      })
+      batchDeleteAftersale({ ids: ids })
+        .then(response => {
+          this.$notify.success({
+            title: '成功',
+            message: '批量删除售后成功'
+          })
+          this.getList()
+        })
+        .catch(response => {
+          this.$notify.error({
+            title: '失败',
+            message: response.data.errmsg
+          })
+        })
+    },
+    handleDownload() {
+      this.downloadLoading = true
+      import('@/vendor/Export2Excel').then(excel => {
+        const tHeader = [
+          '服务编号',
+          '订单ID',
+          '用户ID',
+          '售后类型',
+          '退款原因',
+          '退款价格',
+          '申请时间'
+        ]
+        const filterVal = [
+          'aftersaleSn',
+          'orderId',
+          'userId',
+          'type',
+          'reason',
+          'amount',
+          'addTime'
+        ]
+        excel.export_json_to_excel2(tHeader, this.list, filterVal, '售后信息')
+        this.downloadLoading = false
+      })
+    }
+  }
+}
+</script>