chore(web): 收口前几轮后台改动(品牌 / 媒资上传 / 轮播图 / 类型管理 / 操作日志 / App 用户)

为什么:这些改动在前几轮就已完成并在 :3005 验证过,但一直留在工作区没有入库。
下一步 3-4 的四个页面依赖其中的公共样式入口(src/styles/business/index.css)与
api/admin 的公共类型(PageResult 等),如果不先收口,新页面的提交就会夹带旧改动,
既说不清 diff 边界,也让 index.css 这类多轮共用的文件长期处于半提交状态。

本提交只做归档,不改行为:
- 品牌与接口基址改成 FruitShorts / 短剧服务(.env.*、README、vite 代理)
- 去掉前端 mock 数据目录(src/data、src/permissions、stores/auth),改为走真实接口
- 新增 api/admin 下的接口封装与 src/utils/uploader.ts(媒资分片直传)
- 新增/改造:轮播图管理、类型管理、操作日志、App 用户管理、后台布局与公共样式
This commit is contained in:
Vicky committed 2026-10-15 13:28:01 +08:00
1 parent 40546bfd01
commit 44c2c46a68
59 files changed
+4082 -982

No files matched your search

+53 -16
View File
@@ -1,53 +1,85 @@
<script setup>
import { computed, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { VideoCamera, User, Clock, CaretRight, Plus } from '@element-plus/icons-vue'
import { dramas } from '@/data/dramas'
import { VideoCamera, CaretRight, Clock, CircleCheck, Plus } from '@element-plus/icons-vue'
import { pageDramasApi } from '@/api/admin/drama'
import { useRbac } from '@/stores/rbac'
import { formatCount } from '@/utils/format'
import { statusClass } from '@/utils/status'
const router = useRouter()
const { can } = useRbac()
const loading = ref(false)
const dramas = ref([])
const total = ref(0)
const totalViews = computed(() =>
dramas.value.reduce((sum, item) => sum + Number(item.views || 0), 0)
)
const reviewingCount = computed(
() => dramas.value.filter((item) => item.status === 'reviewing').length
)
const publishedCount = computed(
() => dramas.value.filter((item) => item.status === 'published').length
)
const recentDramas = computed(() =>
[...dramas.value]
.sort((a, b) => String(b.updatedAt || '').localeCompare(String(a.updatedAt || '')))
.slice(0, 5)
)
onMounted(async () => {
loading.value = true
try {
const res = await pageDramasApi({ pageIndex: 1, pageSize: 200 })
dramas.value = res.data?.list || []
total.value = res.data?.total || 0
} finally {
loading.value = false
}
})
</script>
<template>
<div class="page-heading"
><div><div class="eyebrow">内容概览</div><h1>工作台</h1><p>查看短剧内容与近期处理事项。</p></div
><el-button
v-if="can('创建短剧')"
v-if="can('drama:create')"
type="primary"
class="primary-button"
@click="router.push({ name: 'dramas' })"
><el-icon><Plus /></el-icon>上传新短剧</el-button
></div
>
<div class="stats-grid">
<div v-loading="loading" class="stats-grid">
<div class="stat-card"
><div class="stat-top"
><span>短剧总数</span
><span class="stat-icon"
><el-icon><VideoCamera /></el-icon></span></div
><div class="stat-value">{{ dramas.length }} <small>部</small></div></div
><div class="stat-value">{{ total }} <small>部</small></div></div
>
<div class="stat-card"
><div class="stat-top"
><span>累计播放量</span
><span class="stat-icon"
><el-icon><CaretRight /></el-icon></span></div
><div class="stat-value">8.64 <small>千万</small></div></div
><div class="stat-value">{{ formatCount(totalViews) }}</div></div
>
<div class="stat-card"
><div class="stat-top"
><span>待审核内容</span
><span class="stat-icon"
><el-icon><Clock /></el-icon></span></div
><div class="stat-value">06 <small>项</small></div></div
><div class="stat-value">{{ reviewingCount }} <small>项</small></div></div
>
<div class="stat-card"
><div class="stat-top"
><span>本月新增用户</span
><span>已上线</span
><span class="stat-icon"
><el-icon><User /></el-icon></span></div
><div class="stat-value">12,486 <small>人</small></div></div
><el-icon><CircleCheck /></el-icon></span></div
><div class="stat-value">{{ publishedCount }} <small>部</small></div></div
>
</div>
<section class="panel recent-panel"
@@ -57,24 +89,29 @@ const { can } = useRbac()
>短剧管理</el-button
></div
>
<el-table :data="dramas.slice(0, 5)" row-key="id" class="dashboard-el-table"
<el-table
v-loading="loading"
:data="recentDramas"
row-key="id"
empty-text="暂无短剧数据"
class="dashboard-el-table"
><el-table-column prop="title" label="短剧名称" min-width="280" /><el-table-column
prop="genre"
label="类型"
width="150" /><el-table-column label="集数" width="120"
><template #default="scope">{{ scope?.row?.episodes }} 集</template></el-table-column
><el-table-column prop="views" label="播放量" width="140" /><el-table-column
label="状态"
width="130"
><el-table-column label="播放量" width="140"
><template #default="scope">{{ formatCount(scope?.row?.views) }}</template></el-table-column
><el-table-column label="状态" width="130"
><template #default="scope"
><el-tag
v-if="scope?.row"
:class="['status-badge', statusClass(scope.row.status)]"
effect="light"
>{{ scope.row.status }}</el-tag
>{{ scope.row.statusText }}</el-tag
></template
></el-table-column
><el-table-column prop="updatedAt" label="更新时间" width="160"
><el-table-column prop="updatedAt" label="更新时间" width="180"
/></el-table>
</section>
</template>