diff --git a/src/api/mall/statistics/member.ts b/src/api/mall/statistics/member.ts
index d4680d3d..e0d77e40 100644
--- a/src/api/mall/statistics/member.ts
+++ b/src/api/mall/statistics/member.ts
@@ -54,6 +54,20 @@ export interface MemberTerminalStatisticsRespVO {
   userCount: number
 }
 
+/** 会员数量统计 Response VO */
+export interface MemberCountRespVO {
+  /** 用户访问量 */
+  visitUserCount: string
+  /** 新增用户数量 */
+  createUserCount: number
+}
+
+/** 会员注册数量 Response VO */
+export interface MemberRegisterCountRespVO {
+  date: string
+  count: number
+}
+
 // 查询会员统计
 export const getMemberSummary = () => {
   return request.get<MemberSummaryRespVO>({
@@ -89,3 +103,21 @@ export const getMemberTerminalStatisticsList = () => {
     url: '/statistics/member/get-terminal-statistics-list'
   })
 }
+
+// 获得用户数量量对照
+export const getUserCountComparison = () => {
+  return request.get<TradeStatisticsComparisonRespVO<MemberCountRespVO>>({
+    url: '/statistics/member/user-count-comparison'
+  })
+}
+
+// 获得会员注册数量列表
+export const getMemberRegisterCountList = (
+  beginTime: dayjs.ConfigType,
+  endTime: dayjs.ConfigType
+) => {
+  return request.get<MemberRegisterCountRespVO[]>({
+    url: '/statistics/member/register-count-list',
+    params: { times: [formatDate(beginTime), formatDate(endTime)] }
+  })
+}
diff --git a/src/api/mall/statistics/pay.ts b/src/api/mall/statistics/pay.ts
new file mode 100644
index 00000000..1593f38d
--- /dev/null
+++ b/src/api/mall/statistics/pay.ts
@@ -0,0 +1,6 @@
+import request from '@/config/axios'
+
+/** 获取钱包充值金额 */
+export const getWalletRechargePrice = async () => {
+  return await request.get<number>({ url: `/statistics/pay/wallet-recharge-price` })
+}
diff --git a/src/api/mall/statistics/trade.ts b/src/api/mall/statistics/trade.ts
index f7829ccb..76da08ca 100644
--- a/src/api/mall/statistics/trade.ts
+++ b/src/api/mall/statistics/trade.ts
@@ -33,6 +33,36 @@ export interface TradeTrendSummaryRespVO {
   orderRefundPrice: number
 }
 
+/** 交易订单数量 Response VO */
+export interface TradeOrderCountRespVO {
+  /** 待发货 */
+  undelivered?: number
+  /** 待核销 */
+  pickUp?: number
+  /** 退款中 */
+  afterSaleApply?: number
+  /** 提现待审核 */
+  auditingWithdraw?: number
+}
+
+/** 交易订单统计 Response VO */
+export interface TradeOrderSummaryRespVO {
+  /** 支付订单商品数 */
+  orderPayCount?: number
+  /** 总支付金额,单位:分 */
+  orderPayPrice?: number
+}
+
+/** 订单量趋势统计 Response VO */
+export interface TradeOrderTrendRespVO {
+  /** 日期 */
+  date: string
+  /** 订单数量 */
+  orderPayCount: number
+  /** 订单支付金额 */
+  orderPayPrice: number
+}
+
 // 查询交易统计
 export const getTradeStatisticsSummary = () => {
   return request.get<TradeStatisticsComparisonRespVO<TradeSummaryRespVO>>({
@@ -64,6 +94,30 @@ export const exportTradeTrend = (params: TradeTrendReqVO) => {
   })
 }
 
+// 获得交易订单数量
+export const getOrderCount = async () => {
+  return await request.get<TradeOrderCountRespVO>({ url: `/statistics/trade/order-count` })
+}
+
+// 获得交易订单数量对照
+export const getOrderComparison = async () => {
+  return await request.get<TradeStatisticsComparisonRespVO<TradeOrderSummaryRespVO>>({
+    url: `/statistics/trade/order-comparison`
+  })
+}
+
+// 获得订单量趋势统计
+export const getOrderCountTrendComparison = (
+  type: number,
+  beginTime: dayjs.ConfigType,
+  endTime: dayjs.ConfigType
+) => {
+  return request.get<TradeStatisticsComparisonRespVO<TradeOrderTrendRespVO>[]>({
+    url: '/statistics/trade/order-count-trend',
+    params: { type, beginTime: formatDate(beginTime), endTime: formatDate(endTime) }
+  })
+}
+
 /** 时间参数需要格式化, 确保接口能识别 */
 const formatDateParam = (params: TradeTrendReqVO) => {
   return { times: [formatDate(params.times[0]), formatDate(params.times[1])] } as TradeTrendReqVO
diff --git a/src/components/ShortcutDateRangePicker/index.vue b/src/components/ShortcutDateRangePicker/index.vue
new file mode 100644
index 00000000..d7fa90cb
--- /dev/null
+++ b/src/components/ShortcutDateRangePicker/index.vue
@@ -0,0 +1,89 @@
+<template>
+  <div class="flex flex-row items-center gap-2">
+    <el-radio-group v-model="shortcutDays" @change="handleShortcutDaysChange">
+      <el-radio-button :label="1">昨天</el-radio-button>
+      <el-radio-button :label="7">最近7天</el-radio-button>
+      <el-radio-button :label="30">最近30天</el-radio-button>
+    </el-radio-group>
+    <el-date-picker
+      v-model="times"
+      value-format="YYYY-MM-DD HH:mm:ss"
+      type="daterange"
+      start-placeholder="开始日期"
+      end-placeholder="结束日期"
+      :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+      :shortcuts="shortcuts"
+      class="!w-240px"
+      @change="emitDateRangePicker"
+    />
+    <slot></slot>
+  </div>
+</template>
+<script lang="ts" setup>
+import dayjs from 'dayjs'
+import * as DateUtil from '@/utils/formatTime'
+
+/** 快捷日期范围选择组件 */
+defineOptions({ name: 'ShortcutDateRangePicker' })
+
+const shortcutDays = ref(7) // 日期快捷天数(单选按钮组), 默认7天
+const times = ref<[dayjs.ConfigType, dayjs.ConfigType]>(['', '']) // 时间范围参数
+defineExpose({ times }) // 暴露时间范围参数
+/** 日期快捷选择 */
+const shortcuts = [
+  {
+    text: '昨天',
+    value: () => DateUtil.getDayRange(new Date(), -1)
+  },
+  {
+    text: '最近7天',
+    value: () => DateUtil.getLast7Days()
+  },
+  {
+    text: '本月',
+    value: () => [dayjs().startOf('M'), dayjs().subtract(1, 'd')]
+  },
+  {
+    text: '最近30天',
+    value: () => DateUtil.getLast30Days()
+  },
+  {
+    text: '最近1年',
+    value: () => DateUtil.getLast1Year()
+  }
+]
+
+/** 设置时间范围 */
+function setTimes() {
+  const beginDate = dayjs().subtract(shortcutDays.value, 'd')
+  const yesterday = dayjs().subtract(1, 'd')
+  times.value = DateUtil.getDateRange(beginDate, yesterday)
+}
+
+/** 快捷日期单选按钮选中 */
+const handleShortcutDaysChange = async () => {
+  // 设置时间范围
+  setTimes()
+  // 发送时间范围选中事件
+  await emitDateRangePicker()
+}
+
+/** 触发事件:时间范围选中 */
+const emits = defineEmits<{
+  (e: 'change', times: [dayjs.ConfigType, dayjs.ConfigType]): void
+}>()
+/** 触发时间范围选中事件 */
+const emitDateRangePicker = async () => {
+  // 开始与截止在同一天的, 折线图出不来, 需要延长一天
+  if (DateUtil.isSameDay(times.value[0], times.value[1])) {
+    // 前天
+    times.value[0] = DateUtil.formatDate(dayjs(times.value[0]).subtract(1, 'd'))
+  }
+  emits('change', times.value)
+}
+
+/** 初始化 **/
+onMounted(() => {
+  handleShortcutDaysChange()
+})
+</script>
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 6c9a5df2..e6b3173c 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -233,3 +233,16 @@ export const yuanToFen = (amount: string | number): number => {
 export const fenToYuan = (price: string | number): number => {
   return formatToFraction(price)
 }
+
+/**
+ * 计算环比
+ *
+ * @param value 当前数值
+ * @param reference 对比数值
+ */
+export const calculateRelativeRate = (value?: number, reference?: number) => {
+  // 防止除0
+  if (!reference) return 0
+
+  return ((100 * ((value || 0) - reference)) / reference).toFixed(0)
+}
diff --git a/src/views/mall/home/components/ComparisonCard.vue b/src/views/mall/home/components/ComparisonCard.vue
new file mode 100644
index 00000000..ee1c2f0c
--- /dev/null
+++ b/src/views/mall/home/components/ComparisonCard.vue
@@ -0,0 +1,42 @@
+<template>
+  <div class="flex flex-col gap-2 bg-[var(--el-bg-color-overlay)] p-6">
+    <div class="flex items-center justify-between text-gray-500">
+      <span>{{ title }}</span>
+      <el-tag>{{ tag }}</el-tag>
+    </div>
+    <div class="flex flex-row items-baseline justify-between">
+      <CountTo :prefix="prefix" :end-val="value" :decimals="decimals" class="text-3xl" />
+      <span :class="toNumber(percent) > 0 ? 'text-red-500' : 'text-green-500'">
+        {{ Math.abs(toNumber(percent)) }}%
+        <Icon :icon="toNumber(percent) > 0 ? 'ep:caret-top' : 'ep:caret-bottom'" class="!text-sm" />
+      </span>
+    </div>
+    <el-divider class="mb-1! mt-2!" />
+    <div class="flex flex-row items-center justify-between text-sm">
+      <span class="text-gray-500">昨日数据</span>
+      <span>{{ prefix || '' }}{{ reference }}</span>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import { propTypes } from '@/utils/propTypes'
+import { toNumber } from 'lodash-es'
+import { calculateRelativeRate } from '@/utils'
+
+/** 交易对照卡片 */
+defineOptions({ name: 'ComparisonCard' })
+
+const props = defineProps({
+  title: propTypes.string.def('').isRequired,
+  tag: propTypes.string.def(''),
+  prefix: propTypes.string.def(''),
+  value: propTypes.number.def(0).isRequired,
+  reference: propTypes.number.def(0).isRequired,
+  decimals: propTypes.number.def(0)
+})
+
+// 计算环比
+const percent = computed(() =>
+  calculateRelativeRate(props.value as number, props.reference as number)
+)
+</script>
diff --git a/src/views/mall/home/components/MemberStatisticsCard.vue b/src/views/mall/home/components/MemberStatisticsCard.vue
new file mode 100644
index 00000000..2f9d7ab5
--- /dev/null
+++ b/src/views/mall/home/components/MemberStatisticsCard.vue
@@ -0,0 +1,91 @@
+<template>
+  <el-card shadow="never">
+    <template #header>
+      <CardTitle title="用户统计" />
+    </template>
+    <!-- 折线图 -->
+    <Echart :height="300" :options="lineChartOptions" />
+  </el-card>
+</template>
+<script lang="ts" setup>
+import dayjs from 'dayjs'
+import { EChartsOption } from 'echarts'
+import * as MemberStatisticsApi from '@/api/mall/statistics/member'
+import { formatDate } from '@/utils/formatTime'
+import { CardTitle } from '@/components/Card'
+
+/** 会员用户统计卡片 */
+defineOptions({ name: 'MemberStatisticsCard' })
+
+const loading = ref(true) // 加载中
+/** 折线图配置 */
+const lineChartOptions = reactive<EChartsOption>({
+  dataset: {
+    dimensions: ['date', 'count'],
+    source: []
+  },
+  grid: {
+    left: 20,
+    right: 20,
+    bottom: 20,
+    top: 80,
+    containLabel: true
+  },
+  legend: {
+    top: 50
+  },
+  series: [{ name: '注册量', type: 'line', smooth: true, areaStyle: {} }],
+  toolbox: {
+    feature: {
+      // 数据区域缩放
+      dataZoom: {
+        yAxisIndex: false // Y轴不缩放
+      },
+      brush: {
+        type: ['lineX', 'clear'] // 区域缩放按钮、还原按钮
+      },
+      saveAsImage: { show: true, name: '会员统计' } // 保存为图片
+    }
+  },
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'cross'
+    },
+    padding: [5, 10]
+  },
+  xAxis: {
+    type: 'category',
+    boundaryGap: false,
+    axisTick: {
+      show: false
+    },
+    axisLabel: {
+      formatter: (date: string) => formatDate(date, 'MM-DD')
+    }
+  },
+  yAxis: {
+    axisTick: {
+      show: false
+    }
+  }
+}) as EChartsOption
+
+const getMemberRegisterCountList = async () => {
+  loading.value = true
+  // 查询最近一月数据
+  const beginTime = dayjs().subtract(30, 'd').startOf('d')
+  const endTime = dayjs().endOf('d')
+  const list = await MemberStatisticsApi.getMemberRegisterCountList(beginTime, endTime)
+  // 更新 Echarts 数据
+  if (lineChartOptions.dataset && lineChartOptions.dataset['source']) {
+    lineChartOptions.dataset['source'] = list
+  }
+  loading.value = false
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getMemberRegisterCountList()
+})
+</script>
diff --git a/src/views/mall/home/components/OperationDataCard.vue b/src/views/mall/home/components/OperationDataCard.vue
new file mode 100644
index 00000000..cae09a3e
--- /dev/null
+++ b/src/views/mall/home/components/OperationDataCard.vue
@@ -0,0 +1,91 @@
+<template>
+  <el-card shadow="never">
+    <template #header>
+      <CardTitle title="运营数据" />
+    </template>
+    <div class="flex flex-row flex-wrap items-center gap-8 p-4">
+      <div
+        v-for="item in data"
+        :key="item.name"
+        class="h-20 w-20% flex flex-col cursor-pointer items-center justify-center gap-2"
+        @click="handleClick(item.routerName)"
+      >
+        <CountTo
+          :prefix="item.prefix"
+          :end-val="item.value"
+          :decimals="item.decimals"
+          class="text-3xl"
+        />
+        <span class="text-center">{{ item.name }}</span>
+      </div>
+    </div>
+  </el-card>
+</template>
+<script lang="ts" setup>
+import * as ProductSpuApi from '@/api/mall/product/spu'
+import * as TradeStatisticsApi from '@/api/mall/statistics/trade'
+import * as PayStatisticsApi from '@/api/mall/statistics/pay'
+import { CardTitle } from '@/components/Card'
+
+/** 运营数据卡片 */
+defineOptions({ name: 'OperationDataCard' })
+
+const router = useRouter() // 路由
+
+/** 数据 */
+const data = reactive({
+  orderUndelivered: { name: '待发货订单', value: 9, routerName: 'TradeOrder' },
+  orderAfterSaleApply: { name: '退款中订单', value: 4, routerName: 'TradeAfterSale' },
+  orderWaitePickUp: { name: '待核销订单', value: 0, routerName: 'TradeOrder' },
+  productAlertStock: { name: '库存预警', value: 0, routerName: 'ProductSpu' },
+  productForSale: { name: '上架商品', value: 0, routerName: 'ProductSpu' },
+  productInWarehouse: { name: '仓库商品', value: 0, routerName: 'ProductSpu' },
+  withdrawAuditing: { name: '提现待审核', value: 0, routerName: 'TradeBrokerageWithdraw' },
+  rechargePrice: {
+    name: '账户充值',
+    value: 0.0,
+    prefix: '¥',
+    decimals: 2,
+    routerName: 'PayWalletRecharge'
+  }
+})
+
+/** 查询订单数据 */
+const getOrderData = async () => {
+  const orderCount = await TradeStatisticsApi.getOrderCount()
+  data.orderUndelivered.value = orderCount.undelivered
+  data.orderAfterSaleApply.value = orderCount.afterSaleApply
+  data.orderWaitePickUp.value = orderCount.pickUp
+  data.withdrawAuditing.value = orderCount.auditingWithdraw
+}
+
+/** 查询商品数据 */
+const getProductData = async () => {
+  // TODO: @芋艿:这个接口的返回值,是不是用命名字段更好些?
+  const productCount = await ProductSpuApi.getTabsCount()
+  data.productForSale.value = productCount['0']
+  data.productInWarehouse.value = productCount['1']
+  data.productAlertStock.value = productCount['3']
+}
+
+/** 查询钱包充值数据 */
+const getWalletRechargeData = async () => {
+  data.rechargePrice.value = await PayStatisticsApi.getWalletRechargePrice()
+}
+
+/**
+ * 跳转到对应页面
+ *
+ * @param routerName 路由页面组件的名称
+ */
+const handleClick = (routerName: string) => {
+  router.push({ name: routerName })
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getOrderData()
+  getProductData()
+  getWalletRechargeData()
+})
+</script>
diff --git a/src/views/mall/home/components/ShortcutCard.vue b/src/views/mall/home/components/ShortcutCard.vue
new file mode 100644
index 00000000..9fdd5cd4
--- /dev/null
+++ b/src/views/mall/home/components/ShortcutCard.vue
@@ -0,0 +1,79 @@
+<template>
+  <el-card shadow="never">
+    <template #header>
+      <CardTitle title="快捷入口" />
+    </template>
+    <div class="flex flex-row flex-wrap gap-8 p-4">
+      <div
+        v-for="menu in menuList"
+        :key="menu.name"
+        class="h-20 w-20% flex flex-col cursor-pointer items-center justify-center gap-2"
+        @click="handleMenuClick(menu.routerName)"
+      >
+        <div :class="menu.bgColor" class="rounded p-3 text-white">
+          <Icon :icon="menu.icon" class="text-7.5!" />
+        </div>
+        <span>{{ menu.name }}</span>
+      </div>
+    </div>
+  </el-card>
+</template>
+<script lang="ts" setup>
+/** 快捷入口卡片 */
+import { CardTitle } from '@/components/Card'
+
+defineOptions({ name: 'ShortcutCard' })
+
+const router = useRouter() // 路由
+
+/** 菜单列表 */
+const menuList = [
+  { name: '用户管理', icon: 'ep:user-filled', bgColor: 'bg-red-400', routerName: 'MemberUser' },
+  {
+    name: '商品管理',
+    icon: 'fluent-mdl2:product',
+    bgColor: 'bg-orange-400',
+    routerName: 'ProductSpu'
+  },
+  { name: '订单管理', icon: 'ep:list', bgColor: 'bg-yellow-500', routerName: 'TradeOrder' },
+  {
+    name: '售后管理',
+    icon: 'ri:refund-2-line',
+    bgColor: 'bg-green-600',
+    routerName: 'TradeAfterSale'
+  },
+  {
+    name: '分销管理',
+    icon: 'fa-solid:project-diagram',
+    bgColor: 'bg-cyan-500',
+    routerName: 'TradeBrokerageUser'
+  },
+  {
+    name: '优惠券',
+    icon: 'ep:ticket',
+    bgColor: 'bg-blue-500',
+    routerName: 'PromotionCoupon'
+  },
+  {
+    name: '拼团活动',
+    icon: 'fa:group',
+    bgColor: 'bg-purple-500',
+    routerName: 'PromotionBargainActivity'
+  },
+  {
+    name: '佣金提现',
+    icon: 'vaadin:money-withdraw',
+    bgColor: 'bg-rose-500',
+    routerName: 'TradeBrokerageWithdraw'
+  }
+]
+
+/**
+ * 跳转到菜单对应页面
+ *
+ * @param routerName 路由页面组件的名称
+ */
+const handleMenuClick = (routerName: string) => {
+  router.push({ name: routerName })
+}
+</script>
diff --git a/src/views/mall/home/components/TradeTrendCard.vue b/src/views/mall/home/components/TradeTrendCard.vue
new file mode 100644
index 00000000..6aa9fdcc
--- /dev/null
+++ b/src/views/mall/home/components/TradeTrendCard.vue
@@ -0,0 +1,208 @@
+<template>
+  <el-card shadow="never">
+    <template #header>
+      <div class="flex flex-row items-center justify-between">
+        <CardTitle title="交易量趋势" />
+        <!-- 查询条件 -->
+        <div class="flex flex-row items-center gap-2">
+          <el-radio-group v-model="timeRangeType" @change="handleTimeRangeTypeChange">
+            <el-radio-button v-for="[key, value] in timeRange.entries()" :key="key" :label="key">
+              {{ value.name }}
+            </el-radio-button>
+          </el-radio-group>
+        </div>
+      </div>
+    </template>
+    <!-- 折线图 -->
+    <Echart :height="300" :options="eChartOptions" />
+  </el-card>
+</template>
+<script lang="ts" setup>
+import dayjs, { Dayjs } from 'dayjs'
+import { EChartsOption } from 'echarts'
+import * as TradeStatisticsApi from '@/api/mall/statistics/trade'
+import { fenToYuan } from '@/utils'
+import { formatDate } from '@/utils/formatTime'
+import { CardTitle } from '@/components/Card'
+
+/** 交易量趋势 */
+defineOptions({ name: 'TradeTrendCard' })
+
+enum TimeRangeTypeEnum {
+  DAY30 = 1,
+  WEEK = 7,
+  MONTH = 30,
+  YEAR = 365
+} // 日期类型
+const timeRangeType = ref(TimeRangeTypeEnum.DAY30) // 日期快捷选择按钮, 默认30天
+const loading = ref(true) // 加载中
+// 时间范围 Map
+const timeRange = new Map()
+  .set(TimeRangeTypeEnum.DAY30, {
+    name: '30天',
+    series: [
+      { name: '订单金额', type: 'bar', smooth: true, data: [] },
+      { name: '订单数量', type: 'line', smooth: true, data: [] }
+    ]
+  })
+  .set(TimeRangeTypeEnum.WEEK, {
+    name: '周',
+    series: [
+      { name: '上周金额', type: 'bar', smooth: true, data: [] },
+      { name: '本周金额', type: 'bar', smooth: true, data: [] },
+      { name: '上周数量', type: 'line', smooth: true, data: [] },
+      { name: '本周数量', type: 'line', smooth: true, data: [] }
+    ]
+  })
+  .set(TimeRangeTypeEnum.MONTH, {
+    name: '月',
+    series: [
+      { name: '上月金额', type: 'bar', smooth: true, data: [] },
+      { name: '本月金额', type: 'bar', smooth: true, data: [] },
+      { name: '上月数量', type: 'line', smooth: true, data: [] },
+      { name: '本月数量', type: 'line', smooth: true, data: [] }
+    ]
+  })
+  .set(TimeRangeTypeEnum.YEAR, {
+    name: '年',
+    series: [
+      { name: '去年金额', type: 'bar', smooth: true, data: [] },
+      { name: '今年金额', type: 'bar', smooth: true, data: [] },
+      { name: '去年数量', type: 'line', smooth: true, data: [] },
+      { name: '今年数量', type: 'line', smooth: true, data: [] }
+    ]
+  })
+/** 图表配置 */
+const eChartOptions = reactive<EChartsOption>({
+  grid: {
+    left: 20,
+    right: 20,
+    bottom: 20,
+    top: 80,
+    containLabel: true
+  },
+  legend: {
+    top: 50,
+    data: []
+  },
+  series: [],
+  toolbox: {
+    feature: {
+      // 数据区域缩放
+      dataZoom: {
+        yAxisIndex: false // Y轴不缩放
+      },
+      brush: {
+        type: ['lineX', 'clear'] // 区域缩放按钮、还原按钮
+      },
+      saveAsImage: { show: true, name: '订单量趋势' } // 保存为图片
+    }
+  },
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'cross'
+    },
+    padding: [5, 10]
+  },
+  xAxis: {
+    type: 'category',
+    inverse: true,
+    boundaryGap: false,
+    axisTick: {
+      show: false
+    },
+    data: [],
+    axisLabel: {
+      formatter: (date: string) => {
+        switch (timeRangeType.value) {
+          case TimeRangeTypeEnum.DAY30:
+            return formatDate(date, 'MM-DD')
+          case TimeRangeTypeEnum.WEEK:
+            let weekDay = formatDate(date, 'ddd')
+            if (weekDay == '0') weekDay = '日'
+            return '周' + weekDay
+          case TimeRangeTypeEnum.MONTH:
+            return formatDate(date, 'D')
+          case TimeRangeTypeEnum.YEAR:
+            return formatDate(date, 'M') + '月'
+          default:
+            return date
+        }
+      }
+    }
+  },
+  yAxis: {
+    axisTick: {
+      show: false
+    }
+  }
+}) as EChartsOption
+
+/** 时间范围类型单选按钮选中 */
+const handleTimeRangeTypeChange = async () => {
+  // 设置时间范围
+  let beginTime: Dayjs
+  let endTime: Dayjs
+  switch (timeRangeType.value) {
+    case TimeRangeTypeEnum.WEEK:
+      beginTime = dayjs().startOf('week')
+      endTime = dayjs().endOf('week')
+      break
+    case TimeRangeTypeEnum.MONTH:
+      beginTime = dayjs().startOf('month')
+      endTime = dayjs().endOf('month')
+      break
+    case TimeRangeTypeEnum.YEAR:
+      beginTime = dayjs().startOf('year')
+      endTime = dayjs().endOf('year')
+      break
+    case TimeRangeTypeEnum.DAY30:
+    default:
+      beginTime = dayjs().subtract(30, 'day').startOf('d')
+      endTime = dayjs().endOf('d')
+      break
+  }
+  // 发送时间范围选中事件
+  await getOrderCountTrendComparison(beginTime, endTime)
+}
+
+/** 查询订单数量趋势对照数据 */
+const getOrderCountTrendComparison = async (
+  beginTime: dayjs.ConfigType,
+  endTime: dayjs.ConfigType
+) => {
+  loading.value = true
+  // 查询数据
+  const list = await TradeStatisticsApi.getOrderCountTrendComparison(
+    timeRangeType.value,
+    beginTime,
+    endTime
+  )
+  // 处理数据
+  const dates: string[] = []
+  const series = [...timeRange.get(timeRangeType.value).series]
+  for (let item of list) {
+    dates.push(item.value.date)
+    if (series.length === 2) {
+      series[0].data.push(fenToYuan(item?.value?.orderPayPrice || 0)) // 当前金额
+      series[1].data.push(fenToYuan(item?.value?.orderPayCount || 0)) // 对照数量
+    } else {
+      series[0].data.push(fenToYuan(item?.reference?.orderPayPrice || 0)) // 对照金额
+      series[1].data.push(fenToYuan(item?.value?.orderPayPrice || 0)) // 当前金额
+      series[2].data.push(item?.reference?.orderPayCount || 0) // 对照数量
+      series[3].data.push(item?.value?.orderPayCount || 0) // 当前数量
+    }
+  }
+  eChartOptions.xAxis!['data'] = dates
+  eChartOptions.series = series
+  // legend在4个切换到2个的时候,还是显示成4个,需要手动配置一下
+  eChartOptions.legend['data'] = series.map((item) => item.name)
+  loading.value = false
+}
+
+/** 初始化 **/
+onMounted(() => {
+  handleTimeRangeTypeChange()
+})
+</script>
diff --git a/src/views/mall/home/index.vue b/src/views/mall/home/index.vue
new file mode 100644
index 00000000..95e2e1da
--- /dev/null
+++ b/src/views/mall/home/index.vue
@@ -0,0 +1,113 @@
+<template>
+  <div class="flex flex-col">
+    <!-- 数据对照 -->
+    <el-row :gutter="16" class="row">
+      <el-col :md="6" :sm="12" :xs="24" :loading="loading">
+        <ComparisonCard
+          tag="今日"
+          title="销售额"
+          prefix="¥"
+          ::decimals="2"
+          :value="fenToYuan(orderComparison?.value?.orderPayPrice || 0)"
+          :reference="fenToYuan(orderComparison?.reference?.orderPayPrice || 0)"
+        />
+      </el-col>
+      <el-col :md="6" :sm="12" :xs="24" :loading="loading">
+        <ComparisonCard
+          tag="今日"
+          title="用户访问量"
+          :value="userComparison?.value?.visitUserCount || 0"
+          :reference="userComparison?.reference?.visitUserCount || 0"
+        />
+      </el-col>
+      <el-col :md="6" :sm="12" :xs="24" :loading="loading">
+        <ComparisonCard
+          tag="今日"
+          title="订单量"
+          :value="fenToYuan(orderComparison?.value?.orderPayCount || 0)"
+          :reference="fenToYuan(orderComparison?.reference?.orderPayCount || 0)"
+        />
+      </el-col>
+      <el-col :md="6" :sm="12" :xs="24" :loading="loading">
+        <ComparisonCard
+          tag="今日"
+          title="新增用户"
+          :value="userComparison?.value?.createUserCount || 0"
+          :reference="userComparison?.reference?.createUserCount || 0"
+        />
+      </el-col>
+    </el-row>
+    <el-row :gutter="16" class="row">
+      <el-col :md="12">
+        <!-- 快捷入口 -->
+        <ShortcutCard />
+      </el-col>
+      <el-col :md="12">
+        <!-- 运营数据 -->
+        <OperationDataCard />
+      </el-col>
+    </el-row>
+    <el-row :gutter="16" class="mb-4">
+      <el-col :md="18" :sm="24">
+        <!-- 会员概览 -->
+        <MemberFunnelCard />
+      </el-col>
+      <el-col :md="6" :sm="24">
+        <!-- 会员终端 -->
+        <MemberTerminalCard />
+      </el-col>
+    </el-row>
+    <!-- 交易量趋势 -->
+    <TradeTrendCard class="mb-4" />
+    <!-- 会员统计 -->
+    <MemberStatisticsCard />
+  </div>
+</template>
+<script lang="ts" setup>
+import * as TradeStatisticsApi from '@/api/mall/statistics/trade'
+import * as MemberStatisticsApi from '@/api/mall/statistics/member'
+import {
+  TradeOrderSummaryRespVO,
+  TradeStatisticsComparisonRespVO
+} from '@/api/mall/statistics/trade'
+import { MemberCountRespVO } from '@/api/mall/statistics/member'
+import { fenToYuan } from '@/utils'
+import ComparisonCard from './components/ComparisonCard.vue'
+import MemberStatisticsCard from './components/MemberStatisticsCard.vue'
+import OperationDataCard from './components/OperationDataCard.vue'
+import ShortcutCard from './components/ShortcutCard.vue'
+import TradeTrendCard from './components/TradeTrendCard.vue'
+import MemberTerminalCard from '@/views/mall/statistics/member/components/MemberTerminalCard.vue'
+import MemberFunnelCard from '@/views/mall/statistics/member/components/MemberFunnelCard.vue'
+
+/** 商城首页 */
+defineOptions({ name: 'MallHome' })
+
+const loading = ref(true) // 加载中
+const orderComparison = ref<TradeStatisticsComparisonRespVO<TradeOrderSummaryRespVO>>() // 交易对照数据
+const userComparison = ref<TradeStatisticsComparisonRespVO<MemberCountRespVO>>() // 用户对照数据
+
+/** 查询交易对照卡片数据 */
+const getOrderComparison = async () => {
+  orderComparison.value = await TradeStatisticsApi.getOrderComparison()
+}
+
+/** 查询会员用户数量对照卡片数据 */
+const getUserCountComparison = async () => {
+  userComparison.value = await MemberStatisticsApi.getUserCountComparison()
+}
+
+/** 初始化 **/
+onMounted(async () => {
+  loading.value = true
+  await Promise.all([getOrderComparison(), getUserCountComparison()])
+  loading.value = false
+})
+</script>
+<style lang="scss" scoped>
+.row {
+  .el-col {
+    margin-bottom: 1rem;
+  }
+}
+</style>
diff --git a/src/views/mall/statistics/member/components/MemberFunnelCard.vue b/src/views/mall/statistics/member/components/MemberFunnelCard.vue
new file mode 100644
index 00000000..15c954e1
--- /dev/null
+++ b/src/views/mall/statistics/member/components/MemberFunnelCard.vue
@@ -0,0 +1,119 @@
+<template>
+  <el-card shadow="never">
+    <template #header>
+      <div class="my--1.5 flex flex-row items-center justify-between">
+        <CardTitle title="会员概览" />
+        <!-- 查询条件 -->
+        <ShortcutDateRangePicker @change="handleTimeRangeChange" />
+      </div>
+    </template>
+    <div class="min-w-225 py-1.75" v-loading="loading">
+      <div class="relative h-24 flex">
+        <div class="h-full w-75% bg-blue-50 <lg:w-35% <xl:w-55%">
+          <div class="ml-15 h-full flex flex-col justify-center">
+            <div class="font-bold">
+              注册用户数量:{{ analyseData?.comparison?.value?.userCount || 0 }}
+            </div>
+            <div class="mt-2 text-3.5">
+              环比增长率:{{
+                calculateRelativeRate(
+                  analyseData?.comparison?.value?.userCount,
+                  analyseData?.comparison?.reference?.userCount
+                )
+              }}%
+            </div>
+          </div>
+        </div>
+        <div
+          class="trapezoid1 ml--38.5 mt-1.5 h-full w-77 flex flex-col items-center justify-center bg-blue-5 text-3.5 text-white"
+        >
+          <span class="text-6 font-bold">{{ analyseData?.visitorCount || 0 }}</span>
+          <span>访客</span>
+        </div>
+      </div>
+      <div class="relative h-24 flex">
+        <div class="h-full w-75% flex bg-cyan-50 <lg:w-35% <xl:w-55%">
+          <div class="ml-15 h-full flex flex-col justify-center">
+            <div class="font-bold">
+              活跃用户数量:{{ analyseData?.comparison?.value?.activeUserCount || 0 }}
+            </div>
+            <div class="mt-2 text-3.5">
+              环比增长率:{{
+                calculateRelativeRate(
+                  analyseData?.comparison?.value?.activeUserCount,
+                  analyseData?.comparison?.reference?.activeUserCount
+                )
+              }}%
+            </div>
+          </div>
+        </div>
+        <div
+          class="trapezoid2 ml--28 mt-1.7 h-25 w-56 flex flex-col items-center justify-center bg-cyan-5 text-3.5 text-white"
+        >
+          <span class="text-6 font-bold">{{ analyseData?.orderUserCount || 0 }}</span>
+          <span>下单</span>
+        </div>
+      </div>
+      <div class="relative h-24 flex">
+        <div class="w-75% flex bg-slate-50 <lg:w-35% <xl:w-55%">
+          <div class="ml-15 h-full flex flex-row gap-x-16">
+            <div class="flex flex-col justify-center">
+              <div class="font-bold">
+                充值用户数量:{{ analyseData?.comparison?.value?.rechargeUserCount || 0 }}
+              </div>
+              <div class="mt-2 text-3.5">
+                环比增长率:{{
+                  calculateRelativeRate(
+                    analyseData?.comparison?.value?.rechargeUserCount,
+                    analyseData?.comparison?.reference?.rechargeUserCount
+                  )
+                }}%
+              </div>
+            </div>
+            <div class="flex flex-col justify-center">
+              <div class="font-bold">客单价:{{ fenToYuan(analyseData?.atv || 0) }}</div>
+            </div>
+          </div>
+        </div>
+        <div
+          class="trapezoid3 ml--18 mt-3.25 h-23 w-36 flex flex-col items-center justify-center bg-slate-5 text-3.5 text-white"
+        >
+          <span class="text-6 font-bold">{{ analyseData?.payUserCount || 0 }}</span>
+          <span>成交用户</span>
+        </div>
+      </div>
+    </div>
+  </el-card>
+</template>
+<script lang="ts" setup>
+import * as MemberStatisticsApi from '@/api/mall/statistics/member'
+import dayjs from 'dayjs'
+import { calculateRelativeRate, fenToYuan } from '@/utils'
+import { MemberAnalyseRespVO } from '@/api/mall/statistics/member'
+import { CardTitle } from '@/components/Card'
+
+/** 会员概览卡片 */
+defineOptions({ name: 'MemberFunnelCard' })
+
+const loading = ref(true) // 加载中
+const analyseData = ref<MemberAnalyseRespVO>() // 会员分析数据
+
+/** 查询会员概览数据列表 */
+const handleTimeRangeChange = async (times: [dayjs.ConfigType, dayjs.ConfigType]) => {
+  loading.value = true
+  // 查询数据
+  analyseData.value = await MemberStatisticsApi.getMemberAnalyse({ times })
+  loading.value = false
+}
+</script>
+<style lang="scss" scoped>
+.trapezoid1 {
+  transform: perspective(5em) rotateX(-11deg);
+}
+.trapezoid2 {
+  transform: perspective(7em) rotateX(-20deg);
+}
+.trapezoid3 {
+  transform: perspective(3em) rotateX(-13deg);
+}
+</style>
diff --git a/src/views/mall/statistics/member/components/MemberTerminalCard.vue b/src/views/mall/statistics/member/components/MemberTerminalCard.vue
new file mode 100644
index 00000000..7bbab76c
--- /dev/null
+++ b/src/views/mall/statistics/member/components/MemberTerminalCard.vue
@@ -0,0 +1,69 @@
+<template>
+  <el-card shadow="never" v-loading="loading">
+    <template #header>
+      <CardTitle title="会员终端" />
+    </template>
+    <Echart :height="300" :options="terminalChartOptions" />
+  </el-card>
+</template>
+<script lang="ts" setup>
+import * as MemberStatisticsApi from '@/api/mall/statistics/member'
+import { EChartsOption } from 'echarts'
+import { MemberTerminalStatisticsRespVO } from '@/api/mall/statistics/member'
+import { DICT_TYPE, DictDataType, getIntDictOptions } from '@/utils/dict'
+import { CardTitle } from '@/components/Card'
+
+/** 会员终端卡片 */
+defineOptions({ name: 'MemberTerminalCard' })
+
+const loading = ref(true) // 加载中
+
+/** 会员终端统计图配置 */
+const terminalChartOptions = reactive<EChartsOption>({
+  tooltip: {
+    trigger: 'item',
+    confine: true,
+    formatter: '{a} <br/>{b} : {c} ({d}%)'
+  },
+  legend: {
+    orient: 'vertical',
+    left: 'right'
+  },
+  roseType: 'area',
+  series: [
+    {
+      name: '会员终端',
+      type: 'pie',
+      label: {
+        show: false
+      },
+      labelLine: {
+        show: false
+      },
+      data: []
+    }
+  ]
+}) as EChartsOption
+
+/** 按照终端,查询会员统计列表 */
+const getMemberTerminalStatisticsList = async () => {
+  loading.value = true
+  const list = await MemberStatisticsApi.getMemberTerminalStatisticsList()
+  const dictDataList = getIntDictOptions(DICT_TYPE.TERMINAL)
+  terminalChartOptions.series![0].data = dictDataList.map((dictData: DictDataType) => {
+    const userCount = list.find(
+      (item: MemberTerminalStatisticsRespVO) => item.terminal === dictData.value
+    )?.userCount
+    return {
+      name: dictData.label,
+      value: userCount || 0
+    }
+  })
+  loading.value = false
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getMemberTerminalStatisticsList()
+})
+</script>
diff --git a/src/views/mall/statistics/member/index.vue b/src/views/mall/statistics/member/index.vue
index e76e861c..713f7776 100644
--- a/src/views/mall/statistics/member/index.vue
+++ b/src/views/mall/statistics/member/index.vue
@@ -44,118 +44,20 @@
     </el-row>
     <el-row :gutter="16" class="mb-4">
       <el-col :md="18" :sm="24">
