一套代码、多端分发、多租户隔离、多语言出海——这是短剧系统最主流的工程形态。
本文从架构设计、数据建模、前端跨端、后端 SaaS 化、多语言方案到部署上线,完整拆解一套可开源、可二开、可商用的短剧源码系统该怎么搭。
源码及演示:v.dyedus.top
一、先定义边界:我们要解决什么问题
短剧业务的本质不是"视频网站",而是高并发内容检索 + 强事务付费解锁 + 多端流量分发的三重叠加。
- 内容侧:剧集批量上传、HLS 切片、CDN 分发、防盗链、多语言字段
- 交易侧:单集解锁 / 整剧解锁 / VIP 会员 / 钻石充值 / 广告解锁,每一笔都要对账
- 分发侧:微信小程序、抖音小程序、H5、App 四端共用一套业务逻辑
- 运营侧:多租户 SaaS,一个平台服务 N 个短剧品牌,数据严格隔离
如果只做单端单租户,随便写都行;一旦要"开源 + SaaS + 多语言 + 多端",架构就必须提前想清楚,否则二开时会踩满坑。
二、整体技术栈选型
2.1 推荐组合(生产级)
| 层 | 技术选型 | 说明 |
|---|---|---|
| 前端 | uni-app(Vue3 + Vite + TS) | 一套代码编译微信/抖音/快手小程序、H5、App |
| 管理后台 | Vue3 + Element Plus / Arco Design | 内容、订单、财务、分销一体化 |
| 后端 | Spring Boot 3.x + MyBatis Plus(重业务)/ ThinkPHP 8(轻量快速) | 按团队 Java/PHP 储备二选一 |
| 数据库 | MySQL 8.0 + Redis 6+ | 结构化数据 + 缓存/分布式锁 |
| 对象存储 | 阿里云 OSS / 腾讯云 COS / MinIO | 视频不走业务服务器 |
| 转码切片 | FFmpeg + 消息队列异步 | HLS m3u8 多码率输出 |
| 鉴权 | JWT + Shiro/Spring Security | 多端统一 Token |
| 部署 | Docker + Nginx + 宝塔 | 私有化交付友好 |
💡 技术栈没有绝对标准。Java 系优势在分账事务和分布式锁成熟;PHP 系优势在开发速度快、二开门槛低。开源项目建议后端用 NestJS 或 ThinkPHP,降低贡献者门槛;商用重负载再切 Java。
2.2 为什么前端锁死 uni-app
短剧流量入口在微信小程序,但投流落地页在 H5,留存场景在 App。三端各写一套,人力直接 ×3。
uni-app 的编译器把 Vue SFC 分别编译到各端 runtime,业务代码复用率能做到 75% 以上,差异点集中在登录、支付、分享等平台能力——这些用条件编译 + 适配器模式收口即可。
// utils/platform.js —— 平台能力适配器
// #ifdef MP-WEIXIN
export const login = () => wx.login().then(res => res.code)
// #endif
// #ifdef MP-TOUTIAO
export const login = () => tt.login().then(res => res.code)
// #endif
// #ifdef MP-KUAISHOU
export const login = () => ks.login().then(res => res.code)
// #ifdef H5
export const login = () => fetch('/api/auth/h5').then(r => r.json())
// #endif
业务页面里永远只调 login(),不关心底层是哪一端。
三、SaaS 多租户架构:最核心也最容易翻车
3.1 三种隔离方案对比

