Files
as-partner-frontend/src/views/modules/manage/card-pool.vue
2026-07-26 12:54:46 +08:00

313 lines
11 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>
<div class="mod-card-pool">
<!-- 卡池统计 -->
<el-row :gutter="16" class="stats-row">
<el-col :span="6">
<el-card shadow="hover">
<div class="stat-card">
<div class="stat-value">{{ stats.total }}</div>
<div class="stat-label">总卡数</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover">
<div class="stat-card">
<div class="stat-value" style="color: #67c23a;">{{ stats.available }}</div>
<div class="stat-label">可用(UNUSED)</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover">
<div class="stat-card">
<div class="stat-value" style="color: #e6a23c;">{{ stats.reserved }}</div>
<div class="stat-label">已预留(RESERVED)</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover">
<div class="stat-card">
<div class="stat-value" style="color: #409eff;">{{ stats.used }}</div>
<div class="stat-label">已使用(USED)</div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 搜索 + 操作 -->
<el-form :inline="true" :model="dataForm" @keyup.enter="getDataList()">
<el-form-item>
<el-input v-model="dataForm.cardCode" placeholder="卡密/激活码" clearable></el-input>
</el-form-item>
<el-form-item>
<el-input v-model="dataForm.orderNo" placeholder="关联订单号" clearable></el-input>
</el-form-item>
<el-form-item>
<el-select v-model="dataForm.status" placeholder="卡状态" clearable>
<el-option label="未使用" value="UNUSED"></el-option>
<el-option label="已预留" value="RESERVED"></el-option>
<el-option label="已使用" value="USED"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<org-tree-select v-model="dataForm.partnerId" placeholder="合作商" width="160px" />
</el-form-item>
<el-form-item>
<el-button @click="getDataList()">查询</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="importVisible = true">导入卡密</el-button>
</el-form-item>
</el-form>
<!-- 列表 -->
<div class="table-page-wrap">
<el-table :data="dataList" border v-loading="dataListLoading" style="width: 100%;">
<el-table-column type="index" header-align="center" align="center" width="60" label="序号" />
<el-table-column prop="cardCode" header-align="center" align="center" min-width="160" label="卡密(激活码)" show-overflow-tooltip />
<el-table-column prop="thirdCardNo" header-align="center" align="center" min-width="180" label="第三方卡号" show-overflow-tooltip />
<el-table-column prop="thirdPartyRef" header-align="center" align="center" min-width="180" label="第三方引用(UID)" show-overflow-tooltip />
<el-table-column prop="partnerId" header-align="center" align="center" width="100" label="合作商" />
<el-table-column prop="status" header-align="center" align="center" width="100" label="卡状态">
<template #default="{ row }">
<el-tag v-if="row.status === 'UNUSED'" size="small" type="success">未使用</el-tag>
<el-tag v-else-if="row.status === 'RESERVED'" size="small" type="warning">已预留</el-tag>
<el-tag v-else-if="row.status === 'USED'" size="small" type="primary">已使用</el-tag>
<el-tag v-else size="small">{{ row.status }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="activateStatus" header-align="center" align="center" width="100" label="激活状态">
<template #default="{ row }">
<el-tag v-if="row.activateStatus === 'PENDING'" size="small" type="info">待激活</el-tag>
<el-tag v-else-if="row.activateStatus === 'SUCCESS'" size="small" type="success">已激活</el-tag>
<el-tag v-else-if="row.activateStatus === 'FAILED'" size="small" type="danger">激活失败</el-tag>
<el-tag v-else size="small">{{ row.activateStatus || '-' }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="deviceId" header-align="center" align="center" width="90" label="设备" />
<el-table-column prop="orderNo" header-align="center" align="center" min-width="160" label="关联订单号" show-overflow-tooltip />
<el-table-column prop="expireAt" header-align="center" align="center" width="170" label="到期时间">
<template #default="{ row }">{{ row.expireAt || '-' }}</template>
</el-table-column>
<el-table-column prop="activatedAt" header-align="center" align="center" width="170" label="激活时间">
<template #default="{ row }">{{ row.activatedAt || '-' }}</template>
</el-table-column>
<el-table-column prop="createdAt" header-align="center" align="center" width="170" label="创建时间" />
</el-table>
<el-pagination
@size-change="sizeChangeHandle"
@current-change="currentChangeHandle"
:current-page="pageIndex"
:page-sizes="[10, 20, 50, 100]"
:page-size="pageSize"
:total="totalPage"
layout="total, sizes, prev, pager, next, jumper">
</el-pagination>
</div>
<!-- 导入卡密弹窗 -->
<el-dialog v-model="importVisible" title="导入天卡卡密" width="600px">
<el-form :model="importForm" :rules="importRules" ref="importFormRef" label-width="100px">
<el-form-item label="合作商" prop="partnerId">
<org-tree-select v-model="importForm.partnerId" placeholder="请选择合作商" />
</el-form-item>
<el-form-item label="卡密列表" prop="cardCodesText">
<el-input
v-model="importForm.cardCodesText"
type="textarea"
:rows="10"
placeholder="每行一个卡密/激活码,例如:&#10;XXXX-XXXX-XXXX&#10;YYYY-YYYY-YYYY" />
<div style="font-size: 12px; color: #999; margin-top: 4px;">
每行一个橘视厅激活码,系统会自动生成第三方卡号和引用标识
</div>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="importVisible = false">取消</el-button>
<el-button type="primary" :loading="importLoading" @click="submitImport">开始导入</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, onMounted } from 'vue'
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
import {
getDayCardPoolList,
getDayCardPoolStats,
importDayCardPool,
type DayCardPoolItem,
type DayCardPoolStats
} from '@/api/manage/daycard'
interface DataForm {
cardCode: string
orderNo: string
status: string
partnerId: string
}
const dataForm = reactive<DataForm>({
cardCode: '',
orderNo: '',
status: '',
partnerId: ''
})
const dataList = ref<DayCardPoolItem[]>([])
const pageIndex = ref(1)
const pageSize = ref(10)
const totalPage = ref(0)
const dataListLoading = ref(false)
const stats = reactive<DayCardPoolStats>({
total: 0,
available: 0,
reserved: 0,
used: 0
})
// 导入弹窗
const importVisible = ref(false)
const importLoading = ref(false)
const importFormRef = ref<FormInstance>()
interface ImportForm {
partnerId: number | null
cardCodesText: string
}
const importForm = reactive<ImportForm>({
partnerId: 1,
cardCodesText: ''
})
const importRules: FormRules = {
partnerId: [{ required: true, message: '请输入合作商ID', trigger: 'blur' }],
cardCodesText: [{ required: true, message: '请输入卡密', trigger: 'blur' }]
}
async function loadStats (): Promise<void> {
try {
const res = await getDayCardPoolStats()
if (res && res.code === 0 && res.data?.stats) {
stats.total = res.data.stats.total || 0
stats.available = res.data.stats.available || 0
stats.reserved = res.data.stats.reserved || 0
stats.used = res.data.stats.used || 0
}
} catch {
// 静默
}
}
async function getDataList (): Promise<void> {
dataListLoading.value = true
try {
const params: Record<string, unknown> = {
page: pageIndex.value,
limit: pageSize.value
}
if (dataForm.cardCode) params.cardCode = dataForm.cardCode
if (dataForm.orderNo) params.orderNo = dataForm.orderNo
if (dataForm.status) params.status = dataForm.status
if (dataForm.partnerId) params.partnerId = dataForm.partnerId
const res = await getDayCardPoolList(params as any)
if (res && res.code === 0) {
dataList.value = res.data?.page?.list || []
totalPage.value = res.data?.page?.totalCount || 0
} else {
dataList.value = []
totalPage.value = 0
if (res?.msg) ElMessage.error(res.msg)
}
} catch (e: any) {
dataList.value = []
totalPage.value = 0
ElMessage.error(e?.message || '请求异常')
} finally {
dataListLoading.value = false
}
}
function sizeChangeHandle (val: number): void {
pageSize.value = val
pageIndex.value = 1
getDataList()
}
function currentChangeHandle (val: number): void {
pageIndex.value = val
getDataList()
}
async function submitImport (): Promise<void> {
if (!importFormRef.value) return
await importFormRef.value.validate(async (valid) => {
if (!valid) return
const cardCodes = importForm.cardCodesText
.split('\n')
.map(s => s.trim())
.filter(s => s.length > 0)
if (cardCodes.length === 0) {
ElMessage.warning('请输入至少一个卡密')
return
}
importLoading.value = true
try {
const res = await importDayCardPool({
partnerId: importForm.partnerId ?? 0,
cardCodes
})
if (res && res.code === 0) {
const successCount = (res as any).data?.successCount ?? 0
const totalCount = (res as any).data?.totalCount ?? cardCodes.length
ElMessage.success(`导入完成:成功 ${successCount} / 总计 ${totalCount}`)
importVisible.value = false
importForm.cardCodesText = ''
getDataList()
loadStats()
} else {
ElMessage.error(res?.msg || '导入失败')
}
} catch (e: any) {
ElMessage.error(e?.message || '导入异常')
} finally {
importLoading.value = false
}
})
}
onMounted(() => {
getDataList()
loadStats()
})
</script>
<style scoped>
.mod-card-pool {
padding: 10px;
}
.stats-row {
margin-bottom: 16px;
}
.stat-card {
text-align: center;
padding: 10px 0;
}
.stat-value {
font-size: 28px;
font-weight: bold;
color: #303133;
}
.stat-label {
font-size: 13px;
color: #909399;
margin-top: 4px;
}
</style>