Преглед на файлове

!279 交易:核销订单
Merge pull request !279 from 疯狂的世界/dev

芋道源码 преди 1 година
родител
ревизия
83501f9b09

+ 18 - 1
src/api/mall/trade/order/index.ts

@@ -108,11 +108,28 @@ export interface ProductPropertiesVO {
   valueName?: string // 属性值的名称
 }
 
+/** 交易订单统计 */
+export interface TradeOrderSummaryRespVO {
+  /** 订单数量 */
+  orderCount?: number
+  /** 订单金额 */
+  orderPayPrice?: string
+  /** 退款单数 */
+  afterSaleCount?: number
+  /** 退款金额 */
+  afterSalePrice?: string
+}
+
 // 查询交易订单列表
-export const getOrderPage = async (params) => {
+export const getOrderPage = async (params: any) => {
   return await request.get({ url: `/trade/order/page`, params })
 }
 
+// 查询交易订单统计
+export const getOrderSummary = async (params: any) => {
+  return await request.get<TradeOrderSummaryRespVO>({ url: `/trade/order/summary`, params })
+}
+
 // 查询交易订单详情
 export const getOrder = async (id: number | null) => {
   return await request.get({ url: `/trade/order/get-detail?id=` + id })

+ 2 - 2
src/views/mall/statistics/trade/components/TradeTrendValue.vue → src/components/SummaryCard/index.vue

@@ -35,8 +35,8 @@
 import { propTypes } from '@/utils/propTypes'
 import { toNumber } from 'lodash-es'
 
-/** 交易状况统计值组件 */
-defineOptions({ name: 'TradeTrendValue' })
+/** 统计卡片 */
+defineOptions({ name: 'SummaryCard' })
 
 defineProps({
   title: propTypes.string.def(''),

+ 5 - 5
src/views/mall/statistics/member/index.vue

@@ -2,7 +2,7 @@
   <div class="flex flex-col">
     <el-row :gutter="16" class="summary">
       <el-col :sm="6" :xs="12" v-loading="loading">
-        <TradeTrendValue
+        <SummaryCard
           title="累计会员数"
           icon="fa-solid:users"
           icon-color="bg-blue-100"
@@ -11,7 +11,7 @@
         />
       </el-col>
       <el-col :sm="6" :xs="12" v-loading="loading">
-        <TradeTrendValue
+        <SummaryCard
           title="累计充值人数"
           icon="fa-solid:user"
           icon-color="bg-purple-100"
@@ -20,7 +20,7 @@
         />
       </el-col>
       <el-col :sm="6" :xs="12" v-loading="loading">
-        <TradeTrendValue
+        <SummaryCard
           title="累计充值金额"
           icon="fa-solid:money-check-alt"
           icon-color="bg-yellow-100"
@@ -31,7 +31,7 @@
         />
       </el-col>
       <el-col :sm="6" :xs="12" v-loading="loading">
-        <TradeTrendValue
+        <SummaryCard
           title="累计消费金额"
           icon="fa-solid:yen-sign"
           icon-color="bg-green-100"
@@ -120,7 +120,7 @@
 </template>
 <script lang="ts" setup>
 import * as MemberStatisticsApi from '@/api/mall/statistics/member'
-import TradeTrendValue from '../trade/components/TradeTrendValue.vue'
+import SummaryCard from '@/components/SummaryCard/index.vue'
 import { EChartsOption } from 'echarts'
 import china from '@/assets/map/json/china.json'
 import { fenToYuan } from '@/utils'

+ 8 - 8
src/views/mall/statistics/trade/index.vue

@@ -76,7 +76,7 @@
       <!-- 统计值 -->
       <el-row :gutter="16">
         <el-col :md="6" :sm="12" :xs="24">
-          <TradeTrendValue
+          <SummaryCard
             title="营业额"
             tooltip="商品支付金额、充值金额"
             icon="fa-solid:yen-sign"
@@ -94,7 +94,7 @@
           />
         </el-col>
         <el-col :md="6" :sm="12" :xs="24">
-          <TradeTrendValue
+          <SummaryCard
             title="商品支付金额"
             tooltip="用户购买商品的实际支付金额,包括微信支付、余额支付、支付宝支付、线下支付金额(拼团商品在成团之后计入,线下支付订单在后台确认支付后计入)"
             icon="fa-solid:shopping-cart"
@@ -112,7 +112,7 @@
           />
         </el-col>
         <el-col :md="6" :sm="12" :xs="24">
-          <TradeTrendValue
+          <SummaryCard
             title="充值金额"
             tooltip="用户成功充值的金额"
             icon="fa-solid:money-check-alt"
@@ -130,7 +130,7 @@
           />
         </el-col>
         <el-col :md="6" :sm="12" :xs="24">
-          <TradeTrendValue
+          <SummaryCard
             title="支出金额"
             tooltip="余额支付金额、支付佣金金额、商品退款金额"
             icon="ep:warning-filled"
@@ -148,7 +148,7 @@
           />
         </el-col>
         <el-col :md="6" :sm="12" :xs="24">
-          <TradeTrendValue
+          <SummaryCard
             title="余额支付金额"
             tooltip="用户下单时使用余额实际支付的金额"
             icon="fa-solid:wallet"
@@ -166,7 +166,7 @@
           />
         </el-col>
         <el-col :md="6" :sm="12" :xs="24">
-          <TradeTrendValue
+          <SummaryCard
             title="支付佣金金额"
             tooltip="后台给推广员支付的推广佣金,以实际支付为准"
             icon="fa-solid:award"
@@ -184,7 +184,7 @@
           />
         </el-col>
         <el-col :md="6" :sm="12" :xs="24">
-          <TradeTrendValue
+          <SummaryCard
             title="商品退款金额"
             tooltip="用户成功退款的商品金额"
             icon="fa-solid:times-circle"
@@ -212,7 +212,7 @@
 <script lang="ts" setup>
 import * as TradeStatisticsApi from '@/api/mall/statistics/trade'
 import TradeStatisticValue from './components/TradeStatisticValue.vue'
-import TradeTrendValue from './components/TradeTrendValue.vue'
+import SummaryCard from '@/components/SummaryCard/index.vue'
 import { EChartsOption } from 'echarts'
 import { DataComparisonRespVO } from '@/api/mall/statistics/common'
 import { TradeSummaryRespVO, TradeTrendSummaryRespVO } from '@/api/mall/statistics/trade'

+ 309 - 0
src/views/mall/trade/delivery/pickUpOrder/index.vue

@@ -0,0 +1,309 @@
+<template>
+  <!-- 搜索 -->
+  <ContentWrap>
+    <el-form
+      ref="queryFormRef"
+      :inline="true"
+      :model="queryParams"
+      class="-mb-15px"
+      label-width="68px"
+    >
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-280px"
+          end-placeholder="自定义时间"
+          start-placeholder="自定义时间"
+          type="daterange"
+          value-format="YYYY-MM-DD HH:mm:ss"
+        />
+      </el-form-item>
+      <el-form-item label="自提门店" prop="pickUpStoreId">
+        <el-select
+          v-model="queryParams.pickUpStoreId"
+          class="!w-280px"
+          clearable
+          multiple
+          placeholder="全部"
+        >
+          <el-option
+            v-for="item in pickUpStoreList"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="聚合搜索">
+        <el-input
+          v-show="true"
+          v-model="queryParams[queryType.queryParam]"
+          class="!w-280px"
+          clearable
+          placeholder="请输入"
+          :type="queryType.queryParam === 'userId' ? 'number' : 'text'"
+        >
+          <template #prepend>
+            <el-select
+              v-model="queryType.queryParam"
+              class="!w-110px"
+              placeholder="全部"
+              @change="inputChangeSelect"
+            >
+              <el-option
+                v-for="dict in dynamicSearchList"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </template>
+        </el-input>
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery">
+          <Icon class="mr-5px" icon="ep:search" />
+          搜索
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon class="mr-5px" icon="ep:refresh" />
+          重置
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+  <!-- 统计卡片 -->
+  <el-row :gutter="16" class="summary">
+    <el-col :sm="6" :xs="12" v-loading="loading">
+      <SummaryCard
+        title="订单数量"
+        icon="icon-park-outline:transaction-order"
+        icon-color="bg-blue-100"
+        icon-bg-color="text-blue-500"
+        :value="summary?.orderCount || 0"
+      />
+    </el-col>
+    <el-col :sm="6" :xs="12" v-loading="loading">
+      <SummaryCard
+        title="订单金额"
+        icon="streamline:money-cash-file-dollar-common-money-currency-cash-file"
+        icon-color="bg-purple-100"
+        icon-bg-color="text-purple-500"
+        prefix="¥"
+        :decimals="2"
+        :value="fenToYuan(summary?.orderPayPrice || 0)"
+      />
+    </el-col>
+    <el-col :sm="6" :xs="12" v-loading="loading">
+      <SummaryCard
+        title="退款单数"
+        icon="heroicons:receipt-refund"
+        icon-color="bg-yellow-100"
+        icon-bg-color="text-yellow-500"
+        :value="summary?.afterSaleCount || 0"
+      />
+    </el-col>
+    <el-col :sm="6" :xs="12" v-loading="loading">
+      <SummaryCard
+        title="退款金额"
+        icon="ri:refund-2-line"
+        icon-color="bg-green-100"
+        icon-bg-color="text-green-500"
+        prefix="¥"
+        :decimals="2"
+        :value="fenToYuan(summary?.afterSalePrice || 0)"
+      />
+    </el-col>
+  </el-row>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list">
+      <el-table-column label="订单号" align="center" prop="no" min-width="180" />
+      <el-table-column label="用户信息" align="center" prop="user.nickname" min-width="80" />
+      <el-table-column
+        label="推荐人信息"
+        align="center"
+        prop="brokerageUser.nickname"
+        min-width="100"
+      />
+      <el-table-column label="商品信息" align="center" prop="spuName" min-width="300">
+        <template #default="{ row }">
+          <div class="flex items-center" v-for="item in row.items" :key="item.id">
+            <el-image
+              :src="item.picUrl"
+              class="mr-10px h-30px w-30px flex-shrink-0"
+              :preview-src-list="[item.picUrl]"
+              preview-teleported
+            />
+            <span class="mr-10px">{{ item.spuName }}</span>
+            <div class="flex flex-col flex-wrap gap-1">
+              <el-tag
+                v-for="property in item.properties"
+                :key="property.propertyId"
+                class="mr-10px"
+              >
+                {{ property.propertyName }}: {{ property.valueName }}
+              </el-tag>
+              <span>{{ floatToFixed2(item.price) }} 元 x {{ item.count }}</span>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="实付金额(元)"
+        align="center"
+        prop="payPrice"
+        min-width="110"
+        :formatter="fenToYuanFormat"
+      />
+      <el-table-column label="核销员" align="center" prop="storeStaffName" min-width="70" />
+      <el-table-column label="核销门店" align="center" prop="pickUpStoreId" min-width="80">
+        <template #default="{ row }">
+          {{ pickUpStoreList.find((p) => p.id === row.pickUpStoreId)?.name }}
+        </template>
+      </el-table-column>
+      <el-table-column label="支付状态" align="center" prop="payStatus" min-width="80">
+        <template #default="{ row }">
+          <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.payStatus || false" />
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="订单状态" prop="status" width="120">
+        <template #default="{ row }">
+          <dict-tag :type="DICT_TYPE.TRADE_ORDER_STATUS" :value="row.status" />
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="下单时间"
+        align="center"
+        prop="createTime"
+        min-width="170"
+        :formatter="dateFormatter"
+      />
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      v-model:limit="queryParams.pageSize"
+      v-model:page="queryParams.pageNo"
+      :total="total"
+      @pagination="getList"
+    />
+  </ContentWrap>
+</template>
+
+<script lang="ts" setup>
+import type { FormInstance } from 'element-plus'
+import * as TradeOrderApi from '@/api/mall/trade/order'
+import * as PickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore'
+import { DICT_TYPE } from '@/utils/dict'
+import { fenToYuan, floatToFixed2 } from '@/utils'
+import { fenToYuanFormat } from '@/utils/formatter'
+import SummaryCard from '@/components/SummaryCard/index.vue'
+import { dateFormatter } from '@/utils/formatTime'
+import { DeliveryTypeEnum } from '@/utils/constants'
+import { TradeOrderSummaryRespVO } from '@/api/mall/trade/order'
+import { DeliveryPickUpStoreVO } from '@/api/mall/trade/delivery/pickUpStore'
+
+defineOptions({ name: 'PickUpOrder' })
+
+// 列表的加载中
+const loading = ref(true)
+// 列表的总页数
+const total = ref(2)
+// 列表的数据
+const list = ref<TradeOrderApi.OrderVO[]>([])
+// 搜索的表单
+const queryFormRef = ref<FormInstance>()
+// 初始表单参数
+const INIT_QUERY_PARAMS = {
+  // 页数
+  pageNo: 1,
+  // 每页显示数量
+  pageSize: 10,
+  // 创建时间
+  createTime: undefined,
+  // 配送方式
+  deliveryType: DeliveryTypeEnum.PICK_UP.type,
+  // 自提门店
+  pickUpStoreId: undefined
+}
+// 表单搜索
+const queryParams = ref({ ...INIT_QUERY_PARAMS })
+// 订单搜索类型 queryParam
+const queryType = reactive({ queryParam: 'no' })
+// 订单统计数据
+const summary = ref<TradeOrderSummaryRespVO>()
+
+// 订单聚合搜索 select 类型配置(动态搜索)
+const dynamicSearchList = ref([
+  { value: 'no', label: '订单号' },
+  { value: 'userId', label: '用户UID' },
+  { value: 'userNickname', label: '用户昵称' },
+  { value: 'userMobile', label: '用户电话' }
+])
+/**
+ * 聚合搜索切换查询对象时触发
+ * @param val
+ */
+const inputChangeSelect = (val: string) => {
+  dynamicSearchList.value
+    .filter((item) => item.value !== val)
+    ?.forEach((item) => {
+      // 清除集合搜索无用属性
+      if (queryParams.value.hasOwnProperty(item.value)) {
+        delete queryParams.value[item.value]
+      }
+    })
+}
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    // 统计
+    summary.value = await TradeOrderApi.getOrderSummary(unref(queryParams))
+    // 分页
+    const data = await TradeOrderApi.getOrderPage(unref(queryParams))
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = async () => {
+  queryParams.value.pageNo = 1
+  await getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields()
+  queryParams.value = { ...INIT_QUERY_PARAMS }
+  handleQuery()
+}
+
+/** 自提门店精简列表 */
+const pickUpStoreList = ref<DeliveryPickUpStoreVO[]>([])
+const getPickUpStoreList = async () => {
+  pickUpStoreList.value = await PickUpStoreApi.getListAllSimple()
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+  getPickUpStoreList()
+})
+</script>
+<style lang="scss" scoped>
+:deep(.order-table-col > .cell) {
+  padding: 0;
+}
+.summary {
+  .el-col {
+    margin-bottom: 1rem;
+  }
+}
+</style>

+ 1 - 0
src/views/mall/trade/order/index.vue

@@ -128,6 +128,7 @@
           class="!w-280px"
           clearable
           placeholder="请输入"
+          :type="queryType.queryParam === 'userId' ? 'number' : 'text'"
         >
           <template #prepend>
             <el-select