| 方案 | 隔离强度 | 成本 | 适用阶段 |
|---|---|---|---|
| 独立数据库 | 最强 | 高 | 大客户私有化 |
| 独立 Schema | 中 | 中 | 中大型 SaaS |
| 共享表 + tenant_id | 逻辑隔离 | 低 | 早期铺量(主流) |
短剧 SaaS 起步阶段几乎都选第三种:共享库共享表,所有业务表加 tenant_id 字段。
3.2 强制租户作用域(以 Laravel 风格示例)
// 模型基类
protected static function booted()
{
static::addGlobalScope('tenant', function (Builder $query) {
$tenantId = app(TenantContext::class)->id();
if ($tenantId) {
$query->where('tenant_id', $tenantId);
}
});
}
// 后台跨租户统计时显式放行(必须逐处审计)
Order::withoutGlobalScope('tenant')->where(...)->paginate();
关键坑点:
- 所有查询必须走模型,禁止裸写 SQL 绕过作用域
- 中间件在请求入口注入
tenant_id到上下文,从域名/Token 解析 - 后台超级管理员查询要用
withoutGlobalScope显式放行,且留操作日志 - 分账、退款、提现等写操作必须二次校验租户归属
⚠️ 漏一个作用域 = A 租户能看到 B 租户的订单和剧集。这是 SaaS 最短的短板。
3.3 租户路由识别
# 子域名模式
server_name *.drama.com;
location / {
proxy_set_header X-Tenant $subdomain;
}
或者在 JWT 里塞 tenant_id,后端中间件解码即信。
四、多语言方案:不是 i18n 那么简单
很多团队把多语言理解成"前端做个语言切换",这是认知误区。短剧的多语言是内容多语言,不是 UI 多语言。
4.1 分层策略

┌─ UI 文案层(前端 i18n)
│ zh-CN / en / ja / vi / ko ...
│
├─ 内容字段层(后端按语言下发)
│ drama_title_zh / drama_title_en / drama_title_ja ...
│
└─ 字幕层(SRT / WebVTT 动态加载)
原片 + 多语字幕轨道
4.2 数据库设计:JSON 字段 vs 多列
推荐用 JSON 扩展列,避免表结构爆炸:
ALTER TABLE drama ADD COLUMN i18n JSON COMMENT '{
"zh": {"title":"霸总娇妻","desc":"...","tags":["甜宠"]},
"en": {"title":"CEO's Sweet Wife","desc":"...","tags":["romance"]},
"ja": {"title":"社長の愛妻","desc":"...","tags":["ラブコメ"]},
"vi": {"title":"Vợ Tổng Giám Đốc","desc":"...","tags":["tinh cam"]}
}';
接口按需返回当前语言字段:
GET /api/v1/drama/123?lang=ja
{
"id": 123,
"title": "社長の愛妻",
"desc": "...",
"episodes": 80,
"free_episodes": 10
}
4.3 AI 翻译 + 人工校准闭环
中文录入 → 调用翻译 API(DeepL / GPT / 火山)预译 → 运营后台人工校对 → 落库。SRT 字幕同理,FFmpeg 把多语字幕烧录或作为独立轨道打包。
出海短剧的真实痛点不是"能不能翻译",是"翻译得不像本地人说话"。AI 预译 + 本地母语审核员,是目前最稳的流水线。
五、核心数据建模

