feat:活跃卡密页面

This commit is contained in:
Ygb 2025-07-16 18:43:00 +08:00
parent d01304460e
commit 74a9910782
5 changed files with 259 additions and 33 deletions

View File

@ -41,7 +41,32 @@ const cardsApi = {
batchCreateCards: (data) => instance.post('/cards/batchCreate', data),
// 修改卡密状态
updateCardStatus: (data) => instance.put('/cards/updateStatus', data)
updateCardStatus: (data) => instance.put('/cards/updateStatus', data),
// 获取活跃卡密列表(分页)
getActiveCardsPage: (params) => {
// 转换分页参数名称
const convertedParams = {
pageNum: params.current,
pageSize: params.size
}
// 删除旧的参数
delete convertedParams.current
delete convertedParams.size
console.log('活跃卡密查询参数:', convertedParams)
return instance.get('/verifyPrice/getActiveCardsPage', {
params: convertedParams,
paramsSerializer: params => {
return Object.entries(params)
.filter(([_, v]) => v !== undefined)
.map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
.join('&')
}
})
}
}
export { cardsApi }

View File

@ -133,7 +133,10 @@
children: [{
title: '卡密列表',
path: '/tools/cards/list'
}]
},{
title: '活跃卡密列表',
path: '/tools/cards/activeCardsList'
}]
}]
},
{

View File

@ -48,6 +48,11 @@ const routes = [{
component: () => import('@/views/Tools/Cards/List.vue'),
meta: { title: '卡密列表' }
},
{
path: '/tools/cards/activeCardsList',
component: () => import('@/views/Tools/Cards/ActiveCardsList.vue'),
meta: { title: '活跃卡密列表' }
},
{
path: '/examine/violation/list',
component: () => import('@/views/Examine/Violation/List.vue'),

View File

@ -1,28 +1,29 @@
<template>
<div class="login-container">
<el-form ref="formRef" :model="form" :rules="rules" @keyup.enter="handleLogin">
<div class="header">
<h2 class="title">登录</h2>
<p class="subtitle">欢迎使用{{ global?.system.name }}管理系统</p>
<el-divider />
</div>
<el-form-item prop="username" class="form-item">
<el-input v-model="form.username" placeholder="请输入用户名" prefix-icon="User" class="input-item" />
</el-form-item>
<el-form-item prop="password" class="form-item">
<el-input v-model="form.password" type="password" placeholder="请输入密码" prefix-icon="Lock" show-password
class="input-item" />
</el-form-item>
<el-form-item prop="captcha" class="form-item">
<div class="captcha-wrapper">
<el-input v-model="form.captcha" placeholder="请输入验证码" prefix-icon="Picture" class="captcha-input input-item" />
<img :src="captchaUrl" class="captcha-image" @click="refreshCaptcha">
</div>
</el-form-item>
<el-divider class="custom-divider" />
<el-button type="primary" class="login-btn" :loading="loading" @click="handleLogin">登录</el-button>
</el-form>
</div>
<div class="login-container">
<el-form ref="formRef" :model="form" :rules="rules" @keyup.enter="handleLogin">
<div class="header">
<h2 class="title">登录</h2>
<p class="subtitle">欢迎使用{{ global?.system.name }}管理系统</p>
<el-divider/>
</div>
<el-form-item prop="username" class="form-item">
<el-input v-model="form.username" placeholder="请输入用户名" prefix-icon="User" class="input-item"/>
</el-form-item>
<el-form-item prop="password" class="form-item">
<el-input v-model="form.password" type="password" placeholder="请输入密码" prefix-icon="Lock" show-password
class="input-item"/>
</el-form-item>
<el-form-item prop="captcha" class="form-item">
<div class="captcha-wrapper">
<el-input v-model="form.captcha" placeholder="请输入验证码" prefix-icon="Picture"
class="captcha-input input-item"/>
<img :src="captchaUrl" class="captcha-image" @click="refreshCaptcha">
</div>
</el-form-item>
<el-divider class="custom-divider"/>
<el-button type="primary" class="login-btn" :loading="loading" @click="handleLogin">登录</el-button>
</el-form>
</div>
</template>
<script setup>

View File

@ -0,0 +1,192 @@
<template>
<div class="active-cards-container">
<!-- 操作按钮 -->
<ActionBar @refresh="refreshData"/>
<!-- 数据表格 -->
<el-table
:data="tableData"
border
stripe
style="width: 100%;"
v-loading="loading"
>
<el-table-column label="状态" width="80" align="center">
<template #default>
<div class="status-indicator active"></div>
</template>
</el-table-column>
<el-table-column prop="cardId" label="卡密账号" min-width="180"/>
<el-table-column prop="cardSecret" label="卡密密码" min-width="180"/>
<el-table-column prop="status" label="使用状态" width="120">
<template #default="{ row }">
<el-tag :type="getStatusType(row.status)">
{{ getStatusText(row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="effectiveDays" label="有效期" width="100">
<template #default="{ row }">
{{ row.effectiveDays }}
</template>
</el-table-column>
<el-table-column prop="activateTime" label="激活时间" min-width="160">
<template #default="{ row }">
{{ formatDateTime(row.activateTime) }}
</template>
</el-table-column>
<el-table-column prop="expireTime" label="过期时间" min-width="160">
<template #default="{ row }">
{{ formatDateTime(row.expireTime) }}
</template>
</el-table-column>
<el-table-column prop="note" label="备注" min-width="120"/>
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination
v-model:current-page="pagination.current"
v-model:page-size="pagination.size"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</template>
<script setup>
import {ref, reactive, onMounted} from 'vue'
import {ElMessage} from 'element-plus'
import ActionBar from '@/components/ActionBar.vue'
import { cardsApi } from '@/api/modules/cards'
//
const tableData = ref([])
const loading = ref(false)
//
const pagination = reactive({
current: 1,
size: 10,
total: 0
})
//
onMounted(() => {
fetchData()
})
//
const fetchData = async () => {
loading.value = true
try {
const res = await cardsApi.getActiveCardsPage(pagination)
if (res.code === 200) {
tableData.value = res.data.list || []
pagination.total = res.data.total || 0
} else {
ElMessage.error(res.message || '获取数据失败')
}
} catch (error) {
console.error('获取数据失败:', error)
ElMessage.error('获取数据失败,请稍后再试')
tableData.value = []
pagination.total = 0
} finally {
loading.value = false
}
}
//
const refreshData = () => {
fetchData()
}
//
const handleSizeChange = (size) => {
pagination.size = size
pagination.current = 1
fetchData()
}
//
const handleCurrentChange = (current) => {
pagination.current = current
fetchData()
}
//
const getStatusType = (status) => {
const map = {
0: 'info',
1: 'success',
2: 'warning',
3: 'danger',
4: 'info'
}
return map[status] || 'info'
}
//
const getStatusText = (status) => {
const map = {
0: '未激活',
1: '未使用',
2: '已使用',
3: '已冻结',
4: '已过期'
}
return map[status] || '未知'
}
//
const formatDateTime = (timestamp) => {
if (!timestamp) return '-'
const date = new Date(timestamp)
return date.toLocaleString()
}
</script>
<style scoped>
.active-cards-container {
padding: 20px;
background-color: #f5f7fa;
min-height: calc(100vh - 40px);
}
.status-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
margin: 0 auto;
}
.status-indicator.active {
background-color: #67c23a;
box-shadow: 0 0 6px rgba(103, 194, 58, 0.5);
}
.pagination-container {
margin-top: 20px;
display: flex;
justify-content: center;
background-color: #fff;
padding: 15px;
border-radius: 4px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}
.el-table {
margin-bottom: 20px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}
.el-table ::v-deep(.el-table__header) th {
background-color: #f8f8f9;
}
</style>