zxl
10 天以前 37486e9d5beb6112c072625e74d3782f8bed7a01
导出以及页面
4个文件已添加
950 ■■■■■ 已修改文件
manager/src/api/prize-grant-record.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager/src/api/prize-record.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager/src/views/prize-grant-record/index.vue 406 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager/src/views/prize-record/index.vue 518 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager/src/api/prize-grant-record.js
New file
@@ -0,0 +1,13 @@
import service, {getRequest} from "../libs/axios";
export const queryExport = (params) =>{
  return getRequest("/lmk/prizeGrantRecord/queryExport", params,'blob')
}
export const getPage = (params) =>{
  return service({
    url: "/lmk/prizeGrantRecord",
    method: "GET",
    params: params
  })
}
manager/src/api/prize-record.js
New file
@@ -0,0 +1,13 @@
import service, {getRequest} from "../libs/axios";
export const queryExport = (params) =>{
  return getRequest("/lmk/prizeRecord/queryExport", params,'blob')
}
export const getPage = (params) =>{
  return service({
    url: "/lmk/prizeRecord",
    method: "GET",
    params: params
  })
}
manager/src/views/prize-grant-record/index.vue
New file
@@ -0,0 +1,406 @@
<template>
  <div>
    <Card>
      <!-- 搜索表单 -->
      <Form
        ref="searchForm"
        @keydown.enter.native="handleSearch"
        :model="searchForm"
        inline
        :label-width="80"
        class="search-form"
      >
        <FormItem label="用户昵称" prop="nickName">
          <Input
            type="text"
            v-model="searchForm.nickName"
            placeholder="请输入用户昵称"
            clearable
            @on-clear="handleSearch"
            style="width: 180px"
          />
        </FormItem>
        <FormItem label="活动名称" prop="activityName">
          <Input
            type="text"
            v-model="searchForm.activityName"
            placeholder="请输入活动名称"
            clearable
            @on-clear="handleSearch"
            style="width: 180px"
          />
        </FormItem>
        <FormItem label="中奖状态" prop="beginTime">
          <Select
            v-model="searchForm.grantStatus"
            placeholder="请选择中奖状态"
            style="width: 180px"
            clearable
            @on-clear="handleSearch"
            @on-change="handleSearch"
          >
            <Option
              v-for="item in typeSelect"
              :value="item.value"
              :key="item.id"
            >
              {{ item.label }}
            </Option>
          </Select>
        </FormItem>
        <Button
          @click="handleSearch"
          type="primary"
          icon="ios-search"
          class="search-btn"
        >搜索</Button>
        <Button
          @click="resetSearch"
          icon="md-refresh"
          style="margin-left: 8px"
        >重置</Button>
        <Button
          @click="queryExport"
          class="search-btn"
          type="primary"
        >导出</Button
        >
      </Form>
      <!-- 活动表格 -->
      <Table
        :loading="loading"
        border
        :columns="columns"
        :data="data"
        ref="table"
        class="table"
      >
        <!-- 操作按钮插槽 -->
        <template slot-scope="{ row }" slot="action">
          <div class="action-btns">
            <Button
              type="info"
              size="small"
              @click="detail(row)"
            >详情</Button>
          </div>
        </template>
      </Table>
      <!-- 分页 -->
      <Row type="flex" justify="end" class="page-footer">
        <Page
          :current="searchForm.pageNumber"
          :total="total"
          :page-size="searchForm.pageSize"
          @on-change="changePage"
          @on-page-size-change="changePageSize"
          :page-size-opts="[10, 20, 50]"
          size="small"
          show-total
          show-elevator
          show-sizer
        ></Page>
      </Row>
      <!-- 详情-->
      <Modal
        v-model="infoModalShow"
        title="活动详情"
        @on-cancel="infoModelClose"
        width="800"
        :mask-closable="false"
      >
        <div class="detail-container">
          <Row :gutter="16">
            <Col span="12">
              <div class="detail-item">
                <label>活动名称:</label>
                <span>{{ detailData.activityName }}</span>
              </div>
            </Col>
            <Col span="12">
              <div class="detail-item">
                <label>用户昵称:</label>
                <span>{{ detailData.nickName}}</span>
              </div>
            </Col>
            <Col span="12">
              <div class="detail-item">
                <label>奖品名称:</label>
                <span>{{ detailData.prizeName }}</span>
              </div>
            </Col>
            <Col span="12">
              <div class="detail-item">
                <label>奖品内容:</label>
                <span>{{ detailData.prizeContent }}</span>
              </div>
            </Col>
            <Col span="12">
              <div class="detail-item">
                <label>描述:</label>
                <span>{{ detailData.desc }}</span>
              </div>
            </Col>
            <Col span="24">
              <div class="detail-item">
                <label>发放状态:</label>
                <Tag :color="detailData.grantStatus === 'SUCCESS' ? 'green' : 'red'">
                  {{ detailData.grantStatus === 'SUCCESS' ? '发放成功' : '发放失败' }}
                </Tag>
              </div>
            </Col>
          </Row>
        </div>
      </Modal>
    </Card>
  </div>
