|
@@ -0,0 +1,460 @@
|
|
|
+<template>
|
|
|
+ <div class="behavior-track-container">
|
|
|
+ <!-- 筛选区域 -->
|
|
|
+ <div class="filter-section">
|
|
|
+ <div class="filter-item">
|
|
|
+ <label>操作类型:</label>
|
|
|
+ <el-select
|
|
|
+ v-model="queryParams.operationType"
|
|
|
+ class="type-select"
|
|
|
+ @change="handleTypeChange"
|
|
|
+ placeholder="请选择行为类型"
|
|
|
+ clearable
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in typeList"
|
|
|
+ :key="item.dictValue"
|
|
|
+ :label="item.dictLabel"
|
|
|
+ :value="item.dictLabel"
|
|
|
+ ></el-option>
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="steps.length === 0" class="no-data">
|
|
|
+ <p>暂无数据</p>
|
|
|
+ </div>
|
|
|
+ <!-- 按日期分组展示(分页后的数据) -->
|
|
|
+ <div v-if="steps.length != 0" v-for="(records, date) in groupedPaginatedSteps" :key="date" class="date-group">
|
|
|
+ <!-- 日期标题(如果是今天,显示“今天”,否则显示具体日期) -->
|
|
|
+ <div class="date-title">
|
|
|
+ {{ isToday(date) ? '今天' : date }}
|
|
|
+ </div>
|
|
|
+ <div class="date-divider"></div>
|
|
|
+
|
|
|
+ <!-- 当前日期下的记录 -->
|
|
|
+ <el-steps
|
|
|
+ direction="vertical"
|
|
|
+ :space="120"
|
|
|
+ process-status="process"
|
|
|
+ finish-status="success"
|
|
|
+ class="custom-steps"
|
|
|
+ >
|
|
|
+ <el-step
|
|
|
+ v-for="(step, index) in records"
|
|
|
+ :key="index"
|
|
|
+ :icon="index === 0 ? 'el-icon-s-help' : 'el-icon-bangzhu'"
|
|
|
+ >
|
|
|
+ <template #title>
|
|
|
+ <div class="step-title">
|
|
|
+ {{ step.operationType }}
|
|
|
+ <span class="step-time">{{ step.createTime }}</span> <!-- 每个步骤的时间 -->
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template #description>
|
|
|
+ <!-- 答题 -->
|
|
|
+ <div v-if="step.operationType == '答题'" class="step-content">
|
|
|
+ <!-- 第一行 -->
|
|
|
+ <div class="step-row first-row">
|
|
|
+ <div v-if="step.paramVo" class="detail-item">
|
|
|
+ <span class="detail-label"><i class="el-icon-notebook-2"></i> 课节名称:</span>
|
|
|
+ <span class="detail-value">{{ step.paramVo.courseName }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 第二行 -->
|
|
|
+ <div v-if="step.details" class="step-row second-row">
|
|
|
+ <div class="detail-item">
|
|
|
+ <span class="detail-label"><i class="el-icon-chat-dot-round"></i> 备注:</span>
|
|
|
+ <span class="detail-value">{{ step.details }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 发放奖励 -->
|
|
|
+ <div v-else-if="step.operationType == '发送奖励'" class="step-content">
|
|
|
+ <!-- 第一行 -->
|
|
|
+ <div class="step-row first-row">
|
|
|
+ <div v-if="step.paramVo" class="detail-item">
|
|
|
+ <span class="detail-label"><i class="el-icon-gift"></i> 课程名称:</span>
|
|
|
+ <span class="detail-value">{{ step.paramVo.courseName }}</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="step.paramVo" class="detail-item">
|
|
|
+ <span class="detail-label"><i class="el-icon-coin"></i> 小节名称:</span>
|
|
|
+ <span class="detail-value">{{ step.paramVo.title }}</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="step.fsCourseRedPacketLog" class="detail-item">
|
|
|
+ <span class="detail-label"><i class="el-icon-coin"></i> 发放金额:</span>
|
|
|
+ <span class="detail-value">{{ step.fsCourseRedPacketLog.amount }} 元</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 第二行 -->
|
|
|
+ <div v-if="step.details" class="step-row second-row">
|
|
|
+ <div class="detail-item">
|
|
|
+ <span class="detail-label"><i class="el-icon-chat-dot-round"></i> 备注:</span>
|
|
|
+ <span class="detail-value">{{ step.details }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 其他类型 -->
|
|
|
+ <div v-else class="step-content">
|
|
|
+ <!-- 第一行 -->
|
|
|
+ <div class="step-row first-row">
|
|
|
+ <div v-if="step.paramVo" class="detail-item">
|
|
|
+ <span class="detail-label"><i class="el-icon-office-building"></i> 训练营:</span>
|
|
|
+ <span class="detail-value">{{ step.paramVo.trainingCampName }}</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="step.paramVo" class="detail-item">
|
|
|
+ <span class="detail-label"><i class="el-icon-collection-tag"></i> 营期名称:</span>
|
|
|
+ <span class="detail-value">{{ step.paramVo.periodName }}</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="step.paramVo" class="detail-item">
|
|
|
+ <span class="detail-label"><i class="el-icon-notebook-2"></i> 课节名称:</span>
|
|
|
+ <span class="detail-value">{{ step.paramVo.courseName }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 第二行 -->
|
|
|
+ <div v-if="step.details" class="step-row second-row">
|
|
|
+ <div class="detail-item">
|
|
|
+ <span class="detail-label"><i class="el-icon-chat-dot-round"></i> 备注:</span>
|
|
|
+ <span class="detail-value">{{ step.details }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ </el-step>
|
|
|
+ </el-steps>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 分页 -->
|
|
|
+ <pagination
|
|
|
+ v-show="total>0"
|
|
|
+ :total="total"
|
|
|
+ :page.sync="queryParams.pageNum"
|
|
|
+ :limit.sync="queryParams.pageSize"
|
|
|
+ @pagination="getList"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { listUserOperationLog} from "@/api/his/userOperationLog";
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ // 遮罩层
|
|
|
+ loading: true,
|
|
|
+ typeList: [],
|
|
|
+ queryParams: {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ operationType:null,
|
|
|
+ userId:null,
|
|
|
+ },
|
|
|
+ total: 0,
|
|
|
+ steps: [
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ this.getDicts("fs_user_operation_type").then(response => {
|
|
|
+ this.typeList = response.data;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ // 删除这个属性,直接在 getList 中使用后端的操作类型
|
|
|
+ groupedPaginatedSteps() {
|
|
|
+ const groups = {};
|
|
|
+ this.steps.forEach((step) => {
|
|
|
+ const date = step.createTime ?
|
|
|
+ (step.createTime instanceof Date ? step.createTime.toISOString().substr(0, 10) : new Date(step.createTime).toISOString().substr(0, 10))
|
|
|
+ : null;
|
|
|
+ if (!groups[date]) {
|
|
|
+ groups[date] = [];
|
|
|
+ }
|
|
|
+ groups[date].push(step);
|
|
|
+ });
|
|
|
+ return groups;
|
|
|
+ },
|
|
|
+
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ getList() {
|
|
|
+ this.loading = true;
|
|
|
+ listUserOperationLog(this.queryParams).then(response => {
|
|
|
+ this.steps = response.rows;
|
|
|
+ this.total = response.total;
|
|
|
+ this.loading = false;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 判断是否为今天
|
|
|
+ isToday(date) {
|
|
|
+ const today = new Date();
|
|
|
+ const formattedDate = `${today.getFullYear()}-${(today.getMonth() + 1).toString().padStart(2, '0')}-${today.getDate().toString().padStart(2, '0')}`;
|
|
|
+ return date === formattedDate;
|
|
|
+ },
|
|
|
+ getDetails(orderId) {
|
|
|
+ this.queryParams.userId=orderId;
|
|
|
+ this.getList();
|
|
|
+
|
|
|
+ },
|
|
|
+ handleTypeChange() {
|
|
|
+ this.queryParams.pageNum = 1; // 重置分页为第一页
|
|
|
+ this.getList(); // 重新获取数据
|
|
|
+ }
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.behavior-track-container {
|
|
|
+ width: 100%;
|
|
|
+ padding: 24px;
|
|
|
+ font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
|
|
|
+ background-color: #f9fbfd;
|
|
|
+ border-radius: 12px;
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
|
+}
|
|
|
+
|
|
|
+.filter-section {
|
|
|
+ margin-bottom: 24px;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 16px 20px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.filter-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.filter-item label {
|
|
|
+ font-weight: 600;
|
|
|
+ color: #333;
|
|
|
+ margin-right: 12px;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.type-select {
|
|
|
+ width: 240px;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-steps {
|
|
|
+ padding: 0 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.step-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.step-detail p {
|
|
|
+ margin: 8px 0;
|
|
|
+ line-height: 1.6;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #555;
|
|
|
+}
|
|
|
+
|
|
|
+/* 步骤条样式优化 - 移除图标边框 */
|
|
|
+.custom-steps >>> .el-step__head {
|
|
|
+ padding-right: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-steps >>> .el-step__icon {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-steps >>> .el-step__icon.is-icon {
|
|
|
+ color: #52c41a;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-steps >>> .el-step__line {
|
|
|
+ top: 36px;
|
|
|
+ left: 11px;
|
|
|
+ background-color: #e8e8e8;
|
|
|
+}
|
|
|
+
|
|
|
+/* 分页样式优化 */
|
|
|
+.pagination-wrapper {
|
|
|
+ margin-top: 32px;
|
|
|
+ text-align: center;
|
|
|
+ padding: 16px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-pagination >>> .el-pager li {
|
|
|
+ border-radius: 4px;
|
|
|
+ margin: 0 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-pagination >>> .el-pager li.active {
|
|
|
+ background-color: #52c41a;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-pagination >>> .el-pagination__jump {
|
|
|
+ margin-left: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-pagination >>> .el-input__inner {
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 新增和修改的样式 */
|
|
|
+.step-content {
|
|
|
+ margin-top: 8px;
|
|
|
+ padding: 16px;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 8px;
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
+ box-shadow: 0 1px 6px rgba(0, 0, 0, 0.06);
|
|
|
+ transition: all 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.step-content:hover {
|
|
|
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
|
|
+ transform: translateY(-1px);
|
|
|
+}
|
|
|
+
|
|
|
+.detail-label {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ width: 100px;
|
|
|
+ color: #606266;
|
|
|
+ font-weight: 500;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-label i {
|
|
|
+ margin-right: 6px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-value {
|
|
|
+ flex: 1;
|
|
|
+ color: #303133;
|
|
|
+ word-break: break-word;
|
|
|
+ padding-left: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.step-row {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.first-row .detail-item {
|
|
|
+ flex: 1 1 30%; /* 平均分布 */
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-right: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.second-row .detail-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.time-item {
|
|
|
+ margin-left: auto; /* 时间靠右 */
|
|
|
+}
|
|
|
+
|
|
|
+.detail-label {
|
|
|
+ font-weight: 500;
|
|
|
+ color: #606266;
|
|
|
+ margin-right: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-value {
|
|
|
+ color: #303133;
|
|
|
+ word-break: break-word;
|
|
|
+}
|
|
|
+
|
|
|
+@media (max-width: 768px) {
|
|
|
+ .first-row,
|
|
|
+ .second-row {
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+ .time-item {
|
|
|
+ margin-left: 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+/* 完全重置步骤描述区域的样式 */
|
|
|
+.custom-steps >>> .el-step__description {
|
|
|
+ width: 100% !important;
|
|
|
+ max-width: 100% !important;
|
|
|
+ padding: 0 !important;
|
|
|
+ margin: 0 !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 确保步骤内容使用弹性布局 */
|
|
|
+.step-content {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+/* 调整时间项 */
|
|
|
+.time-item {
|
|
|
+ align-self: flex-end; /* 替代 margin-left: auto */
|
|
|
+ margin-top: 8px; /* 如果需要与上方的间距 */
|
|
|
+}
|
|
|
+/* 日期标题样式 */
|
|
|
+.date-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+ margin-top: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.date-divider {
|
|
|
+ height: 1px;
|
|
|
+ background: #e8e8e8;
|
|
|
+ margin: 4px 0 12px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 在步骤条标题旁边显示时间 */
|
|
|
+.step-title {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.step-time {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #999;
|
|
|
+ margin-left: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 第二行的备注 */
|
|
|
+.second-row {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.second-row .detail-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.no-data {
|
|
|
+ text-align: center;
|
|
|
+ color: #999;
|
|
|
+ font-size: 18px;
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+</style>
|