feat: 搜索用户和用户详情 搭建

This commit is contained in:
inc904 2023-03-31 14:24:24 +08:00
parent bd060e3b15
commit f888fe65fe
24 changed files with 1310 additions and 1123 deletions

View File

@ -1,33 +1,33 @@
import { cdn } from "./cdn";
import { resolve } from "path";
import vue from "@vitejs/plugin-vue";
import { viteBuildInfo } from "./info";
import svgLoader from "vite-svg-loader";
import vueJsx from "@vitejs/plugin-vue-jsx";
import { viteMockServe } from "vite-plugin-mock";
import { configCompressPlugin } from "./compress";
import { cdn } from './cdn'
import { resolve } from 'path'
import vue from '@vitejs/plugin-vue'
import { viteBuildInfo } from './info'
import svgLoader from 'vite-svg-loader'
import vueJsx from '@vitejs/plugin-vue-jsx'
// import { viteMockServe } from 'vite-plugin-mock'
import { configCompressPlugin } from './compress'
// import ElementPlus from "unplugin-element-plus/vite";
import { visualizer } from "rollup-plugin-visualizer";
import removeConsole from "vite-plugin-remove-console";
import themePreprocessorPlugin from "@pureadmin/theme";
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
import DefineOptions from "unplugin-vue-define-options/vite";
import { genScssMultipleScopeVars } from "../src/layout/theme";
import { visualizer } from 'rollup-plugin-visualizer'
import removeConsole from 'vite-plugin-remove-console'
import themePreprocessorPlugin from '@pureadmin/theme'
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
import DefineOptions from 'unplugin-vue-define-options/vite'
import { genScssMultipleScopeVars } from '../src/layout/theme'
export function getPluginsList(
command: string,
VITE_CDN: boolean,
VITE_COMPRESSION: ViteCompression
) {
const prodMock = true;
const lifecycle = process.env.npm_lifecycle_event;
const prodMock = true
const lifecycle = process.env.npm_lifecycle_event
return [
vue(),
// https://github.com/intlify/bundle-tools/tree/main/packages/vite-plugin-vue-i18n
VueI18nPlugin({
runtimeOnly: true,
compositionOnly: true,
include: [resolve("locales/**")]
include: [resolve('locales/**')]
}),
// jsx、tsx语法支持
vueJsx(),
@ -35,7 +35,7 @@ export function getPluginsList(
configCompressPlugin(VITE_COMPRESSION),
DefineOptions(),
// 线上环境删除console
removeConsole({ external: ["src/assets/iconfont/iconfont.js"] }),
removeConsole({ external: ['src/assets/iconfont/iconfont.js'] }),
viteBuildInfo(),
// 自定义主题
themePreprocessorPlugin({
@ -48,19 +48,19 @@ export function getPluginsList(
svgLoader(),
// ElementPlus({}),
// mock支持
viteMockServe({
mockPath: "mock",
localEnabled: command === "serve",
prodEnabled: command !== "serve" && prodMock,
injectCode: `
import { setupProdMockServer } from './mockProdServer';
setupProdMockServer();
`,
logger: false
}),
// viteMockServe({
// mockPath: 'mock',
// localEnabled: command === 'serve',
// prodEnabled: command !== 'serve' && prodMock,
// injectCode: `
// import { setupProdMockServer } from './mockProdServer';
// setupProdMockServer();
// `,
// logger: false
// }),
// 打包分析
lifecycle === "report"
? visualizer({ open: true, brotliSize: true, filename: "report.html" })
lifecycle === 'report'
? visualizer({ open: true, brotliSize: true, filename: 'report.html' })
: null
];
]
}

View File

@ -1,36 +1,36 @@
// 根据角色动态生成路由
import { MockMethod } from "vite-plugin-mock";
import { MockMethod } from 'vite-plugin-mock'
export default [
{
url: "/login",
method: "post",
url: '/login',
method: 'post',
response: ({ body }) => {
if (body.username === "admin") {
if (body.username === 'admin') {
return {
success: true,
data: {
username: "admin",
username: 'admin',
// 一个用户可能有多个角色
roles: ["admin"],
accessToken: "eyJhbGciOiJIUzUxMiJ9.admin",
refreshToken: "eyJhbGciOiJIUzUxMiJ9.adminRefresh",
expires: "2023/10/30 00:00:00"
roles: ['admin'],
accessToken: 'eyJhbGciOiJIUzUxMiJ9.admin',
refreshToken: 'eyJhbGciOiJIUzUxMiJ9.adminRefresh',
expires: '2023/10/30 00:00:00'
}
};
}
} else {
return {
success: true,
data: {
username: "common",
username: 'common',
// 一个用户可能有多个角色
roles: ["common"],
accessToken: "eyJhbGciOiJIUzUxMiJ9.common",
refreshToken: "eyJhbGciOiJIUzUxMiJ9.commonRefresh",
expires: "2023/10/30 00:00:00"
roles: ['common'],
accessToken: 'eyJhbGciOiJIUzUxMiJ9.common',
refreshToken: 'eyJhbGciOiJIUzUxMiJ9.commonRefresh',
expires: '2023/10/30 00:00:00'
}
};
}
}
}
}
] as MockMethod[];
] as MockMethod[]

78
mock/playerData.ts Normal file
View File

@ -0,0 +1,78 @@
import { MockMethod } from 'vite-plugin-mock'
export default [
{
url: '/dev-api/getCurrentDayData',
method: 'post',
response: () => {
return {
success: true,
data: [
{
active_count: 12398,
play_count: 123,
register_count: 222,
channel: 'PC',
nlh_player: 98,
plo4_player: 715,
plo5_player: 123,
plo6_player: 123
},
{
active_count: 23,
play_count: 212,
register_count: 253,
channel: 'IOS',
nlh_player: 254,
plo4_player: 2213,
plo5_player: 2123,
plo6_player: 512
}
]
}
}
},
{
url: '/getHistoricalData',
method: 'post',
response: () => {
return {
success: true,
data: [
{
play_account: 2132,
register_account: 232,
active_account: 2123,
channel: 'PC'
},
{
play_account: 21232,
register_account: 12313,
active_account: 67123,
channel: 'IOS'
}
]
}
}
},
{
url: '/snow/getUserData',
method: 'post',
response: () => {
return {
success: true,
data: [
{
username: 2132,
club_name: '12123',
channel: 'PC',
mobile: 'P123123213123',
area: 'beijing',
last_login_date: '2023/12/12',
last_area: 'beijing'
}
]
}
}
}
] as MockMethod[]

View File

@ -1,27 +1,27 @@
import { MockMethod } from "vite-plugin-mock";
import { MockMethod } from 'vite-plugin-mock'
// 模拟刷新token接口
export default [
{
url: "/refreshToken",
method: "post",
url: '/refreshToken',
method: 'post',
response: ({ body }) => {
if (body.refreshToken) {
return {
success: true,
data: {
accessToken: "eyJhbGciOiJIUzUxMiJ9.newAdmin",
refreshToken: "eyJhbGciOiJIUzUxMiJ9.newAdminRefresh",
accessToken: 'eyJhbGciOiJIUzUxMiJ9.newAdmin',
refreshToken: 'eyJhbGciOiJIUzUxMiJ9.newAdminRefresh',
// `expires`选择这种日期格式是为了方便调试,后端直接设置时间戳或许更方便(每次都应该递增)。如果后端返回的是时间戳格式,前端开发请来到这个目录`src/utils/auth.ts`,把第`38`行的代码换成expires = data.expires即可。
expires: "2023/10/30 23:59:59"
expires: '2023/10/30 23:59:59'
}
};
}
} else {
return {
success: false,
data: {}
};
}
}
}
}
] as MockMethod[];
] as MockMethod[]