</template>
<script>
import {
  getPage,
  queryExport
} from '@/api/prize-grant-record.js'
export default {
  name: "prizeGrantRecord",
  data() {
    return {
      infoModalShow:false,
      detailData: {},
      modelShow:false,
      modelTitle:'',
      loading:false,
      columns:[
        {
          title: '用户昵称',
          key: 'nickName',
          minWidth: 100,
        },
        {
          title: '活动名称',
          key: 'activityName',
          minWidth: 100,
        },
        {
          title: '奖品名称',
          key: 'prizeName',
          minWidth: 100,
        },
        {
          title: '描述',
          key: 'des',
          minWidth: 100,
        },
        {
          title: '发放状态',
          key: 'grantStatus',
          minWidth: 100,
          render: (h, params) => {
            return h('Tag', {
              props: {
                color: params.row.grantStatus === 'SUCCESS' ? 'green' : 'red'
              }}, params.row.grantStatus === 'SUCCESS' ? '发放成功' : '发放失败')
          }
        },
        {
          title: '操作',
          slot: 'action',
          width: 280,
          align: 'center',
          fixed: 'right'
        },
      ],
      data:[],
      total:0,
      searchForm:{
        pageSize:10,
        pageNumber:1,
        nickName:'',
        activityName:'',
        grantStatus:''
      },
      typeSelect:[
        {id: 1, value: 'SUCCESS', label: '发放成功'},
        {id: 2, value: 'FAILED', label: '发放失败'}
      ],
      activityCover:null,
    }
  },
  // 在组件创建前注册
  beforeCreate() {
  },
  mounted() {
    this.init();
  },
  methods: {
    queryExport(){
      queryExport(this.searchForm).then(res =>{
        const blob = new Blob([res], {
          type: "application/vnd.ms-excel;charset=utf-8",
        });
        //对于<a>标签,只有 Firefox 和 Chrome(内核) 支持 download 属性
        //IE10以上支持blob但是依然不支持download
        if ("download" in document.createElement("a")) {
          //支持a标签download的浏览器
          const link = document.createElement("a"); //创建a标签
          link.download = "用户抽奖记录.xlsx"; //a标签添加属性
          link.style.display = "none";
          link.href = URL.createObjectURL(blob);
          document.body.appendChild(link);
          link.click(); //执行下载
          URL.revokeObjectURL(link.href); //释放url
          document.body.removeChild(link); //释放标签
        } else {
          navigator.msSaveBlob(blob, fileName);
        }
      })
    },
    // 格式化奖品类型
    replaceText(type) {
      if (type === "coupon") {
        return "优惠券";
      }
      return type; // 如果不是目标词,返回原文本
    },
    resetSearch(){
      this.$refs.searchForm.resetFields()
      this.searchForm.pageNumber = 1
      this.getPage()
    },
    infoModelClose(){
      this.infoModalShow = false;
    },
    getPage(){
      this.loading = true;
      getPage(this.searchForm).then(res =>{
        this.loading = false;
        if (res.code === 200){
          this.data = res.data;
          this.total = res.total;
        }else {
          this.$Message.error(res.msg)
        }
      })
    },
    detail(row){
      this.infoModalShow = true;
      this.detailData = {...row};
    },
    handleSearch(type,value){
      if (type === 'beginTime') {
        this.searchForm.beginTime = value
      } else if (type === 'endTime') {
        this.searchForm.endTime = value
      }
      this.getPage()
    },
    // 初始化数据
    init() {
      this.getPage()
    },
    changePage(){
      this.searchForm.pageNumber = 1
      this.searchForm.pageSize = pageSize
      this.getPage()
    },
    changePageSize(){
      this.searchForm.pageNumber = page
      this.getPage()
    },
  },
}
</script>
<style lang="scss" scoped>
.search-form {
  padding: 16px;
  background: #f8f8f9;
  border-radius: 4px;
  margin-bottom: 16px;
  .ivu-form-item {
    margin-bottom: 16px;
    margin-right: 16px;
  }
  .search-btn {
    margin-left: 8px;
  }
}
.table {
  .thumbnail {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    cursor: pointer;
    transition: all 0.3s;
    &:hover {
      transform: scale(1.05);
      box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
    }
  }
  .action-btns {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    .ivu-btn {
      margin: 4px;
      font-size: 12px;
      padding: 2px 6px;
      min-width: 60px;
    }
  }
}
.detail-container {
  padding: 16px;
}
.detail-item {
  margin-bottom: 16px;
  line-height: 1.5;
}
.detail-item label {
  display: inline-block;
  width: 120px;
  font-weight: bold;
  color: #515a6e;
  vertical-align: top;
}
.detail-item span {
  display: inline-block;
  max-width: calc(100% - 120px);
}
.detail-image {
  display: inline-block;
  margin-top: 8px;
  border: 1px dashed #dcdee2;
  padding: 4px;
  border-radius: 4px;
  background: #f8f8f9;
}
</style>
manager/src/views/prize-record/index.vue
New file
@@ -0,0 +1,518 @@
<template>
  <div>
    <Card>
      <!-- 搜索表单 -->
      <Form
        ref="searchForm"
        @keydown.enter.native="handleSearch"
        :model="searchForm"
        inline
        :label-width="80"
        class="search-form"
      >
        <FormItem label="用户昵称" prop="nickName">
          <Input
            type="text"
            v-model="searchForm.nickName"
            placeholder="请输入用户昵称"
            clearable
            @on-clear="handleSearch"
            style="width: 180px"
          />
        </FormItem>
        <FormItem label="活动名称" prop="activityName">
          <Input
            type="text"
            v-model="searchForm.activityName"
            placeholder="请输入活动名称"
            clearable
            @on-clear="handleSearch"
            style="width: 180px"
          />
        </FormItem>
        <FormItem label="中奖状态" prop="beginTime">
          <Select
            v-model="searchForm.prizeStatus"
            placeholder="请选择中奖状态"
            style="width: 180px"
            clearable
            @on-clear="handleSearch"
            @on-change="handleSearch"
          >
            <Option
              v-for="item in typeSelect"
              :value="item.value"
              :key="item.id"
            >
              {{ item.label }}
            </Option>
          </Select>
        </FormItem>
        <FormItem label="奖品发放状态" prop="beginTime">
          <Select
            v-model="searchForm.distributeStatus"
            placeholder="请选择奖品发放状态"
            style="width: 180px"
            clearable
            @on-clear="handleSearch"
            @on-change="handleSearch"
          >
            <Option
              v-for="item in distributeSelect"
              :value="item.value"
              :key="item.id"
            >
              {{ item.label }}
            </Option>
          </Select>
        </FormItem>
        <Button
          @click="handleSearch"
          type="primary"
          icon="ios-search"
          class="search-btn"
        >搜索</Button>
        <Button
          @click="resetSearch"
          icon="md-refresh"
          style="margin-left: 8px"
        >重置</Button>
        <Button
          @click="queryExport"
          class="search-btn"
          type="primary"
        >导出</Button
        >
      </Form>
      <!-- 活动表格 -->
      <Table
        :loading="loading"
        border
        :columns="columns"
        :data="data"
        ref="table"
        class="table"
      >
        <!-- 操作按钮插槽 -->
        <template slot-scope="{ row }" slot="action">
          <div class="action-btns">
            <Button
              type="info"
              size="small"
              @click="detail(row)"
            >详情</Button>
          </div>
        </template>
      </Table>
      <!-- 分页 -->
      <Row type="flex" justify="end" class="page-footer">
        <Page
          :current="searchForm.pageNumber"
          :total="total"
          :page-size="searchForm.pageSize"
          @on-change="changePage"
          @on-page-size-change="changePageSize"
          :page-size-opts="[10, 20, 50]"
          size="small"
          show-total
          show-elevator
          show-sizer
        ></Page>
      </Row>
      <!-- 详情-->
      <Modal
        v-model="infoModalShow"
        title="活动详情"
        @on-cancel="infoModelClose"
        width="800"
        :mask-closable="false"
      >
        <div class="detail-container">
          <Row :gutter="16">
            <Col span="12">
              <div class="detail-item">
                <label>活动名称:</label>
                <span>{{ detailData.activityName }}</span>
              </div>
            </Col>
            <Col span="12">
              <div class="detail-item">
                <label>用户昵称:</label>
                <span>{{ detailData.nickName}}</span>
              </div>
            </Col>
            <Col span="12">
              <div class="detail-item">
                <label>奖品内容:</label>
                <span>{{ detailData.prizeContent }}</span>
              </div>
            </Col>
            <Col span="24">
              <div class="detail-item">
                <label>中奖状态:</label>
                <Tag :color="detailData.prizeStatus === 'WIN' ? 'green' : 'red'">
                  {{ detailData.prizeStatus === 'WIN' ? '中奖' : '未中奖' }}
                </Tag>
              </div>
            </Col>
            <Col span="24">
              <div class="detail-item">
                <label>奖品发放:</label>
                <Tag
                  :color="getStatusColor(detailData.distributeStatus)"
                >
                  {{ getStatusText(detailData.distributeStatus) }}
                </Tag>
              </div>
            </Col>
            <Col span="24">
              <div class="detail-item">
                <label>活动封面:</label>
                <div v-if="detailData.activityCoverUrl" class="detail-image">
                  <img
                    :src="detailData.activityCoverUrl" alt="活动封面"
                    class="preview-image-limit"
                  >
                </div>
                <span v-else>-</span>
              </div>
            </Col>
            <Col span="24">
              <div class="detail-item">
                <label>奖品封面:</label>
                <div v-if="detailData.prizeImgUrl" class="detail-image">
                  <img
                    :src="detailData.prizeImgUrl" alt="奖品封面"
                    class="preview-image-limit"
                  >
                </div>
                <span v-else>-</span>
              </div>
            </Col>
          </Row>
        </div>
      </Modal>
    </Card>
  </div>
