feat(custom): 订单列表改版
This commit is contained in:
5
.env.sentry-build-plugin
Normal file
5
.env.sentry-build-plugin
Normal file
@@ -0,0 +1,5 @@
|
||||
# DO NOT commit this file to your repository!
|
||||
# The SENTRY_AUTH_TOKEN variable is picked up by the Sentry Build Plugin.
|
||||
# It's used for authentication when uploading source maps.
|
||||
# You can also set this env variable in your own `.env` files and remove this file.
|
||||
SENTRY_AUTH_TOKEN="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"
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -30,5 +30,8 @@
|
||||
"files.associations": {
|
||||
"*.env.*": "dotenv",
|
||||
"*.css": "postcss"
|
||||
},
|
||||
"[dockerfile]": {
|
||||
"editor.defaultFormatter": "ms-azuretools.vscode-docker"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ export function createVitePlugins(viteEnv, isBuild) {
|
||||
if (isBuild) {
|
||||
plugins.push(
|
||||
visualizer({
|
||||
open: true,
|
||||
open: false,
|
||||
gzipSize: true,
|
||||
brotliSize: true,
|
||||
})
|
||||
|
||||
@@ -4,6 +4,7 @@ import Components from 'unplugin-vue-components/vite'
|
||||
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
|
||||
import { FileSystemIconLoader } from 'unplugin-icons/loaders'
|
||||
import IconsResolver from 'unplugin-icons/resolver'
|
||||
// import { sentryVitePlugin } from '@sentry/vite-plugin'
|
||||
|
||||
/**
|
||||
* * unplugin-icons插件,自动引入iconify图标
|
||||
@@ -43,4 +44,10 @@ export default [
|
||||
inject: 'body-last',
|
||||
customDomId: '__CUSTOM_SVG_ICON__',
|
||||
}),
|
||||
// sentryVitePlugin({
|
||||
// authToken: process.env.SENTRY_AUTH_TOKEN,
|
||||
// org: 'sentry',
|
||||
// project: 'jdt-admin',
|
||||
// url: 'https://w.huakk.top',
|
||||
// }),
|
||||
]
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/vite-plugin": "^2.9.0",
|
||||
"@sentry/vue": "^7.77.0",
|
||||
"@unocss/eslint-config": "^0.55.7",
|
||||
"@vueuse/core": "^10.5.0",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
|
||||
15547
pnpm-lock.yaml
generated
15547
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@ import { setupRouterGuard } from './guard'
|
||||
import { basicRoutes, EMPTY_ROUTE, NOT_FOUND_ROUTE } from './routes'
|
||||
import { getToken, isNullOrWhitespace } from '@/utils'
|
||||
import { usePermissionStore } from '@/store'
|
||||
import * as Sentry from '@sentry/vue'
|
||||
|
||||
const isHash = true
|
||||
export const router = createRouter({
|
||||
@@ -14,6 +15,23 @@ export const router = createRouter({
|
||||
export async function setupRouter(app) {
|
||||
await addDynamicRoutes()
|
||||
setupRouterGuard(router)
|
||||
Sentry.init({
|
||||
app,
|
||||
dsn: 'https://589c2c58683b4e8fa87a87609fd95e3b@w.huakk.top/2',
|
||||
integrations: [
|
||||
new Sentry.BrowserTracing({
|
||||
// Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
|
||||
tracePropagationTargets: ['localhost', /^https:\/\/yourserver\.io\/api/],
|
||||
routingInstrumentation: Sentry.vueRouterInstrumentation(router),
|
||||
}),
|
||||
new Sentry.Replay(),
|
||||
],
|
||||
// Performance Monitoring
|
||||
tracesSampleRate: 1.0, // Capture 100% of the transactions
|
||||
// Session Replay
|
||||
replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
|
||||
replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.
|
||||
})
|
||||
app.use(router)
|
||||
}
|
||||
|
||||
|
||||
@@ -56,21 +56,20 @@ function filterAsyncRoutes(routes = [], firstRoute = true) {
|
||||
order: route.sort,
|
||||
}
|
||||
|
||||
let redirect = ''
|
||||
|
||||
if (route.route === '/' && firstRoute) {
|
||||
// 重定向
|
||||
redirect = route.subMenu[0].route
|
||||
}
|
||||
|
||||
const curRoute = {
|
||||
path: route.route,
|
||||
name: route.name,
|
||||
isHidden,
|
||||
meta,
|
||||
redirect,
|
||||
children: [],
|
||||
}
|
||||
|
||||
if (route.route === '/' && firstRoute) {
|
||||
curRoute['redirect'] = route.subMenu[0].route
|
||||
} else if (route.subMenu && route.type === 1) {
|
||||
curRoute['redirect'] = `${route.subMenu[0].route}`
|
||||
}
|
||||
|
||||
if (route.subMenu && route.subMenu.length) {
|
||||
curRoute.children = filterAsyncRoutes(route.subMenu, false)
|
||||
} else {
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
remote
|
||||
:row-key="rowKey"
|
||||
children-key="Classify"
|
||||
/>
|
||||
<n-modal v-model:show="showModal">
|
||||
<n-card
|
||||
@@ -55,6 +57,10 @@ const vPerms = resolveDirective('perms')
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const rowKey = (row) => {
|
||||
return row.Classify || []
|
||||
}
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: 'ID',
|
||||
|
||||
@@ -82,9 +82,9 @@
|
||||
<n-form-item label="商户地址:" path="address">
|
||||
<n-input v-model:value="formValue.address" placeholder="请输入商户地址" />
|
||||
</n-form-item>
|
||||
<n-form-item label="经营类目:" path="classId">
|
||||
<n-form-item label="经营类目:" path="store_class_id">
|
||||
<n-select
|
||||
v-model:value="formValue.classId"
|
||||
v-model:value="formValue.store_class_id"
|
||||
label-field="name"
|
||||
value-field="ID"
|
||||
clearable
|
||||
@@ -98,16 +98,16 @@
|
||||
<n-form-item v-else label="修改密码:" path="password">
|
||||
<n-input v-model:value="formValue.password" placeholder="不修改密码请留空" />
|
||||
</n-form-item>
|
||||
<n-form-item label="商户类型:" path="bType">
|
||||
<n-select
|
||||
v-model:value="formValue.bType"
|
||||
label-field="name"
|
||||
value-field="ID"
|
||||
placeholder="请选择商户类型"
|
||||
clearable
|
||||
:options="typeOptions"
|
||||
/>
|
||||
</n-form-item>
|
||||
<!-- <n-form-item label="商户类型:" path="bType">-->
|
||||
<!-- <n-select-->
|
||||
<!-- v-model:value="formValue.bType"-->
|
||||
<!-- label-field="name"-->
|
||||
<!-- value-field="ID"-->
|
||||
<!-- placeholder="请选择商户类型"-->
|
||||
<!-- clearable-->
|
||||
<!-- :options="typeOptions"-->
|
||||
<!-- />-->
|
||||
<!-- </n-form-item>-->
|
||||
<n-form-item label="手续费收取类型:" path="scaleType">
|
||||
<n-select
|
||||
v-model:value="formValue.scaleType"
|
||||
@@ -152,6 +152,7 @@
|
||||
import { onMounted, ref, h, withDirectives, resolveDirective } from 'vue'
|
||||
import { NButton } from 'naive-ui'
|
||||
import api from './api'
|
||||
|
||||
const vPerms = resolveDirective('perms')
|
||||
|
||||
const isEdit = computed(() => drawerTitle.value === '编辑商户')
|
||||
@@ -162,18 +163,10 @@ const columns = ref([
|
||||
align: 'center',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '商户类型',
|
||||
align: 'center',
|
||||
key: 'type',
|
||||
render(row) {
|
||||
return h('span', row.bType === 1 ? '供应商' : '兑换商')
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
align: 'center',
|
||||
key: 'status',
|
||||
slot: 'status',
|
||||
render(row) {
|
||||
return h('span', row.status === 1 ? '正常' : '禁用')
|
||||
},
|
||||
@@ -265,10 +258,9 @@ let formValue = ref({
|
||||
phone: '',
|
||||
mobile: '',
|
||||
address: '',
|
||||
classId: null,
|
||||
store_class_id: null,
|
||||
local: '',
|
||||
password: '',
|
||||
bType: null,
|
||||
scaleType: null,
|
||||
scale: null,
|
||||
status: 2,
|
||||
@@ -305,7 +297,7 @@ const rules = {
|
||||
message: '请搜索商户经纬度',
|
||||
trigger: 'blur',
|
||||
},
|
||||
classId: {
|
||||
store_class_id: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请选择经营类目',
|
||||
@@ -316,12 +308,6 @@ const rules = {
|
||||
// message: '请输入商户密码',
|
||||
// trigger: 'blur',
|
||||
// },
|
||||
bType: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请选择商户类型',
|
||||
trigger: 'change',
|
||||
},
|
||||
scaleType: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
@@ -388,8 +374,8 @@ const handleValidateClick = (e) => {
|
||||
await api.addMer(formValue.value)
|
||||
$message.success('成功')
|
||||
handleClearValidateClick()
|
||||
getMertype()
|
||||
getList()
|
||||
await getMertype()
|
||||
await getList()
|
||||
showModal.value = false
|
||||
} catch (error) {
|
||||
$message.error(error.msg)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<div mt-10>联系电话:{{ nowRow.phone }}</div>
|
||||
<div mt-10>开户行:{{ nowRow.bank }}</div>
|
||||
<div mt-10>银行卡号:{{ nowRow.bank_card }}</div>
|
||||
<div mt-10>商户类型:{{ atype.name }}</div>
|
||||
<!-- <div mt-10>商户类型:{{ atype.name }}</div>-->
|
||||
<div mt-10>经营类目:{{ btype.name }}</div>
|
||||
<div mt-10>
|
||||
<div>营业执照:</div>
|
||||
@@ -59,6 +59,7 @@ import { h, withDirectives, resolveDirective } from 'vue'
|
||||
import api from './api'
|
||||
import api1 from '../mer_list/api'
|
||||
import { NButton } from 'naive-ui'
|
||||
|
||||
const vPerms = resolveDirective('perms')
|
||||
|
||||
const loading = ref(false)
|
||||
@@ -110,6 +111,7 @@ const columns = ref([
|
||||
...row,
|
||||
img: row.img.split(','),
|
||||
}
|
||||
console.log(nowRow.value)
|
||||
active.value = true
|
||||
},
|
||||
},
|
||||
@@ -150,23 +152,23 @@ const getData = async () => {
|
||||
}
|
||||
|
||||
const classOptions = ref([])
|
||||
const typeOptions = ref([])
|
||||
// const typeOptions = ref([])
|
||||
|
||||
const getMertype = async () => {
|
||||
const res = await api1.getMerType()
|
||||
classOptions.value = res.data.class
|
||||
typeOptions.value = res.data.type
|
||||
// typeOptions.value = res.data.type
|
||||
}
|
||||
|
||||
const atype = computed(() => {
|
||||
return typeOptions.value.find((item) => {
|
||||
if (item.ID === nowRow.value.bType) return item
|
||||
})
|
||||
})
|
||||
// const atype = computed(() => {
|
||||
// return typeOptions.value.find((item) => {
|
||||
// if (item.ID === nowRow.value.bType) return item
|
||||
// })
|
||||
// })
|
||||
|
||||
const btype = computed(() => {
|
||||
return classOptions.value.find((item) => {
|
||||
if (item.ID === nowRow.value.classId) return item
|
||||
if (item.ID === nowRow.value.store_class_id) return item
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-data-table
|
||||
@@ -37,20 +38,20 @@
|
||||
>
|
||||
<n-form ref="formRef" :model="nowRow" :rules="rules" label-placement="left">
|
||||
<n-grid :cols="24">
|
||||
<n-form-item-gi :span="20" label="商品赠送豆子" path="pulse_number">
|
||||
<n-form-item-gi :span="20" label="商品赠送豆子" path="pulse">
|
||||
<n-input-number
|
||||
v-model:value="nowRow.pulse_number"
|
||||
v-model:value="nowRow.pulse"
|
||||
clearable
|
||||
:precision="2"
|
||||
placeholder="请输入赠送豆子数量...."
|
||||
:min="0"
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="20" label="商品赠送积分" path="integral">
|
||||
<n-input-number
|
||||
v-model:value="nowRow.integral"
|
||||
clearable
|
||||
:precision="2"
|
||||
placeholder="请输入赠送积分数量...."
|
||||
:min="0"
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="18" label="商品分佣类型" path="commission_type">
|
||||
@@ -75,13 +76,15 @@
|
||||
v-model:value="nowRow.commission"
|
||||
clearable
|
||||
placeholder="请输入分佣比例...."
|
||||
:min="0"
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="20" label="豆子过期时间" path="expiration">
|
||||
<n-input-number
|
||||
v-model:value="nowRow.expiration"
|
||||
clearable
|
||||
placeholder="请输入豆子过期时间...."
|
||||
placeholder="请输入豆子过期时间"
|
||||
:min="0"
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="12">
|
||||
@@ -169,7 +172,7 @@ const notesVal = ref('')
|
||||
const formRef = ref(null)
|
||||
|
||||
const rules = {
|
||||
pulse_number: {
|
||||
pulse: {
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '请输入赠送豆子数量',
|
||||
@@ -234,8 +237,17 @@ const columns = ref([
|
||||
},
|
||||
{
|
||||
title: '商品分类',
|
||||
key: 'class_name',
|
||||
slot: 'Classify',
|
||||
align: 'center',
|
||||
render(row) {
|
||||
return h(
|
||||
'div',
|
||||
{},
|
||||
{
|
||||
default: () => row.Classify.name,
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商品价格(元)',
|
||||
@@ -249,7 +261,7 @@ const columns = ref([
|
||||
},
|
||||
{
|
||||
title: '赠送豆子',
|
||||
key: 'pulse_number',
|
||||
key: 'pulse',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -21,15 +21,15 @@ export default {
|
||||
order: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'PointList',
|
||||
path: 'point_list',
|
||||
component: () => import('./point/index.vue'),
|
||||
meta: {
|
||||
title: '积分商品',
|
||||
icon: 'mdi:account-multiple',
|
||||
order: 10,
|
||||
},
|
||||
},
|
||||
// {
|
||||
// name: 'PointList',
|
||||
// path: 'point_list',
|
||||
// component: () => import('./point/index.vue'),
|
||||
// meta: {
|
||||
// title: '积分商品',
|
||||
// icon: 'mdi:account-multiple',
|
||||
// order: 10,
|
||||
// },
|
||||
// },
|
||||
],
|
||||
}
|
||||
|
||||
@@ -26,4 +26,18 @@ export default {
|
||||
|
||||
// 全部投注用户
|
||||
allUser: () => request.post('/all/draw/user', {}),
|
||||
|
||||
// 吹气球相关
|
||||
// 游戏状态
|
||||
getisBalloonStart: () => request.post('/getisBalloonStart'),
|
||||
// 修改游戏状态
|
||||
setisBalloonStart: (data) => request.post('/isBalloonStart', data),
|
||||
// 全部开奖记录
|
||||
getBalloonList: () => request.post('/balloon/draw'),
|
||||
// 本局投注记录
|
||||
getBalloonUser: () => request.post('/now/balloon/draw/user'),
|
||||
// 全部投注记录
|
||||
getAllBalloonUser: () => request.post('/all/balloon/draw/user'),
|
||||
// 统计全部投注和中奖列表
|
||||
getUserList: () => request.post('/user/balloon/list'),
|
||||
}
|
||||
|
||||
206
src/views/game/balloon/data/index.vue
Normal file
206
src/views/game/balloon/data/index.vue
Normal file
@@ -0,0 +1,206 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<div flex items-center>
|
||||
<div mr-20 flex>
|
||||
<div>游戏状态:</div>
|
||||
<n-switch
|
||||
v-model:value="gameStatus"
|
||||
:checked-value="1"
|
||||
:unchecked-value="2"
|
||||
@update:value="handleUpdateValue"
|
||||
/>
|
||||
</div>
|
||||
<div ml-20 flex items-center>
|
||||
<div>本局记录:</div>
|
||||
<n-button type="primary" @click="openModal(1)">预览</n-button>
|
||||
</div>
|
||||
<div ml-20 flex items-center>
|
||||
<div>全部记录:</div>
|
||||
<n-button type="primary" @click="openModal(2)">预览</n-button>
|
||||
</div>
|
||||
</div>
|
||||
<n-modal v-model:show="showModal">
|
||||
<n-card
|
||||
style="width: 900px"
|
||||
:title="modalTitle"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<template v-if="keyModal === 1">
|
||||
<div>
|
||||
<span>
|
||||
总投注(豆子):
|
||||
<span text-red>{{ nowData.total_number }}</span>
|
||||
</span>
|
||||
<span ml-20>
|
||||
总积分:
|
||||
<span text-red>{{ nowData.total_integral }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<n-data-table
|
||||
:loading="nowData.Loading"
|
||||
:columns="nowData.Columns"
|
||||
:data="nowData.data"
|
||||
:max-height="700"
|
||||
:pagination="false"
|
||||
:bordered="false"
|
||||
remote
|
||||
@update:sorter="nowData.handleSorterChange"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div>
|
||||
<span>
|
||||
总投注(豆子):
|
||||
<span text-red>{{ allData.total_number }}</span>
|
||||
</span>
|
||||
<span ml-20>
|
||||
总积分:
|
||||
<span text-red>{{ allData.total_integral }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<n-data-table
|
||||
:loading="allData.Loading"
|
||||
:columns="allData.Columns"
|
||||
:data="allData.data"
|
||||
:max-height="700"
|
||||
:pagination="false"
|
||||
:bordered="false"
|
||||
remote
|
||||
@update:sorter="allData.handleSorterChange"
|
||||
/>
|
||||
</template>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from '../../api'
|
||||
|
||||
const gameStatus = ref(2)
|
||||
|
||||
onMounted(() => {
|
||||
get_status()
|
||||
})
|
||||
|
||||
const get_status = async () => {
|
||||
const res = await api.getisBalloonStart()
|
||||
gameStatus.value = res.data.balloonStart
|
||||
}
|
||||
|
||||
const handleUpdateValue = async (e) => {
|
||||
await api.setisBalloonStart({
|
||||
Start: e,
|
||||
})
|
||||
$message.success('修改成功')
|
||||
get_status()
|
||||
}
|
||||
|
||||
const showModal = ref(false)
|
||||
|
||||
const keyModal = ref(null)
|
||||
|
||||
const modalTitle = ref('')
|
||||
|
||||
const openModal = (type) => {
|
||||
keyModal.value = type
|
||||
showModal.value = true
|
||||
modalTitle.value = type === 1 ? '本局记录' : '全部记录'
|
||||
if (type === 1) return fetchData(nowData)
|
||||
fetchData(allData)
|
||||
}
|
||||
|
||||
const { value: tempCol } = ref([
|
||||
{
|
||||
title: '昵称',
|
||||
key: 'User',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '电话',
|
||||
key: 'Phone',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '期数',
|
||||
key: 'Periods',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '下注豆子',
|
||||
key: 'TotalCount',
|
||||
align: 'center',
|
||||
sorter: true,
|
||||
sortOrder: false,
|
||||
},
|
||||
{
|
||||
title: '赢积分',
|
||||
key: 'NumberSum',
|
||||
align: 'center',
|
||||
sorter: true,
|
||||
sortOrder: false,
|
||||
},
|
||||
{
|
||||
title: '购买秒数',
|
||||
key: 'DrawTime',
|
||||
align: 'center',
|
||||
},
|
||||
])
|
||||
|
||||
const { value: nowData } = ref({
|
||||
Loading: false,
|
||||
Columns: [...tempCol],
|
||||
data: [],
|
||||
total_number: 0,
|
||||
total_integral: 0,
|
||||
handleSorterChange: (sorter) => sortData(sorter, nowData),
|
||||
api: api.getBalloonUser,
|
||||
})
|
||||
|
||||
const { value: allData } = ref({
|
||||
Loading: false,
|
||||
Columns: [...tempCol],
|
||||
data: [],
|
||||
total_number: 0,
|
||||
total_integral: 0,
|
||||
handleSorterChange: (sorter) => sortData(sorter, allData),
|
||||
api: api.getAllBalloonUser,
|
||||
})
|
||||
|
||||
const fetchData = async (target) => {
|
||||
target.Loading = true
|
||||
const res = await target.api()
|
||||
target.data = res.data.data || []
|
||||
target.total_integral = res.data.total_integral
|
||||
target.total_number = res.data.total_number
|
||||
target.Loading = false
|
||||
}
|
||||
|
||||
const sortData = (sorter, target) => {
|
||||
if (!target.Loading) {
|
||||
target.Loading = true
|
||||
switch (sorter.columnKey) {
|
||||
case 'TotalCount':
|
||||
target.Columns[3].sortOrder = !sorter ? false : sorter.order
|
||||
target.data = target.data.sort((a, b) => {
|
||||
if (sorter.order === 'descend') return b.TotalCount - a.TotalCount
|
||||
return a.TotalCount - b.TotalCount
|
||||
})
|
||||
break
|
||||
case 'NumberSum':
|
||||
target.Columns[4].sortOrder = !sorter ? false : sorter.order
|
||||
target.data = target.data.sort((a, b) => {
|
||||
if (sorter.order === 'descend') return b.NumberSum - a.NumberSum
|
||||
return a.NumberSum - b.NumberSum
|
||||
})
|
||||
break
|
||||
}
|
||||
target.Loading = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
214
src/views/game/balloon/statistics/index.vue
Normal file
214
src/views/game/balloon/statistics/index.vue
Normal file
@@ -0,0 +1,214 @@
|
||||
<template>
|
||||
<CommonPage show-footer :title="$route.title">
|
||||
<n-grid class="mb-10" x-gap="12" :cols="4">
|
||||
<n-gi>
|
||||
<n-date-picker
|
||||
v-model:formatted-value="range"
|
||||
value-format="yyyy-MM-dd"
|
||||
type="daterange"
|
||||
clearable
|
||||
/>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-button type="primary" @click="getList">搜索</n-button>
|
||||
<n-button ml-10 @click="clear">重置</n-button>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
<div w-full flex items-center>
|
||||
<Echarts :loading="loading" :option="option" />
|
||||
<Echarts :loading="loading" :option="option1" />
|
||||
</div>
|
||||
<div w-full flex items-center justify-between>
|
||||
<n-card title="开奖记录" :bordered="false" content-style="padding: 0;">
|
||||
<n-data-table
|
||||
:max-height="500"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:bordered="true"
|
||||
:virtual-scroll="true"
|
||||
remote
|
||||
/>
|
||||
</n-card>
|
||||
</div>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import api from '../../api.js'
|
||||
import Echarts from '@/components/Echarts.vue'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const range = ref(null)
|
||||
|
||||
const option = ref({
|
||||
title: {
|
||||
text: '单期下注(豆子)/赔付(积分) 统计',
|
||||
left: 'center',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: [],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '下注(豆子)',
|
||||
data: [],
|
||||
type: 'bar',
|
||||
},
|
||||
{
|
||||
name: '赔付(积分)',
|
||||
data: [],
|
||||
type: 'bar',
|
||||
},
|
||||
],
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside',
|
||||
},
|
||||
{
|
||||
type: 'slider',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const option1 = ref({
|
||||
title: {
|
||||
text: '总下注(豆子)/总赔付(积分)',
|
||||
left: 'center',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'right',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '50%',
|
||||
data: [],
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '期数',
|
||||
key: 'Periods',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '开奖秒数',
|
||||
key: 'Name',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '下注',
|
||||
key: 'NumberSum',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '赔付',
|
||||
key: 'TotalCount',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
key: 'Date',
|
||||
align: 'center',
|
||||
},
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
const clear = () => {
|
||||
range.value = null
|
||||
getList()
|
||||
}
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
const dataObj = {
|
||||
StartTime: dayjs().format('YYYY-MM-DD'),
|
||||
EndTime: dayjs().format('YYYY-MM-DD'),
|
||||
}
|
||||
if (range.value) {
|
||||
dataObj.StartTime = range.value[0]
|
||||
dataObj.EndTime = range.value[1]
|
||||
}
|
||||
const res = await api.getUserList(dataObj)
|
||||
const newData = res.data.data || []
|
||||
data.value = newData
|
||||
option.value.xAxis.data = []
|
||||
option.value.series[0].data = []
|
||||
option.value.series[1].data = []
|
||||
option1.value.series[0].data = []
|
||||
if (newData.length > 0) {
|
||||
res.data.data.forEach((item) => {
|
||||
const a = (
|
||||
((res.data.total * 10) / (res.data.total * 10 + res.data.totalDices)) *
|
||||
100
|
||||
).toFixed(2)
|
||||
|
||||
const b = ((res.data.totalDices / (res.data.total * 10 + res.data.totalDices)) * 100).toFixed(
|
||||
2
|
||||
)
|
||||
option.value.xAxis.data.push(`第${item.Periods}期-${item.Name}`)
|
||||
option.value.series[0].name = `下注(豆子): ${a}%`
|
||||
option.value.series[0].data.push(item.NumberSum * 10)
|
||||
option.value.series[1].name = `赔付(积分): ${b}%`
|
||||
option.value.series[1].data.push(item.TotalCount)
|
||||
})
|
||||
|
||||
const a = (((res.data.total * 10) / (res.data.total * 10 + res.data.totalDices)) * 100).toFixed(
|
||||
2
|
||||
)
|
||||
const b = ((res.data.totalDices / (res.data.total * 10 + res.data.totalDices)) * 100).toFixed(2)
|
||||
|
||||
option1.value.series[0].data.push({ value: res.data.total * 10, name: `总下注: ${a}%` })
|
||||
option1.value.series[0].data.push({
|
||||
value: res.data.totalDices,
|
||||
name: `总赔付: ${b}%`,
|
||||
})
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.chart {
|
||||
width: 50%;
|
||||
height: 400px;
|
||||
}
|
||||
</style>
|
||||
@@ -136,7 +136,7 @@
|
||||
|
||||
<script setup>
|
||||
import { h } from 'vue'
|
||||
import api from '../api'
|
||||
import api from '../../api'
|
||||
import { getToken } from '@/utils'
|
||||
|
||||
const ws = new WebSocket(`wss://${import.meta.env.VITE_WS_URL}`)
|
||||
@@ -334,8 +334,8 @@ const handleSorterChange = (sorter) => {
|
||||
case 'TotalCount':
|
||||
jlColumns.value[3].sortOrder = !sorter ? false : sorter.order
|
||||
jlData.value.data = jlData.value.data.sort((a, b) => {
|
||||
if (sorter.order === 'descend') return b.NumberSum - a.NumberSum
|
||||
return a.NumberSum - b.NumberSum
|
||||
if (sorter.order === 'descend') return b.TotalCount - a.TotalCount
|
||||
return a.TotalCount - b.TotalCount
|
||||
})
|
||||
break
|
||||
case 'NumberSum':
|
||||
@@ -14,29 +14,6 @@
|
||||
<n-button ml-10 @click="clear">重置</n-button>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
<!-- <n-grid class="mb-10" x-gap="12" :cols="3">
|
||||
<n-gi>
|
||||
<n-card>
|
||||
<n-statistic label="总下注">
|
||||
<n-number-animation :from="0" :to="TYVal.total" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-card>
|
||||
<n-statistic label="总赔付">
|
||||
<n-number-animation :from="0" :to="TYVal.totalNum" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-card>
|
||||
<n-statistic label="总盈利">
|
||||
<n-number-animation :from="0" :to="TYVal.total / 10 - TYVal.totalNum / 100" />
|
||||
</n-statistic>
|
||||
</n-card>
|
||||
</n-gi>
|
||||
</n-grid> -->
|
||||
<div w-full flex items-center>
|
||||
<Echarts :loading="loading" :option="option" />
|
||||
<Echarts :loading="loading" :option="option1" />
|
||||
@@ -59,7 +36,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import api from '../api.js'
|
||||
import api from '../../api.js'
|
||||
import Echarts from '@/components/Echarts.vue'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
@@ -78,11 +55,6 @@ const option = ref({
|
||||
type: 'shadow',
|
||||
},
|
||||
},
|
||||
// legend: {
|
||||
// data: ['下注(豆子)', '赔付(积分)'],
|
||||
// left: 'left',
|
||||
// type: 'scroll',
|
||||
// },
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
@@ -148,11 +120,6 @@ const option1 = ref({
|
||||
|
||||
const data = ref([])
|
||||
|
||||
const TYVal = ref({
|
||||
total: 0,
|
||||
totalNum: 0,
|
||||
})
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '期数',
|
||||
@@ -203,10 +170,6 @@ const getList = async () => {
|
||||
const res = await api.getStatistics(dataObj)
|
||||
const newData = res.data.data || []
|
||||
data.value = newData
|
||||
TYVal.value = {
|
||||
total: res.data.total,
|
||||
totalNum: res.data.totalDices,
|
||||
}
|
||||
option.value.xAxis.data = []
|
||||
option.value.series[0].data = []
|
||||
option.value.series[1].data = []
|
||||
@@ -33,7 +33,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import api from '../api.js'
|
||||
import api from '../../api.js'
|
||||
import { NButton } from 'naive-ui'
|
||||
import { h, ref, onMounted } from 'vue'
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script setup>
|
||||
import { h, ref, resolveDirective, withDirectives } from 'vue'
|
||||
import api from '../api'
|
||||
import { NTag, NImage, NButton } from 'naive-ui'
|
||||
import { NTag, NImage, NButton, NDropdown } from 'naive-ui'
|
||||
import Upload from '@/components/Upload.vue'
|
||||
import Editor from '@/components/Editor.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const vPerms = resolveDirective('perms')
|
||||
|
||||
@@ -65,6 +66,56 @@ const columns = ref([
|
||||
),
|
||||
[[vPerms, ['/admin/game/edit']]]
|
||||
),
|
||||
withDirectives(
|
||||
h(
|
||||
'span',
|
||||
{
|
||||
class: 'ml-10',
|
||||
},
|
||||
{
|
||||
default: () => [
|
||||
h(
|
||||
NDropdown,
|
||||
{
|
||||
trigger: 'click',
|
||||
size: 'small',
|
||||
options: [
|
||||
{
|
||||
key: 0,
|
||||
label: '实时数据',
|
||||
},
|
||||
{
|
||||
key: 1,
|
||||
label: '数据统计',
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
label: '宙斯统计',
|
||||
},
|
||||
],
|
||||
onSelect: (e) => dropdownSelect(e),
|
||||
},
|
||||
{
|
||||
default: () =>
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
class: 'ml-5',
|
||||
type: 'primary',
|
||||
text: true,
|
||||
size: 'small',
|
||||
},
|
||||
{
|
||||
default: () => '操作',
|
||||
}
|
||||
),
|
||||
}
|
||||
),
|
||||
],
|
||||
}
|
||||
),
|
||||
[[vPerms, ['待定']]]
|
||||
),
|
||||
]
|
||||
},
|
||||
},
|
||||
@@ -165,6 +216,14 @@ const clear = () => {
|
||||
showModal.value = false
|
||||
getList()
|
||||
}
|
||||
|
||||
const route = useRouter()
|
||||
|
||||
const paths = ['/game/game_data', '/game/game_statistics', '/game/game_zs']
|
||||
|
||||
const dropdownSelect = (e) => {
|
||||
route.push(paths[e])
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -80,7 +80,6 @@
|
||||
|
||||
<script setup>
|
||||
import api from './api'
|
||||
import { NEllipsis } from 'naive-ui'
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
@@ -154,27 +153,54 @@ const columns = ref([
|
||||
{
|
||||
title: '用户',
|
||||
align: 'center',
|
||||
key: 'user_name',
|
||||
slot: 'user',
|
||||
render: (row) => {
|
||||
return [
|
||||
h(
|
||||
'div',
|
||||
{},
|
||||
{
|
||||
default: () => row.User.nickName,
|
||||
}
|
||||
),
|
||||
]
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '用户电话',
|
||||
align: 'center',
|
||||
key: 'phone',
|
||||
slot: 'phone',
|
||||
render: (row) => {
|
||||
return [
|
||||
h(
|
||||
'div',
|
||||
{},
|
||||
{
|
||||
default: () => row.User.phone,
|
||||
}
|
||||
),
|
||||
]
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '商品名称',
|
||||
align: 'center',
|
||||
slot: 'goods_name',
|
||||
render: (row) => {
|
||||
return h(
|
||||
NEllipsis,
|
||||
{
|
||||
style: 'max-width: 240px',
|
||||
},
|
||||
{
|
||||
default: () => row.goods_name,
|
||||
}
|
||||
)
|
||||
const el = []
|
||||
row.OrderGoods.forEach((item) => {
|
||||
el.push(
|
||||
h(
|
||||
'div',
|
||||
{},
|
||||
{
|
||||
default: () =>
|
||||
`${item.Goods.name}|${item.pay_price}元或${item.pay_integral}积分|X${item.number}`,
|
||||
}
|
||||
)
|
||||
)
|
||||
})
|
||||
return el
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -185,12 +211,20 @@ const columns = ref([
|
||||
{
|
||||
title: '订单总价',
|
||||
align: 'center',
|
||||
key: 'number',
|
||||
slot: 'number',
|
||||
render: (row) => h('span', row.pay_type === 1 ? `${row.price}元` : `${row.exchange}积分`),
|
||||
},
|
||||
{
|
||||
title: '支付方式',
|
||||
align: 'center',
|
||||
slot: 'pay_type',
|
||||
render: (row) => h('span', row.pay_type === 1 ? '微信' : '积分'),
|
||||
},
|
||||
{
|
||||
title: '商家名称',
|
||||
align: 'center',
|
||||
key: 'store_name',
|
||||
slot: 'store_name',
|
||||
render: (row) => h('span', row.Store.name),
|
||||
},
|
||||
// {
|
||||
// title: '订单佣金(元)',
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<!-- {{ model }} -->
|
||||
<!-- {{ model }}-->
|
||||
<n-form ref="formRef" :model="model" :rules="rules" label-placement="left">
|
||||
<n-grid :cols="24" :x-gap="24">
|
||||
<n-form-item-gi :span="16" label="父级分类:" path="pid">
|
||||
@@ -85,7 +85,7 @@
|
||||
<n-switch v-model:value="model.status" :checked-value="1" :unchecked-value="2" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi v-if="model.type !== 3" :span="10" label="是否显示:" path="isShow">
|
||||
<n-switch v-model:value="model.isShow" :checked-value="1" :unchecked-value="2" />
|
||||
<n-switch v-model:value="model.is_show" :checked-value="1" :unchecked-value="2" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="16" label="菜单名称:" path="name">
|
||||
<n-input v-model:value="model.name" placeholder="请填写菜单名称" />
|
||||
@@ -307,7 +307,7 @@ const model = ref({
|
||||
type: null,
|
||||
icon: '',
|
||||
status: 1,
|
||||
isShow: 1,
|
||||
is_show: 1,
|
||||
name: '',
|
||||
route: '',
|
||||
params: '',
|
||||
@@ -359,7 +359,7 @@ const openModal = (type, row = {}) => {
|
||||
type: row.type,
|
||||
icon: row.icon,
|
||||
status: row.status,
|
||||
isShow: row.isShow,
|
||||
is_show: row.is_show,
|
||||
name: row.name,
|
||||
route: row.route,
|
||||
params: row.params,
|
||||
@@ -386,7 +386,7 @@ const handleValidateClick = () => {
|
||||
Icon: model.value.icon,
|
||||
Type: model.value.type,
|
||||
Status: model.value.status,
|
||||
IsShow: model.value.isShow,
|
||||
IsShow: model.value.is_show,
|
||||
Name: model.value.name,
|
||||
Route: model.value.route,
|
||||
Params: model.value.params,
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
</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="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>
|
||||
|
||||
@@ -38,6 +38,7 @@ export default defineConfig(({ command, mode }) => {
|
||||
outDir: OUTPUT_DIR || 'dist',
|
||||
reportCompressedSize: false, // 启用/禁用 gzip 压缩大小报告
|
||||
chunkSizeWarningLimit: 1024, // chunk 大小警告的限制(单位kb)
|
||||
sourcemap: true,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user