5.1 关键表结构(精简版)
-- 租户表
tenant(id, name, domain, plan, expire_at)
-- 短剧主表
drama(id, tenant_id, category_id, cover, i18n_json,
total_episodes, free_episodes, status, created_at)
-- 剧集表
episode(id, drama_id, tenant_id, ep_no, title,
video_url, duration, is_vip, price_diamond, sort)
-- 用户表
user(id, tenant_id, unionid, nickname, avatar,
vip_type, vip_expire_at, diamond_balance)
-- 解锁记录
unlock_log(id, user_id, drama_id, episode_id,
pay_type, amount, order_id, created_at)
-- 订单表
order(id, tenant_id, user_id, type[vip|diamond|episode],
amount, currency, channel, status, paid_at)
-- 分销关系
affiliate(user_id, parent_id, level, rate, created_at)
affiliate_log(order_id, user_id, commission, settled_at)
-- 多语言文案表(UI 层)
i18n_message(key, lang, value)
5.2 解锁逻辑的原子性
"用户付钻石看一集"这条链路必须保证不超扣、不重复解锁:
DB::transaction(function () use ($user, $episode) {
// 乐观锁扣余额
$affected = User::where('id', $user->id)
->where('diamond_balance', '>=', $episode->price_diamond)
->update([
'diamond_balance' => DB::raw("diamond_balance - {$episode->price_diamond}")
]);
if (!$affected) throw new Exception('余额不足');
UnlockLog::create([...]);
// 触发消息队列:分账 / 片方通知 / 投流回传
Queue::push(new AfterUnlockJob($order));
});
用数据库事务 + 乐观锁,比应用层判断稳得多。
六、uni-app 前端工程实践
6.1 目录结构
drama-uniapp/
├── pages/
│ ├── index/ # 首页信息流(上下滑)
│ ├── detail/ # 剧集详情
│ ├── player/ # 播放页(核心)
│ ├── recharge/ # 充值中心
│ ├── vip/ # 会员开通
│ └── user/ # 个人中心
├── components/
│ ├── DramaCard/
│ ├── EpisodeList/
│ └── PayModal/ # 解锁弹窗
├── utils/
│ ├── platform.js # 平台适配器
│ ├── request.js # 统一 HTTP 封装
│ └── i18n.js # 语言切换
├── store/ # Pinia 状态
├── locale/ # 多语言包
│ ├── zh.json
│ ├── en.json
│ ├── ja.json
│ └── vi.json
└── manifest.json # 各端配置
6.2 播放器:短剧体验的灵魂
短剧播放器不是"放个 video 标签"就完事,核心诉求是:起播快、连播顺、续播准、弱网不卡。
<template>
<video
:src="currentSrc"
autoplay
loop=false
:poster="poster"
@ended="onEpisodeEnd"
@timeupdate="onProgress"
enable-danmu
/>
</template>
<script setup>
import { onShow } from '@dcloudio/uni-app'
const play = () => {
// HLS 切片地址(m3u8),弱网自动降码率
currentSrc.value = episode.hls_url
videoCtx.value.play()
}
onShow(() => {
// 页面回来续播兜底
videoCtx.value.seek(lastPosition)
play()
})
</script>
关键优化点:
- 视频格式用 HLS(m3u8) 而非裸 mp4,天然多码率自适应
- 预加载下一集地址,滑屏即播
- 断点续播:记录
last_position,onShow恢复 - 防盗链:播放地址带时效签名,OSS 回源校验 Referer/Token
- 同层渲染:避免覆盖层挡住控件
6.3 多语言切换实现
// utils/i18n.js
import zh from '@/locale/zh.json'
import en from '@/locale/en.json'
const messages = {
zh, en, ja, vi }
let current = uni.getStorageSync('lang') || 'zh'
export function t(key) {
return messages[current][key] || key
}
export function setLang(lang) {
current = lang
uni.setStorageSync('lang', lang)
// 通知后端按语言下发内容
uni.reLaunch({
url: '/pages/index/index' })
}
内容层多语言由后端按 ?lang= 参数返回,UI 层多语言走前端 locale 包,两层解耦。
七、后端 API 设计
7.1 接口规范
/api/v1/drama/list GET 剧集列表(分页/分类/排序)
/api/v1/drama/{id} GET 剧集详情(按语言)
/api/v1/episode/{id}/url GET 获取播放地址(鉴权后签名)
/api/v1/episode/unlock POST 解锁单集
/api/v1/vip/plans GET VIP 套餐列表(多语言)
/api/v1/order/create POST 创建订单
/api/v1/order/notify POST 支付回调(微信/支付宝/PayPal)
/api/v1/user/me GET 用户信息
/api/v1/affiliate/log GET 分销佣金明细
7.2 播放地址鉴权(防爬关键)
public function episodeUrl($id)
{
$ep = Episode::with('drama')->find($id);
// 校验用户是否有解锁权限
if ($ep->is_vip && !$this->user->hasAccess($ep)) {
return response()->json(['code' => 403, 'msg' => '需解锁']);
}
// 生成带时效的签名 URL
$sign = md5($ep->video_url . time() . config('app.key'));
$expire = time() + 300; // 5 分钟有效
return [
'url' => $ep->video_url . "?sign={$sign}&expire={$expire}",
'expire' => $expire
];
}
OSS/CDN 侧再校验 sign 和 expire,防止地址被扒走批量盗播。
7.3 支付回调的幂等处理
支付回调是重灾区:网络重试、重复通知、伪造回调。
public function notify(Request $req)
{
$data = $this->verifySign($req); // 平台公钥验签
$orderNo = $data['out_trade_no'];
return DB::transaction(function () use ($orderNo, $data) {
$order = Order::where('order_no', $orderNo)->lockForUpdate()->first();
if (!$order || $order->status === 'paid') {
return 'success'; // 已处理,直接返回,防重放
}
$order->markPaid($data);
// 发放权益:VIP / 钻石 / 解锁记录
app(EntitlementService::class)->grant($order);
// 触发分账
Queue::push(new SettleAffiliateJob($order));
return 'success';
});
}
八、SaaS 运营能力模块
一套能"卖出去"的短剧系统,光有播放不够,还得有运营闭环:
8.1 必备模块清单
- 内容 CMS:分类、标签、演员、批量上传、Excel 导入、AI 翻译
- 变现体系:单集解锁 / 整剧解锁 / VIP 包月包年 / 钻石充值 / 广告解锁
- 分销分账:一级二级分销,比例后台可配,提现审核 + 流水对账
- 投流回传:巨量引擎/广点通事件回传(注册、付费、完播),优化 ROI
- 数据看板:播放量、完播率、付费转化、渠道 ROI、LTV
- 权限审计:RBAC,超级管理员/运营/审核/财务分级,操作留痕
- 合规配置:青少年模式、用户协议、隐私政策、版权水印、AI 鉴黄
8.2 分销关系建模
affiliate(
user_id, parent_id_1, parent_id_2,
rate_l1, rate_l2, source_channel
)
订单支付成功后按层级结算:
$commission1 = $order->amount * $relation->rate_l1;
$commission2 = $order->amount * $relation->rate_l2;
AffiliateLog::create([...]); // 写入待结算
// T+1 或手动提现审批后打款
九、开源开发落地路径
9.1 开源版 vs 商业版边界
| 模块 | 开源版 | 商业版 |
|---|---|---|
| 播放/CMS/会员 | ✅ | ✅ |
| 多租户 SaaS | 基础版 | 完整隔离 + 计费 |
| 多语言 | 中/英/日/越 | 全语种 + AI 翻译 |
| 分销分账 | 单级 | 多级 + 自动提现 |
| 投流回传 | 埋点接口 | 巨量/广点通适配 |
| 移动端 | uni-app | 加 Flutter App |
开源版先把"能跑、能看、能付"的主链路打通,商业能力做插件化。
9.2 GitHub / Gitee 项目结构建议
drama-saas/
├── server/ # 后端(NestJS / ThinkPHP / Spring Boot 三选一)
├── admin/ # Vue3 管理后台
├── client-uniapp/ # 小程序/H5/App 前端
├── docker/ # 一键部署编排
├── docs/ # 架构图、API 文档、部署手册
├── scripts/ # 数据库初始化、演示数据
└── README.md
9.3 开源合规提醒
- 视频素材必须用授权片源,别把盗版剧塞进 demo
- 支付模块默认走"模拟支付",接入真实通道由使用者自己配证书
- 开源协议推荐 Apache-2.0(允许商用,但保留署名)
- 多语言文案涉及翻译数据时,注明数据来源与授权
十、部署上线清单
10.1 服务器基线
2 核 4G 起(视频走 CDN 后,业务服务器压力很小)
MySQL 8.0 + Redis 6+
Nginx + PHP-FPM 或 Java 运行环境
宝塔面板可加速交付
10.2 Nginx 关键配置
# HLS 分段支持
location /hls/ {
types {
application/vnd.apple.mpegurl m3u8; video/mp2t ts; }
add_header Cache-Control no-cache;
}
# 防盗链
location ~* \.(m3u8|ts)$ {
valid_referers none blocked *.drama.com;
if ($invalid_referer) return 403;
}
# API 反代
location /api/ {
proxy_pass http://127.0.0.1:8080;
proxy_set_header X-Tenant $subdomain;
}
10.3 小程序上架避坑
- 微信小程序需配置 业务域名 + downloadFile 合法域名
- 虚拟支付(VIP/解锁)要走微信官方虚拟支付,不能绕
- 抖音小程序对接字节支付 + 巨量回传
- 海外版 H5 需处理 GDPR、隐私弹窗、本地支付(PayPal/本地钱包)
- 内容审核:AI 鉴黄 + 人工复核双保险,避免下架
十一、性能与扩展要点
11.1 热点优化
- 热门剧集列表进 Redis,TTL 60s,防止击穿
- 播放地址签名缓存 5 分钟,避免每次查库
- 转码切片走消息队列,主接口不阻塞
- 数据库读写分离:订单写主库,列表读从库
11.2 横向扩展路径
单实例 → 多副本无状态 API → 独立转码服务
→ 独立分账服务 → 多区域 CDN(出海)
租户量上来后,核心表可按 tenant_id 做分库分表,或把大租户迁独立库。