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,215 @@
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
createDramaApi,
|
||||
getCreatorProfileApi,
|
||||
listCreatorNoticesApi,
|
||||
pageMyDramasApi,
|
||||
submitDramaApi,
|
||||
withdrawSubmissionApi
|
||||
} from '@/api/admin/creatorCenter'
|
||||
|
||||
/** 作品状态:与后端 ContentStatus 一一对应 */
|
||||
export const DRAMA_STATUS = [
|
||||
{ value: 'draft', label: '草稿', tag: 'info' },
|
||||
{ value: 'reviewing', label: '审核中', tag: 'warning' },
|
||||
{ value: 'approved', label: '待发布', tag: 'warning' },
|
||||
{ value: 'published', label: '已上线', tag: 'success' },
|
||||
{ value: 'offline', label: '已下线', tag: 'info' }
|
||||
]
|
||||
|
||||
/** 提交状态:与后端 content_submission.status 一一对应 */
|
||||
export const SUBMISSION_STATUS = [
|
||||
{ value: 'DRAFT', label: '草稿', tag: 'info' },
|
||||
{ value: 'SUBMITTED', label: '已提交', tag: 'warning' },
|
||||
{ value: 'REVIEWING', label: '审核中', tag: 'warning' },
|
||||
{ value: 'APPROVED', label: '已通过', tag: 'success' },
|
||||
{ value: 'REJECTED', label: '已驳回', tag: 'danger' },
|
||||
{ value: 'WITHDRAWN', label: '已撤回', tag: 'info' }
|
||||
]
|
||||
|
||||
export const SUBMISSION_TYPE = [
|
||||
{ value: 'CREATE', label: '新建' },
|
||||
{ value: 'UPDATE', label: '编辑' },
|
||||
{ value: 'PUBLISH', label: '申请上线' },
|
||||
{ value: 'OFFLINE', label: '申请下线' }
|
||||
]
|
||||
|
||||
export function dramaStatusMeta(status) {
|
||||
return DRAMA_STATUS.find((item) => item.value === status) || { label: status || '-', tag: 'info' }
|
||||
}
|
||||
|
||||
export function submissionStatusMeta(status) {
|
||||
return (
|
||||
SUBMISSION_STATUS.find((item) => item.value === status) || { label: status || '-', tag: 'info' }
|
||||
)
|
||||
}
|
||||
|
||||
export function submissionTypeText(type) {
|
||||
return SUBMISSION_TYPE.find((item) => item.value === type)?.label || type || '-'
|
||||
}
|
||||
|
||||
/**
|
||||
* 可提交的类型:与后端 submit 的状态矩阵一一对应,前端只做"给不给出这个按钮",
|
||||
* 真正的校验仍在服务端(前端不复制规则,只减少无效点击)。
|
||||
*/
|
||||
export function submitOptions(row) {
|
||||
const firstSubmit = !row.submissionId
|
||||
const options = []
|
||||
if (row.status === 'draft') {
|
||||
options.push(firstSubmit ? 'CREATE' : 'UPDATE')
|
||||
options.push('PUBLISH')
|
||||
} else if (row.status === 'offline') {
|
||||
options.push('UPDATE', 'PUBLISH')
|
||||
} else if (row.status === 'reviewing' || row.status === 'approved') {
|
||||
options.push('PUBLISH')
|
||||
} else if (row.status === 'published') {
|
||||
options.push('OFFLINE')
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
export function useCreatorWorkspace() {
|
||||
const profileLoading = ref(false)
|
||||
const profile = ref(null)
|
||||
|
||||
const dramas = reactive({
|
||||
rows: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
page: 1,
|
||||
size: 10,
|
||||
keyword: '',
|
||||
status: undefined
|
||||
})
|
||||
|
||||
const notices = reactive({ rows: [], loading: false, loaded: false })
|
||||
|
||||
async function loadProfile() {
|
||||
profileLoading.value = true
|
||||
try {
|
||||
profile.value = (await getCreatorProfileApi()).data || null
|
||||
} finally {
|
||||
profileLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDramas() {
|
||||
dramas.loading = true
|
||||
try {
|
||||
const res = await pageMyDramasApi({
|
||||
pageIndex: dramas.page,
|
||||
pageSize: dramas.size,
|
||||
keyword: dramas.keyword.trim() || undefined,
|
||||
status: dramas.status || undefined
|
||||
})
|
||||
dramas.rows = res.data?.list || []
|
||||
dramas.total = res.data?.total || 0
|
||||
} finally {
|
||||
dramas.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
function queryDramas() {
|
||||
dramas.page = 1
|
||||
loadDramas()
|
||||
}
|
||||
|
||||
async function loadNotices() {
|
||||
notices.loading = true
|
||||
try {
|
||||
notices.rows = (await listCreatorNoticesApi()).data || []
|
||||
notices.loaded = true
|
||||
} finally {
|
||||
notices.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
async function submit(row, type) {
|
||||
const label = submissionTypeText(type)
|
||||
if (type === 'OFFLINE') {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`提交「申请下线」后由后台审核,审核通过前内容仍在线。确认提交?`,
|
||||
label,
|
||||
{ confirmButtonText: '确认提交', cancelButtonText: '取消', type: 'warning' }
|
||||
)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
}
|
||||
await submitDramaApi(row.id, type)
|
||||
ElMessage.success(`已提交「${label}」,等待后台审核`)
|
||||
await loadDramas()
|
||||
if (notices.loaded) await loadNotices()
|
||||
}
|
||||
|
||||
async function withdraw(row) {
|
||||
if (!row.submissionId) return
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
'撤回后作品回到草稿、可以继续编辑,确认撤回这次提交?',
|
||||
'撤回提交',
|
||||
{
|
||||
confirmButtonText: '确认撤回',
|
||||
cancelButtonText: '取消'
|
||||
}
|
||||
)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
await withdrawSubmissionApi(row.submissionId)
|
||||
ElMessage.success('已撤回,作品回到草稿')
|
||||
await loadDramas()
|
||||
}
|
||||
|
||||
const createVisible = ref(false)
|
||||
const createSaving = ref(false)
|
||||
const createForm = reactive({ title: '', genre: '', description: '' })
|
||||
|
||||
function openCreate() {
|
||||
Object.assign(createForm, { title: '', genre: '', description: '' })
|
||||
createVisible.value = true
|
||||
}
|
||||
|
||||
async function confirmCreate() {
|
||||
if (!createForm.title.trim()) return ElMessage.warning('请填写作品名称')
|
||||
createSaving.value = true
|
||||
try {
|
||||
const res = await createDramaApi({
|
||||
title: createForm.title.trim(),
|
||||
genre: createForm.genre.trim(),
|
||||
description: createForm.description.trim()
|
||||
})
|
||||
ElMessage.success('草稿已创建,可以继续编辑分集')
|
||||
createVisible.value = false
|
||||
await loadDramas()
|
||||
return res.data
|
||||
} finally {
|
||||
createSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadProfile()
|
||||
loadDramas()
|
||||
})
|
||||
|
||||
return {
|
||||
profile,
|
||||
profileLoading,
|
||||
dramas,
|
||||
notices,
|
||||
createVisible,
|
||||
createSaving,
|
||||
createForm,
|
||||
loadProfile,
|
||||
loadDramas,
|
||||
queryDramas,
|
||||
loadNotices,
|
||||
submit,
|
||||
withdraw,
|
||||
openCreate,
|
||||
confirmCreate
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user