1335
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

77
src/api/basic.ts Normal file
View File

@ -0,0 +1,77 @@
import { http } from '@/utils/http'
import { baseUrlApi } from './utils'
export type UserResult = {
success: boolean
data: {
/** 用户名 */
username: string
/** 当前登陆用户的角色 */
roles: Array<string>
/** `token` */
accessToken: string
/** 用于调用刷新`accessToken`的接口时所需的`token` */
refreshToken: string
/** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx' */
expires: Date
}
}
// 不同渠道下的各维度数据
interface dailyData {
active_count: number
play_count: number
register_count: number
channel: string
nlh_player: number
plo4_player: number
plo5_player: number
plo6_player: number
}
export type CurrentDayData = {
success: boolean
data: Array<dailyData>
}
interface OHistoricalData {
play_account: number
register_account: number
active_account: number
channel: string
}
export type HistoricalData = {
success: boolean
data: Array<OHistoricalData>
}
/** 当日用户数据 */
// export const getCurrentDayData = (data?: object) => {
// return http.request<CurrentDayData>('post', '/getCurrentDayData', { data })
// }
export const getCurrentDayData = (data?: object) => {
return http.request<any>('post', baseUrlApi('/cms/user/dataset/today'), {
data
})
}
/** 历史用户数据 */
export const getHistoricalData = (data?: object) => {
console.log('api', data)
return http.request<HistoricalData>(
'post',
baseUrlApi('/cms/user/dataset/history'),
{
data
}
)
}
/** 搜索用户 */
export const getUserData = (data?: object) => {
return http.request<HistoricalData>('post', baseUrlApi('/cms/user/list'), {
data
})
}

