Files
observer/server_admin/src/views/Licenses.vue
T
admin a0b115d954 训练体系整合与标注单阶段化
- 标注:AI 预标注直写 labels_json(去候选确认两阶段);重叠去重(minIoU);全量标注按钮
- 训练:脚本迁移入 server/training/(Go 化 prepare_yolo/analyze_rfdetr,保留 train_server.py);tflite 产物自检并入训练流程(check_tflite)
- 数据目录/权重不进 git;.gitignore 迁移至仓库根
2026-08-26 18:22:56 +08:00

217 lines
6.7 KiB
Vue

<script setup>
import { onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import request from '../api/request'
const filter = reactive({ phoneNum: '' })
const loading = ref(false)
const list = ref([])
const total = ref(0)
const page = ref(1)
const size = ref(20)
const grantVisible = ref(false)
const grantForm = reactive({ phoneNum: '', planId: 'day' })
const granting = ref(false)
const remarkVisible = ref(false)
const remarkForm = reactive({ phoneNum: '', remark: '' })
const remarking = ref(false)
const planOptions = [
{ value: 'day', label: '1天' },
{ value: 'week', label: '7天' },
{ value: 'month', label: '30天' },
]
function load() {
loading.value = true
request
.get('/licenses', {
params: {
page: page.value,
size: size.value,
phoneNum: filter.phoneNum || undefined,
},
})
.then((data) => {
list.value = data.list || []
total.value = data.total || 0
})
.finally(() => {
loading.value = false
})
}
function search() {
page.value = 1
load()
}
function openGrant(row) {
grantForm.phoneNum = row.phoneNum
grantForm.planId = 'day'
grantVisible.value = true
}
function submitGrant() {
granting.value = true
request
.post('/licenses/grant', { phoneNum: grantForm.phoneNum.trim(), planId: grantForm.planId })
.then((data) => {
ElMessage.success(`授权成功,到期时间 ${data.expiresAt}`)
grantVisible.value = false
load()
})
.finally(() => {
granting.value = false
})
}
function openRemark(row) {
remarkForm.phoneNum = row.phoneNum
remarkForm.remark = row.remark || ''
remarkVisible.value = true
}
function submitRemark() {
remarking.value = true
request
.post('/licenses/remark', {
phoneNum: remarkForm.phoneNum.trim(),
remark: remarkForm.remark.trim(),
})
.then(() => {
ElMessage.success(remarkForm.remark ? '备注已保存' : '备注已清空')
remarkVisible.value = false
load()
})
.finally(() => {
remarking.value = false
})
}
function revoke(row) {
ElMessageBox.confirm(`确认撤销 ${row.phoneNum} 的授权?撤销后该账号额度立即失效,账号保留可继续登录。`, '撤销授权', {
type: 'warning',
confirmButtonText: '确认撤销',
cancelButtonText: '取消',
})
.then(() => request.post('/licenses/revoke', { phoneNum: row.phoneNum }))
.then(() => {
ElMessage.success('已撤销')
load()
})
.catch(() => {})
}
onMounted(load)
</script>
<template>
<el-card shadow="never">
<div class="toolbar">
<el-form :model="filter" inline @submit.prevent="search">
<el-form-item label="手机号">
<el-input v-model="filter.phoneNum" placeholder="模糊匹配" clearable style="width: 220px" @keyup.enter="search" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="filter.phoneNum = ''; search()">重置</el-button>
</el-form-item>
</el-form>
</div>
<el-table v-loading="loading" :data="list" border stripe>
<el-table-column prop="phoneNum" label="手机号" min-width="140" show-overflow-tooltip />
<el-table-column label="授权状态" width="110">
<template #default="{ row }">
<el-tag v-if="row.expiresAt" type="success" size="small">已授权</el-tag>
<el-tag v-else type="info" size="small">未充值</el-tag>
</template>
</el-table-column>
<el-table-column prop="expiresAt" label="到期时间" width="180">
<template #default="{ row }">{{ row.expiresAt || '-' }}</template>
</el-table-column>
<el-table-column prop="createdAt" label="注册时间" width="180">
<template #default="{ row }">{{ row.createdAt || '-' }}</template>
</el-table-column>
<el-table-column prop="updatedAt" label="更新时间" width="180">
<template #default="{ row }">{{ row.updatedAt || '-' }}</template>
</el-table-column>
<el-table-column prop="remark" label="备注" min-width="160" show-overflow-tooltip>
<template #default="{ row }">{{ row.remark || '-' }}</template>
</el-table-column>
<el-table-column label="操作" width="180" fixed="right">
<template #default="{ row }">
<el-button type="primary" link size="small" @click="openGrant(row)">授权</el-button>
<el-button type="warning" link size="small" @click="openRemark(row)">备注</el-button>
<el-button type="danger" link size="small" :disabled="!row.expiresAt" @click="revoke(row)">撤销</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
class="pager"
v-model:current-page="page"
v-model:page-size="size"
:total="total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next"
@change="load"
/>
<el-dialog v-model="grantVisible" title="手动授权" width="min(420px, 92vw)">
<el-form label-width="80px">
<el-form-item label="手机号">
<el-input :model-value="grantForm.phoneNum" disabled />
</el-form-item>
<el-form-item label="套餐">
<el-select v-model="grantForm.planId" style="width: 100%">
<el-option v-for="p in planOptions" :key="p.value" :label="p.label" :value="p.value" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="grantVisible = false">取消</el-button>
<el-button type="primary" :loading="granting" @click="submitGrant">确认授权</el-button>
</template>
</el-dialog>
<el-dialog v-model="remarkVisible" title="账号备注" width="min(420px, 92vw)">
<el-form label-width="80px">
<el-form-item label="手机号">
<el-input :model-value="remarkForm.phoneNum" disabled />
</el-form-item>
<el-form-item label="备注">
<el-input
v-model="remarkForm.remark"
type="textarea"
:rows="3"
maxlength="200"
show-word-limit
placeholder="运营备注(如发卡渠道/人工记录),留空提交即清空"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="remarkVisible = false">取消</el-button>
<el-button type="primary" :loading="remarking" @click="submitRemark">保存</el-button>
</template>
</el-dialog>
</el-card>
</template>
<style scoped>
.toolbar {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 14px;
}
.pager {
margin-top: 14px;
justify-content: flex-end;
}
</style>