peng
2025-10-22 5596ea666d2b2b69ab4d18740c4074ad4cc53dd6
用户行为分析调整
1个文件已修改
1个文件已添加
783 ■■■■■ 已修改文件
manager/src/api/userAction.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager/src/views/userAction/userActionRecord.vue 776 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager/src/api/userAction.js
@@ -18,4 +18,11 @@
    method: "GET",
    params: params
  })
}//获取用户分享页面
export const userStayListRecord = (params) =>{
  return service({
    url: "/lmk/action-record/userStayListRecord",
    method: "GET",
    params: params
  })
}
manager/src/views/userAction/userActionRecord.vue
New file
@@ -0,0 +1,776 @@
<template>
  <div class="wrapper">
    <Card class="user-action-card">
      <Row @keydown.enter.native="handleSearch">
        <Form ref="searchForm" :model="searchForm" inline :label-width="80" style="width: 100%" class="search-form">
          <Form-item label="用户昵称" prop="userName">
            <Input type="text" v-model="searchForm.userName" placeholder="请输入用户昵称" clearable style="width: 200px" />
          </Form-item>
<!--          <Form-item label="页面类型" prop="pageCode">-->
<!--            <Select-->
<!--              v-model="searchForm.pageCode"-->
<!--              clearable-->
<!--              filterable-->
<!--              style="width: 200px"-->
<!--              placeholder="请选择页面类型">-->
<!--              <Option-->
<!--                v-for="item in pageTypeOptions"-->
<!--                :key="item.value"-->
<!--                :value="item.value"-->
<!--                :label="item.label">-->
<!--                {{ item.label }}-->
<!--              </Option>-->
<!--            </Select>-->
<!--          </Form-item>-->
          <Form-item label="开始时间" prop="beginDate">
            <DatePicker
              v-model="searchForm.beginDate"
              type="datetime"
              placeholder="请选择开始时间"
              style="width: 200px">
            </DatePicker>
          </Form-item>
          <Form-item label="结束时间" prop="endDate">
            <DatePicker
              v-model="searchForm.endDate"
              type="datetime"
              placeholder="请选择结束时间"
              style="width: 200px">
            </DatePicker>
          </Form-item>
          <Button @click="handleSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
          <Button @click="handleReset" type="default" class="search-btn">重置</Button>
        </Form>
      </Row>
      <div class="table-container">
        <Table
          :loading="loading"
          border
          :columns="columns"
          :data="data"
          ref="table">
        </Table>
      </div>
      <Row type="flex" justify="end" class="mt_10">
        <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>
    </Card>
    <!-- 用户行为详情弹窗 -->
    <Modal
      v-model="detailModalVisible"
      title="用户行为详情"
      width="80%"
      :loading="detailLoading"
      :footer-hide="true">
      <Spin size="large" fix v-if="detailLoading"></Spin>
      <div v-else>
        <!-- 详情筛选条件 -->
        <Row @keydown.enter.native="handleDetailSearch">
          <Form ref="detailSearchForm" :model="detailSearchForm" inline :label-width="80" style="width: 100%" class="search-form">
            <Form-item label="用户昵称" prop="userName">
              <Input type="text" v-model="detailSearchForm.userName" placeholder="请输入用户昵称" clearable style="width: 200px" />
            </Form-item>
            <Form-item label="页面类型" prop="pageCode">
              <Select
                v-model="detailSearchForm.pageCode"
                clearable
                filterable
                style="width: 200px"
                placeholder="请选择页面类型">
                <Option
                  v-for="item in pageTypeOptions"
                  :key="item.value"
                  :value="item.value"
                  :label="item.label">
                  {{ item.label }}
                </Option>
              </Select>
            </Form-item>
            <Form-item label="开始时间" prop="beginDate">
              <DatePicker
                v-model="detailSearchForm.beginDate"
                type="datetime"
                placeholder="请选择开始时间"
                style="width: 200px">
              </DatePicker>
            </Form-item>
            <Form-item label="结束时间" prop="endDate">
              <DatePicker
                v-model="detailSearchForm.endDate"
                type="datetime"
                placeholder="请选择结束时间"
                style="width: 200px">
              </DatePicker>
            </Form-item>
            <Button @click="handleDetailSearch" type="primary" icon="ios-search" class="search-btn">搜索</Button>
            <Button @click="handleDetailReset" type="default" class="search-btn">重置</Button>
          </Form>
        </Row>
        <div class="table-container">
          <Table
            :loading="detailTableLoading"
            border
            :columns="detailColumns"
            :data="detailData"
            ref="detailTable">
          </Table>
        </div>
        <Row type="flex" justify="end" class="mt_10">
          <Page
            :current="detailSearchForm.pageNumber"
            :total="detailTotal"
            :page-size="detailSearchForm.pageSize"
            @on-change="changeDetailPage"
            @on-page-size-change="changeDetailPageSize"
            :page-size-opts="[10, 20, 50]"
            size="small"
            show-total
            show-elevator
            show-sizer>
          </Page>
        </Row>
      </div>
    </Modal>
  </div>
