merge: 合并 K88 短剧内容类型与互动数据管理
This commit is contained in:
commit
c1e03f94be
4 files changed
+132
-2
No files matched your search
@@ -16,6 +16,7 @@ export interface DramaPageParams {
|
|||||||
status?: string
|
status?: string
|
||||||
categoryId?: number
|
categoryId?: number
|
||||||
isHot?: boolean
|
isHot?: boolean
|
||||||
|
dramaTypes?: Array<'ANIME' | 'LIVE'>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const pageDramasApi = (params: DramaPageParams) => {
|
export const pageDramasApi = (params: DramaPageParams) => {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export interface DramaItem {
|
|||||||
description?: string
|
description?: string
|
||||||
cover?: string
|
cover?: string
|
||||||
language?: string
|
language?: string
|
||||||
|
dramaType?: 'ANIME' | 'LIVE'
|
||||||
episodes?: number
|
episodes?: number
|
||||||
freeEpisodes?: number
|
freeEpisodes?: number
|
||||||
unlockCoin?: number
|
unlockCoin?: number
|
||||||
@@ -33,6 +34,9 @@ export interface DramaItem {
|
|||||||
status: string
|
status: string
|
||||||
statusText: string
|
statusText: string
|
||||||
views?: number
|
views?: number
|
||||||
|
favoriteCount?: number
|
||||||
|
likeCount?: number
|
||||||
|
commentCount?: number
|
||||||
sort?: number
|
sort?: number
|
||||||
publishAt?: string
|
publishAt?: string
|
||||||
createdAt?: string
|
createdAt?: string
|
||||||
@@ -47,8 +51,12 @@ export interface DramaSaveData {
|
|||||||
description?: string
|
description?: string
|
||||||
cover?: string
|
cover?: string
|
||||||
language?: string
|
language?: string
|
||||||
|
dramaType?: 'ANIME' | 'LIVE'
|
||||||
freeEpisodes?: number
|
freeEpisodes?: number
|
||||||
unlockCoin?: number
|
unlockCoin?: number
|
||||||
|
favoriteCount?: number
|
||||||
|
likeCount?: number
|
||||||
|
heat?: number
|
||||||
isHot?: boolean
|
isHot?: boolean
|
||||||
sort?: number
|
sort?: number
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,6 +147,24 @@
|
|||||||
width: 180px !important;
|
width: 180px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.readonly-stat {
|
||||||
|
min-width: 180px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 0 12px;
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
line-height: 32px;
|
||||||
|
background: var(--el-fill-color-lighter);
|
||||||
|
border: 1px solid var(--el-border-color-lighter);
|
||||||
|
border-radius: var(--el-border-radius-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
.readonly-stat-hint {
|
||||||
|
margin: 4px 0 0;
|
||||||
|
color: var(--el-text-color-placeholder);
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
.cover-editor {
|
.cover-editor {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 18px;
|
gap: 18px;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ const categories = ref([])
|
|||||||
const keyword = ref('')
|
const keyword = ref('')
|
||||||
const statusFilter = ref(undefined)
|
const statusFilter = ref(undefined)
|
||||||
const categoryId = ref(undefined)
|
const categoryId = ref(undefined)
|
||||||
|
const dramaTypeFilter = ref(undefined)
|
||||||
const hotFilter = ref(undefined)
|
const hotFilter = ref(undefined)
|
||||||
const pageIndex = ref(1)
|
const pageIndex = ref(1)
|
||||||
const pageSize = ref(10)
|
const pageSize = ref(10)
|
||||||
@@ -41,13 +42,18 @@ const coverPercent = ref(0)
|
|||||||
const coverError = ref('')
|
const coverError = ref('')
|
||||||
const coverFileName = ref('')
|
const coverFileName = ref('')
|
||||||
const editingId = ref(null)
|
const editingId = ref(null)
|
||||||
|
const editingCommentCount = ref(0)
|
||||||
const formRef = ref()
|
const formRef = ref()
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
title: '',
|
title: '',
|
||||||
categoryId: undefined,
|
categoryId: undefined,
|
||||||
|
dramaType: 'LIVE',
|
||||||
description: '',
|
description: '',
|
||||||
freeEpisodes: 3,
|
freeEpisodes: 3,
|
||||||
unlockCoin: 0,
|
unlockCoin: 0,
|
||||||
|
favoriteCount: 0,
|
||||||
|
likeCount: 0,
|
||||||
|
heat: 0,
|
||||||
isHot: false,
|
isHot: false,
|
||||||
cover: ''
|
cover: ''
|
||||||
})
|
})
|
||||||
@@ -57,7 +63,8 @@ const COVER_TYPES = ['image/jpeg', 'image/png', 'image/webp']
|
|||||||
|
|
||||||
const formRules = {
|
const formRules = {
|
||||||
title: [{ required: true, message: '请输入短剧名称', trigger: 'blur' }],
|
title: [{ required: true, message: '请输入短剧名称', trigger: 'blur' }],
|
||||||
categoryId: [{ required: true, message: '请选择短剧类型', trigger: 'change' }]
|
categoryId: [{ required: true, message: '请选择短剧类型', trigger: 'change' }],
|
||||||
|
dramaType: [{ required: true, message: '请选择内容类型', trigger: 'change' }]
|
||||||
}
|
}
|
||||||
|
|
||||||
const coverDisplayName = computed(
|
const coverDisplayName = computed(
|
||||||
@@ -78,6 +85,11 @@ const statusOptions = [
|
|||||||
{ code: 'offline', text: '已下线' }
|
{ code: 'offline', text: '已下线' }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const dramaTypeOptions = [
|
||||||
|
{ value: 'ANIME', label: '漫剧' },
|
||||||
|
{ value: 'LIVE', label: '真人剧' }
|
||||||
|
]
|
||||||
|
|
||||||
const actionMeta = {
|
const actionMeta = {
|
||||||
submit: { label: '提交审核', done: '已提交审核' },
|
submit: { label: '提交审核', done: '已提交审核' },
|
||||||
approve: { label: '审核通过', done: '已通过审核' },
|
approve: { label: '审核通过', done: '已通过审核' },
|
||||||
@@ -95,6 +107,7 @@ async function load() {
|
|||||||
keyword: keyword.value.trim() || undefined,
|
keyword: keyword.value.trim() || undefined,
|
||||||
status: statusFilter.value || undefined,
|
status: statusFilter.value || undefined,
|
||||||
categoryId: categoryId.value,
|
categoryId: categoryId.value,
|
||||||
|
dramaTypes: dramaTypeFilter.value ? [dramaTypeFilter.value] : undefined,
|
||||||
isHot: hotFilter.value
|
isHot: hotFilter.value
|
||||||
})
|
})
|
||||||
list.value = res.data?.list || []
|
list.value = res.data?.list || []
|
||||||
@@ -118,6 +131,7 @@ function resetFilters() {
|
|||||||
keyword.value = ''
|
keyword.value = ''
|
||||||
statusFilter.value = undefined
|
statusFilter.value = undefined
|
||||||
categoryId.value = undefined
|
categoryId.value = undefined
|
||||||
|
dramaTypeFilter.value = undefined
|
||||||
hotFilter.value = undefined
|
hotFilter.value = undefined
|
||||||
search()
|
search()
|
||||||
}
|
}
|
||||||
@@ -143,14 +157,19 @@ function openCreate() {
|
|||||||
Object.assign(form, {
|
Object.assign(form, {
|
||||||
title: '',
|
title: '',
|
||||||
categoryId: undefined,
|
categoryId: undefined,
|
||||||
|
dramaType: 'LIVE',
|
||||||
description: '',
|
description: '',
|
||||||
freeEpisodes: 3,
|
freeEpisodes: 3,
|
||||||
unlockCoin: 0,
|
unlockCoin: 0,
|
||||||
|
favoriteCount: 0,
|
||||||
|
likeCount: 0,
|
||||||
|
heat: 0,
|
||||||
isHot: false,
|
isHot: false,
|
||||||
cover: ''
|
cover: ''
|
||||||
})
|
})
|
||||||
coverFileName.value = ''
|
coverFileName.value = ''
|
||||||
coverError.value = ''
|
coverError.value = ''
|
||||||
|
editingCommentCount.value = 0
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
resetValidation()
|
resetValidation()
|
||||||
}
|
}
|
||||||
@@ -160,18 +179,27 @@ function openEdit(row) {
|
|||||||
Object.assign(form, {
|
Object.assign(form, {
|
||||||
title: row.title,
|
title: row.title,
|
||||||
categoryId: row.categoryId || undefined,
|
categoryId: row.categoryId || undefined,
|
||||||
|
dramaType: row.dramaType || 'LIVE',
|
||||||
description: row.description || '',
|
description: row.description || '',
|
||||||
freeEpisodes: row.freeEpisodes ?? 3,
|
freeEpisodes: row.freeEpisodes ?? 3,
|
||||||
unlockCoin: row.unlockCoin ?? 0,
|
unlockCoin: row.unlockCoin ?? 0,
|
||||||
|
favoriteCount: row.favoriteCount ?? 0,
|
||||||
|
likeCount: row.likeCount ?? 0,
|
||||||
|
heat: row.views ?? 0,
|
||||||
isHot: !!row.isHot,
|
isHot: !!row.isHot,
|
||||||
cover: row.cover || ''
|
cover: row.cover || ''
|
||||||
})
|
})
|
||||||
coverFileName.value = row.cover ? coverBasename(row.cover) : ''
|
coverFileName.value = row.cover ? coverBasename(row.cover) : ''
|
||||||
coverError.value = ''
|
coverError.value = ''
|
||||||
|
editingCommentCount.value = row.commentCount ?? 0
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
resetValidation()
|
resetValidation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function dramaTypeLabel(value) {
|
||||||
|
return dramaTypeOptions.find((item) => item.value === value)?.label || '真人剧'
|
||||||
|
}
|
||||||
|
|
||||||
async function saveDrama() {
|
async function saveDrama() {
|
||||||
if (saving.value || uploadingCover.value) return
|
if (saving.value || uploadingCover.value) return
|
||||||
try {
|
try {
|
||||||
@@ -344,6 +372,12 @@ onMounted(async () => {
|
|||||||
:key="item.id"
|
:key="item.id"
|
||||||
:label="item.name"
|
:label="item.name"
|
||||||
:value="item.id" /></el-select
|
:value="item.id" /></el-select
|
||||||
|
><el-select v-model="dramaTypeFilter" clearable placeholder="全部内容类型" @change="search"
|
||||||
|
><el-option
|
||||||
|
v-for="item in dramaTypeOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value" /></el-select
|
||||||
><el-select v-model="hotFilter" clearable placeholder="全部热度" @change="search"
|
><el-select v-model="hotFilter" clearable placeholder="全部热度" @change="search"
|
||||||
><el-option label="仅热门" :value="true" /><el-option
|
><el-option label="仅热门" :value="true" /><el-option
|
||||||
label="非热门"
|
label="非热门"
|
||||||
@@ -383,12 +417,34 @@ onMounted(async () => {
|
|||||||
></el-table-column
|
></el-table-column
|
||||||
>
|
>
|
||||||
<el-table-column prop="genre" label="类型" width="110" />
|
<el-table-column prop="genre" label="类型" width="110" />
|
||||||
|
<el-table-column label="内容类型" width="110"
|
||||||
|
><template #default="{ row }"
|
||||||
|
><el-tag :type="row.dramaType === 'ANIME' ? 'warning' : 'info'" effect="light">{{
|
||||||
|
dramaTypeLabel(row.dramaType)
|
||||||
|
}}</el-tag></template
|
||||||
|
></el-table-column
|
||||||
|
>
|
||||||
<el-table-column label="集数" width="90"
|
<el-table-column label="集数" width="90"
|
||||||
><template #default="{ row }">{{ row.episodes }} 集</template></el-table-column
|
><template #default="{ row }">{{ row.episodes }} 集</template></el-table-column
|
||||||
>
|
>
|
||||||
<el-table-column label="播放量" width="110"
|
<el-table-column label="热度" width="110"
|
||||||
><template #default="{ row }">{{ formatCount(row.views) }}</template></el-table-column
|
><template #default="{ row }">{{ formatCount(row.views) }}</template></el-table-column
|
||||||
>
|
>
|
||||||
|
<el-table-column label="收藏" width="90"
|
||||||
|
><template #default="{ row }">{{
|
||||||
|
formatCount(row.favoriteCount ?? 0)
|
||||||
|
}}</template></el-table-column
|
||||||
|
>
|
||||||
|
<el-table-column label="点赞" width="90"
|
||||||
|
><template #default="{ row }">{{
|
||||||
|
formatCount(row.likeCount ?? 0)
|
||||||
|
}}</template></el-table-column
|
||||||
|
>
|
||||||
|
<el-table-column label="评论" width="90"
|
||||||
|
><template #default="{ row }">{{
|
||||||
|
formatCount(row.commentCount ?? 0)
|
||||||
|
}}</template></el-table-column
|
||||||
|
>
|
||||||
<el-table-column label="状态" width="110"
|
<el-table-column label="状态" width="110"
|
||||||
><template #default="{ row }"
|
><template #default="{ row }"
|
||||||
><el-tag :class="['status-badge', statusClass(row.status)]" effect="light">{{
|
><el-tag :class="['status-badge', statusClass(row.status)]" effect="light">{{
|
||||||
@@ -487,6 +543,16 @@ onMounted(async () => {
|
|||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="内容类型" prop="dramaType">
|
||||||
|
<el-select v-model="form.dramaType" placeholder="请选择内容类型">
|
||||||
|
<el-option
|
||||||
|
v-for="item in dramaTypeOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
<el-form-item label="简介">
|
<el-form-item label="简介">
|
||||||
<el-input
|
<el-input
|
||||||
@@ -527,6 +593,43 @@ onMounted(async () => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="editor-section">
|
||||||
|
<h3 class="editor-section-title">互动数据</h3>
|
||||||
|
<div class="editor-grid editor-grid--two">
|
||||||
|
<el-form-item label="收藏数">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.favoriteCount"
|
||||||
|
class="editor-number"
|
||||||
|
controls-position="right"
|
||||||
|
:min="0"
|
||||||
|
:precision="0"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="点赞数">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.likeCount"
|
||||||
|
class="editor-number"
|
||||||
|
controls-position="right"
|
||||||
|
:min="0"
|
||||||
|
:precision="0"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="热度">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.heat"
|
||||||
|
class="editor-number"
|
||||||
|
controls-position="right"
|
||||||
|
:min="0"
|
||||||
|
:precision="0"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="评论数">
|
||||||
|
<div class="readonly-stat">{{ formatCount(editingCommentCount) }}</div>
|
||||||
|
<p class="readonly-stat-hint">实时统计,不可编辑</p>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="editor-section">
|
<section class="editor-section">
|
||||||
<h3 class="editor-section-title">封面</h3>
|
<h3 class="editor-section-title">封面</h3>
|
||||||
<div class="cover-editor">
|
<div class="cover-editor">
|
||||||
|
|||||||
Reference in new issue
Block a user