|
@@ -0,0 +1,436 @@
|
|
|
+<template>
|
|
|
+ <div class="app-container">
|
|
|
+ <!-- 顶部操作区域 -->
|
|
|
+ <el-tabs v-model="activeName" type="border-card" @tab-click="handleClick">
|
|
|
+ <el-tab-pane label="今日数据" name="first" />
|
|
|
+ <el-tab-pane label="过往数据" name="second" />
|
|
|
+ <div class="filter-container">
|
|
|
+ <div class="filter-control">
|
|
|
+ <span>公司名称:</span>
|
|
|
+ <el-input
|
|
|
+ v-model="listQuery.corporateName"
|
|
|
+ placeholder="公司名称"
|
|
|
+ clearable
|
|
|
+ @keyup.enter.native="getList"
|
|
|
+ @clear="getList"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="filter-control">
|
|
|
+ <span>IP:</span>
|
|
|
+ <el-input
|
|
|
+ v-model="listQuery.ip"
|
|
|
+ placeholder="IP"
|
|
|
+ clearable
|
|
|
+ @keyup.enter.native="getList"
|
|
|
+ @clear="getList"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="filter-control">
|
|
|
+ <span>手机号:</span>
|
|
|
+ <el-input
|
|
|
+ v-model="listQuery.phoneNumber"
|
|
|
+ placeholder="手机号"
|
|
|
+ clearable
|
|
|
+ style="width:160px;"
|
|
|
+ @keyup.enter.native="getList"
|
|
|
+ @clear="getList"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="filter-control">
|
|
|
+ <span>联系人:</span>
|
|
|
+ <el-input
|
|
|
+ v-model="listQuery.contacts"
|
|
|
+ placeholder="联系人"
|
|
|
+ clearable
|
|
|
+ style="width:160px;"
|
|
|
+ @keyup.enter.native="getList"
|
|
|
+ @clear="getList"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="filter-control">
|
|
|
+ <span>协销:</span>
|
|
|
+ <el-input
|
|
|
+ v-model="listQuery.spName"
|
|
|
+ placeholder="协销"
|
|
|
+ clearable
|
|
|
+ style="width:120px;"
|
|
|
+ @keyup.enter.native="getList"
|
|
|
+ @clear="getList"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="filter-control">
|
|
|
+ <span>公司类型:</span>
|
|
|
+ <el-select v-model="listQuery.companyType" style="width:120px;" clearable @change="getList">
|
|
|
+ <el-option :value="0" label="请选择" />
|
|
|
+ <el-option :value="1" label="游客" />
|
|
|
+ <el-option :value="2" label="机构" />
|
|
|
+ <el-option :value="3" label="供应商" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div class="filter-control">
|
|
|
+ <span>访问客户端:</span>
|
|
|
+ <el-select v-model="listQuery.accessClient" style="width:120px;" clearable @change="getList">
|
|
|
+ <el-option value="" label="请选择" />
|
|
|
+ <el-option :value="0" label="网站" />
|
|
|
+ <el-option :value="1" label="小程序" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div class="filter-control">
|
|
|
+ <span>关联供应商:</span>
|
|
|
+ <el-select v-model="listQuery.relevanceShop" clearable @change="getList">
|
|
|
+ <el-option
|
|
|
+ v-for="item in supplierList"
|
|
|
+ :key="item.shopId"
|
|
|
+ :label="item.shopName"
|
|
|
+ :value="item.shopName"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div class="filter-control">
|
|
|
+ <span>标签:</span>
|
|
|
+ <el-select v-model="tagsList" multiple filterable placeholder="请选择" @change="handleTagsOptions">
|
|
|
+ <el-option
|
|
|
+ v-for="item in tagsOptions"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.value"
|
|
|
+ :value="item.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div v-if="tabsCurrent === 1" class="filter-control">
|
|
|
+ <span>访问日期:</span>
|
|
|
+ <el-date-picker
|
|
|
+ v-model="time"
|
|
|
+ type="daterange"
|
|
|
+ unlink-panels
|
|
|
+ range-separator="至"
|
|
|
+ start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期"
|
|
|
+ :picker-options="pickerOptions"
|
|
|
+ @change="getList"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="filter-control">
|
|
|
+ <el-button type="primary" @click="getList">查询</el-button>
|
|
|
+ <el-button v-permission="'keyword:list:export'" type="primary" @click="handleExport">
|
|
|
+ 导出
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 关键词列表 -->
|
|
|
+ <el-table v-loading="isLoading" :data="list" border>
|
|
|
+ <el-table-column prop="ip" label="IP" align="center" />
|
|
|
+ <el-table-column prop="region" label="地区" align="center" width="160" />
|
|
|
+ <el-table-column prop="accessClient" label="访问客户端" align="center" width="80">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.accessClient | accessClientFilters }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="companyType" label="公司类型" align="center" width="80">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.companyType | companyTypeFilters }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="corporateName" label="公司名称" align="center">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.corporateName ? row.corporateName : '---' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="contacts" label="联系人" align="center">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.contacts ? row.contacts : '---' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="phoneNumber" label="手机号" align="center">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.phoneNumber ? row.phoneNumber : '---' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="spName" label="所属协销" align="center" width="100">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.spName ? row.spName : '---' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="relevanceShop" label="关联供应商" align="center" width="250">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.relevanceShop ? row.relevanceShop : '---' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="spName" label="标签" align="center">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.label ? row.label : '---' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="addTime" label="注册时间" align="center">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.addTime ? row.addTime : '---' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="numbers" label="访问页面数量" align="center" width="50">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ {{ row.numbers ? row.numbers : '0' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="accessDuration" label="总时长" align="center" />
|
|
|
+ <el-table-column prop="accessDate" label="访问日期" align="center" />
|
|
|
+ <el-table-column prop="lastAccessTime" label="最后访问时间" align="center" />
|
|
|
+ <el-table-column label="操作" align="center" width="120">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <el-button type="primary" size="mini" @click="handleRecordDetail(row)">查看详情</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!-- 页码 -->
|
|
|
+ <pagination
|
|
|
+ :total="total"
|
|
|
+ :page-sizes="[100, 200]"
|
|
|
+ :page-size="100"
|
|
|
+ :page.sync="listQuery.pageNum"
|
|
|
+ :limit.sync="listQuery.pageSize"
|
|
|
+ @pagination="fetchRecordList"
|
|
|
+ />
|
|
|
+ </el-tabs>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { downloadWithUrl } from '@/utils'
|
|
|
+import { fetchRecordList } from '@/api/user/record/record'
|
|
|
+import { fetchShopRelevanceList, searchBehaviorList } from '@/api/user/supplier/supplier'
|
|
|
+import { export_json_to_excel } from '@/vendor/Export2Excel'
|
|
|
+
|
|
|
+export default {
|
|
|
+ filters: {
|
|
|
+ companyTypeFilters(value) {
|
|
|
+ // 公司类型
|
|
|
+ const map = {
|
|
|
+ '1': '游客',
|
|
|
+ '2': '机构',
|
|
|
+ '3': '供应商'
|
|
|
+ }
|
|
|
+ return map[value]
|
|
|
+ },
|
|
|
+ accessClientFilters(value) {
|
|
|
+ // 访问客户端
|
|
|
+ const map = {
|
|
|
+ '0': '网站',
|
|
|
+ '1': '小程序'
|
|
|
+ }
|
|
|
+ return map[value]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ const pickerOptions = {
|
|
|
+ shortcuts: [
|
|
|
+ {
|
|
|
+ text: '近1年',
|
|
|
+ onClick(picker) {
|
|
|
+ const end = new Date()
|
|
|
+ const start = new Date()
|
|
|
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 365)
|
|
|
+ picker.$emit('pick', [start, end])
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '近半年',
|
|
|
+ onClick(picker) {
|
|
|
+ const end = new Date()
|
|
|
+ const start = new Date()
|
|
|
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 183)
|
|
|
+ picker.$emit('pick', [start, end])
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '近1月',
|
|
|
+ onClick(picker) {
|
|
|
+ const end = new Date()
|
|
|
+ const start = new Date()
|
|
|
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
|
|
|
+ picker.$emit('pick', [start, end])
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '近1周',
|
|
|
+ onClick(picker) {
|
|
|
+ const end = new Date()
|
|
|
+ const start = new Date()
|
|
|
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
|
|
+ picker.$emit('pick', [start, end])
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '昨天',
|
|
|
+ onClick(picker) {
|
|
|
+ const end = new Date()
|
|
|
+ const start = new Date()
|
|
|
+ start.setTime(start.getTime() - 3600 * 1000 * 24)
|
|
|
+ picker.$emit('pick', [start, end])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ activeName: 'first',
|
|
|
+ isLoading: true,
|
|
|
+ pickerOptions,
|
|
|
+ time: '',
|
|
|
+ listQuery: {
|
|
|
+ todayType: 0, // 0 今日数据 1 以往数据
|
|
|
+ ip: '', // 访问人ID
|
|
|
+ corporateName: '', // 公司名称
|
|
|
+ companyType: '', // 公司类型
|
|
|
+ accessClient: '', // 访问客户端
|
|
|
+ relevanceShop: '', // 供应商名称
|
|
|
+ label: '', // 标签
|
|
|
+ contacts: '', // 联系人
|
|
|
+ phoneNumber: '', // 手机号
|
|
|
+ spName: '', // 协销
|
|
|
+ startTime: '',
|
|
|
+ endTime: '',
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 100
|
|
|
+ },
|
|
|
+ shopListQuery: {
|
|
|
+ shopName: '',
|
|
|
+ linkMan: '',
|
|
|
+ contractMobile: '',
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 100
|
|
|
+ },
|
|
|
+ list: [],
|
|
|
+ total: 0,
|
|
|
+ currentList: [],
|
|
|
+ supplierList: [], // 关联供应商列表
|
|
|
+ tagsOptions: [],
|
|
|
+ tagsList: [],
|
|
|
+ tabsCurrent: 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ this.getList()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // tab切换
|
|
|
+ handleClick(tab, event) {
|
|
|
+ if (tab.name === 'first') {
|
|
|
+ console.log('data', '今日数据')
|
|
|
+ this.tabsCurrent = this.listQuery.todayType = 0
|
|
|
+ this.listQuery.startTime = ''
|
|
|
+ this.listQuery.endTime = ''
|
|
|
+ this.getList()
|
|
|
+ } else if (tab.name === 'second') {
|
|
|
+ console.log('data', '以往数据')
|
|
|
+ this.tabsCurrent = this.listQuery.todayType = 1
|
|
|
+ this.getList()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleTagsOptions(arr) {
|
|
|
+ this.listQuery.label = arr.join(',')
|
|
|
+ this.getList()
|
|
|
+ console.log('label', this.listQuery.label)
|
|
|
+ },
|
|
|
+ // 获取行为记录列表
|
|
|
+ getList() {
|
|
|
+ this.listQuery.pageNum = 1
|
|
|
+ if (this.time && this.time.length > 0) {
|
|
|
+ this.listQuery.startTime = this.time[0]
|
|
|
+ this.listQuery.endTime = this.time[1]
|
|
|
+ } else {
|
|
|
+ this.listQuery.startTime = ''
|
|
|
+ this.listQuery.endTime = ''
|
|
|
+ }
|
|
|
+ this.fetchRecordList()
|
|
|
+ this.fetchShopRelevanceList()
|
|
|
+ this.searchBehaviorList()
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取关键词列表
|
|
|
+ async fetchRecordList() {
|
|
|
+ try {
|
|
|
+ this.isLoading = true
|
|
|
+ const res = await fetchRecordList(this.listQuery)
|
|
|
+ this.list = res.data.results
|
|
|
+ this.total = res.data.totalRecord
|
|
|
+ this.isLoading = false
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取关联供应商列表选项
|
|
|
+ async fetchShopRelevanceList() {
|
|
|
+ try {
|
|
|
+ const res = await fetchShopRelevanceList(this.shopListQuery)
|
|
|
+ this.supplierList = res.data.results
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取标签库列表选项
|
|
|
+ async searchBehaviorList() {
|
|
|
+ try {
|
|
|
+ const res = await searchBehaviorList()
|
|
|
+ this.tagsOptions = res.data
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 查看详情
|
|
|
+ handleRecordDetail(row) {
|
|
|
+ this.$router.push({ path: '/user/record/detail', query: { ip: row.ip, accessDate: row.accessDate, userId: row.userId }})
|
|
|
+ },
|
|
|
+
|
|
|
+ // 导出
|
|
|
+ async handleExport() {
|
|
|
+ if (this.tabsCurrent === 0) {
|
|
|
+ // 导出今日数据
|
|
|
+ const url = process.env.VUE_APP_BASE_API + '/user/behavior/exportToday'
|
|
|
+ downloadWithUrl(url, '用户行为记录')
|
|
|
+ } else {
|
|
|
+ // 导出以往当前数据
|
|
|
+ try {
|
|
|
+ await this.$confirm('确定将用户行为记录导出为xlsx?', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ // 导出数据格式化
|
|
|
+ const filterVal = ['ip', 'region', 'accessClient', 'companyType', 'corporateName', 'contacts', 'phoneNumber', 'spName', 'relevanceShop', 'label', 'addTime', 'numbers', 'accessDuration', 'accessDate']
|
|
|
+ const data = this.formatJson(filterVal, this.list.slice(0))
|
|
|
+ export_json_to_excel({
|
|
|
+ header: ['IP', '地区', '访问客户端', '公司类型', '公司名称', '联系人', '手机号', '所属协销', '关联供应商', '标签', '注册时间', '访问页面数量', '总时长', '访问日期'],
|
|
|
+ data,
|
|
|
+ filename: '用户行为记录'
|
|
|
+ })
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error)
|
|
|
+ this.$message.info('已取消导出操作')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ formatJson(filterVal, jsonData) {
|
|
|
+ return jsonData.map((v, index) =>
|
|
|
+ filterVal.map((key) => {
|
|
|
+ if (key === 'accessClient') {
|
|
|
+ const t = ['网站', '小程序']
|
|
|
+ return t[v[key]]
|
|
|
+ }
|
|
|
+ if (key === 'companyType') {
|
|
|
+ const t = ['游客', '机构', '供应商']
|
|
|
+ return t[v[key]]
|
|
|
+ }
|
|
|
+ return v[key]
|
|
|
+ })
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style></style>
|