|
|
@@ -0,0 +1,367 @@
|
|
|
+<template>
|
|
|
+ <el-dialog
|
|
|
+ :title="dialogTitle"
|
|
|
+ :visible.sync="visible"
|
|
|
+ width="92%"
|
|
|
+ top="4vh"
|
|
|
+ append-to-body
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ @close="handleClose"
|
|
|
+ >
|
|
|
+ <el-row :gutter="16" class="stats-row">
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-card shadow="never" class="stats-card">
|
|
|
+ <div class="stats-label">参与人数</div>
|
|
|
+ <div class="stats-value">{{ stats.participantCount || 0 }}</div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-card shadow="never" class="stats-card">
|
|
|
+ <div class="stats-label">订单量</div>
|
|
|
+ <div class="stats-value">{{ stats.orderCount || 0 }}</div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-card shadow="never" class="stats-card">
|
|
|
+ <div class="stats-label">优惠金额(元)</div>
|
|
|
+ <div class="stats-value">{{ formatMoney(stats.discountAmount) }}</div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="6">
|
|
|
+ <el-card shadow="never" class="stats-card">
|
|
|
+ <div class="stats-label">成交额(元)</div>
|
|
|
+ <div class="stats-value">{{ formatMoney(stats.transactionAmount) }}</div>
|
|
|
+ </el-card>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="88px" class="mt16">
|
|
|
+ <el-form-item label="订单号" prop="orderCode">
|
|
|
+ <el-input v-model="queryParams.orderCode" placeholder="请输入订单号" clearable size="small" style="width: 180px" @keyup.enter.native="handleQuery"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="所属公司" prop="companyId">
|
|
|
+ <el-select
|
|
|
+ v-model="queryParams.companyId"
|
|
|
+ placeholder="请选择公司"
|
|
|
+ clearable
|
|
|
+ filterable
|
|
|
+ size="small"
|
|
|
+ style="width: 180px"
|
|
|
+ @change="handleCompanyChange"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in companyOptions"
|
|
|
+ :key="item.companyId"
|
|
|
+ :label="item.companyName"
|
|
|
+ :value="item.companyId"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="所属销售" prop="companyUserId">
|
|
|
+ <el-select
|
|
|
+ v-model="queryParams.companyUserId"
|
|
|
+ placeholder="请先选择公司"
|
|
|
+ clearable
|
|
|
+ filterable
|
|
|
+ size="small"
|
|
|
+ style="width: 180px"
|
|
|
+ :disabled="!queryParams.companyId"
|
|
|
+ :loading="companyUserLoading"
|
|
|
+ @change="handleCompanyUserChange"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in companyUserOptions"
|
|
|
+ :key="item.userId"
|
|
|
+ :label="item.nickName"
|
|
|
+ :value="item.userId"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="用户昵称" prop="nickname">
|
|
|
+ <el-input v-model="queryParams.nickname" placeholder="请输入用户昵称" clearable size="small" style="width: 160px" @keyup.enter.native="handleQuery"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="订单来源" prop="orderSourceType">
|
|
|
+ <el-select v-model="queryParams.orderSourceType" placeholder="全部" clearable size="small" style="width: 140px">
|
|
|
+ <el-option v-for="item in orderSourceOptions" :key="item.value" :label="item.label" :value="item.value"/>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
|
|
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <el-tabs v-model="activeStatus" type="card" @tab-click="handleStatusTab">
|
|
|
+ <el-tab-pane label="全部订单" name="all"/>
|
|
|
+ <el-tab-pane v-for="item in statusOptions" :key="item.dictValue" :label="item.dictLabel" :name="String(item.dictValue)"/>
|
|
|
+ </el-tabs>
|
|
|
+
|
|
|
+ <el-table v-loading="loading" :data="orderList" border height="420">
|
|
|
+ <el-table-column label="订单号" align="center" prop="orderCode" min-width="180" show-overflow-tooltip/>
|
|
|
+ <el-table-column label="店铺名称" align="center" prop="storeName" min-width="120" show-overflow-tooltip/>
|
|
|
+ <el-table-column label="商家ID" align="center" prop="merchantId" width="120"/>
|
|
|
+ <el-table-column label="店铺ID" align="center" prop="storeSeq" width="120"/>
|
|
|
+ <el-table-column label="所属公司" align="center" prop="companyName" min-width="120" show-overflow-tooltip/>
|
|
|
+ <el-table-column label="所属员工" align="center" prop="companyUserNickName" min-width="100" show-overflow-tooltip/>
|
|
|
+ <el-table-column label="用户昵称" align="center" prop="nickname" min-width="100" show-overflow-tooltip/>
|
|
|
+ <el-table-column label="收件人" align="center" prop="realName" width="100"/>
|
|
|
+ <el-table-column label="订单金额" align="center" prop="totalPrice" width="100">
|
|
|
+ <template slot-scope="scope">{{ formatMoney(scope.row.totalPrice) }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="应付金额" align="center" prop="payPrice" width="100">
|
|
|
+ <template slot-scope="scope">{{ formatMoney(scope.row.payPrice) }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="优惠金额" align="center" prop="promotionDiscountAmount" width="100">
|
|
|
+ <template slot-scope="scope">{{ formatMoney(scope.row.promotionDiscountAmount) }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="订单来源" align="center" width="90">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag size="mini" :type="scope.row.orderSourceType === 1 ? 'success' : 'info'">
|
|
|
+ {{ scope.row.orderSourceType === 1 ? '销售订单' : '商城订单' }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="订单状态" align="center" prop="status" width="90">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag size="mini">{{ getStatusLabel(scope.row.status) }}</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <pagination
|
|
|
+ v-show="total > 0"
|
|
|
+ :total="total"
|
|
|
+ :page.sync="queryParams.pageNum"
|
|
|
+ :limit.sync="queryParams.pageSize"
|
|
|
+ @pagination="loadOrders"
|
|
|
+ />
|
|
|
+ </el-dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { getPromotionReportStats, listPromotionReportOrders } from '@/api/hisStore/storePromotion'
|
|
|
+import { getCompanyList } from '@/api/company/company'
|
|
|
+import { getUserList } from '@/api/company/companyUser'
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'PromotionReportDialog',
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ visible: false,
|
|
|
+ loading: false,
|
|
|
+ activity: null,
|
|
|
+ stats: {
|
|
|
+ participantCount: 0,
|
|
|
+ orderCount: 0,
|
|
|
+ discountAmount: 0,
|
|
|
+ transactionAmount: 0
|
|
|
+ },
|
|
|
+ orderList: [],
|
|
|
+ total: 0,
|
|
|
+ activeStatus: 'all',
|
|
|
+ statusOptions: [],
|
|
|
+ companyOptions: [],
|
|
|
+ companyUserOptions: [],
|
|
|
+ companyUserLoading: false,
|
|
|
+ orderSourceOptions: [
|
|
|
+ { value: 1, label: '销售订单' },
|
|
|
+ { value: 2, label: '商城订单' }
|
|
|
+ ],
|
|
|
+ queryParams: {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ activityId: null,
|
|
|
+ orderCode: null,
|
|
|
+ companyId: null,
|
|
|
+ companyUserId: null,
|
|
|
+ nickname: null,
|
|
|
+ status: null,
|
|
|
+ orderSourceType: null
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ dialogTitle() {
|
|
|
+ if (!this.activity) {
|
|
|
+ return '活动报表统计'
|
|
|
+ }
|
|
|
+ return `活动报表统计 - ${this.activity.title || ''}`
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ open(row) {
|
|
|
+ this.activity = row
|
|
|
+ this.visible = true
|
|
|
+ this.queryParams.activityId = row.id
|
|
|
+ this.resetQueryParams()
|
|
|
+ this.loadStatusOptions()
|
|
|
+ this.loadCompanyOptions()
|
|
|
+ this.loadData()
|
|
|
+ },
|
|
|
+ handleClose() {
|
|
|
+ this.activity = null
|
|
|
+ this.orderList = []
|
|
|
+ this.total = 0
|
|
|
+ this.activeStatus = 'all'
|
|
|
+ },
|
|
|
+ resetQueryParams() {
|
|
|
+ this.queryParams = {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ activityId: this.activity ? this.activity.id : null,
|
|
|
+ orderCode: null,
|
|
|
+ companyId: null,
|
|
|
+ companyUserId: null,
|
|
|
+ nickname: null,
|
|
|
+ status: null,
|
|
|
+ orderSourceType: null
|
|
|
+ }
|
|
|
+ this.companyUserOptions = []
|
|
|
+ this.activeStatus = 'all'
|
|
|
+ },
|
|
|
+ loadCompanyOptions() {
|
|
|
+ if (this.companyOptions.length) {
|
|
|
+ return Promise.resolve(this.companyOptions)
|
|
|
+ }
|
|
|
+ return getCompanyList().then(res => {
|
|
|
+ this.companyOptions = this.normalizeCompanyOptions(res.data)
|
|
|
+ return this.companyOptions
|
|
|
+ }).catch(() => {
|
|
|
+ this.companyOptions = []
|
|
|
+ this.$message.error('加载公司列表失败')
|
|
|
+ return []
|
|
|
+ })
|
|
|
+ },
|
|
|
+ normalizeCompanyOptions(list) {
|
|
|
+ return (list || [])
|
|
|
+ .map(item => ({
|
|
|
+ companyId: item.companyId != null ? item.companyId : item.dictValue,
|
|
|
+ companyName: item.companyName || item.dictLabel
|
|
|
+ }))
|
|
|
+ .filter(item => item.companyId != null && item.companyName)
|
|
|
+ },
|
|
|
+ normalizeCompanyUserOptions(list) {
|
|
|
+ return (list || [])
|
|
|
+ .map(item => ({
|
|
|
+ userId: item.userId,
|
|
|
+ nickName: item.nickName || item.userName || item.phonenumber || ('员工' + item.userId)
|
|
|
+ }))
|
|
|
+ .filter(item => item.userId != null)
|
|
|
+ },
|
|
|
+ loadStatusOptions() {
|
|
|
+ if (this.statusOptions.length) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.getDicts('store_order_status').then(res => {
|
|
|
+ this.statusOptions = res.data || []
|
|
|
+ })
|
|
|
+ },
|
|
|
+ handleCompanyChange(companyId) {
|
|
|
+ this.queryParams.companyUserId = null
|
|
|
+ this.companyUserOptions = []
|
|
|
+ if (!companyId) {
|
|
|
+ this.handleQuery()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.loadCompanyUserOptions(companyId)
|
|
|
+ },
|
|
|
+ handleCompanyUserChange() {
|
|
|
+ this.handleQuery()
|
|
|
+ },
|
|
|
+ loadCompanyUserOptions(companyId) {
|
|
|
+ this.companyUserLoading = true
|
|
|
+ return getUserList(companyId).then(res => {
|
|
|
+ this.companyUserOptions = this.normalizeCompanyUserOptions(res.data)
|
|
|
+ this.handleQuery()
|
|
|
+ }).catch(() => {
|
|
|
+ this.companyUserOptions = []
|
|
|
+ this.$message.error('加载销售列表失败')
|
|
|
+ }).finally(() => {
|
|
|
+ this.companyUserLoading = false
|
|
|
+ })
|
|
|
+ },
|
|
|
+ handleStatusTab() {
|
|
|
+ this.queryParams.status = this.activeStatus === 'all' ? null : Number(this.activeStatus)
|
|
|
+ this.queryParams.pageNum = 1
|
|
|
+ this.loadData()
|
|
|
+ },
|
|
|
+ handleQuery() {
|
|
|
+ this.queryParams.pageNum = 1
|
|
|
+ this.loadData()
|
|
|
+ },
|
|
|
+ resetQuery() {
|
|
|
+ this.resetQueryParams()
|
|
|
+ this.loadData()
|
|
|
+ },
|
|
|
+ loadData() {
|
|
|
+ this.loadStats()
|
|
|
+ this.loadOrders()
|
|
|
+ },
|
|
|
+ loadStats() {
|
|
|
+ getPromotionReportStats(this.buildQuery()).then(res => {
|
|
|
+ this.stats = res.data || {
|
|
|
+ participantCount: 0,
|
|
|
+ orderCount: 0,
|
|
|
+ discountAmount: 0,
|
|
|
+ transactionAmount: 0
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ loadOrders() {
|
|
|
+ this.loading = true
|
|
|
+ listPromotionReportOrders(this.buildQuery()).then(res => {
|
|
|
+ this.orderList = res.rows || []
|
|
|
+ this.total = res.total || 0
|
|
|
+ this.loading = false
|
|
|
+ }).catch(() => {
|
|
|
+ this.loading = false
|
|
|
+ })
|
|
|
+ },
|
|
|
+ buildQuery() {
|
|
|
+ const query = { ...this.queryParams }
|
|
|
+ if (query.orderSourceType === '' || query.orderSourceType === undefined) {
|
|
|
+ query.orderSourceType = null
|
|
|
+ }
|
|
|
+ if (query.companyId === '' || query.companyId === undefined) {
|
|
|
+ query.companyId = null
|
|
|
+ }
|
|
|
+ if (query.companyUserId === '' || query.companyUserId === undefined) {
|
|
|
+ query.companyUserId = null
|
|
|
+ }
|
|
|
+ return query
|
|
|
+ },
|
|
|
+ formatMoney(value) {
|
|
|
+ if (value == null || value === '') {
|
|
|
+ return '0.00'
|
|
|
+ }
|
|
|
+ return Number(value).toFixed(2)
|
|
|
+ },
|
|
|
+ getStatusLabel(status) {
|
|
|
+ const item = this.statusOptions.find(opt => String(opt.dictValue) === String(status))
|
|
|
+ return item ? item.dictLabel : status
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.stats-row {
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+.stats-card {
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.stats-label {
|
|
|
+ font-size: 13px;
|
|
|
+ color: #909399;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+.stats-value {
|
|
|
+ font-size: 22px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+}
|
|
|
+.mt16 {
|
|
|
+ margin-top: 16px;
|
|
|
+}
|
|
|
+</style>
|