-        <el-card shadow="never">
-          <template #header>
-            <div class="flex flex-row items-center justify-between">
-              <span>会员概览</span>
-              <!-- 查询条件 -->
-              <div class="my--2 flex flex-row items-center gap-2">
-                <el-radio-group v-model="shortcutDays" @change="handleDateTypeChange">
-                  <el-radio-button :label="1">昨天</el-radio-button>
-                  <el-radio-button :label="7">最近7天</el-radio-button>
-                  <el-radio-button :label="30">最近30天</el-radio-button>
-                </el-radio-group>
-                <el-date-picker
-                  v-model="queryParams.times"
-                  value-format="YYYY-MM-DD HH:mm:ss"
-                  type="daterange"
-                  start-placeholder="开始日期"
-                  end-placeholder="结束日期"
-                  :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
-                  :shortcuts="shortcuts"
-                  class="!w-240px"
-                  @change="getMemberAnalyse"
-                />
-              </div>
-            </div>
-          </template>
-          <div class="min-w-225 py-1.75" v-loading="analyseLoading">
-            <div class="relative h-24 flex">
-              <div class="h-full w-75% bg-blue-50 <lg:w-35% <xl:w-55%">
-                <div class="ml-15 h-full flex flex-col justify-center">
-                  <div class="font-bold">
-                    注册用户数量:{{ analyseData?.comparison?.value?.userCount || 0 }}
-                  </div>
-                  <div class="mt-2 text-3.5">
-                    环比增长率:{{
-                      calculateRelativeRate(
-                        analyseData?.comparison?.value?.userCount,
-                        analyseData?.comparison?.reference?.userCount
-                      )
-                    }}%
-                  </div>
-                </div>
-              </div>
-              <div
-                class="trapezoid1 ml--38.5 mt-1.5 h-full w-77 flex flex-col items-center justify-center bg-blue-5 text-3.5 text-white"
-              >
-                <span class="text-6 font-bold">{{ analyseData?.visitorCount || 0 }}</span>
-                <span>访客</span>
-              </div>
-            </div>
-            <div class="relative h-24 flex">
-              <div class="h-full w-75% flex bg-cyan-50 <lg:w-35% <xl:w-55%">
-                <div class="ml-15 h-full flex flex-col justify-center">
-                  <div class="font-bold">
-                    活跃用户数量:{{ analyseData?.comparison?.value?.activeUserCount || 0 }}
-                  </div>
-                  <div class="mt-2 text-3.5">
-                    环比增长率:{{
-                      calculateRelativeRate(
-                        analyseData?.comparison?.value?.activeUserCount,
-                        analyseData?.comparison?.reference?.activeUserCount
-                      )
-                    }}%
-                  </div>
-                </div>
-              </div>
-              <div
-                class="trapezoid2 ml--28 mt-1.7 h-25 w-56 flex flex-col items-center justify-center bg-cyan-5 text-3.5 text-white"
-              >
-                <span class="text-6 font-bold">{{ analyseData?.orderUserCount || 0 }}</span>
-                <span>下单</span>
-              </div>
-            </div>
-            <div class="relative h-24 flex">
-              <div class="w-75% flex bg-slate-50 <lg:w-35% <xl:w-55%">
-                <div class="ml-15 h-full flex flex-row gap-x-16">
-                  <div class="flex flex-col justify-center">
-                    <div class="font-bold">
-                      充值用户数量:{{ analyseData?.comparison?.value?.rechargeUserCount || 0 }}
-                    </div>
-                    <div class="mt-2 text-3.5">
-                      环比增长率:{{
-                        calculateRelativeRate(
-                          analyseData?.comparison?.value?.rechargeUserCount,
-                          analyseData?.comparison?.reference?.rechargeUserCount
-                        )
-                      }}%
-                    </div>
-                  </div>
-                  <div class="flex flex-col justify-center">
-                    <div class="font-bold">客单价:{{ fenToYuan(analyseData?.atv || 0) }}</div>
-                  </div>
-                </div>
-              </div>
-              <div
-                class="trapezoid3 ml--18 mt-3.25 h-23 w-36 flex flex-col items-center justify-center bg-slate-5 text-3.5 text-white"
-              >
-                <span class="text-6 font-bold">{{ analyseData?.payUserCount || 0 }}</span>
-                <span>成交用户</span>
-              </div>
-            </div>
-          </div>
-        </el-card>
+        <!-- 会员概览 -->
+        <MemberFunnelCard />
       </el-col>
       <el-col :md="6" :sm="24">
