350 lines
11 KiB
Vue
350 lines
11 KiB
Vue
<!-- Author: fruit.com.cn -->
|
||
|
||
<script setup>
|
||
import { AppIcons } from '@/constants/icons'
|
||
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 canOpenAccount = can('creator:account')
|
||
|
||
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,
|
||
createVisible,
|
||
createSaving,
|
||
createForm,
|
||
openCreate,
|
||
confirmCreate,
|
||
accountVisible,
|
||
accountSaving,
|
||
accountResult,
|
||
openAccount,
|
||
resetPassword,
|
||
copyCredential,
|
||
closeAccount
|
||
} = useCreatorAudit()
|
||
</script>
|
||
|
||
<template>
|
||
<PageHeading
|
||
eyebrow="创作者管理"
|
||
title="创作者入驻"
|
||
description="审核创作者主体与资质,通过后创作者才能提交内容。"
|
||
>
|
||
<el-button v-if="canAudit" type="primary" @click="openCreate">新增创作者</el-button>
|
||
</PageHeading>
|
||
|
||
<section class="panel">
|
||
<div class="console-toolbar">
|
||
<el-input
|
||
v-model="keyword"
|
||
class="console-keyword"
|
||
clearable
|
||
placeholder="搜索名称 / 编号 / 联系人 / 联系方式"
|
||
@keyup.enter="query"
|
||
@clear="query"
|
||
>
|
||
<template #prefix><AppIcon :icon="AppIcons.search" /></template>
|
||
</el-input>
|
||
<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 label="账号" width="110">
|
||
<template #default="{ row }">
|
||
<el-tag v-if="row.adminUserId" type="success" effect="light">已开通</el-tag>
|
||
<span v-else class="console-muted">未开通</span>
|
||
</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="330" fixed="right">
|
||
<template #default="{ row }">
|
||
<div class="table-actions">
|
||
<el-button type="primary" size="small" @click="openDocuments(row)">资质</el-button>
|
||
<!-- 状态机:通过可从 pending/rejected/frozen 发起,驳回只允许 pending,冻结只允许 approved。
|
||
已通过的行走「冻结 / 重置密码」,不再给「审核」入口(点了必然被后端拒) -->
|
||
<el-button
|
||
v-if="canAudit && row.status !== 'approved'"
|
||
size="small"
|
||
@click="openAudit(row, 'APPROVE')"
|
||
>审核</el-button
|
||
>
|
||
<el-button
|
||
v-if="canAudit && row.status === 'approved'"
|
||
type="danger"
|
||
size="small"
|
||
@click="freeze(row)"
|
||
>冻结</el-button
|
||
>
|
||
<el-button
|
||
v-if="canOpenAccount && !row.adminUserId"
|
||
type="primary"
|
||
size="small"
|
||
:loading="accountSaving"
|
||
:disabled="row.status !== 'approved'"
|
||
@click="openAccount(row)"
|
||
>开通账号</el-button
|
||
>
|
||
<el-button
|
||
v-if="canOpenAccount && row.adminUserId"
|
||
size="small"
|
||
@click="resetPassword(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 label="APPROVE">通过</el-radio>
|
||
<!-- 驳回只对「待审核」开放(与后端 requireState 一致);已驳回/已冻结的行重新审核时只能「通过」 -->
|
||
<el-radio v-if="auditTarget?.status === 'pending'" label="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>
|
||
|
||
<el-dialog v-model="createVisible" title="新增创作者" width="480px">
|
||
<el-form label-position="top">
|
||
<el-form-item label="创作者名称" required>
|
||
<el-input v-model="createForm.name" maxlength="128" placeholder="公司名或个人名" />
|
||
</el-form-item>
|
||
<el-form-item label="类型">
|
||
<el-radio-group v-model="createForm.type">
|
||
<el-radio v-for="item in CREATOR_TYPE" :key="item.value" :label="item.value">{{
|
||
item.label
|
||
}}</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="联系人">
|
||
<el-input v-model="createForm.contactName" maxlength="64" />
|
||
</el-form-item>
|
||
<el-form-item label="联系邮箱">
|
||
<el-input v-model="createForm.contactEmail" maxlength="128" />
|
||
</el-form-item>
|
||
<el-form-item label="国家 / 地区">
|
||
<el-input v-model="createForm.countryCode" maxlength="8" placeholder="ID" />
|
||
</el-form-item>
|
||
<el-alert
|
||
type="info"
|
||
:closable="false"
|
||
show-icon
|
||
title="编号自动生成(CR+日期+序号),也是开通账号时默认的登录名;录入后需要先通过入驻审核才能开通账号"
|
||
/>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="createVisible = false">取消</el-button>
|
||
<el-button type="primary" :loading="createSaving" @click="confirmCreate">录入</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<el-dialog
|
||
:model-value="accountVisible"
|
||
:title="accountResult?.created ? '账号已开通' : '账号凭据'"
|
||
width="520px"
|
||
@close="closeAccount"
|
||
@update:model-value="closeAccount"
|
||
>
|
||
<el-alert
|
||
v-if="accountResult?.password"
|
||
class="creator-account-alert"
|
||
type="warning"
|
||
:closable="false"
|
||
show-icon
|
||
title="密码只显示这一次,关闭后无法再次查看;请立即复制并转达给创作者"
|
||
/>
|
||
<el-descriptions :column="1" border>
|
||
<el-descriptions-item label="登录账号">
|
||
<span class="creator-account-value">{{ accountResult?.username }}</span>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="初始密码">
|
||
<span v-if="accountResult?.password" class="creator-account-value">{{
|
||
accountResult.password
|
||
}}</span>
|
||
<span v-else class="console-muted">本次未生成新密码(账号此前已开通)</span>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="说明">
|
||
<span class="console-muted">{{ accountResult?.message }}</span>
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
<template #footer>
|
||
<el-button v-if="accountResult?.password" @click="copyCredential">复制账号与密码</el-button>
|
||
<el-button type="primary" @click="closeAccount">我已保存</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</template>
|