feat(web): 增加角色列表和充值流水功能

- 在 HomeView 中添加角色列表和充值流水两个表格
- 实现角色列表数据的获取和搜索功能
- 添加充值流水数据的获取功能
- 引入 dayjs 库对时间进行格式化
- 优化表单选择框,使用 el-select-v2 组件
This commit is contained in:
2025-04-24 18:14:28 +08:00
parent 278684d3ff
commit 26bd2029e7
5 changed files with 108 additions and 35 deletions

1
package-lock.json generated
View File

@@ -4755,6 +4755,7 @@
"web": {
"version": "0.0.0",
"dependencies": {
"dayjs": "^1.11.13",
"element-plus": "^2.9.8",
"vue": "^3.5.13",
"vue-router": "^4.5.0"

View File

@@ -1,30 +1,31 @@
const express = require('express');
const { getConnection, query } = require('../utils/db.util');
const express = require("express");
const { getConnection, query } = require("../utils/db.util");
const router = express.Router();
// 获取角色列表
router.get('/roles', async (req, res) => {
try {
const connection = await getConnection();
const results = await query('SELECT * FROM role', [], connection);
res.json(results);
} catch (error) {
console.error('获取角色数据失败:', error);
res.status(500).json({ error: '获取角色数据失败' });
}
router.get("/roles", async (req, res) => {
try {
const { search = "" } = req.query;
const connection = await getConnection();
const results = await query(`SELECT * FROM role where name like '%${search}%'`, [], connection);
res.json(results);
} catch (error) {
console.error("获取角色数据失败:", error);
res.status(500).json({ error: "获取角色数据失败" });
}
});
// 获取充值列表
router.get('/recharges', async (req, res) => {
try {
const connection = await getConnection();
const results = await query('SELECT * FROM recharge', [], connection);
res.json(results);
} catch (error) {
console.error('获取充值列表失败:', error);
res.status(500).json({ error: '获取充值列表失败' });
}
router.get("/recharges", async (req, res) => {
try {
const connection = await getConnection();
const results = await query("SELECT * FROM recharge", [], connection);
res.json(results);
} catch (error) {
console.error("获取充值列表失败:", error);
res.status(500).json({ error: "获取充值列表失败" });
}
});
module.exports = router;
module.exports = router;

View File

@@ -10,6 +10,7 @@
"format": "prettier --write src/"
},
"dependencies": {
"dayjs": "^1.11.13",
"element-plus": "^2.9.8",
"vue": "^3.5.13",
"vue-router": "^4.5.0"

53
web/src/assets/items.json Normal file
View File

@@ -0,0 +1,53 @@
[{"resId":3,"name":"经验","useType":1},
{"resId":6,"name":"钻石","useType":1},
{"resId":7,"name":"金币","useType":1},
{"resId":8,"name":"洗炼石","useType":1},
{"resId":9,"name":"体力","useType":1},
{"resId":10,"name":"充值币","useType":1},
{"resId":10002,"name":"发冠升级图纸","useType":1},
{"resId":10003,"name":"道袍升级图纸","useType":1},
{"resId":10004,"name":"项链升级图纸","useType":1},
{"resId":10005,"name":"戒指升级图纸","useType":1},
{"resId":10006,"name":"靴子升级图纸","useType":1},
{"resId":10007,"name":"新手道书","useType":1},
{"resId":10008,"name":"五色土","useType":1},
{"resId":10009,"name":"女娲石","useType":1},
{"resId":10010,"name":"突破丹","useType":1},
{"resId":10011,"name":"随机装备图纸","useType":2},
{"resId":10012,"name":"随机技能卷轴","useType":4},
{"resId":10013,"name":"随机宝石箱子","useType":3},
{"resId":10014,"name":"普通宝石箱","useType":3},
{"resId":10015,"name":"璀璨宝石箱","useType":3},
{"resId":10016,"name":"随机紫色宝石宝箱","useType":3},
{"resId":10017,"name":"随机金色宝石宝箱","useType":3},
{"resId":10018,"name":"随机红色宝石宝箱","useType":3},
{"resId":10019,"name":"随机多彩宝石宝箱","useType":3},
{"resId":10020,"name":"宝石抽取券","useType":1},
{"resId":10021,"name":"灵宠抽取券","useType":1},
{"resId":10022,"name":"随机宝石箱子","useType":3},
{"resId":10023,"name":"随机稀有宝石","useType":3},
{"resId":10024,"name":"随机宝石箱子","useType":3},
{"resId":10101,"name":"御剑术卷轴","useType":1},
{"resId":10102,"name":"毒气弹卷轴","useType":1},
{"resId":10103,"name":"寒冰箭卷轴","useType":1},
{"resId":10104,"name":"惊雷咒卷轴","useType":1},
{"resId":10105,"name":"石狮子卷轴","useType":1},
{"resId":10106,"name":"剑气斩卷轴","useType":1},
{"resId":10107,"name":"万剑诀卷轴","useType":1},
{"resId":10108,"name":"寒冰突刺卷轴","useType":1},
{"resId":10109,"name":"连环闪电卷轴","useType":1},
{"resId":10110,"name":"泰山压顶卷轴","useType":1},
{"resId":10111,"name":"风暴术卷轴","useType":1},
{"resId":10112,"name":"天雷网卷轴","useType":1},
{"resId":10113,"name":"巨石突刺卷轴","useType":1},
{"resId":10114,"name":"旋风术卷轴","useType":1},
{"resId":10115,"name":"闪电球卷轴","useType":1},
{"resId":10116,"name":"改名卡","useType":1},
{"resId":10117,"name":"随机宝石箱子","useType":1},
{"resId":10118,"name":"随机蓝色宝石宝箱","useType":3},
{"resId":10119,"name":"晶石掉落","useType":1},
{"resId":10120,"name":"技能卷轴自选宝箱","useType":5},
{"resId":10121,"name":"灵宠口粮","useType":1},
{"resId":10122,"name":"灵宠抽卡箱","useType":1},
{"resId":10123,"name":"灵宠口粮","useType":1},
{"resId":10999,"name":"1元代金券","useType":1}]

View File

@@ -1,6 +1,9 @@
<script setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'
import itemList from "@/assets/items.json"
import dayjs from 'dayjs'
// 第一个卡片:表单数据
const form = ref({
@@ -8,7 +11,7 @@ const form = ref({
item: '',
recharge: ''
})
const items = ref(['物品1', '物品2', '物品3'])
const items = ref(itemList)
const recharges = ref(['充值1', '充值2', '充值3'])
// 第二个卡片:角色表格数据
@@ -16,10 +19,14 @@ const roleList = ref([])
const roleSearch = ref('')
const fetchRoleList = async () => {
try {
const response = await axios.get('/api/role', {
const response = await axios.get('/api/roles', {
params: { search: roleSearch.value }
})
roleList.value = response.data
roleList.value = response.data.map(e => {
e.lastLoginTime = dayjs(e.lastLoginTime).format("YYYY-MM-DD HH:mm:ss")
e.createTime = dayjs(e.createTime).format("YYYY-MM-DD HH:mm:ss")
return { ...e }
})
} catch (error) {
console.error('获取角色列表失败:', error)
}
@@ -30,7 +37,7 @@ const rechargeList = ref([])
const rechargeSearch = ref('')
const fetchRechargeList = async () => {
try {
const response = await axios.get('/api/recharge', {
const response = await axios.get('/api/recharges', {
params: { search: rechargeSearch.value }
})
rechargeList.value = response.data
@@ -70,15 +77,15 @@ const submitForm = () => {
</el-col>
<el-col :span="8">
<el-form-item label="物品道具">
<el-select v-model="form.item" placeholder="请选择物品">
<el-option v-for="item in items" :key="item" :label="item" :value="item"></el-option>
</el-select>
<el-select-v2 v-model="form.item" placeholder="请选择物品" :options="items"
:props="{ label: 'name', value: 'resId' }" filterable />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="充值">
<el-select v-model="form.recharge" placeholder="请选择充值">
<el-option v-for="recharge in recharges" :key="recharge" :label="recharge" :value="recharge"></el-option>
<el-option v-for="recharge in recharges" :key="recharge" :label="recharge"
:value="recharge"></el-option>
</el-select>
</el-form-item>
</el-col>
@@ -91,13 +98,20 @@ const submitForm = () => {
<template #header>
<div class="card-header">
<span>角色列表</span>
<el-input style="width: 240px;" v-model="roleSearch" placeholder="请输入角色名称或ID" @input="fetchRoleList"></el-input>
<el-input style="width: 240px;" v-model="roleSearch" placeholder="请输入角色名称或ID" @change="fetchRoleList" clearable />
</div>
</template>
<el-table :data="roleList" style="width: 100%" border>
<el-table-column prop="id" label="ID" width="180"></el-table-column>
<el-table-column prop="name" label="角色名称" width="180"></el-table-column>
<el-table-column prop="level" label="等级"></el-table-column>
<el-table :data="roleList" style="width: 100%" border height="400">
<el-table-column prop="id" label="ID"></el-table-column>
<el-table-column prop="name" label="角色名称"></el-table-column>
<el-table-column prop="lv" label="等级"></el-table-column>
<el-table-column prop="lastLoginTime" label="上次登录" width="220" />
<el-table-column prop="createTime" label="创建时间" width="220" />
<el-table-column label="是否禁用">
<template v-slot="{ row }">
<el-switch v-model="row.ban" disabled />
</template>
</el-table-column>
</el-table>
</el-card>
@@ -106,7 +120,8 @@ const submitForm = () => {
<template #header>
<div class="card-header">
<span>充值流水</span>
<el-input style="width: 240px;" v-model="rechargeSearch" placeholder="请输入角色名称或流水单号" @input="fetchRechargeList"></el-input>
<el-input style="width: 240px;" v-model="rechargeSearch" placeholder="请输入角色名称或流水单号"
@input="fetchRechargeList"></el-input>
</div>
</template>
<el-table :data="rechargeList" style="width: 100%" border>
@@ -127,9 +142,11 @@ const submitForm = () => {
gap: 20px;
padding: 20px;
}
.card-item {
width: 100%;
}
.card-header {
display: flex;
justify-content: space-between;