-        <el-card shadow="never" header="会员终端" v-loading="loading">
-          <Echart :height="300" :options="terminalChartOptions" />
-        </el-card>
+        <!-- 会员终端 -->
+        <MemberTerminalCard />
       </el-col>
     </el-row>
     <el-row :gutter="16">
       <el-col :md="18" :sm="24">
-        <el-card shadow="never" header="会员地域分布">
+        <el-card shadow="never">
+          <template #header>
+            <CardTitle title="会员地域分布" />
+          </template>
           <el-row v-loading="loading">
             <el-col :span="10">
               <Echart :height="300" :options="areaChartOptions" />
@@ -206,7 +108,10 @@
         </el-card>
       </el-col>
       <el-col :md="6" :sm="24">
-        <el-card shadow="never" header="会员性别比例" v-loading="loading">
+        <el-card shadow="never" v-loading="loading">
+          <template #header>
+            <CardTitle title="会员性别比例" />
+          </template>
           <Echart :height="300" :options="sexChartOptions" />
         </el-card>
       </el-col>
@@ -214,63 +119,34 @@
   </div>
 </template>
 <script lang="ts" setup>
-import * as TradeMemberApi from '@/api/mall/statistics/member'
+import * as MemberStatisticsApi from '@/api/mall/statistics/member'
 import TradeTrendValue from '../trade/components/TradeTrendValue.vue'
 import { EChartsOption } from 'echarts'
 import china from '@/assets/map/json/china.json'