</template>
<script>
import {
  getPage,
  queryExport
} from '@/api/prize-record.js'
export default {
  name: "prizeRecord",
  data() {
    return {
      infoModalShow:false,
      detailData: {},
      modelShow:false,
      modelTitle:'',
      loading:false,
      columns:[
        {
          title: '用户昵称',
          key: 'nickName',
          minWidth: 100,
        },
        {
          title: '活动名称',
          key: 'prizeActivityName',
          minWidth: 100,
        },
        {
          title: '中奖状态',
          key: 'prizeStatus',
          minWidth: 100,
          render: (h, params) => {
            return h('Tag', {
              props: {
                color: params.row.prizeStatus === 'WIN' ? 'green' : 'red'
              }}, params.row.prizeStatus === 'WIN' ? '中奖' : '未中奖')
          }
        },
        {
          title: '奖品发放状态',
          key: 'distributeStatus',
          minWidth: 100,
          render: (h, params) => {
            // 获取当前状态
            const status = params.row.distributeStatus;
            // 根据状态确定颜色和文本
            let color, text;
            switch(status) {
              case 'SUCCESS':
                color = 'green';
                text = '已发放';
                break;
              case 'NOT_WAIT':
                color = 'blue';
                text = '未中奖';
                break;
              case 'FAILED':
                color = 'red';
                text = '发放失败';
                break;
              case 'WAIT':
                color = 'orange';
                text = '待发放';
                break;
              default:
                color = 'default';
                text = '未知状态';
            }
            return h('Tag', {
              props: { color }
            }, text);
          }
        },
        {
          title: '操作',
          slot: 'action',
          width: 280,
          align: 'center',
          fixed: 'right'
        },
      ],
      data:[],
      total:0,
      searchForm:{
        pageSize:10,
        pageNumber:1,
        nickName:'',
        activityName:'',
        prizeStatus:'',
        distributeStatus:''
      },
      distributeSelect:[
        {id: 1, value: 'NOT_WAIT', label: '未中奖'},
        {id: 2, value: 'WAIT', label: '待发放'},
        {id: 3, value: 'FAILED', label: '发放失败'},
        {id: 4, value: 'SUCCESS', label: '已发放'},
      ],
      typeSelect:[
        {id: 1, value: 'WIN', label: '中奖'},
        {id: 2, value: 'NOT_WIN', label: '未中奖'}
      ],
      activityCover:null,
    }
  },
  // 在组件创建前注册
  beforeCreate() {
  },
  mounted() {
    this.init();
  },
  methods: {
    queryExport(){
      queryExport(this.searchForm).then(res =>{
        const blob = new Blob([res], {
          type: "application/vnd.ms-excel;charset=utf-8",
        });
        //对于<a>标签,只有 Firefox 和 Chrome(内核) 支持 download 属性
        //IE10以上支持blob但是依然不支持download
        if ("download" in document.createElement("a")) {
          //支持a标签download的浏览器
          const link = document.createElement("a"); //创建a标签
          link.download = "用户抽奖记录.xlsx"; //a标签添加属性
          link.style.display = "none";
          link.href = URL.createObjectURL(blob);
          document.body.appendChild(link);
          link.click(); //执行下载
          URL.revokeObjectURL(link.href); //释放url
          document.body.removeChild(link); //释放标签
        } else {
          navigator.msSaveBlob(blob, fileName);
        }
      })
    },
    // 获取状态对应的颜色
    getStatusColor(status) {
      // 处理空值情况
      if (!status) return 'default'
      // 根据状态返回对应颜色
      switch(status) {
        case 'NOT_WAIT':
          return 'blue'
        case 'WAIT':
          return 'orange'
        case 'FAILED':
          return 'red'
        case 'SUCCESS':
          return 'green'
        // 默认颜色
        default:
          return 'default'
      }
    },
    // 获取状态对应的文本
    getStatusText(status) {
      if (!status) return '未知状态'
      switch(status) {
        case 'NOT_WAIT':
          return '未中奖'
        case 'WAIT':
          return '待发放'
        case 'FAILED':
          return '发放失败'
        case 'SUCCESS':
          return '已发放'
        // 默认文本
        default:
          return '未知状态'
      }
    },
    // 格式化奖品类型
    replaceText(type) {
      if (type === "coupon") {
        return "优惠券";
      }
      return type; // 如果不是目标词,返回原文本
    },
    resetSearch(){
      this.$refs.searchForm.resetFields()
      this.searchForm.pageNumber = 1
      this.getPage()
    },
    infoModelClose(){
      this.infoModalShow = false;
    },
    getPage(){
      this.loading = true;
      getPage(this.searchForm).then(res =>{
        this.loading = false;
        if (res.code === 200){
          this.data = res.data;
          this.total = res.total;
        }else {
          this.$Message.error(res.msg)
        }
      })
    },
    detail(row){
      this.infoModalShow = true;
      this.detailData = {...row};
    },
    handleSearch(type,value){
      if (type === 'beginTime') {
        this.searchForm.beginTime = value
      } else if (type === 'endTime') {
        this.searchForm.endTime = value
      }
      this.getPage()
    },
    // 初始化数据
    init() {
      this.getPage()
    },
    changePage(){
      this.searchForm.pageNumber = 1
      this.searchForm.pageSize = pageSize
      this.getPage()
    },
    changePageSize(){
      this.searchForm.pageNumber = page
      this.getPage()
    },
  },
}
</script>
<style lang="scss" scoped>
.search-form {
  padding: 16px;
  background: #f8f8f9;
  border-radius: 4px;
  margin-bottom: 16px;
  .ivu-form-item {
    margin-bottom: 16px;
    margin-right: 16px;
  }
  .search-btn {
    margin-left: 8px;
  }
}
.table {
  .thumbnail {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    cursor: pointer;
    transition: all 0.3s;
    &:hover {
      transform: scale(1.05);
      box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
    }
  }
  .action-btns {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    .ivu-btn {
      margin: 4px;
      font-size: 12px;
      padding: 2px 6px;
      min-width: 60px;
    }
  }
}
.detail-container {
  padding: 16px;
}
.detail-item {
  margin-bottom: 16px;
  line-height: 1.5;
}
.detail-item label {
  display: inline-block;
  width: 120px;
  font-weight: bold;
  color: #515a6e;
  vertical-align: top;
}
.detail-item span {
  display: inline-block;
  max-width: calc(100% - 120px);
}
.detail-image {
  display: inline-block;
  margin-top: 8px;
  border: 1px dashed #dcdee2;
  padding: 4px;
  border-radius: 4px;
  background: #f8f8f9;
}
</style>