feat(web): 07 创作者中心四个页面(我的作品 / 作品编辑 / 收费配置 / 数据看板)
为什么:07 的接口五批都做完了,但创作者在界面上一个都点不到 —— 只能靠 curl。 这批把创作者中心做进后台管理(沿用 AppUsersView 那套 api 封装 + composable + 视图 + 样式与 console.css), 创作者用自己的后台账号登录就能完成"建草稿 → 编辑分集传片 → 提交审核 → 配置收费 → 看数据"的闭环。 - WorkspaceView:主体状态 / 我的作品(含最近一次提交的审核进度)/ 通知列表;新建草稿、按状态给出可提交的动作、撤回 - DramaEditView:作品信息(封面、预告片)、分集增删与上移下移、分片上传(复用 /admin/media)+ 断点续传 (会话存 localStorage,中断后「继续上传」接着传)、产物挂载、提交记录与撤回;非草稿/已下线状态整页转只读 - PriceConfigView:整剧免费集数与解锁金币 + 逐集免费/收费/试看秒数;已上线只读(需先申请下线) - DashboardView:作品 / 播放 / 互动 / 解锁收入四组指标,取不到的显示「暂无数据源」+ notes 口径说明 - 时间列统一 yyyy-MM-dd HH:mm:ss;表格列与后端字段一一对应,不在前端编字段 - media.ts 补上传进度接口;uploader 补 resumeUpload(先查服务端进度再续传)
This commit is contained in:
1 parent
f037d243cd
commit
0a2e3e0b81
13 files changed
+2113
-1
No files matched your search
@@ -0,0 +1,295 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
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 {
|
||||
DRAMA_STATUS,
|
||||
dramaStatusMeta,
|
||||
submissionStatusMeta,
|
||||
submissionTypeText,
|
||||
submitOptions,
|
||||
useCreatorWorkspace
|
||||
} from './composables/useCreatorWorkspace'
|
||||
|
||||
const router = useRouter()
|
||||
const { can } = useRbac()
|
||||
const canEdit = can('creator-center:drama:edit')
|
||||
|
||||
const {
|
||||
profile,
|
||||
profileLoading,
|
||||
dramas,
|
||||
notices,
|
||||
createVisible,
|
||||
createSaving,
|
||||
createForm,
|
||||
queryDramas,
|
||||
loadDramas,
|
||||
loadNotices,
|
||||
submit,
|
||||
withdraw,
|
||||
openCreate,
|
||||
confirmCreate
|
||||
} = useCreatorWorkspace()
|
||||
|
||||
const activeTab = ref('dramas')
|
||||
|
||||
function onTabChange(name) {
|
||||
if (name === 'notices' && !notices.loaded) loadNotices()
|
||||
}
|
||||
|
||||
function openEdit(row) {
|
||||
router.push(`/creator-center/dramas/${row.id}`)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PageHeading
|
||||
eyebrow="创作者中心"
|
||||
title="我的作品"
|
||||
description="查看作品与审核进度,提交上线 / 下线申请。"
|
||||
>
|
||||
<el-button v-if="canEdit" type="primary" @click="openCreate">新建作品</el-button>
|
||||
</PageHeading>
|
||||
|
||||
<section v-loading="profileLoading" class="panel creator-profile">
|
||||
<div class="creator-profile-main">
|
||||
<span class="creator-profile-name">{{ profile?.name || '—' }}</span>
|
||||
<el-tag
|
||||
size="small"
|
||||
effect="light"
|
||||
:type="profile?.status === 'approved' ? 'success' : 'warning'"
|
||||
>
|
||||
{{ profile?.statusText || '—' }}
|
||||
</el-tag>
|
||||
<span class="console-muted">{{ profile?.code || '' }}</span>
|
||||
</div>
|
||||
<div class="creator-profile-meta">
|
||||
<span
|
||||
>作品数 <b>{{ profile?.dramaTotal ?? 0 }}</b></span
|
||||
>
|
||||
<span
|
||||
>联系人 <b>{{ profile?.contactName || '—' }}</b></span
|
||||
>
|
||||
<span
|
||||
>联系邮箱 <b>{{ profile?.contactEmail || '—' }}</b></span
|
||||
>
|
||||
</div>
|
||||
<el-alert
|
||||
v-if="profile && profile.status === 'rejected'"
|
||||
class="creator-profile-alert"
|
||||
type="error"
|
||||
:closable="false"
|
||||
show-icon
|
||||
:title="`入驻审核未通过:${profile.auditNote || '未填写原因'}`"
|
||||
/>
|
||||
<el-alert
|
||||
v-else-if="profile && profile.status !== 'approved'"
|
||||
class="creator-profile-alert"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="入驻审核通过后才能创建作品与提交审核"
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<el-tabs v-model="activeTab" @tab-change="onTabChange">
|
||||
<el-tab-pane label="我的作品" name="dramas">
|
||||
<div class="console-toolbar">
|
||||
<el-input
|
||||
v-model="dramas.keyword"
|
||||
class="console-keyword"
|
||||
:prefix-icon="Search"
|
||||
clearable
|
||||
placeholder="搜索作品名称"
|
||||
@keyup.enter="queryDramas"
|
||||
@clear="queryDramas"
|
||||
/>
|
||||
<el-select
|
||||
v-model="dramas.status"
|
||||
class="console-select"
|
||||
clearable
|
||||
placeholder="全部状态"
|
||||
@change="queryDramas"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in DRAMA_STATUS"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<el-button type="primary" @click="queryDramas">查询</el-button>
|
||||
<span class="console-count">共 {{ dramas.total }} 部作品</span>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
v-loading="dramas.loading"
|
||||
:data="dramas.rows"
|
||||
row-key="id"
|
||||
border
|
||||
class="drama-el-table"
|
||||
empty-text="还没有作品,点右上角「新建作品」开始"
|
||||
>
|
||||
<el-table-column label="作品" min-width="220">
|
||||
<template #default="{ row }">
|
||||
<div class="creator-drama-cell">
|
||||
<div class="creator-drama-cover">
|
||||
<img v-if="row.cover" :src="row.cover" alt="" />
|
||||
<span v-else>{{ (row.title || '?').slice(0, 1) }}</span>
|
||||
</div>
|
||||
<div class="creator-drama-meta">
|
||||
<span class="creator-drama-title">{{ row.title }}</span>
|
||||
<span class="creator-drama-code">{{ row.code }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="dramaStatusMeta(row.status).tag" effect="light">{{
|
||||
dramaStatusMeta(row.status).label
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="episodes" label="分集" width="80" />
|
||||
<el-table-column prop="views" label="播放" width="100" />
|
||||
<el-table-column label="审核进度" min-width="200">
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.submissionStatus" class="creator-progress">
|
||||
<el-tag
|
||||
size="small"
|
||||
:type="submissionStatusMeta(row.submissionStatus).tag"
|
||||
effect="plain"
|
||||
>
|
||||
{{ submissionTypeText(row.submissionType) }}·{{
|
||||
submissionStatusMeta(row.submissionStatus).label
|
||||
}}
|
||||
</el-tag>
|
||||
<span v-if="row.reviewNote" class="console-muted" :title="row.reviewNote">{{
|
||||
row.reviewNote
|
||||
}}</span>
|
||||
</div>
|
||||
<span v-else class="console-muted">尚未提交</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="updatedAt"
|
||||
label="更新时间"
|
||||
min-width="165"
|
||||
:formatter="dateCell"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="操作" width="210" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<div class="table-actions">
|
||||
<el-button v-if="canEdit" type="primary" size="small" @click="openEdit(row)"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-dropdown
|
||||
v-if="canEdit && submitOptions(row).length"
|
||||
trigger="click"
|
||||
@command="(type) => submit(row, type)"
|
||||
>
|
||||
<el-button size="small">提交审核</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
v-for="type in submitOptions(row)"
|
||||
:key="type"
|
||||
:command="type"
|
||||
>
|
||||
{{ submissionTypeText(type) }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-button
|
||||
v-if="
|
||||
canEdit &&
|
||||
row.submissionId &&
|
||||
['SUBMITTED', 'REVIEWING'].includes(row.submissionStatus)
|
||||
"
|
||||
size="small"
|
||||
class="danger-action"
|
||||
@click="withdraw(row)"
|
||||
>撤回</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination">
|
||||
<el-pagination
|
||||
v-model:current-page="dramas.page"
|
||||
v-model:page-size="dramas.size"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
:total="dramas.total"
|
||||
layout="total, prev, pager, next, sizes"
|
||||
background
|
||||
@current-change="loadDramas"
|
||||
@size-change="queryDramas"
|
||||
/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="通知" name="notices">
|
||||
<div v-loading="notices.loading" class="creator-notice-list">
|
||||
<el-empty v-if="!notices.rows.length" description="还没有审核结果通知" />
|
||||
<div
|
||||
v-for="item in notices.rows"
|
||||
:key="`${item.bizType}-${item.id}`"
|
||||
class="creator-notice"
|
||||
>
|
||||
<div class="creator-notice-head">
|
||||
<span class="creator-notice-title">{{ item.title }}</span>
|
||||
<span class="console-muted">{{
|
||||
item.time ? String(item.time).replace('T', ' ').slice(0, 19) : ''
|
||||
}}</span>
|
||||
</div>
|
||||
<p class="creator-notice-body">{{ item.content || '—' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</section>
|
||||
|
||||
<el-dialog v-model="createVisible" title="新建作品" width="480px">
|
||||
<el-form label-position="top">
|
||||
<el-form-item label="作品名称" required>
|
||||
<el-input
|
||||
v-model="createForm.title"
|
||||
maxlength="64"
|
||||
placeholder="例如:闪婚后,傅先生每天都在撒糖"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="题材">
|
||||
<el-input v-model="createForm.genre" maxlength="32" placeholder="例如:都市情感" />
|
||||
</el-form-item>
|
||||
<el-form-item label="简介">
|
||||
<el-input
|
||||
v-model="createForm.description"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-alert
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="先建草稿,再去作品编辑页完善信息、分集与视频,然后提交审核"
|
||||
/>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="createVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="createSaving" @click="confirmCreate">创建草稿</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
Reference in new issue
Block a user