| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- <template>
- <div class="app-container coupon-user-page">
- <el-card shadow="never" class="search-card">
- <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="88px" size="small">
- <el-form-item label="会员名称" prop="nickname">
- <el-input
- v-model="queryParams.nickname"
- placeholder="请输入会员名称"
- clearable
- style="width: 160px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="手机号" prop="phone">
- <el-input
- v-model="queryParams.phone"
- placeholder="请输入手机号"
- clearable
- style="width: 160px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="优惠券" prop="couponTitle">
- <el-input
- v-model="queryParams.couponTitle"
- placeholder="请输入优惠券名称"
- clearable
- style="width: 180px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="优惠券类型" prop="couponType">
- <el-select v-model="queryParams.couponType" placeholder="全部类型" clearable style="width: 140px">
- <el-option
- v-for="item in couponTypeOptions"
- :key="item.dictValue"
- :label="item.dictLabel"
- :value="item.dictValue"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="状态" prop="status">
- <el-select v-model="queryParams.status" placeholder="全部状态" clearable style="width: 150px">
- <el-option
- v-for="item in statusFilterOptions"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="领取时间">
- <el-date-picker
- v-model="dateRange"
- style="width: 240px"
- value-format="yyyy-MM-dd"
- type="daterange"
- range-separator="-"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" 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-card>
- <el-card shadow="never" class="table-card">
- <div class="toolbar">
- <div class="toolbar-left">
- <el-button
- type="warning"
- plain
- icon="el-icon-download"
- size="mini"
- @click="handleExport"
- v-hasPermi="['store:storeCouponUser:export', 'live:issue:export']"
- >导出</el-button>
- <span class="toolbar-tip">普通券状态为待使用/已使用;核销券为未核销/已核销</span>
- </div>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
- </div>
- <el-table
- height="520"
- border
- size="mini"
- v-loading="loading"
- :data="storeCouponUserList"
- class="coupon-table"
- >
- <el-table-column label="会员" min-width="130" show-overflow-tooltip>
- <template slot-scope="scope">
- <div class="cell-main">{{ scope.row.nickname || '-' }}</div>
- <div class="cell-sub">{{ scope.row.phone || '-' }}</div>
- </template>
- </el-table-column>
- <el-table-column label="优惠券" min-width="160" show-overflow-tooltip>
- <template slot-scope="scope">
- <div class="cell-main">{{ scope.row.couponTitle || '-' }}</div>
- <div class="cell-sub">面值 ¥{{ scope.row.couponPrice }} · 满 ¥{{ scope.row.useMinPrice }}</div>
- </template>
- </el-table-column>
- <el-table-column label="类型" width="100" align="center">
- <template slot-scope="scope">
- <el-tag size="mini" :type="couponTypeTagType(scope.row.couponType)" effect="plain">
- {{ couponTypeLabel(scope.row.couponType) }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="领取 / 有效期" min-width="160">
- <template slot-scope="scope">
- <div class="cell-sub">领 {{ formatTime(scope.row.createTime) }}</div>
- <div class="cell-sub">止 {{ formatTime(scope.row.limitTime) }}</div>
- </template>
- </el-table-column>
- <el-table-column label="使用信息" min-width="150">
- <template slot-scope="scope">
- <template v-if="isVerifyCouponType(scope.row.couponType)">
- <div class="cell-main">{{ scope.row.verifyUserName || '-' }}</div>
- <div class="cell-sub">{{ formatTime(scope.row.verifyTime || scope.row.useTime) }}</div>
- </template>
- <template v-else>
- <div class="cell-main cell-muted">普通券不可核销</div>
- <div class="cell-sub">{{ formatTime(scope.row.useTime) !== '-' ? ('使用 ' + formatTime(scope.row.useTime)) : '-' }}</div>
- </template>
- </template>
- </el-table-column>
- <el-table-column label="状态" width="96" align="center">
- <template slot-scope="scope">
- <el-tag size="mini" :type="statusTagType(scope.row.status)">
- {{ rowStatusLabel(scope.row) }}
- </el-tag>
- </template>
- </el-table-column>
- </el-table>
- <pagination
- v-show="total > 0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
- </el-card>
- </div>
- </template>
- <script>
- import axios from "axios";
- import { getToken } from "@/utils/auth";
- import { listStoreCouponUser, exportStoreCouponUser } from "@/api/live/liveCouponUser";
- export default {
- name: "StoreCouponUser",
- data() {
- return {
- statusOptions: [],
- couponTypeOptions: [],
- loading: true,
- dateRange: [],
- showSearch: true,
- total: 0,
- storeCouponUserList: [],
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- couponId: null,
- userId: null,
- nickname: null,
- phone: null,
- couponTitle: null,
- couponPrice: null,
- useMinPrice: null,
- endTime: null,
- useTime: null,
- type: null,
- couponType: null,
- status: null,
- isFail: null,
- isDel: null
- },
- // 筛选用中性文案(同一 status 码,展示因券类型不同)
- statusFilterOptions: [
- { value: "0", label: "待使用 / 未核销" },
- { value: "1", label: "已使用 / 已核销" },
- { value: "2", label: "已过期" }
- ]
- };
- },
- created() {
- this.getDicts("live_coupon_user_status").then((response) => {
- this.statusOptions = response.data || [];
- });
- this.getDicts("store_coupon_type").then((response) => {
- this.couponTypeOptions = response.data || [];
- });
- this.getList();
- },
- methods: {
- couponTypeLabel(type) {
- if (type === null || type === undefined || type === "") {
- return "-";
- }
- const hit = (this.couponTypeOptions || []).find(item => String(item.dictValue) === String(type));
- return hit ? hit.dictLabel : `类型${type}`;
- },
- isVerifyCouponType(type) {
- const label = this.couponTypeLabel(type) || "";
- return label.includes("核销") || label.includes("代金券");
- },
- couponTypeTagType(type) {
- return this.isVerifyCouponType(type) ? "warning" : "";
- },
- /** 按券类型展示状态:普通券=待使用/已使用;核销券=未核销/已核销 */
- rowStatusLabel(row) {
- const status = row == null ? null : row.status;
- if (status === null || status === undefined || status === "") {
- return "-";
- }
- const code = Number(status);
- if (this.isVerifyCouponType(row.couponType)) {
- const map = { 0: "未核销", 1: "已核销", 2: "已过期" };
- return map[code] != null ? map[code] : String(status);
- }
- const map = { 0: "待使用", 1: "已使用", 2: "已过期" };
- return map[code] != null ? map[code] : String(status);
- },
- statusTagType(status) {
- const map = { 0: "info", 1: "success", 2: "danger" };
- return map[Number(status)] || "info";
- },
- formatTime(val) {
- if (!val) {
- return "-";
- }
- const text = String(val).replace("T", " ");
- return text.length >= 16 ? text.substring(0, 16) : text;
- },
- getList() {
- this.loading = true;
- listStoreCouponUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
- this.storeCouponUserList = response.rows || [];
- this.total = response.total || 0;
- this.loading = false;
- }).catch(() => {
- this.loading = false;
- });
- },
- handleQuery() {
- this.queryParams.pageNum = 1;
- this.getList();
- },
- resetQuery() {
- this.dateRange = [];
- this.resetForm("queryForm");
- this.handleQuery();
- },
- handleExport() {
- const queryParams = this.addDateRange({ ...this.queryParams }, this.dateRange);
- this.$confirm("是否确认导出所有优惠券发放记录数据项?", "警告", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- type: "warning"
- }).then(() => {
- return exportStoreCouponUser(queryParams);
- }).then(response => {
- return this.downloadFileWithAuth(response.msg);
- }).catch(() => {});
- },
- downloadFileWithAuth(fileName) {
- if (!fileName) {
- this.msgError("导出失败,未获取到文件名");
- return Promise.reject("empty fileName");
- }
- return axios({
- method: "get",
- url: process.env.VUE_APP_BASE_API + "/common/download",
- params: { fileName: fileName, delete: false },
- responseType: "blob",
- headers: {
- Authorization: "Bearer " + getToken(),
- "X-Frontend-Type": "admin"
- }
- }).then(res => {
- const disposition = res.headers["content-disposition"] || "";
- let downloadName = fileName.indexOf("_") > -1 ? fileName.substring(fileName.indexOf("_") + 1) : fileName;
- const match = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(disposition);
- if (match && match[1]) {
- downloadName = decodeURIComponent(match[1].replace(/['"]/g, ""));
- }
- const blob = new Blob([res.data]);
- const link = document.createElement("a");
- link.href = window.URL.createObjectURL(blob);
- link.setAttribute("download", downloadName);
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- window.URL.revokeObjectURL(link.href);
- });
- }
- }
- };
- </script>
- <style scoped>
- .coupon-user-page {
- padding-bottom: 12px;
- }
- .search-card {
- margin-bottom: 12px;
- border-radius: 8px;
- }
- .search-card >>> .el-card__body {
- padding: 14px 16px 2px;
- }
- .table-card {
- border-radius: 8px;
- }
- .table-card >>> .el-card__body {
- padding: 12px 16px 8px;
- }
- .toolbar {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 12px;
- }
- .toolbar-left {
- display: flex;
- align-items: center;
- gap: 12px;
- }
- .toolbar-tip {
- font-size: 12px;
- color: #909399;
- }
- .coupon-table {
- width: 100%;
- }
- .cell-main {
- line-height: 18px;
- color: #303133;
- font-weight: 500;
- }
- .cell-muted {
- color: #909399;
- font-weight: 400;
- }
- .cell-sub {
- line-height: 18px;
- font-size: 12px;
- color: #909399;
- margin-top: 2px;
- }
- </style>
|