1
src/api/utils.ts Normal file
View File

@ -0,0 +1 @@
export const baseUrlApi = (url: string) => `/dev-api${url}`

View File

@ -9,7 +9,7 @@ import { MotionPlugin } from '@vueuse/motion'
// import { useEcharts } from "@/plugins/echarts";
import { injectResponsiveStorage } from '@/utils/responsive'
// import Table from "@pureadmin/table";
import Table from '@pureadmin/table'
// import PureDescriptions from "@pureadmin/descriptions";
// 引入重置样式
@ -50,9 +50,12 @@ getServerConfig(app).then(async config => {
await router.isReady()
injectResponsiveStorage(app, config)
setupStore(app)
app.use(MotionPlugin).use(useI18n).use(ElementPlus)
// .use(useEcharts);
// .use(Table);
app
.use(MotionPlugin)
.use(useI18n)
.use(ElementPlus)
// .use(useEcharts);
.use(Table)
// .use(PureDescriptions);
app.mount('#app')
})

View File

@ -6,47 +6,58 @@ export default {
redirect: '/basic/liveData',
meta: {
title: $t('menus.basicData'),
icon: 'lineChartLine'
icon: 'lineChartLine',
rank: 6
},
children: [
{
path: '/basic/liveData',
name: 'LiveData',
component: () => import('@/views/basicData/LiveData.vue'),
component: () => import('@/views/basic/LiveData.vue'),
meta: {
title: $t('menus.liveData'),
roles: ['admin']
}
},
{
path: '/basic/liveData2',
name: 'LiveData2',
component: () => import('@/views/basicData/LiveData.vue'),
meta: {
title: '测试2',
roles: ['admin1']
}
},
{
path: '/basic/userData',
name: 'UserData',
component: () => import('@/views/basicData/queryUser/index.vue'),
component: () => import('@/views/basic/queryUser/index.vue'),
meta: {
title: $t('menus.userData')
}
},
{
path: '/basic/queryUser',
name: 'QueryUser',
component: () => import('@/views/basicData/queryUser/queryUser.vue'),
component: () => import('@/views/basic/queryUser/queryUser.vue'),
meta: {
title: $t('menus.searchUser')
}
},
{
path: '/basic/queryUser/users/:id',
name: 'UserInfo',
component: () => import('@/views/basic/queryUser/user/index.vue'),
meta: {
title: '用户信息',
showLink: false
}
},
{
path: '/basic/queryUser/users/:id/basicInfo',
name: 'UserBasicInfo',
component: () => import('@/views/basic/queryUser/user/basicInfo.vue'),
meta: {
title: '基础信息',
showLink: false
}
},
{
path: '/basic/gameData',
name: 'GameData',
component: () => import('@/views/basicData/GameData.vue'),
component: () => import('@/views/basic/GameData.vue'),
meta: {
title: $t('menus.gameData')
}
@ -54,7 +65,7 @@ export default {
{
path: '/basic/clubData',
name: 'ClubData',
component: () => import('@/views/basicData/queryClub/index.vue'),
component: () => import('@/views/basic/queryClub/index.vue'),
meta: {
title: $t('menus.clubData')
}
@ -62,7 +73,7 @@ export default {
{
path: '/basic/queryClub',
name: 'QueryData',
component: () => import('@/views/basicData/queryClub/queryClub.vue'),
component: () => import('@/views/basic/queryClub/queryClub.vue'),
meta: {
title: $t('menus.searchClub')
}

View File

@ -27,7 +27,58 @@ const IFrame = () => import('@/layout/frameView.vue')
const modulesRoutes = import.meta.glob('/src/views/**/*.{vue,tsx}')
// 动态路由
import { getAsyncRoutes, getAsyncPath } from '@/api/routes'
// import { getAsyncRoutes, getAsyncPath } from '@/api/routes'
// start 只使用静态路由
const permissionRouter = {
path: '/permission',
meta: {
title: 'menus.permission',
icon: 'informationLine',
rank: 99
},
children: [
{
path: '/permission/page/index',
name: 'PermissionPage',
meta: {
title: 'menus.permissionPage',
roles: ['admin', 'common']
}
},
{
path: '/permission/button/index',
name: 'PermissionButton',
meta: {
title: 'menus.permissionButton',
roles: ['admin', 'common'],
auths: ['btn_add', 'btn_edit', 'btn_delete']
}
}
]
}
const permissionPath = {
page: [
'/permission',
'/permission/page/index',
'/permission/button/index',
'/finance',
'/finance/diamondData'
],
btn: ['btn-edit', 'edit-create']
}
function getAsyncRoutes() {
return new Promise(resolve => {
resolve({ data: [permissionRouter] })
})
}
function getAsyncPath() {
return new Promise(resolve => {
resolve({ data: permissionPath })
})
}
// end 只使用静态路由
// 本地fake的动态路由
import localFullRouter from './localRouter'
@ -390,6 +441,10 @@ function hasAuth(value: string | Array<string>): boolean {
: isIncludeAllChildren(value, metaAuths)
return isAuths ? true : false
}
export const baseUrlApi = (url: string) =>
process.env.NODE_ENV === 'development'
? `/api/${url}`
: `http://192.168.100.87:8000/${url}`
export {
hasAuth,

View File

@ -3,24 +3,81 @@ import Axios, {
AxiosRequestConfig,
CustomParamsSerializer
} from 'axios'
import Qs from 'qs'
import {
PureHttpError,
RequestMethods,
PureHttpResponse,
PureHttpRequestConfig
} from './types.d'
import { stringify } from 'qs'
import NProgress from '../progress'
import { getToken, formatToken } from '@/utils/auth'
import { useUserStoreHook } from '@/store/modules/user'
function urlEncodeString(data) {
let str = data
if (
data.indexOf('#') != -1 ||
data.indexOf('+') != -1 ||
data.indexOf('/') != -1 ||
data.indexOf('?') != -1 ||
data.indexOf('%') != -1 ||
data.indexOf('&') != -1 ||
data.indexOf('=') != -1
) {
str = data.replace(/([\#|\+|\/|\?|\%|\#|\&|\=])/g, $1 => {
return encodeURIComponent($1)
})
}
return str
}
function stringify(data) {
let ret = ''
for (const it in data) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
}
ret = ret.substring(0, ret.lastIndexOf('&'))
return ret
}
// 相关配置请参考www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
transformRequest: [
function (data) {
// 对 data 进行任意转换处理
// data = http.getPostData(data)
data = {
sig: '681d66eda1b3df8b7b6641e4864452d7',
accesstoken: '',
cmd_id: 0,
extend: {
net: 'wifi',
device: 'huaweiP10',
macid: '12bb540d5f56add5c7a176c36b339ed7',
tz_name: 'Asia%2FShanghai',
tz_delta: 'GMT%2B8'
},
request: { method: 'sysversion%23getsysversion' },
public: {
channel: 'POKIO_H5_NORMAL',
version: 1311,
packid: 200,
lang: 'tw'
}
}
data = { postdata: urlEncodeString(JSON.stringify(data)) }
// data = { postdata: JSON.stringify(data) }
return Qs.stringify(data)
// return stringify(data)
}
],
// 请求超时时间
timeout: 10000,
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
// 'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
// 数组格式参数序列化https://github.com/axios/axios/issues/5142

View File

@ -1,10 +1,67 @@
<script setup lang="ts">
import { ref } from 'vue'
import { useRenderIcon } from '@/components/ReIcon/src/hooks'
import Search from '@iconify-icons/ep/search'
// import Refresh from '@iconify-icons/ep/refresh'
import { useUser } from './indexHook'
defineOptions({
// name name
name: 'UserData'
})
const formRef = ref()
const {
form,
currentDayData,
historicalData,
currentDayColumns,
historicalColumns,
loading,
onSearchHistory
} = useUser()
</script>
<template>
<h1>用户数据</h1>
<el-card shadow="never" class="card1">
<template #header>
<div class="card-header">
<span class="font-medium"> 今日数据 </span>
</div>
</template>
<pure-table :data="currentDayData" :columns="currentDayColumns" border />
<el-divider />
<p class="card-header font-bold pb-5">历史数据</p>
<div class="w-[81%]">
<el-form
ref="formRef"
:inline="true"
:model="form"
class="bg-bg_color w-[99/100]"
>
<el-form-item prop="date">
<el-date-picker
v-model="form.dateRange"
type="daterange"
range-separator="To"
start-placeholder="Start date"
end-placeholder="End date"
format="YYYY/MM/DD"
value-format="x"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
:icon="useRenderIcon(Search)"
:loading="loading"
@click="onSearchHistory"
>
搜索
</el-button>
</el-form-item>
</el-form>
</div>
<pure-table :data="historicalData" :columns="historicalColumns" border />
</el-card>
</template>

View File

@ -0,0 +1,105 @@
import { ref, reactive, onMounted } from 'vue'
import { getCurrentDayData, getHistoricalData } from '@/api/basic'
export function useUser() {
const currentDayColumns: TableColumnList = [
{
label: '渠道',
prop: 'channel'
},
{
label: '在线用户数量',
prop: 'active_count'
},
{
label: '在玩用户数量',
prop: 'play_count'
},
{
label: '当日注册',
prop: 'register_count'
},
{
label: 'NLH在玩',
prop: 'nlh_player'
},
{
label: 'PLO4',
prop: 'nlh_player'
},
{
label: 'PLO4',
prop: 'nlh_player'
},
{
label: 'PLO4',
prop: 'nlh_player'
}
]
const historicalColumns: TableColumnList = [
{
label: '渠道',
prop: 'channel'
},
{
label: '在线用户数量',
prop: 'active_count'
},
{
label: '在玩用户数量',
prop: 'play_count'
},
{
label: '当日注册',
prop: 'register_count'
}
]
const form = reactive({
dateRange: ''
})
const currentDayData = ref([])
const historicalData = ref([])
const loading = ref(true)
function onSearchToday() {
getCurrentDayData().then(res => {
currentDayData.value = res.data
})
}
function onSearchHistory() {
console.log('onSearchHistory1', form.dateRange)
console.log('onSearchHistory2', form.dateRange[0])
getHistoricalData({
start_date: form.dateRange[0],
end_date: form.dateRange[1]
}).then(res => {
historicalData.value = res.data
loading.value = false
})
}
// const resetHistoryForm = formEl => {
// if (!formEl) return
// formEl.resetFields()
// onSearchHistory()
// }
onMounted(() => {
onSearchToday()
onSearchHistory()
})
return {
form,
currentDayData,
historicalData,
currentDayColumns,
historicalColumns,
loading,
onSearchHistory
// resetHistoryForm
}
}

View File

@ -0,0 +1,54 @@
import { useMultiTagsStoreHook } from '@/store/modules/multiTags'
import { useRouter, useRoute } from 'vue-router'
import { onBeforeMount } from 'vue'
export function useDetail() {
const route = useRoute()
const router = useRouter()
const id = route.query?.id ? route.query?.id : route.params?.id
function toDetail(
index: number | string | string[] | number[],
model: string
) {
if (model === 'query') {
// 保存信息到标签页
useMultiTagsStoreHook().handleTags('push', {
path: `/basic/queryUser/users/`,
name: 'UserInfo',
query: { id: String(index) },
meta: {
title: {
zh: `No.${index} - 详情信息`,
en: `No.${index} - DetailInfo`
},
// 最大打开标签数
dynamicLevel: 3
}
})
// 路由跳转
router.push({ name: 'TabQueryDetail', query: { id: String(index) } })
} else {
useMultiTagsStoreHook().handleTags('push', {
path: `/basic/queryUser/users/:id`,
name: 'UserInfo',
params: { id: String(index) },
meta: {
title: {
zh: `No.${index} - 详情信息`,
en: `No.${index} - DetailInfo`
}
}
})
router.push({ name: 'UserInfo', params: { id: String(index) } })
}
}
function initToDetail(model) {
onBeforeMount(() => {
if (id) toDetail(id, model)
})
}
return { toDetail, initToDetail, id, router }
}

View File

@ -1,10 +1,100 @@
<script setup lang="ts">
import { ref } from 'vue'
import { useRenderIcon } from '@/components/ReIcon/src/hooks'
import Search from '@iconify-icons/ep/search'
// import Refresh from '@iconify-icons/ep/refresh'
import { useUser } from './queryUserHook'
import { useDetail } from './infoHook'
defineOptions({
// name name
name: 'QueryUser'
})
const { toDetail, router } = useDetail()
const formRef = ref()
const { form, historicalData, historicalColumns, loading, onSearchUser } =
useUser()
</script>
<template>
<h1>查询用户</h1>
<el-card shadow="never" class="card1">
<template #header>
<div class="card-header">
<span class="font-medium"> 搜索用户 </span>
</div>
</template>
<div>
<el-form
ref="formRef"
:inline="true"
:model="form"
class="bg-bg_color w-[99/100]"
>
<el-form-item prop="username">
<el-input
v-model="form.username"
placeholder="用户名"
clearable
class="!w-[160px]"
/>
</el-form-item>
<el-form-item prop="mobile">
<el-input
v-model="form.mobile"
placeholder="手机号码"
clearable
class="!w-[160px]"
/>
</el-form-item>
<el-form-item prop="email">
<el-input
v-model="form.email"
placeholder="邮箱"
clearable
class="!w-[200px]"
/>
</el-form-item>
<el-form-item prop="dateRange">
<el-date-picker
v-model="form.dateRange"
type="daterange"
range-separator="To"
start-placeholder="Start date"
end-placeholder="End date"
format="YYYY/MM/DD"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
:icon="useRenderIcon(Search)"
:loading="loading"
@click="onSearchUser"
>
搜索
</el-button>
</el-form-item>
</el-form>
</div>
<pure-table :data="historicalData" :columns="historicalColumns" border />
<!-- <el-button>
<router-link :to="{ name: 'UserInfo', params: { id: 12318 } }"
>User</router-link
>
</el-button> -->
<div class="flex flex-wrap items-center">
<p>params传参模式</p>
<el-button
class="m-2"
v-for="index in 6"
:key="index"
@click="toDetail(index, 'params')"
>
打开{{ index }}详情页
</el-button>
</div>
</el-card>
</template>

View File

@ -0,0 +1,74 @@
import { ref, reactive, onMounted } from 'vue'
import { getUserData } from '@/api/basic'
export function useUser() {
const historicalColumns: TableColumnList = [
{
label: '用户名',
prop: 'user_name'
},
{
label: '所属俱乐部',
prop: 'club_name'
},
{
label: '注册渠道',
prop: 'register_channel'
},
{
label: '绑定手机/邮箱',
prop: 'mobile'
},
{
label: '注册IP及归属地',
prop: 'reg_ip'
},
{
label: '最后登录',
prop: 'last_login_date'
},
{
label: '最后登录IP及归属地',
prop: 'last_area'
}
]
const form = reactive({
username: '',
mobile: '',
email: '',
dateRange: ''
})
const historicalData = ref([])
const loading = ref(true)
function onSearchUser() {
console.log(form.dateRange)
console.log(form.dateRange[0])
getUserData({ date: form }).then(res => {
historicalData.value = res.data
loading.value = false
})
}
// const resetHistoryForm = formEl => {
// if (!formEl) return
// formEl.resetFields()
// onSearchUser()
// }
onMounted(() => {
onSearchUser()
})
return {
form,
historicalData,
historicalColumns,
loading,
onSearchUser
// resetHistoryForm
}
}

View File

@ -0,0 +1,20 @@
<template>
<div>基础信息-{{ id }}-{{ props.uid }}</div>
</template>
<script setup lang="ts">
import { useRoute } from 'vue-router'
defineOptions({
// name name
name: 'BasicInfo'
})
const props = defineProps(['uid'])
const route = useRoute()
// const router = useRouter()
const id = route.query?.id ? route.query?.id : route.params?.id
</script>
<style scoped></style>

View File

@ -0,0 +1,20 @@
<template>
<div>游戏记录-{{ id }}-{{ props.uid }}</div>
</template>
<script setup lang="ts">
import { useRoute } from 'vue-router'
defineOptions({
// name name
name: 'GameRecord'
})
const props = defineProps(['uid'])
const route = useRoute()
// const router = useRouter()
const id = route.query?.id ? route.query?.id : route.params?.id
</script>
<style scoped></style>

View File

@ -0,0 +1,20 @@
<template>
<div>聊天记录-{{ id }}-{{ props.uid }}</div>
</template>
<script setup lang="ts">
import { useRoute } from 'vue-router'
defineOptions({
// name name
name: 'ChatRecord'
})
const props = defineProps(['uid'])
const route = useRoute()
// const router = useRouter()
const id = route.query?.id ? route.query?.id : route.params?.id
</script>
<style scoped></style>

View File

@ -0,0 +1,20 @@
<template>
<div>钻石记录-{{ id }}-{{ props.uid }}</div>
</template>
<script setup lang="ts">
import { useRoute } from 'vue-router'
defineOptions({
// name name
name: 'DiamondRecord'
})
const props = defineProps(['uid'])
const route = useRoute()
// const router = useRouter()
const id = route.query?.id ? route.query?.id : route.params?.id
</script>
<style scoped></style>

View File

@ -0,0 +1,67 @@
<template>
<el-card>
<div>用户信息 列表页面</div>
<div>{{ id }} - 详情页内容在此params传参</div>
<el-tabs v-model="activeName" type="border-card">
<el-tab-pane
v-for="(_, tab) in tabsMap"
:key="tabsMap[tab].name"
:name="tabsMap[tab].name"
:label="tabsMap[tab].label"
/>
<component :is="tabsMap[activeName].component" :uid="id" />
</el-tabs>
</el-card>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useDetail } from '../infoHook'
import basicInfo from './basicInfo.vue'
import gameRecord from './gameRecord.vue'
import diamondRecord from './diamondRecord.vue'
import loginRecord from './loginRecord.vue'
import chatRecord from './chatRecord.vue'
defineOptions({
// name name
name: 'UserInformation'
})
const { initToDetail, id } = useDetail()
initToDetail('params')
const activeName = ref('basicInfo')
const tabsMap = {
basicInfo: {
name: 'basicInfo',
label: '用户信息',
component: basicInfo
},
gameRecord: {
name: 'gameRecord',
label: '游戏记录',
component: gameRecord
},
diamondRecord: {
name: 'diamondRecord',
label: '钻石记录',
component: diamondRecord
},
loginRecord: {
name: 'loginRecord',
label: '登录记录',
component: loginRecord
},
chatRecord: {
name: 'chatRecord',
label: '聊天记录',
component: chatRecord
}
}
</script>
<style scoped></style>

View File

@ -0,0 +1,20 @@
<template>
<div>登录记录-{{ id }}-{{ props.uid }}</div>
</template>
<script setup lang="ts">
import { useRoute } from 'vue-router'
defineOptions({
// name name
name: 'LoginRecord'
})
const props = defineProps(['uid'])
const route = useRoute()
// const router = useRouter()
const id = route.query?.id ? route.query?.id : route.params?.id
</script>
<style scoped></style>

View File

@ -23,6 +23,11 @@ import Lock from '@iconify-icons/ri/lock-fill'
import Check from '@iconify-icons/ep/check'
import User from '@iconify-icons/ri/user-3-fill'
//
import { setToken } from '@/utils/auth'
import { addPathMatch } from '@/router/utils'
import { usePermissionStoreHook } from '@/store/modules/permission'
defineOptions({
name: 'Login'
})
@ -44,22 +49,43 @@ const ruleForm = reactive({
password: 'admin123'
})
// const onLogin = async (formEl: FormInstance | undefined) => {
// loading.value = true
// if (!formEl) return
// await formEl.validate((valid, fields) => {
// if (valid) {
// useUserStoreHook()
// .loginByUsername({ username: ruleForm.username, password: 'admin123' })
// .then(res => {
// if (res.success) {
// //
// initRouter().then(() => {
// router.push('/')
// message('', { type: 'success' })
// })
// }
// })
// } else {
// loading.value = false
// return fields
// }
// })
// }
const onLogin = async (formEl: FormInstance | undefined) => {
loading.value = true
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
useUserStoreHook()
.loginByUsername({ username: ruleForm.username, password: 'admin123' })
.then(res => {
if (res.success) {
//
initRouter().then(() => {
router.push('/')
message('登录成功', { type: 'success' })
})
}
})
//
usePermissionStoreHook().handleWholeMenus([])
addPathMatch()
setToken({
username: 'admin',
roles: ['admin'],
accessToken: 'eyJhbGciOiJIUzUxMiJ9.admin'
} as any)
router.push('/')
message('登录成功', { type: 'success' })
} else {
loading.value = false
return fields

View File

@ -1,34 +1,34 @@
import dayjs from "dayjs";
import { resolve } from "path";
import pkg from "./package.json";
import { warpperEnv } from "./build";
import { getPluginsList } from "./build/plugins";
import { include, exclude } from "./build/optimize";
import { UserConfigExport, ConfigEnv, loadEnv } from "vite";
import dayjs from 'dayjs'
import { resolve } from 'path'
import pkg from './package.json'
import { warpperEnv } from './build'
import { getPluginsList } from './build/plugins'
import { include, exclude } from './build/optimize'
import { UserConfigExport, ConfigEnv, loadEnv } from 'vite'
/** 当前执行node命令时文件夹的地址工作目录 */
const root: string = process.cwd();
const root: string = process.cwd()
/** 路径查找 */
const pathResolve = (dir: string): string => {
return resolve(__dirname, ".", dir);
};
return resolve(__dirname, '.', dir)
}
/** 设置别名 */
const alias: Record<string, string> = {
"@": pathResolve("src"),
"@build": pathResolve("build")
};
'@': pathResolve('src'),
'@build': pathResolve('build')
}
const { dependencies, devDependencies, name, version } = pkg;
const { dependencies, devDependencies, name, version } = pkg
const __APP_INFO__ = {
pkg: { dependencies, devDependencies, name, version },
lastBuildTime: dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss")
};
lastBuildTime: dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss')
}
export default ({ command, mode }: ConfigEnv): UserConfigExport => {
const { VITE_CDN, VITE_PORT, VITE_COMPRESSION, VITE_PUBLIC_PATH } =
warpperEnv(loadEnv(mode, root));
warpperEnv(loadEnv(mode, root))
return {
base: VITE_PUBLIC_PATH,
root,
@ -41,9 +41,16 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
https: false,
// 端口号
port: VITE_PORT,
host: "0.0.0.0",
host: '0.0.0.0',
// 本地跨域代理 https://cn.vitejs.dev/config/server-options.html#server-proxy
proxy: {}
proxy: {
'^/dev-api/.*': {
// 这里填写后端地址
target: 'http://192.168.100.87:8000',
changeOrigin: true,
rewrite: path => path.replace(/^\/dev-api/, '')
}
}
},
plugins: getPluginsList(command, VITE_CDN, VITE_COMPRESSION),
// https://cn.vitejs.dev/config/dep-optimization-options.html#dep-optimization-options
@ -57,13 +64,13 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
chunkSizeWarningLimit: 4000,
rollupOptions: {
input: {
index: pathResolve("index.html")
index: pathResolve('index.html')
},
// 静态资源分类打包
output: {
chunkFileNames: "static/js/[name]-[hash].js",
entryFileNames: "static/js/[name]-[hash].js",
assetFileNames: "static/[ext]/[name]-[hash].[ext]"
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]'
}
}
},
@ -71,5 +78,5 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
__INTLIFY_PROD_DEVTOOLS__: false,
__APP_INFO__: JSON.stringify(__APP_INFO__)
}
};
};
}
}