feat(web): 08 后台四个页面落地(内容治理 / 订单与权益 / 创作者审核 / 数据看板)

为什么:08 运营后台的接口在前几轮已经实现,但运营在界面上点不到——
评论审核、举报工单、敏感词维护、订单补发/退款、权益回收、金币补发、对账、
创作者入驻与内容提交审核、运营大盘,都只能靠 curl。本轮把这四个页面补齐,
08 才算真正闭环。

- 内容治理:评论审核(通过/驳回/删除)、举报工单处理(可联动封禁)、敏感词库增删改查
- 订单与权益:订单检索与流水、补发、退款、权益检索/人工补发/回收、金币流水与人工补币、对账运行与历史
- 创作者审核:入驻审核(通过/驳回原因码/冻结)+ 资质抽屉;内容提交审核(通过/驳回)
- 数据看板:overview 五组指标 + transcode 队列与失败任务,只读;取不到的指标显示「暂无数据源」而不是 0
- 新增 console.css(工具条/抽屉/看板卡片,含深色模式),四个页面共用;时间列统一 yyyy-MM-dd HH:mm:ss
- 按钮按权限点显隐(没有 *:update / *:audit 的角色看到的是只读态),表格列与后端字段一一对应
This commit is contained in:
Vicky committed 2026-10-15 13:28:46 +08:00
1 parent 44c2c46a68
commit f037d243cd
13 files changed
+2680

No files matched your search

+234
View File
@@ -0,0 +1,234 @@
<script setup>
import { Search } from '@element-plus/icons-vue'
import PageHeading from '@/views/components/PageHeading.vue'
import { useRbac } from '@/stores/rbac'
import { dateCell } from '@/utils/format'
import {
CREATOR_STATUS,
CREATOR_TYPE,
creatorStatusMeta,
creatorTypeText,
useCreatorAudit
} from './composables/useCreatorAudit'
const { can } = useRbac()
const canAudit = can('creator:audit')
const {
rows,
total,
loading,
keyword,
statusFilter,
typeFilter,
currentPage,
pageSize,
auditVisible,
auditSaving,
auditTarget,
auditForm,
documentsVisible,
documentsLoading,
documents,
documentsTarget,
load,
query,
reset,
handleSizeChange,
openDocuments,
openAudit,
confirmAudit,
freeze
} = useCreatorAudit()
</script>
<template>
<PageHeading
eyebrow="创作者管理"
title="创作者入驻"
description="审核创作者主体与资质,通过后创作者才能提交内容。"
/>
<section class="panel">
<div class="console-toolbar">
<el-input
v-model="keyword"
class="console-keyword"
:prefix-icon="Search"
clearable
placeholder="搜索名称 / 编号 / 联系人 / 联系方式"
@keyup.enter="query"
@clear="query"
/>
<el-select
v-model="statusFilter"
class="console-select"
clearable
placeholder="全部状态"
@change="query"
>
<el-option
v-for="item in CREATOR_STATUS"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select
v-model="typeFilter"
class="console-select"
clearable
placeholder="全部类型"
@change="query"
>
<el-option
v-for="item in CREATOR_TYPE"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-button type="primary" @click="query">查询</el-button>
<el-button @click="reset">重置</el-button>
<span class="console-count">共 {{ total }} 位创作者</span>
</div>
<el-table
v-loading="loading"
:data="rows"
row-key="id"
border
class="drama-el-table"
empty-text="没有符合条件的创作者"
>
<el-table-column
type="index"
label="序号"
width="70"
:index="(currentPage - 1) * pageSize + 1"
/>
<el-table-column prop="code" label="编号" min-width="120" show-overflow-tooltip />
<el-table-column prop="name" label="名称" min-width="160" show-overflow-tooltip />
<el-table-column label="类型" width="90">
<template #default="{ row }">{{ creatorTypeText(row.type) }}</template>
</el-table-column>
<el-table-column prop="contactName" label="联系人" min-width="110" show-overflow-tooltip />
<el-table-column
prop="contactMobile"
label="联系方式"
min-width="140"
show-overflow-tooltip
/>
<el-table-column prop="countryCode" label="国家" width="80" />
<el-table-column label="状态" width="90">
<template #default="{ row }">
<el-tag :type="creatorStatusMeta(row.status).tag" effect="light">
{{ creatorStatusMeta(row.status).label }}
</el-tag>
</template>
</el-table-column>
<el-table-column
prop="auditAt"
label="审核时间"
min-width="165"
show-overflow-tooltip
:formatter="dateCell"
/>
<el-table-column
prop="createdAt"
label="入驻时间"
min-width="165"
show-overflow-tooltip
:formatter="dateCell"
/>
<el-table-column label="操作" width="230" fixed="right">
<template #default="{ row }">
<div class="table-actions">
<el-button type="primary" size="small" @click="openDocuments(row)">资质</el-button>
<el-button v-if="canAudit" size="small" @click="openAudit(row, 'APPROVE')"
>审核</el-button
>
<el-button
v-if="canAudit && row.status === 'approved'"
size="small"
class="danger-action"
@click="freeze(row)"
>冻结</el-button
>
</div>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="total"
layout="total, prev, pager, next, sizes, jumper"
background
@current-change="load"
@size-change="handleSizeChange"
/>
</div>
</section>
<el-drawer v-model="documentsVisible" title="创作者资质" size="520px" class="console-drawer">
<p class="console-hint">
{{ documentsTarget ? `${documentsTarget.name}(${documentsTarget.code})` : '' }}
</p>
<el-table
v-loading="documentsLoading"
:data="documents"
size="small"
border
empty-text="没有上传资质"
>
<el-table-column prop="type" label="证件类型" width="140" />
<el-table-column label="文件" min-width="200">
<template #default="{ row }">
<el-link type="primary" :href="row.fileUrl" target="_blank">{{ row.fileUrl }}</el-link>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100" />
</el-table>
</el-drawer>
<el-dialog v-model="auditVisible" title="创作者入驻审核" width="480px">
<el-form label-position="top">
<el-form-item label="目标创作者">
<el-input
:model-value="auditTarget ? `${auditTarget.name}(${auditTarget.code})` : ''"
disabled
/>
</el-form-item>
<el-form-item label="审核动作">
<el-radio-group v-model="auditForm.action">
<el-radio value="APPROVE">通过</el-radio>
<el-radio value="REJECT">驳回</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="auditForm.action === 'REJECT'" label="驳回原因码">
<el-input
v-model="auditForm.rejectCode"
placeholder="例如:DOC_INCOMPLETE"
maxlength="32"
/>
</el-form-item>
<el-form-item :label="auditForm.action === 'REJECT' ? '驳回原因(必填)' : '备注(可选)'">
<el-input
v-model="auditForm.reason"
type="textarea"
:rows="3"
maxlength="200"
show-word-limit
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="auditVisible = false">取消</el-button>
<el-button type="primary" :loading="auditSaving" @click="confirmAudit">提交</el-button>
</template>
</el-dialog>
</template>