Files
jdt-admin/src/views/user/index/index.vue
2023-10-10 15:01:00 +08:00

605 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<CommonPage show-footer :title="$route.title">
<n-grid class="mb-10" x-gap="12">
<n-gi :span="24">
<div flex>
<n-card w-500>
<n-statistic label="用户积分(留存)" tabular-nums>
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.integral" />
</n-statistic>
</n-card>
<n-card ml-10 w-500>
<n-statistic label="用户豆子(留存)" tabular-nums>
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.pulse" />
</n-statistic>
</n-card>
<n-card ml-10 w-500>
<n-statistic label="今日新增用户" tabular-nums>
<n-number-animation
ref="numberAnimationInstRef"
:from="0"
:to="cardData.today_user"
/>
</n-statistic>
</n-card>
<n-card ml-10 w-500>
<n-statistic label="用户总流水(元)" tabular-nums>
<n-number-animation
ref="numberAnimationInstRef"
:from="0"
:to="cardData.total_number"
:precision="2"
/>
</n-statistic>
</n-card>
<n-card ml-10 w-500>
<n-statistic label="总佣金(积分)" tabular-nums>
<n-number-animation
ref="numberAnimationInstRef"
:from="0"
:to="cardData.referee"
:precision="2"
/>
</n-statistic>
</n-card>
<n-card ml-10 w-500>
<n-statistic label="平台总用户" tabular-nums>
<n-number-animation
ref="numberAnimationInstRef"
:from="0"
:to="cardData.total_user"
/>
</n-statistic>
</n-card>
</div>
</n-gi>
<n-gi span="12" mt-10 flex items-center>
<span w-100>筛选条件:</span>
<n-input-group>
<n-select
v-model:value="queryParams.selectKey"
:style="{ width: '20%' }"
:options="selectOptions"
placeholder="请选择"
/>
<n-input v-model:value="queryParams.word" :style="{ width: '30%' }" />
</n-input-group>
</n-gi>
<n-gi span="24" mt-10 flex items-center>
<n-button type="primary" @click="getList">查询</n-button>
<n-button ml-10 @click="clear">重置</n-button>
</n-gi>
</n-grid>
<n-data-table
:loading="loading"
:columns="columns"
:data="data"
:pagination="pagination"
:bordered="false"
remote
@update:sorter="handleSorterChange"
/>
<!-- 用户详情 -->
<n-drawer v-model:show="isDrawer" :width="1000" placement="right" :mask-closable="false">
<n-drawer-content title="用户详情" closable>
<div flex items-center>
<img rounded-full :src="nowRow.avatarUrl" width="70" />
<div ml-10>
<div>昵称{{ nowRow.nickName }}</div>
<div>电话{{ nowRow.phone }}</div>
</div>
</div>
<div mt-10 w-200 flex items-center justify-between text-center>
<div>
<div>用户积分</div>
<div text-red>{{ nowRow.integral }}</div>
</div>
<div>
<div>用户豆子</div>
<div text-red>{{ nowRow.pulse }}</div>
</div>
</div>
<n-tabs v-model:value="tabVal" type="line" animated @update-value="tabsChange">
<n-tab name="1" tab="活动订单"></n-tab>
<n-tab name="2" tab="积分订单"></n-tab>
<n-tab name="3" tab="豆子记录"></n-tab>
<n-tab name="4" tab="积分记录"></n-tab>
<n-tab name="5" tab="推广记录"></n-tab>
</n-tabs>
<n-row gutter="12">
<n-col :span="12">
<div mt-10 flex items-center>
<span w-100>时间筛选</span>
<n-date-picker
v-model:formatted-value="queryData.time"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetimerange"
clearable
/>
</div>
</n-col>
<n-col :span="10" v-if="tabVal === '4'">
<div mt-10 flex items-center>
<span w-100>条件筛选</span>
<n-select
v-model:value="queryData.selectKey"
:style="{ width: '30%' }"
:options="[
{
label: '取消订单',
value: 1,
},
{
label: '支付订单',
value: 2,
},
{
label: '商品赠送',
value: 3,
},
]"
placeholder="请选择类型"
/>
</div>
</n-col>
<n-col :span="4">
<div mt-10>
<n-button type="primary" @click="getTabsList">搜索</n-button>
<n-button ml-10 @click="tabsClear">重置</n-button>
</div>
</n-col>
</n-row>
<n-data-table
class="mt-5"
:columns="tabsColumns"
:loading="tabsLoading"
:data="tabsData"
:pagination="tabsPagination"
:bordered="false"
remote
/>
</n-drawer-content>
</n-drawer>
</CommonPage>
</template>
<script setup>
import { h } from 'vue'
import api from './api'
import { NDropdown, NButton, NEllipsis } from 'naive-ui'
import TheIcon from '@/components/icon/TheIcon.vue'
const loading = ref(false)
const queryParams = ref({
word: '',
selectKey: null,
})
const queryData = ref({
time: null,
selectKey: 2,
})
const cardData = ref({
integral: 0,
pulse: 0,
today_user: 0,
total_number: 0,
total_user: 0,
})
const selectOptions = [
{
label: '用户昵称',
value: 0,
},
{
label: '用户电话',
value: 1,
},
]
const isDrawer = ref(false)
const columns = ref([
{
title: 'ID',
align: 'center',
key: 'ID',
},
{
title: '昵称',
align: 'center',
key: 'nickName',
},
{
title: '头像',
align: 'center',
slot: 'avatar',
render(row) {
return h('img', {
src: row.avatarUrl,
style: {
width: '30px',
height: '30px',
borderRadius: '50%',
},
})
},
},
{
title: '电话',
align: 'center',
key: 'phone',
},
{
title: '用户积分',
align: 'center',
key: 'integral',
sorter: true,
sortOrder: false,
},
{
title: '用户豆子',
align: 'center',
key: 'pulse',
sorter: true,
sortOrder: false,
},
{
title: '操作',
align: 'center',
slot: 'action',
render(row) {
return [
h(
NDropdown,
{
trigger: 'click',
options: [
{
label: '用户详情',
key: 1,
},
],
onSelect: (key) => {
switch (key) {
case 1:
openDrawer(row)
break
}
},
},
{
default: () =>
h(
NButton,
{
text: true,
iconPlacement: 'right',
},
{
default: () => '更多',
icon: () =>
h(TheIcon, {
icon: 'ant-design:down-outlined',
}),
}
),
}
),
]
},
},
])
const data = ref([])
const pagination = ref({
page: 1,
pageSize: 10,
itemCount: 0,
onChange: (page) => {
pagination.value.page = page
getList()
},
onUpdatePageSize: (pageSize) => {
pagination.value.pageSize = pageSize
pagination.value.page = 1
getList()
},
})
onMounted(() => {
getList()
})
const clear = () => {
queryParams.value = {
word: '',
selectKey: null,
}
getList()
}
const getList = async () => {
loading.value = true
try {
const query_data = {}
switch (queryParams.value.selectKey) {
case 0:
query_data['UserName'] = queryParams.value.word
break
case 1:
query_data['Phone'] = queryParams.value.word
break
}
const res = await api.getUser({
pageNum: pagination.value.page,
pageSize: pagination.value.pageSize,
...query_data,
})
data.value = res.data.data || []
pagination.value.itemCount = res.data.total_user
cardData.value.today_user = res.data.today_user
cardData.value.total_user = res.data.total_user
cardData.value.total_number = res.data.total_number
cardData.value.integral = res.data.integral
cardData.value.pulse = res.data.pulse
cardData.value.referee = res.data.referee
} catch (error) {
$message.error(error.msg)
}
loading.value = false
}
const nowRow = ref({})
const tabVal = ref('1')
const tabsLoading = ref(false)
const tabsColumns = ref([])
const tabsData = ref([])
const tabsPagination = ref({
page: 1,
pageSize: 10,
itemCount: 0,
onChange: (page) => {
tabsPagination.value.page = page
getTabsList()
},
})
const openDrawer = (row) => {
nowRow.value = row
isDrawer.value = true
// getTabsList()
tabsChange()
}
const tabsChange = async (e = '1') => {
tabVal.value = e
tabsData.value = []
tabsColumns.value = []
if (tabVal.value === '1' || tabVal.value === '2') {
tabsColumns.value = [
{
title: '订单号',
align: 'center',
key: 'oid',
},
{
title: '商品封面',
align: 'center',
slot: 'cover',
render: (row) => {
return h('img', {
src: row.cover,
style: {
width: '50px',
height: '50px',
},
})
},
},
{
title: '商品名称',
align: 'center',
slot: 'goods_name',
render: (row) => {
return h(
NEllipsis,
{
style: 'max-width: 240px',
},
{
default: () => row.goods_name,
}
)
},
},
{
title: '商品价格',
align: 'center',
key: 'number',
},
{
title: '订单状态',
align: 'center',
slot: 'status',
render: (row) => {
let nameStr = ''
switch (row.status) {
case 0:
nameStr = '待付款'
break
case 1:
nameStr = '待使用'
break
case 2:
nameStr = '已使用'
break
case 3:
nameStr = '已过期'
}
return h(
'span',
{},
{
default: () => nameStr,
}
)
},
},
{
title: '下单时间',
align: 'center',
key: 'add_time',
},
]
} else if (tabVal.value === '3') {
tabsColumns.value = [
{
title: '订单号',
align: 'center',
key: 'oid',
},
{
title: '商品名称',
align: 'center',
key: 'goods_name',
},
{
title: '消费金额',
align: 'center',
key: 'number',
},
{
title: '下单时间',
align: 'center',
key: 'add_time',
},
]
} else if (tabVal.value === '4') {
tabsColumns.value = [
{
title: '订单号',
align: 'center',
key: 'oid',
},
{
title: '商品名称',
align: 'center',
key: 'goods_name',
},
{
title: '积分',
align: 'center',
key: 'number',
},
{
title: '时间',
align: 'center',
key: 'add_time',
},
]
} else {
tabsColumns.value = [
{
title: '订单号',
align: 'center',
key: 'oid',
},
{
title: '用户昵称',
align: 'center',
key: 'nick_name',
},
{
title: '商品名称',
align: 'center',
key: 'goods_name',
},
{
title: '获得积分',
align: 'center',
key: 'number',
},
{
title: '时间',
align: 'center',
key: 'add_time',
},
]
}
tabsPagination.value.page = 1
getTabsList()
}
const getTabsList = async () => {
tabsLoading.value = true
let res
const data = {
uid: nowRow.value.uid,
pageNum: tabsPagination.value.page,
pageSize: tabsPagination.value.pageSize,
StartTime: queryData.value.time === null ? '' : queryData.value.time[0] || '',
EndTime: queryData.value.time === null ? '' : queryData.value.time[1] || '',
}
switch (tabVal.value) {
case '1':
res = await api.gethdlist(data)
break
case '2':
res = await api.getjflist(data)
break
case '3':
res = await api.getdzJllist(data)
break
case '4':
data['Type'] = queryData.value.selectKey
res = await api.getjfJllist(data)
break
case '5':
res = await api.gettgJllist(data)
break
}
tabsData.value = res.data.data || []
tabsPagination.value.itemCount = res.data.total
tabsLoading.value = false
}
const handleSorterChange = (sorter) => {
if (!loading.value) {
loading.value = true
switch (sorter.columnKey) {
case 'pulse':
columns.value[5].sortOrder = !sorter ? false : sorter.order
data.value = data.value.sort((a, b) => {
if (sorter.order === 'descend') return b.pulse - a.pulse
return a.pulse - b.pulse
})
break
case 'integral':
columns.value[4].sortOrder = !sorter ? false : sorter.order
data.value = data.value.sort((a, b) => {
if (sorter.order === 'descend') return b.integral - a.integral
return a.integral - b.integral
})
break
}
loading.value = false
}
}
const tabsClear = async () => {
queryData.value = {
time: null,
selectKey: null,
}
await getTabsList()
}
</script>
<style lang="scss" scoped></style>