-import dayjs from 'dayjs'
 import { fenToYuan } from '@/utils'
-import * as DateUtil from '@/utils/formatTime'
 import {
-  MemberAnalyseRespVO,
   MemberAreaStatisticsRespVO,
   MemberSexStatisticsRespVO,
-  MemberAnalyseReqVO,
   MemberSummaryRespVO,
   MemberTerminalStatisticsRespVO
 } from '@/api/mall/statistics/member'
 import { DICT_TYPE, DictDataType, getIntDictOptions } from '@/utils/dict'
 import echarts from '@/plugins/echarts'
 import { fenToYuanFormat } from '@/utils/formatter'
+import MemberFunnelCard from './components/MemberFunnelCard.vue'
+import MemberTerminalCard from './components/MemberTerminalCard.vue'
+import { CardTitle } from '@/components/Card'
 
 /** 会员统计 */
 defineOptions({ name: 'MemberStatistics' })
 
 const loading = ref(true) // 加载中
-const analyseLoading = ref(true) // 会员概览加载中
-const queryParams = reactive<MemberAnalyseReqVO>({ times: ['', ''] }) // 会员概览查询参数
-const shortcutDays = ref(7) // 日期快捷天数(单选按钮组), 默认7天
 const summary = ref<MemberSummaryRespVO>() // 会员统计数据