</template>
<script>
import { userStayList, userStayListRecord } from "@/api/userAction";
import { formatDate } from "@/utils/filters";
export default {
  name: "userAction",
  data() {
    // 设置默认时间改为最近7天
    const now = new Date();
    const endTime = new Date(now);
    endTime.setHours(23, 59, 59, 999);
    // 开始时间为7天前(包含今天,总共7天)
    const startTime = new Date(now);
    startTime.setDate(startTime.getDate() - 6);
    startTime.setHours(0, 0, 0, 0);
    console.log("默认开始时间(最近7天):", startTime);
    console.log("默认结束时间:", endTime);
    console.log("开始时间类型:", typeof startTime);
    console.log("结束时间类型:", typeof endTime);
    // 验证日期格式化是否正常工作
    try {
      const formattedStart = formatDate(startTime, 'yyyy-MM-dd hh:mm:ss');
      const formattedEnd = formatDate(endTime, 'yyyy-MM-dd hh:mm:ss');
      console.log("默认开始时间格式化结果:", formattedStart);
      console.log("默认结束时间格式化结果:", formattedEnd);
    } catch (e) {
      console.error("初始化时日期格式化出错:", e);
    }
    return {
      loading: false, // 默认不加载
      searchForm: {
        pageNumber: 1,
        pageSize: 10,
        userName: "",
        pageCode: "",
        beginDate: startTime,
        endDate: endTime
      },
      // 页面类型选项(用于下拉框)
      pageTypeOptions: [
        { value: "RECOMMEND_VIDEO", label: "首页推荐视频" },
        { value: "HEALTH_VIDEO", label: "大健康视频" },
        { value: "KITCHEN_VIDEO", label: "神厨视频" },
        { value: "RECOMMEND_VIDEO_GOODS", label: "视频推荐商品页面" },
        { value: "RECOMMEND_VIDEO_LEFT_GOODS", label: "左滑推荐商品" },
        { value: "RECOMMEND_VIDEO_RIGHT_VIDEO", label: "右滑视频页面" },
        { value: "FILL_ORDER", label: "填写订单" },
        { value: "PAY_ORDER", label: "支付订单" },
        { value: "PAY_SUCCESS", label: "支付成功" },
        { value: "ORDER_LIST", label: "订单列表" },
        { value: "ORDER_DETAIL", label: "订单详情" },
        { value: "PRIZE_DETAIL", label: "抽奖活动" },
        { value: "CART_LIST", label: "购物车" },
        { value: "TBA_BAR_MY", label: "我的页面" },
        { value: "SHOPPING_SQUARE", label: "商品广场" },
        { value: "ACTIVITY_LIST", label: "活动列表" },
        { value: "ACTIVITY_DETAIL", label: "活动详情" },
        { value: "PUBLISH_VIDEO", label: "视频发布" },
        { value: "SWIPER_GOODS", label: "滑动商品" },
        { value: "COUPON_CENTER", label: "领卷中心" },
        { value: "MY_COUPON", label: "我的优惠卷" },
        { value: "AFTER_SALE", label: "售后列表" },
        { value: "APPLY_SALE", label: "申请售后" },
        { value: "REFUND_ORDER", label: "退款/退货" },
        { value: "GOODS_DETAILS", label: "商品详情页面" }
      ],
      columns: [
        {
          title: "用户名称",
          key: "userId",
          minWidth: 120
        },
        {
          title: "用户昵称",
          key: "nickName",
          minWidth: 100
        },
        {
          title: "页面类型",
          key: "pageCode",
          minWidth: 150,
          render: (h, params) => {
            const pageCodes = {
              "RECOMMEND_VIDEO": "首页推荐视频",
              "HEALTH_VIDEO": "大健康视频",
              "KITCHEN_VIDEO": "神厨视频",
              "RECOMMEND_VIDEO_GOODS": "视频推荐商品页面",
              "RECOMMEND_VIDEO_LEFT_GOODS": "左滑推荐商品",
              "RECOMMEND_VIDEO_RIGHT_VIDEO": "右滑视频页面",
              "FILL_ORDER": "填写订单",
              "PAY_ORDER": "支付订单",
              "PAY_SUCCESS": "支付成功",
              "ORDER_LIST": "订单列表",
              "ORDER_DETAIL": "订单详情",
              "PRIZE_DETAIL": "抽奖活动",
              "CART_LIST": "购物车",
              "TBA_BAR_MY": "我的页面",
              "SHOPPING_SQUARE": "商品广场",
              "ACTIVITY_LIST": "活动列表",
              "ACTIVITY_DETAIL": "活动详情",
              "PUBLISH_VIDEO": "视频发布",
              "SWIPER_GOODS": "滑动商品",
              "COUPON_CENTER": "领卷中心",
              "MY_COUPON": "我的优惠卷",
              "AFTER_SALE": "售后列表",
              "APPLY_SALE": "申请售后",
              "REFUND_ORDER": "退款/退货",
              "GOODS_DETAILS": "商品详情页面"
            };
            return h('span', pageCodes[params.row.pageCode] || params.row.pageCode);
          }
        },
        {
          title: "进入时间",
          key: "startTime",
          minWidth: 160
        },
        {
          title: "操作",
          key: "action",
          width: 150,
          align: "center",
          render: (h, params) => {
            // 添加查看详情按钮
            return h('div', [
              h('Button', {
                props: {
                  type: 'primary',
                  size: 'small'
                },
                on: {
                  click: () => {
                    this.showDetailModal(params.row.userId);
                  }
                }
              }, '查看'),
              // 只有当页面类型是商品详情页面时才显示跳转按钮
              params.row.pageCode === "GOODS_DETAILS" && params.row.pageParams ? h('Button', {
                props: {
                  type: 'primary',
                  size: 'small',
                  style: { marginLeft: '5px' }
                },
                on: {
                  click: () => {
                    this.goToGoodsDetail(params.row.pageParams);
                  }
                }
              }, '查看商品详情') : null,
              // 当页面类型是订单详情页面时显示跳转按钮
              params.row.pageCode === "ORDER_DETAIL" && params.row.pageParams ? h('Button', {
                props: {
                  type: 'primary',
                  size: 'small',
                  style: { marginLeft: '5px' }
                },
                on: {
                  click: () => {
                    this.goToOrderDetail(params.row.pageParams);
                  }
                }
              }, '查看订单详情') : null
            ].filter(item => item !== null));
          }
        }
      ],
      data: [],
      total: 0,
      // 详情弹窗相关数据
      detailModalVisible: false,
      detailLoading: false,
      detailTableLoading: false,
      detailSearchForm: {
        pageNumber: 1,
        pageSize: 10,
        userId: "",
        userName: "",
        pageCode: "",
        beginDate: startTime,
        endDate: endTime
      },
      detailColumns: [
        {
          title: "用户名称",
          key: "userId",
          minWidth: 120
        },
        {
          title: "用户昵称",
          key: "nickName",
          minWidth: 100
        },
        {
          title: "会话ID",
          key: "sessionId",
          minWidth: 150
        },
        {
          title: "页面类型",
          key: "pageCode",
          minWidth: 150,
          render: (h, params) => {
            const pageCodes = {
              "RECOMMEND_VIDEO": "首页推荐视频",
              "HEALTH_VIDEO": "大健康视频",
              "KITCHEN_VIDEO": "神厨视频",
              "RECOMMEND_VIDEO_GOODS": "视频推荐商品页面",
              "RECOMMEND_VIDEO_LEFT_GOODS": "左滑推荐商品",
              "RECOMMEND_VIDEO_RIGHT_VIDEO": "右滑视频页面",
              "FILL_ORDER": "填写订单",
              "PAY_ORDER": "支付订单",
              "PAY_SUCCESS": "支付成功",
              "ORDER_LIST": "订单列表",
              "ORDER_DETAIL": "订单详情",
              "PRIZE_DETAIL": "抽奖活动",
              "CART_LIST": "购物车",
              "TBA_BAR_MY": "我的页面",
              "SHOPPING_SQUARE": "商品广场",
              "ACTIVITY_LIST": "活动列表",
              "ACTIVITY_DETAIL": "活动详情",
              "PUBLISH_VIDEO": "视频发布",
              "SWIPER_GOODS": "滑动商品",
              "COUPON_CENTER": "领卷中心",
              "MY_COUPON": "我的优惠卷",
              "AFTER_SALE": "售后列表",
              "APPLY_SALE": "申请售后",
              "REFUND_ORDER": "退款/退货",
              "GOODS_DETAILS": "商品详情页面"
            };
            return h('span', pageCodes[params.row.pageCode] || params.row.pageCode);
          }
        },
        {
          title: "页面名称",
          key: "pageNameCn",
          minWidth: 150
        },
        {
          title: "进入时间",
          key: "enterTime",
          minWidth: 160
        },
        {
          title: "离开时间",
          key: "leaveTime",
          minWidth: 160
        },
        {
          title: "停留时长(秒)",
          key: "staySeconds",
          minWidth: 120
        },
        {
          title: "操作",
          key: "action",
          width: 150,
          align: "center",
          render: (h, params) => {
            // 只有当页面类型是商品详情页面时才显示跳转按钮
            if (params.row.pageCode === "GOODS_DETAILS" && params.row.pageParams) {
              return h('div', [
                h('Button', {
                  props: {
                    type: 'primary',
                    size: 'small'
                  },
                  on: {
                    click: () => {
                      this.goToGoodsDetail(params.row.pageParams);
                    }
                  }
                }, '查看商品详情')
              ]);
            }
            // 当页面类型是订单详情页面时显示跳转按钮
            if (params.row.pageCode === "ORDER_DETAIL" && params.row.pageParams) {
              return h('div', [
                h('Button', {
                  props: {
                    type: 'primary',
                    size: 'small'
                  },
                  on: {
                    click: () => {
                      this.goToOrderDetail(params.row.pageParams);
                    }
                  }
                }, '查看订单详情')
              ]);
            }
            return h('span', '-');
          }
        }
      ],
      detailData: [],
      detailTotal: 0
    };
  },
  methods: {
    // 初始化数据
    init() {
      console.log("执行init方法,准备加载数据");
      // 页面初始化时直接调用,检查时间参数
      this.$nextTick(() => {
        console.log("init方法中的nextTick回调,调用getDataListWithoutValidation");
        this.getDataListWithoutValidation();
      });
    },
    // 获取最近7天的开始时间(包含今天,总共7天)
    getDefaultBeginDate() {
      const now = new Date();
      const startTime = new Date(now);
      startTime.setDate(startTime.getDate() - 6); // 7天前,包含今天
      startTime.setHours(0, 0, 0, 0);
      return startTime;
    },
    // 获取当天结束时间
    getDefaultEndDate() {
      const now = new Date();
      now.setHours(23, 59, 59, 999);
      return now;
    },
    // 不进行表单验证的数据获取
    getDataListWithoutValidation() {
      this.loading = true;
      console.log("开始请求数据:", this.searchForm);
      console.log("开始时间值:", this.searchForm.beginDate);
      console.log("结束时间值:", this.searchForm.endDate);
      console.log("开始时间类型:", typeof this.searchForm.beginDate);
      console.log("结束时间类型:", typeof this.searchForm.endDate);
      // 检查时间参数是否为空
      if (!this.searchForm.beginDate) {
        console.log("开始时间为空");
      }
      if (!this.searchForm.endDate) {
        console.log("结束时间为空");
      }
      // 处理时间格式,使用正确的参数名称beginDate和endDate
      const params = { ...this.searchForm };
      if (params.beginDate) {
        params.beginDate = this.formatDate(params.beginDate);
        console.log("格式化后的开始时间:", params.beginDate);
      } else {
        this.loading = false;
        this.$Message.error("开始时间不能为空");
        return;
      }
      if (params.endDate) {
        params.endDate = this.formatDate(params.endDate);
        console.log("格式化后的结束时间:", params.endDate);
      } else {
        this.loading = false;
        this.$Message.error("结束时间不能为空");
        return;
      }
      console.log("最终请求参数:", params);
      userStayListRecord(params).then(res => {
        console.log("请求成功:", res);
        if (res.code === 200) {
          this.data = res.data.records || [];
          this.total = res.data.total || 0;
          console.log("数据加载完成,记录数:", this.data.length);
        } else {
          this.$Message.error(res.msg || "获取数据失败");
          console.error("获取数据失败:", res.msg || "未知错误");
        }
      }).catch(err => {
        console.error("请求失败:", err);
        this.$Message.error("请求异常: " + (err.message || "未知错误"));
      }).finally(() => {
        // 确保在任何情况下都关闭loading状态
        this.loading = false;
        console.log("请求完成,loading状态已关闭");
      });
    },
    // 带表单验证的数据获取
    getDataList() {
      this.$refs.searchForm.validate((valid) => {
        if (valid) {
          this.getDataListWithoutValidation();
        } else {
          this.loading = false; // 验证失败时也要关闭loading
          this.$Message.error("请检查表单输入是否正确");
        }
      });
    },
    // 格式化日期时间
    formatDate(date) {
      if (!date) {
        console.warn("日期格式化时传入了空值");
        return "";
      }
      try {
        const formattedDate = formatDate(new Date(date), 'yyyy-MM-dd hh:mm:ss');
        console.log("日期格式化结果:", formattedDate);
        return formattedDate;
      } catch (error) {
        console.error("日期格式化出错:", error);
        // 如果格式化出错,尝试使用另一种方式
        try {
          const d = new Date(date);
          const year = d.getFullYear();
          const month = ('0' + (d.getMonth() + 1)).slice(-2);
          const day = ('0' + d.getDate()).slice(-2);
          const hours = ('0' + d.getHours()).slice(-2);
          const minutes = ('0' + d.getMinutes()).slice(-2);
          const seconds = ('0' + d.getSeconds()).slice(-2);
          const formatted = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
          console.log("备用日期格式化结果:", formatted);
          return formatted;
        } catch (backupError) {
          console.error("备用日期格式化也出错:", backupError);
          return "";
        }
      }
    },
    // 改变页数
    changePage(page) {
      this.searchForm.pageNumber = page;
      this.getDataListWithoutValidation();
    },
    // 改变页码
    changePageSize(pageSize) {
      this.searchForm.pageNumber = 1;
      this.searchForm.pageSize = pageSize;
      this.getDataListWithoutValidation();
    },
    // 搜索
    handleSearch() {
      console.log("搜索按钮被点击");
      this.searchForm.pageNumber = 1;
      // 直接检查时间参数,不使用表单验证
      console.log("开始搜索,检查时间参数");
      // 检查时间参数是否为空
      if (!this.searchForm.beginDate || !this.searchForm.endDate) {
        this.$Message.error("开始时间和结束时间不能为空");
        return;
      }
      this.getDataListWithoutValidation();
    },
    // 重置
    handleReset() {
      this.searchForm.pageNumber = 1;
      this.searchForm.pageSize = 10;
      this.searchForm.userName = "";
      this.searchForm.pageCode = "";
      // 使用正确的参数名称和方法
      this.searchForm.beginDate = this.getDefaultBeginDate();
      this.searchForm.endDate = this.getDefaultEndDate();
      // 重置后重新加载数据
      this.$nextTick(() => {
        this.getDataListWithoutValidation();
      });
    },
    // 跳转到商品详情页面
    goToGoodsDetail(pageParams) {
      try {
        // 解析pageParams JSON字符串
        const params = JSON.parse(pageParams);
        console.log("解析后的参数:", params);
        // 检查必要参数
        if (!params.id || !params.goodsId) {
          this.$Message.error("商品参数不完整");
          return;
        }
        // 跳转到商品详情页面,传递参数
        this.$router.push({
          name: "goods-detail",
          query: {
            id: params.goodsId
          }
        });
      } catch (error) {
        console.error("解析pageParams出错:", error);
        this.$Message.error("参数解析失败");
      }
    },
    // 跳转到订单详情页面
    goToOrderDetail(pageParams) {
      try {
        // 解析pageParams JSON字符串
        const params = JSON.parse(pageParams);
        console.log("解析后的参数:", params);
        // 检查必要参数
        if (!params.sn) {
          this.$Message.error("订单参数不完整");
          return;
        }
        // 跳转到订单详情页面,传递订单号参数
        this.$router.push({
          name: "order-detail",
          query: {
            sn: params.sn
          }
        });
      } catch (error) {
        console.error("解析pageParams出错:", error);
        this.$Message.error("参数解析失败");
      }
    },
    // 显示详情弹窗
    showDetailModal(userId) {
      this.detailSearchForm.userId = userId;
      this.detailSearchForm.pageNumber = 1;
      this.detailSearchForm.userName = "";
      this.detailSearchForm.pageCode = "";
      this.detailSearchForm.beginDate = this.getDefaultBeginDate();
      this.detailSearchForm.endDate = this.getDefaultEndDate();
      this.detailModalVisible = true;
      this.getDetailData();
    },
    // 获取详情数据
    getDetailData() {
      this.detailTableLoading = true;
      // 处理时间格式
      const params = { ...this.detailSearchForm };
      if (params.beginDate) {
        params.beginDate = this.formatDate(params.beginDate);
      }
      if (params.endDate) {
        params.endDate = this.formatDate(params.endDate);
      }
      // 调用与userAction.vue相同的接口,但增加userId参数
      userStayList(params).then(res => {
        if (res.code === 200) {
          this.detailData = res.data.records || [];
          this.detailTotal = res.data.total || 0;
        } else {
          this.$Message.error(res.msg || "获取详情数据失败");
        }
      }).catch(err => {
        console.error("请求详情数据失败:", err);
        this.$Message.error("请求异常: " + (err.message || "未知错误"));
      }).finally(() => {
        this.detailTableLoading = false;
      });
    },
    // 改变详情页数
    changeDetailPage(page) {
      this.detailSearchForm.pageNumber = page;
      this.getDetailData();
    },
    // 改变详情页码
    changeDetailPageSize(pageSize) {
      this.detailSearchForm.pageNumber = 1;
      this.detailSearchForm.pageSize = pageSize;
      this.getDetailData();
    },
    // 详情搜索
    handleDetailSearch() {
      this.detailSearchForm.pageNumber = 1;
      this.getDetailData();
    },
    // 详情重置
    handleDetailReset() {
      this.detailSearchForm.pageNumber = 1;
      this.detailSearchForm.pageSize = 10;
      this.detailSearchForm.userName = "";
      this.detailSearchForm.pageCode = "";
      this.detailSearchForm.beginDate = this.getDefaultBeginDate();
      this.detailSearchForm.endDate = this.getDefaultEndDate();
      this.getDetailData();
    }
  },
  mounted() {
    console.log("组件已挂载,开始初始化数据");
    this.$nextTick(() => {
      console.log("nextTick回调,调用init方法");
      this.init();
    });
  }
};
</script>
<style scoped>
.search-btn {
  margin-right: 10px;
}
.mt_10 {
  margin-top: 10px;
}
/* 用户行为卡片样式 */
.user-action-card {
  height: calc(100vh - 100px);
  display: flex;
  flex-direction: column;
}
/* 表格容器样式 */
.table-container {
  flex: 1;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
/* 表格样式 */
.table-container /deep/ .ivu-table-wrapper {
  flex: 1;
  overflow-y: auto;
  height: 100%;
}
/* 搜索表单样式 */
.search-form {
  padding: 16px 0;
}
/* 分页样式 */
.mt_10 {
  padding: 10px 0;
}
</style>