| New file |
| | |
| | | import service from "../libs/axios"; |
| | | |
| | | |
| | | |
| | | |
| | | //获取用户停留列表 |
| | | export const userStayList = (params) =>{ |
| | | return service({ |
| | | url: "/lmk/action-record/userStayList", |
| | | method: "GET", |
| | | params: params |
| | | }) |
| | | } |
| | | //获取用户分享页面 |
| | | export const userShareList = (params) =>{ |
| | | return service({ |
| | | url: "/lmk/action-record/userShare", |
| | | method: "GET", |
| | | params: params |
| | | }) |
| | | } |
| | |
| | | return mobile.replace(/(\d{3})(\d{4})(\d{4})/, '$1****$3') |
| | | } |
| | | |
| | | /** |
| | | * 日期格式化辅助函数 |
| | | * @param {string} str |
| | | * @returns |
| | | */ |
| | | function padLeftZero(str) { |
| | | return ('00' + str).substr(str.length); |
| | | } |
| | | |
| | | export function formatDate(date, fmt) { |
| | | if (/(y+)/.test(fmt)) { |
| | |
| | | <div class="single-page-con" :style="{ 'top': setting.isUseTabsRouter ? '100px' : '60px', height: setting.isUseTabsRouter ? 'calc(100% - 110px)' : 'calc(100% - 70px)' }"> |
| | | <div class="single-page"> |
| | | <!-- <keep-alive :include="cachePage">--> |
| | | <keep-alive :include="['orderList','fictitiousOrderList','CarPack','after-sale-order','member']"> |
| | | <keep-alive :include="['orderList','fictitiousOrderList','CarPack','after-sale-order','member','userAction','userShareAction']"> |
| | | <router-view></router-view> |
| | | </keep-alive> |
| | | <!-- </keep-alive>--> |
| | |
| | | console.log("to:",to.fullPath) |
| | | console.log("form:",from.fullPath) |
| | | // 正确打印路由对象的方法 |
| | | if((from.fullPath === "/orderList"|| from.fullPath === "/fictitiousOrderList" ||from.fullPath === "/orderStatistics"||from.fullPath.includes( "/member-detail")) && to.fullPath.includes("/order-detail")){ |
| | | if((from.fullPath === "/orderList"|| from.fullPath === "/fictitiousOrderList" ||from.fullPath === "/orderStatistics"||from.fullPath === "/userAction"||from.fullPath.includes( "/member-detail")) && to.fullPath.includes("/order-detail")){ |
| | | this.sn = this.$route.query.sn; |
| | | this.getDataList(); |
| | | this.getOrderPackage(); |
| New file |
| | |
| | | <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> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { userStayList } 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: "会话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', '-'); |
| | | } |
| | | } |
| | | ], |
| | | data: [], |
| | | total: 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); |
| | | |
| | | userStayList(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("参数解析失败"); |
| | | } |
| | | } |
| | | }, |
| | | 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> |
| New file |
| | |
| | | <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="videoDetailShow" |
| | | :title="videoDetailTitle" |
| | | width="800" |
| | | :mask-closable="false" |
| | | @on-cancel="closeVideoDetail"> |
| | | <div class="video-info" v-if="currentVideoDetail && !videoLoading"> |
| | | <div class="video-basic-info"> |
| | | <h3>{{ currentVideoDetail.title }}</h3> |
| | | </div> |
| | | <div style="margin: 15px 0; height: 1px; background-color: #e8eaec;"></div> |
| | | </div> |
| | | <div class="video-wrapper"> |
| | | <video |
| | | v-if="videoDetailUrl" |
| | | :src="videoDetailUrl" |
| | | autoplay |
| | | controls |
| | | style="width: 100%; height: 450px" |
| | | /> |
| | | <div v-else style="text-align: center; padding: 50px 0;"> |
| | | <Spin v-if="videoLoading" fix /> |
| | | <div v-else>暂无视频内容</div> |
| | | </div> |
| | | </div> |
| | | <div slot="footer"> |
| | | <Button type="text" @click="closeVideoDetail">关闭</Button> |
| | | </div> |
| | | </Modal> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { userShareList } from "@/api/userAction"; |
| | | import { formatDate } from "@/utils/filters"; |
| | | import { getVideoById } from "@/api/video"; |
| | | import { getFilePreview } from "@/api/file"; |
| | | |
| | | export default { |
| | | name: "userShareAction", |
| | | 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); |
| | | |
| | | return { |
| | | loading: false, // 默认不加载 |
| | | searchForm: { |
| | | pageNumber: 1, |
| | | pageSize: 10, |
| | | userName: "", |
| | | pageCode: "", |
| | | beginDate: startTime, |
| | | endDate: endTime |
| | | }, |
| | | // 页面类型选项(用于下拉框) |
| | | pageTypeOptions: [ |
| | | { value: "RECOMMEND_VIDEO", label: "首页推荐视频" }, |
| | | { value: "SHOPPING_SQUARE", label: "商品广场" }, |
| | | { value: "GOODS_DETAILS", label: "商品详情页面" } |
| | | ], |
| | | // 视频详情弹窗相关数据 |
| | | videoDetailShow: false, |
| | | videoDetailTitle: '', |
| | | videoDetailUrl: '', |
| | | videoLoading: false, |
| | | currentVideoDetail: null, // 当前视频详情数据 |
| | | columns: [ |
| | | { |
| | | title: "用户昵称", |
| | | key: "nickName", |
| | | minWidth: 120 |
| | | }, |
| | | { |
| | | 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: "createTime", |
| | | minWidth: 160 |
| | | }, |
| | | { |
| | | title: "操作", |
| | | key: "action", |
| | | width: 150, |
| | | align: "center", |
| | | render: (h, params) => { |
| | | // 只有当页面类型是商品详情页面时才显示跳转按钮 |
| | | if (params.row.pageCode === "GOODS_DETAILS") { |
| | | return h('div', [ |
| | | h('Button', { |
| | | props: { |
| | | type: 'primary', |
| | | size: 'small' |
| | | }, |
| | | on: { |
| | | click: () => { |
| | | this.goToGoodsDetail(params.row.shareOption); |
| | | } |
| | | } |
| | | }, '查看商品详情') |
| | | ]); |
| | | } |
| | | // 当页面类型是推荐视频页面时显示跳转按钮 |
| | | if (params.row.pageCode === "RECOMMEND_VIDEO") { |
| | | // 检查参数是否完整,如果完整才显示查看按钮 |
| | | if (this.canViewVideoDetail(params.row.shareOption)) { |
| | | return h('div', [ |
| | | h('Button', { |
| | | props: { |
| | | type: 'primary', |
| | | size: 'small' |
| | | }, |
| | | on: { |
| | | click: () => { |
| | | // 查看视频详情 |
| | | this.viewVideoDetail(params.row); |
| | | } |
| | | } |
| | | }, '查看视频详情') |
| | | ]); |
| | | } |
| | | } |
| | | return h('span', '-'); |
| | | } |
| | | } |
| | | ], |
| | | data: [], |
| | | total: 0 |
| | | }; |
| | | }, |
| | | methods: { |
| | | // 初始化数据 |
| | | init() { |
| | | this.$nextTick(() => { |
| | | 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; |
| | | |
| | | // 处理时间格式 |
| | | const params = { ...this.searchForm }; |
| | | if (params.beginDate) { |
| | | params.beginDate = this.formatDate(params.beginDate); |
| | | } else { |
| | | this.loading = false; |
| | | this.$Message.error("开始时间不能为空"); |
| | | return; |
| | | } |
| | | if (params.endDate) { |
| | | params.endDate = this.formatDate(params.endDate); |
| | | } else { |
| | | this.loading = false; |
| | | this.$Message.error("结束时间不能为空"); |
| | | return; |
| | | } |
| | | |
| | | userShareList(params).then(res => { |
| | | if (res.code === 200) { |
| | | this.data = res.data.records || []; |
| | | this.total = res.data.total || 0; |
| | | } else { |
| | | this.$Message.error(res.msg || "获取数据失败"); |
| | | } |
| | | }).catch(err => { |
| | | console.error("请求失败:", err); |
| | | this.$Message.error("请求异常: " + (err.message || "未知错误")); |
| | | }).finally(() => { |
| | | this.loading = false; |
| | | }); |
| | | }, |
| | | // 带表单验证的数据获取 |
| | | getDataList() { |
| | | this.$refs.searchForm.validate((valid) => { |
| | | if (valid) { |
| | | this.getDataListWithoutValidation(); |
| | | } else { |
| | | this.loading = false; |
| | | this.$Message.error("请检查表单输入是否正确"); |
| | | } |
| | | }); |
| | | }, |
| | | // 格式化日期时间 |
| | | formatDate(date) { |
| | | if (!date) { |
| | | return ""; |
| | | } |
| | | try { |
| | | const formattedDate = formatDate(new Date(date), 'yyyy-MM-dd hh:mm:ss'); |
| | | return formattedDate; |
| | | } catch (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}`; |
| | | return formatted; |
| | | } catch (backupError) { |
| | | return ""; |
| | | } |
| | | } |
| | | }, |
| | | // 改变页数 |
| | | changePage(page) { |
| | | this.searchForm.pageNumber = page; |
| | | this.getDataListWithoutValidation(); |
| | | }, |
| | | // 改变页码 |
| | | changePageSize(pageSize) { |
| | | this.searchForm.pageNumber = 1; |
| | | this.searchForm.pageSize = pageSize; |
| | | this.getDataListWithoutValidation(); |
| | | }, |
| | | // 搜索 |
| | | handleSearch() { |
| | | this.searchForm.pageNumber = 1; |
| | | // 检查时间参数是否为空 |
| | | 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(); |
| | | }); |
| | | }, |
| | | |
| | | // 检查是否可以查看视频详情 |
| | | canViewVideoDetail(shareOption) { |
| | | try { |
| | | const params = JSON.parse(shareOption); |
| | | return params && params.videoId; |
| | | } catch (error) { |
| | | console.error("解析视频参数出错:", error); |
| | | return false; |
| | | } |
| | | }, |
| | | |
| | | // 查看视频详情 |
| | | viewVideoDetail(row) { |
| | | try { |
| | | // 解析shareOption获取视频ID |
| | | const params = JSON.parse(row.shareOption); |
| | | const videoId = params.videoId; |
| | | |
| | | if (!videoId) { |
| | | this.$Message.error("视频参数不完整"); |
| | | return; |
| | | } |
| | | |
| | | // 显示弹窗并设置加载状态 |
| | | this.videoDetailShow = true; |
| | | this.videoDetailTitle = "视频详情"; |
| | | this.videoLoading = true; |
| | | this.videoDetailUrl = ''; |
| | | this.currentVideoDetail = null; |
| | | |
| | | // 获取视频详情 |
| | | getVideoById(videoId).then(res => { |
| | | if (res.code === 200 && res.data) { |
| | | const videoData = res.data; |
| | | // 保存视频详情数据 |
| | | this.currentVideoDetail = videoData; |
| | | |
| | | // 获取视频预览地址 |
| | | if (videoData.videoFileKey) { |
| | | getFilePreview(videoData.videoFileKey).then(previewRes => { |
| | | if (previewRes.code === 200) { |
| | | this.videoDetailUrl = previewRes.data; |
| | | } else { |
| | | this.$Message.error("获取视频地址失败"); |
| | | } |
| | | }).catch(err => { |
| | | console.error("获取视频预览地址失败:", err); |
| | | this.$Message.error("获取视频地址失败"); |
| | | }).finally(() => { |
| | | this.videoLoading = false; |
| | | }); |
| | | } else { |
| | | this.videoLoading = false; |
| | | this.$Message.info("该视频暂无内容"); |
| | | } |
| | | } else { |
| | | this.videoLoading = false; |
| | | this.$Message.error("获取视频详情失败"); |
| | | } |
| | | }).catch(err => { |
| | | console.error("获取视频详情失败:", err); |
| | | this.videoLoading = false; |
| | | this.$Message.error("获取视频详情失败"); |
| | | }); |
| | | } catch (error) { |
| | | console.error("解析视频参数出错:", error); |
| | | this.videoLoading = false; |
| | | this.$Message.error("视频参数解析失败"); |
| | | } |
| | | }, |
| | | |
| | | // 格式化视频时长 |
| | | formatVideoDuration(seconds) { |
| | | if (isNaN(seconds) || seconds < 0) return '0秒'; |
| | | |
| | | const mins = Math.floor(seconds / 60); |
| | | const secs = seconds % 60; |
| | | |
| | | if (mins === 0) return `${secs}秒`; |
| | | if (secs === 0) return `${mins}分`; |
| | | |
| | | return `${mins}分${secs}秒`; |
| | | }, |
| | | |
| | | // 关闭视频详情弹窗 |
| | | closeVideoDetail() { |
| | | this.videoDetailShow = false; |
| | | this.videoDetailTitle = ''; |
| | | this.videoDetailUrl = ''; |
| | | this.videoLoading = false; |
| | | this.currentVideoDetail = null; |
| | | }, |
| | | |
| | | // 跳转到商品详情页面 |
| | | goToGoodsDetail(shareOption) { |
| | | try { |
| | | // 解析shareOption JSON字符串 |
| | | const params = JSON.parse(shareOption); |
| | | |
| | | // 检查必要参数 |
| | | if (!params.goodsId) { |
| | | this.$Message.error("商品参数不完整"); |
| | | return; |
| | | } |
| | | |
| | | // 跳转到商品详情页面,传递参数 |
| | | this.$router.push({ |
| | | name: "goods-detail", |
| | | query: { |
| | | id: params.goodsId |
| | | } |
| | | }); |
| | | } catch (error) { |
| | | console.error("解析shareOption出错:", error); |
| | | this.$Message.error("参数解析失败"); |
| | | } |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.$nextTick(() => { |
| | | 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; |
| | | } |
| | | |
| | | /* 视频容器样式 */ |
| | | .video-wrapper { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | min-height: 450px; |
| | | } |
| | | |
| | | /* 视频信息样式 */ |
| | | .video-info { |
| | | padding: 10px 0; |
| | | } |
| | | |
| | | .video-basic-info h3 { |
| | | margin-bottom: 15px; |
| | | color: #333; |
| | | } |
| | | |
| | | .info-item { |
| | | margin-bottom: 8px; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .label { |
| | | font-weight: bold; |
| | | color: #666; |
| | | min-width: 60px; |
| | | } |
| | | |
| | | .value { |
| | | color: #333; |
| | | } |
| | | |
| | | .ivu-tag { |
| | | margin-right: 5px; |
| | | } |
| | | </style> |