-const analyseData = ref<MemberAnalyseRespVO>() // 会员分析数据
 const areaStatisticsList = shallowRef<MemberAreaStatisticsRespVO[]>() // 省份会员统计
 
 // 注册地图
 echarts?.registerMap('china', china!)
 
-/** 日期快捷选择 */
-const shortcuts = [
-  {
-    text: '昨天',
-    value: () => DateUtil.getDayRange(new Date(), -1)
-  },
-  {
-    text: '最近7天',
-    value: () => DateUtil.getLast7Days()
-  },
-  {
-    text: '本月',
-    value: () => [dayjs().startOf('M'), dayjs().subtract(1, 'd')]
-  },
-  {
-    text: '最近30天',
-    value: () => DateUtil.getLast30Days()
-  },
-  {
-    text: '最近1年',
-    value: () => DateUtil.getLast1Year()
-  }
-]
-
 /** 会员终端统计图配置 */
 const terminalChartOptions = reactive<EChartsOption>({
   tooltip: {
@@ -357,37 +233,14 @@ const areaChartOptions = reactive<EChartsOption>({
   ]
 }) as EChartsOption
 
-/** 计算环比 */
-const calculateRelativeRate = (value?: number, reference?: number) => {
-  // 防止除0
-  if (!reference) return 0
-
-  return ((100 * ((value || 0) - reference)) / reference).toFixed(0)
-}
-
-/** 设置时间范围 */
-function setTimes() {
-  const beginDate = dayjs().subtract(shortcutDays.value, 'd')
-  const yesterday = dayjs().subtract(1, 'd')
-  queryParams.times = DateUtil.getDateRange(beginDate, yesterday)
-}
-
-/** 处理会员概览查询(日期单选按钮组选择后) */
-const handleDateTypeChange = async () => {
-  // 设置时间范围
-  setTimes()
-  // 查询数据
-  await getMemberAnalyse()
-}
-
 /** 查询会员统计 */
 const getMemberSummary = async () => {
-  summary.value = await TradeMemberApi.getMemberSummary()
+  summary.value = await MemberStatisticsApi.getMemberSummary()
 }
 
 /** 按照省份,查询会员统计列表 */
 const getMemberAreaStatisticsList = async () => {
-  const list = await TradeMemberApi.getMemberAreaStatisticsList()
+  const list = await MemberStatisticsApi.getMemberAreaStatisticsList()
   areaStatisticsList.value = list.map((item: MemberAreaStatisticsRespVO) => {
     return {
       ...item,
@@ -412,7 +265,7 @@ const getMemberAreaStatisticsList = async () => {
 
 /** 按照性别,查询会员统计列表 */
 const getMemberSexStatisticsList = async () => {
-  const list = await TradeMemberApi.getMemberSexStatisticsList()
+  const list = await MemberStatisticsApi.getMemberSexStatisticsList()
   const dictDataList = getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)
   sexChartOptions.series[0].data = dictDataList.map((dictData: DictDataType) => {
     const userCount = list.find((item: MemberSexStatisticsRespVO) => item.sex === dictData.value)
@@ -426,7 +279,7 @@ const getMemberSexStatisticsList = async () => {
 
 /** 按照终端,查询会员统计列表 */
 const getMemberTerminalStatisticsList = async () => {
-  const list = await TradeMemberApi.getMemberTerminalStatisticsList()
+  const list = await MemberStatisticsApi.getMemberTerminalStatisticsList()
   const dictDataList = getIntDictOptions(DICT_TYPE.TERMINAL)
   terminalChartOptions.series![0].data = dictDataList.map((dictData: DictDataType) => {
     const userCount = list.find(
@@ -439,20 +292,6 @@ const getMemberTerminalStatisticsList = async () => {
   })
 }
 
-/** 查询会员概览数据列表 */
-const getMemberAnalyse = async () => {
-  analyseLoading.value = true
-  const times = queryParams.times
-  // 开始与截止在同一天的, 环比出不来, 需要延长一天
-  if (DateUtil.isSameDay(times[0], times[1])) {
-    // 前天
-    times[0] = DateUtil.formatDate(dayjs(times[0]).subtract(1, 'd'))
-  }
-  // 查询数据
-  analyseData.value = await TradeMemberApi.getMemberAnalyse({ times })
-  analyseLoading.value = false
-}
-
 /** 初始化 **/
 onMounted(async () => {
   loading.value = true
@@ -460,8 +299,7 @@ onMounted(async () => {
     getMemberSummary(),
     getMemberTerminalStatisticsList(),
     getMemberAreaStatisticsList(),
-    getMemberSexStatisticsList(),
-    handleDateTypeChange()
+    getMemberSexStatisticsList()
   ])
   loading.value = false
 })
@@ -472,13 +310,4 @@ onMounted(async () => {
     margin-bottom: 1rem;
   }
 }
-.trapezoid1 {
-  transform: perspective(5em) rotateX(-11deg);
-}
-.trapezoid2 {
-  transform: perspective(7em) rotateX(-20deg);
-}
-.trapezoid3 {
-  transform: perspective(3em) rotateX(-13deg);
-}
 </style>
diff --git a/src/views/mall/statistics/trade/index.vue b/src/views/mall/statistics/trade/index.vue
index 8fc2d0cb..e5290dca 100644
--- a/src/views/mall/statistics/trade/index.vue
+++ b/src/views/mall/statistics/trade/index.vue
@@ -59,25 +59,9 @@
       <template #header>
         <!-- 标题 -->
         <div class="flex flex-row items-center justify-between">
-          <span>交易状况</span>
+          <CardTitle title="交易状况" />
           <!-- 查询条件 -->
-          <div class="flex flex-row items-center gap-2">
-            <el-radio-group v-model="shortcutDays" @change="handleDateTypeChange">
-              <el-radio-button :label="1">昨天</el-radio-button>
-              <el-radio-button :label="7">最近7天</el-radio-button>
-              <el-radio-button :label="30">最近30天</el-radio-button>
-            </el-radio-group>
-            <el-date-picker
-              v-model="queryParams.times"
-              value-format="YYYY-MM-DD HH:mm:ss"
-              type="daterange"
-              start-placeholder="开始日期"
-              end-placeholder="结束日期"
-              :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
-              :shortcuts="shortcuts"
-              class="!w-240px"
-              @change="getTradeTrendData"
-            />
+          <ShortcutDateRangePicker ref="shortcutDateRangePicker" @change="getTradeTrendData">
             <el-button
               class="ml-4"
               @click="handleExport"
@@ -86,7 +70,7 @@
             >
               <Icon icon="ep:download" class="mr-1" />导出
             </el-button>
-          </div>
+          </ShortcutDateRangePicker>
         </div>
       </template>
       <!-- 统计值 -->
@@ -233,13 +217,11 @@ import { EChartsOption } from 'echarts'
 import {
   TradeStatisticsComparisonRespVO,
   TradeSummaryRespVO,
-  TradeTrendReqVO,
   TradeTrendSummaryRespVO
 } from '@/api/mall/statistics/trade'
-import dayjs from 'dayjs'
-import { fenToYuan } from '@/utils'
-import * as DateUtil from '@/utils/formatTime'
+import { calculateRelativeRate, fenToYuan } from '@/utils'
 import download from '@/utils/download'
+import { CardTitle } from '@/components/Card'
 
 /** 交易统计 */
 defineOptions({ name: 'TradeStatistics' })
@@ -249,34 +231,9 @@ const message = useMessage() // 消息弹窗
 const loading = ref(true) // 加载中
 const trendLoading = ref(true) // 交易状态加载中
 const exportLoading = ref(false) // 导出的加载中
-const queryParams = reactive<TradeTrendReqVO>({ times: ['', ''] }) // 交易状况查询参数
-const shortcutDays = ref(7) // 日期快捷天数(单选按钮组), 默认7天
 const summary = ref<TradeStatisticsComparisonRespVO<TradeSummaryRespVO>>() // 交易统计数据
 const trendSummary = ref<TradeStatisticsComparisonRespVO<TradeTrendSummaryRespVO>>() // 交易状况统计数据
-
-/** 日期快捷选择 */
-const shortcuts = [
-  {
-    text: '昨天',
-    value: () => DateUtil.getDayRange(new Date(), -1)
-  },
-  {
-    text: '最近7天',
-    value: () => DateUtil.getLast7Days()
-  },
-  {
-    text: '本月',
-    value: () => [dayjs().startOf('M'), dayjs().subtract(1, 'd')]
-  },
-  {
-    text: '最近30天',
-    value: () => DateUtil.getLast30Days()
-  },
-  {
-    text: '最近1年',
-    value: () => DateUtil.getLast1Year()
-  }
-]
+const shortcutDateRangePicker = ref()
 
 /** 折线图配置 */
 const lineChartOptions = reactive<EChartsOption>({
@@ -333,29 +290,6 @@ const lineChartOptions = reactive<EChartsOption>({
   }
 }) as EChartsOption
 
-/** 计算环比 */
-const calculateRelativeRate = (value?: number, reference?: number) => {
-  // 防止除0
-  if (!reference) return 0
-
-  return ((100 * ((value || 0) - reference)) / reference).toFixed(0)
-}
-
-/** 设置时间范围 */
-function setTimes() {
-  const beginDate = dayjs().subtract(shortcutDays.value, 'd')
-  const yesterday = dayjs().subtract(1, 'd')
-  queryParams.times = DateUtil.getDateRange(beginDate, yesterday)
-}
-
-/** 处理交易状况查询(日期单选按钮组选择后) */
-const handleDateTypeChange = async () => {
-  // 设置时间范围
-  setTimes()
-  // 查询数据
-  await getTradeTrendData()
-}
-
 /** 处理交易状况查询 */
 const getTradeTrendData = async () => {
   trendLoading.value = true
@@ -370,20 +304,14 @@ const getTradeStatisticsSummary = async () => {
 
 /** 查询交易状况数据统计 */
 const getTradeTrendSummary = async () => {
-  loading.value = true
-  trendSummary.value = await TradeStatisticsApi.getTradeTrendSummary(queryParams)
-  loading.value = false
+  const times = shortcutDateRangePicker.value.times
+  trendSummary.value = await TradeStatisticsApi.getTradeTrendSummary({ times })
 }
 
 /** 查询交易状况数据列表 */
 const getTradeTrendList = async () => {
-  const times = queryParams.times
-  // 开始与截止在同一天的, 折线图出不来, 需要延长一天
-  if (DateUtil.isSameDay(times[0], times[1])) {
-    // 前天
-    times[0] = DateUtil.formatDate(dayjs(times[0]).subtract(1, 'd'))
-  }
   // 查询数据
+  const times = shortcutDateRangePicker.value.times
   const list = await TradeStatisticsApi.getTradeTrendList({ times })
   // 处理数据
   for (let item of list) {
@@ -405,7 +333,8 @@ const handleExport = async () => {
     await message.exportConfirm()
     // 发起导出
     exportLoading.value = true
-    const data = await TradeStatisticsApi.exportTradeTrend(queryParams)
+    const times = shortcutDateRangePicker.value.times
+    const data = await TradeStatisticsApi.exportTradeTrend({ times })
     download.excel(data, '交易状况.xls')
   } catch {
   } finally {
@@ -416,7 +345,6 @@ const handleExport = async () => {
 /** 初始化 **/
 onMounted(async () => {
   await getTradeStatisticsSummary()
-  await handleDateTypeChange()
 })
 </script>
 <style lang="scss" scoped>