diff --git a/.gitignore b/.gitignore
index 516299c..25c2cbc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,5 +4,6 @@
/vendor
*.log
.env
+.idea
/tests/tmp
/tests/.phpunit.result.cache
diff --git a/.idea/php.xml b/.idea/php.xml
index 1d26366..e84699f 100644
--- a/.idea/php.xml
+++ b/.idea/php.xml
@@ -10,7 +10,7 @@
-
+
diff --git a/app/DbCoroutineContext.php b/app/DbCoroutineContext.php
new file mode 100644
index 0000000..09d5602
--- /dev/null
+++ b/app/DbCoroutineContext.php
@@ -0,0 +1,135 @@
+= 0) {
+ return $cid;
+ }
+ }
+ return null;
+ }
+
+ // put 存数据到 list
+ public static function put(mixed $value): void
+ {
+ $val = self::get('startTrans');
+ if (!empty($val) && $val === true) {
+ $value->startTrans();
+ }
+ $cid = self::getCid();
+ if ($cid !== null) {
+ self::$list[$cid][] = $value;
+ } else {
+ self::$globalList[] = $value;
+ }
+ }
+
+ // set 设置 key-value
+ public static function set(string $key, mixed $value): void
+ {
+ $cid = self::getCid();
+ if ($cid !== null) {
+ self::$data[$cid][$key] = $value;
+ } else {
+ self::$globalData[$key] = $value;
+ }
+ }
+
+ // get 获取 key-value
+ public static function get(string $key, mixed $default = null): mixed
+ {
+ $cid = self::getCid();
+ if ($cid !== null) {
+ return self::$data[$cid][$key] ?? $default;
+ } else {
+ return self::$globalData[$key] ?? $default;
+ }
+ }
+
+ // 获取 list
+ public static function getList(): array
+ {
+ $cid = self::getCid();
+ if ($cid !== null) {
+ return self::$list[$cid] ?? [];
+ } else {
+ return self::$globalList;
+ }
+ }
+
+ // 删除指定 key
+ public static function delete(string $key): void
+ {
+ $cid = self::getCid();
+ if ($cid !== null) {
+ unset(self::$data[$cid][$key]);
+ } else {
+ unset(self::$globalData[$key]);
+ }
+ }
+
+ public static function clearList()
+ {
+ foreach (self::getList() as $conn) {
+ try {
+ $conn->query('SELECT 1');
+ $conn->close();
+ // 连接正常
+ } catch (\Exception $e) {
+ }
+ }
+ $cid = self::getCid();
+ if ($cid !== null) {
+ unset(self::$list[$cid]);
+ } else {
+ self::$globalList = [];
+ }
+ }
+
+ public static function rollback()
+ {
+ foreach (self::getList() as $conn) {
+ $conn->rollback();
+ }
+ }
+
+ // 清理当前上下文
+ public static function clear(): void
+ {
+ foreach (self::getList() as $conn) {
+ try {
+ $conn->query('SELECT 1');
+ $conn->close();
+ // 连接正常
+ } catch (\Exception $e) {
+ }
+ }
+ $cid = self::getCid();
+ if ($cid !== null) {
+ unset(self::$data[$cid], self::$list[$cid]);
+ } else {
+ self::$globalData = [];
+ self::$globalList = [];
+ }
+ }
+
+ public static function commit()
+ {
+ foreach (self::getList() as $conn) {
+ $conn->commit();
+ }
+ }
+}
diff --git a/app/controller/IndexController.php b/app/controller/IndexController.php
index ef309f4..04b61b4 100644
--- a/app/controller/IndexController.php
+++ b/app/controller/IndexController.php
@@ -2,31 +2,192 @@
namespace app\controller;
+use app\api\model\CourseCollect;
+use app\api\model\CourseDetails;
+use app\api\model\TbUser;
+use app\model\DatabaseRoute;
+use app\model\Test;
use support\Request;
+use think\facade\Db;
+use think\facade\Log;
class IndexController
{
public function index(Request $request)
{
- return <<
- * {
- padding: 0;
- margin: 0;
- }
- iframe {
- border: none;
- overflow: scroll;
- }
-
-
-EOF;
+
+
+ $get['courseId'] = $course_id = '1877654905222135809';
+ $user['user_id'] = $user_id = '14240';
+ $user = DatabaseRoute::getDb('tb_user', $user_id)->find();
+ try {
+ if(empty($get['courseId'])) {
+ return json('参数不完整');
+ }
+ $courseId = $get['courseId'];
+ // 获取短剧详情
+ $dd_b = Db::connect('duanju_slave');
+ $db_name = $dd_b->name('course');
+ $bean = $db_name->where(['course_id' => $courseId])->find();
+ if(!$bean) {
+ return json('短剧不存在');
+ }
+
+
+ $courseCollect = DatabaseRoute::getDb('course_collect', $user_id)
+ ->where(['course_id' => $course_id])
+ ->where(['user_id' => $user_id])
+ ->where(['classify' => 3])
+ ->limit(1)
+ ->find();
+
+
+
+ // 是否追剧
+ $collect = DatabaseRoute::getDb('course_collect', $user_id)
+ ->where(['course_id' => $course_id])
+ ->where(['classify' => 1])
+ ->limit(1)
+ ->find();
+
+
+
+
+
+ $db = Db::connect(config('think-orm.search_library'));
+ $userVip = $db->name('user_vip')->where(['user_id' => $user['user_id']])->find();
+
+ if ($userVip) {
+ $user['member'] = $userVip['is_vip'];
+ $user['end_time'] = $userVip['end_time'];
+ }
+
+
+
+
+ $userInfo = $user;
+
+
+
+
+
+
+ if (!empty($userInfo['member']) && $userInfo['member'] == 2) {
+ $isVip = true;
+ }else{
+ $isVip = false;
+ }
+
+
+
+
+
+
+ // 查询用户是否购买了整集
+ $courseUser = DatabaseRoute::getDb('course_user', $user_id)
+ ->where(['course_id' => $course_id])
+ ->where(['classify' => 1])
+ ->find();
+
+
+
+ // 每天购买超过上限,获得免费时间段资格
+ $freeWatch = Test::checkFreeWatchPayCount($user['user_id']);
+
+ $startSort = 0;
+ $endSort = 5;
+ $dn_course_details = DatabaseRoute::getDb('course_details', ['course_id' => $courseId]);
+ $sort = null;
+ if (is_null($sort)) {
+
+ if (!empty($courseCollect)) {
+ $courseDetails = $dn_course_details->field('sort')
+ ->where('course_details_id', $courseCollect['course_details_id'])
+ ->limit(1)
+ ->find();
+ $sort = $courseDetails['sort'];
+ }
+ }
+
+ if ($freeWatch || !empty($courseUser)) {
+ $courseDetailsSetVos = Test::courseSets($courseId, 2, null);
+ } else {
+ $courseDetailsSetVos = Test::courseSets($courseId, 1, $bean['wholesale_price']);
+ }
+
+ // 调整集数范围
+ if (!is_null($sort) && $sort > 2) {
+ $startSort = $sort - 3;
+ $endSort = $sort + 3;
+ if (count($courseDetailsSetVos) < $endSort) {
+ $startSort = count($courseDetailsSetVos) - 5;
+ $endSort = count($courseDetailsSetVos) + 1;
+ }
+ }
+
+ // 已购买剧集ID集合
+ $detailsId = [];
+ if (!$freeWatch) {
+ $det_db = Db::connect(DatabaseRoute::getConnection('course_user', ['user_id' => $user['user_id']]));
+ $detailsId = $det_db->name('course_user')->where(['course_id' => $courseId, 'classify' => 2])->column('course_details_id');
+ $det_db->close();
+ $detailsId = array_flip(array_flip($detailsId)); // 去重
+ }
+ // 处理剧集列表
+ $current = null;
+ foreach ($courseDetailsSetVos as &$s) {
+ $s['wholesalePrice'] = (int) $s['wholesalePrice'];
+ // 当前播放集
+ if (!empty($courseCollect) && $s['courseDetailsId'] == $courseCollect['course_details_id']) {
+ $s['current'] = 1;
+ $current = &$s;
+ }
+
+ // 非免费用户的权限控制
+ if (
+ !$freeWatch &&
+ $s['sort'] > 3 &&
+ (empty($detailsId) || !in_array($s['courseDetailsId'], $detailsId)) &&
+ empty($courseUser) &&
+ !$isVip
+ ) {
+ $s['videoUrl'] = null;
+ }
+
+ // 检查是否已点赞
+ if ($s['sort'] > $startSort && $s['sort'] < $endSort) {
+ $isGood_db = Db::connect(DatabaseRoute::getConnection('course_collect', ['user_id' => $user['user_id']]));
+ $isGood = $isGood_db->name('course_collect')
+ ->where('course_details_id', $s['courseDetailsId'])
+ ->where('classify', 2)
+ ->limit(1)
+ ->count();
+ $isGood_db->close();
+ $s['isGood'] = empty($isGood) || $isGood == 0 ? 0 : 1;
+ }
+ }
+
+ // 如果没有当前播放集,默认第一集
+ if (empty($current) && !empty($courseDetailsSetVos)) {
+ $courseDetailsSetVos[0]['current'] = 1;
+ $current = &$courseDetailsSetVos[0];
+ }
+ Test::setCourseView($bean);
+
+ $price = ($freeWatch ? 0 : ($bean['price'] ?? 0));
+ $price = bccomp($price, '0', 2) <= 0 ? 0 : $price;
+ // 返回结果
+ $map = [
+ 'current' => $current,
+ 'price' => $price,
+ 'title' => $bean['title'],
+ 'collect' => empty($collect) || $collect == 0 ? 0 : 1,
+ 'list' => $courseDetailsSetVos
+ ];
+ return json($map);
+ } catch (\Exception $e) {
+ return json($e->getMessage());
+ }
}
public function view(Request $request)
diff --git a/app/model/DatabaseRoute.php b/app/model/DatabaseRoute.php
new file mode 100644
index 0000000..74ae322
--- /dev/null
+++ b/app/model/DatabaseRoute.php
@@ -0,0 +1,516 @@
+query($countSql)[0]['count'] ?? 0;
+ $counts[$connName] = $count;
+ $total += $count;
+ }
+ }
+ }
+
+
+ if ($total === 0) {
+ return [
+ 'list' => [],
+ 'totalCount' => 0,
+ 'totalPage' => 0,
+ 'currPage' => $page,
+ 'pageSize' => $pageSize,
+ ];
+ }
+
+ $offset = ($page - 1) * $pageSize;
+ if ($offset >= $total) {
+ return [
+ 'list' => [],
+ 'totalCount' => $total,
+ 'totalPage' => (int)ceil($total / $pageSize),
+ 'currPage' => $page,
+ 'pageSize' => $pageSize,
+ ];
+ }
+
+ $limit = $pageSize;
+ $allRows = [];
+ $skip = $offset;
+
+ // 2. 分库分页查询
+ foreach ($counts as $connName => $count) {
+ if ($count <= 0) continue;
+ if ($skip >= $count) {
+ $skip -= $count;
+ continue;
+ }
+
+ $localOffset = $skip;
+ $localLimit = min($count - $localOffset, $limit);
+
+ $baseSql = call_user_func($sqlBuilder, $connName);
+ $sql = rtrim($baseSql, ';');
+
+ if ($orderCol) {
+ $sql .= " ORDER BY {$orderCol} DESC";
+ }
+ $sql .= " LIMIT {$localOffset}, {$localLimit}";
+
+ $rows = Db::connect($connName)->query($sql);
+ $allRows = array_merge($allRows, $rows);
+
+ $limit -= $localLimit;
+ $skip = 0;
+ if ($limit <= 0) break;
+ }
+
+ // 3. 全局排序(若指定排序字段)
+ if ($orderCol) {
+ usort($allRows, function ($a, $b) use ($orderCol) {
+ return strtotime($b[$orderCol]) <=> strtotime($a[$orderCol]);
+ });
+ }
+
+ // 4. 返回结构
+ return [
+ 'list' => $allRows,
+ 'totalCount' => $total,
+ 'totalPage' => (int)ceil($total / $pageSize),
+ 'currPage' => $page,
+ 'pageSize' => $pageSize,
+ ];
+ }
+
+ /**
+ * 从 SELECT SQL 自动构建对应的 COUNT SQL
+ *
+ * @param string $sql
+ * @return string
+ */
+ private static function buildCountSql(string $sql): string
+ {
+ $sql = preg_replace('/\s+ORDER\s+BY\s+.+?$/i', '', $sql);
+ $sql = preg_replace('/\s+LIMIT\s+\d+(\s*,\s*\d+)?$/i', '', $sql);
+ if (preg_match('/FROM\s+(.*)/i', $sql, $matches)) {
+ return 'SELECT COUNT(*) AS count FROM ' . $matches[1];
+ }
+ throw new \RuntimeException("无法从 SQL 自动构建 COUNT 查询,请检查 SQL 是否规范");
+ }
+
+ public static function paginateDb(
+ string $table,
+ \Closure $builder,
+ int $page = 1,
+ int $pageSize = 20,
+ string|array $keyInfo = null,
+ $isRecords = false
+ ) {
+ // 构建基础查询
+ if ($keyInfo) {
+ $query = self::getDb($table, $keyInfo);
+ }else{
+ $query = Db::table($table);
+ }
+ $builder($query); // 应用外部闭包设置查询条件,如 where/order 等
+
+ // 获取总数
+ $totalCount = (clone $query)->count();
+
+ // 计算总页数
+ $totalPage = (int) ceil($totalCount / $pageSize);
+ $currPage = max(1, min($page, $totalPage));
+
+ // 获取分页数据
+ $list = $query
+ ->page($currPage, $pageSize)
+ ->select()
+ ->toArray();
+ $query->getConnection()->close();
+
+ return [
+ 'totalCount' => $totalCount,
+ 'pageSize' => $pageSize,
+ 'totalPage' => $totalPage,
+ 'currPage' => $currPage,
+ $isRecords ? 'records' : 'list' => convertToCamelCase($list),
+ ];
+ }
+
+ /**
+ * 跨所有从库分页(支持游标分页和传统页码分页)
+ * @param string $table 表名
+ * @param \Closure $builder 查询构造器
+ * @param int|null $page 当前页(null 表示使用游标分页)
+ * @param int $pageSize 每页条数
+ * @param string|null $lastCreateTime 游标分页的游标值(create_time)
+ * @return array [list, total|nextCursor, hasMore]
+ */
+ public static function paginateAllDb(
+ string $table,
+ \Closure $builder,
+ int $page = 1,
+ int $pageSize = 20,
+ string $orderCol = 'create_time',
+ string $modelOrderCol = null,
+ bool $isRecords = false
+ ): array
+ {
+ $dbMap = config('database.db_map');
+ $counts = [];
+ $total = 0;
+
+ // 1. 统计每个分库总数
+ $dbList = DatabaseRoute::getAllSelectDb();
+ foreach ($dbMap as $connName) {
+ if (in_array($connName, $dbList) ) {
+ $query = Db::connect($connName)->name($table);
+ $query = call_user_func($builder, $query);
+ // 不要order,避免报错
+ $query->removeOption('order');
+ $count = $query->count();
+ $query->getConnection()->close();
+ $counts[$connName] = $count;
+ $total += $count;
+ }
+ }
+
+ if ($total === 0) {
+ return [
+ $isRecords ? 'records' : 'list' => [],
+ 'totalCount' => 0,
+ 'totalPage' => 0,
+ 'currPage' => $page,
+ 'pageSize' => $pageSize,
+ ];
+ }
+
+ $offset = ($page - 1) * $pageSize;
+ if ($offset >= $total) {
+ // 超出总数,返回空数据
+ return [
+ $isRecords ? 'records' : 'list' => [],
+ 'totalCount' => $total,
+ 'totalPage' => (int)ceil($total / $pageSize),
+ 'currPage' => $page,
+ 'pageSize' => $pageSize,
+ ];
+ }
+
+ $limit = $pageSize;
+ $allRows = [];
+
+ // 2. 计算每个库需要查询的偏移和条数
+ $skip = $offset; // 还需要跳过多少条
+ foreach ($counts as $connName => $count) {
+ if ($count <= 0) continue;
+
+ if ($skip >= $count) {
+ // 跳过整个分库
+ $skip -= $count;
+ continue;
+ }
+
+ // 本库要查询的起始 offset
+ $localOffset = $skip;
+ // 本库剩余条数
+ $localLimit = min($count - $localOffset, $limit);
+
+ // 查询数据
+ $query = Db::connect($connName)->name($table);
+ $query = call_user_func($builder, $query);
+ $rows = $query->order($orderCol, 'desc')
+ ->limit($localOffset, $localLimit)
+ ->select()
+ ->toArray();
+ $query->getConnection()->close();
+
+ $allRows = array_merge($allRows, $rows);
+
+ $limit -= $localLimit; // 剩余要查询的条数
+ $skip = 0; // 之后库不再跳过
+
+ if ($limit <= 0) break; // 已查够
+ }
+
+ // 3. 全局排序(降序)
+ if ($modelOrderCol) {
+ usort($allRows, function ($a, $b) use ($modelOrderCol) {
+ return strtotime($b[$modelOrderCol]) <=> strtotime($a[$modelOrderCol]);
+ });
+ }
+
+ // 4. 返回分页数据
+ return [
+ $isRecords ? 'records' : 'list' => $allRows,
+ 'totalCount' => $total,
+ 'totalPage' => (int)ceil($total / $pageSize),
+ 'currPage' => $page,
+ 'pageSize' => $pageSize,
+ ];
+ }
+
+
+ /**
+ * 对所有从库执行事务(XA 分布式模拟,非真实两阶段提交)
+ * @param \Closure $callback
+ * @return mixed
+ * @throws \Throwable
+ */
+ public static function transactionXa(\Closure $callback)
+ {
+ DbCoroutineContext::set('startTrans', true);
+
+ try {
+
+ // 执行用户操作(传入事务闭包)
+ $result = call_user_func($callback);
+ // 提交所有连接
+ DbCoroutineContext::commit();
+ return $result;
+ } catch (\Throwable $e) {
+ // 回滚所有连接
+ DbCoroutineContext::rollback();
+
+ Log::error("transactionXa 全部回滚:" . $e->getMessage());
+ Log::info('错误信息'.$e->getMessage().'具体信息'.$e->getTraceAsString());
+ throw $e;
+ }finally {
+ DbCoroutineContext::clearList();
+ DbCoroutineContext::set('startTrans', false);
+ }
+ }
+
+ public static function getMasterDb($table, $isWrite = false)
+ {
+ $conn = Db::connect();
+ if ($isWrite) {
+ DbCoroutineContext::put($conn);
+ }
+ return $conn->name($table);
+ }
+
+
+ /**
+ * 根据表和分库值获取db
+ * @param $table string 表名
+ * @param $keyInfo string | array
+ */
+ public static function getDb($table, $keyInfo, $isWrite = false, $isUpdate = false, $addWhere = true)
+ {
+ if (is_array($keyInfo)) {
+ $con = Db::connect(DatabaseRoute::getConnection($table, $keyInfo, $isWrite));
+ if ($isWrite) {
+ DbCoroutineContext::put($con);
+ }
+ $model = $con->name($table);
+ if ($addWhere && (!$isWrite || $isUpdate)) {
+ $model->where($keyInfo);
+ }
+ } else {
+ $con = Db::connect(DatabaseRoute::getConnection($table, ['user_id' => $keyInfo], $isWrite));
+ if ($isWrite) {
+ DbCoroutineContext::put($con);
+ }
+ $model = $con->name($table);
+ if ($addWhere && (!$isWrite || $isUpdate)) {
+ $model->where([
+ 'user_id' => $keyInfo
+ ]);
+ }
+ }
+
+ return $model;
+ }
+
+ /**
+ * 跨所有分库直接删除(危险操作,务必确认条件准确)
+ * @param string $table 表名
+ * @param \Closure $builder 条件构造器,如 function($query) { return $query->where('xxx', xxx); }
+ * @return int 删除的总记录数
+ */
+ public static function deleteAllDbDirect(string $table, \Closure $builder): int
+ {
+ $dbMap = config('database.db_master_map');
+ $totalDeleted = 0;
+
+ foreach ($dbMap as $connName) {
+ if ($connName === 'duanju_master') continue;
+
+ $query = Db::connect($connName)->name($table);
+ $query = call_user_func($builder, $query);
+ $deleted = $query->delete();
+ $query->getConnection()->close();
+ $totalDeleted += $deleted;
+ }
+
+ return $totalDeleted;
+ }
+
+ public static function getAllDbData($table, \Closure $builder)
+ {
+
+ return new class($table, $builder) {
+ protected $table;
+ protected $builder;
+ protected $dbMap;
+ protected $masterDbMap;
+
+ public function __construct($table, $builder)
+ {
+ $this->table = $table;
+ $this->builder = $builder;
+ $this->dbMap = config('database.db_map');
+ $this->masterDbMap = config('database.db_master_map');
+ }
+
+ public function __call($method, $args)
+ {
+ $finalResult = null;
+ try {
+ if ($method == 'insert') {
+ throw new \RuntimeException("不支持insert");
+ }
+ // insert 和 update 使用主库
+ if ($method == 'update' || $method == 'delete') {
+ foreach ($this->masterDbMap as $dbname) {
+ if ($dbname !== 'duanju_master') {
+ $query = Db::connect($dbname)->name($this->table);
+ $query = call_user_func($this->builder, $query);
+ if (method_exists($query, $method)) {
+ $result = call_user_func_array([$query, $method], $args);
+ $finalResult = $result;
+ $query->getConnection()->close();
+ // find 返回 null,select 返回空数组,count 返回数字
+ if ($result || $result === 0) {
+ return $result;
+ }
+ }else {
+ $query->getConnection()->close();
+ }
+ }
+ }
+ return $finalResult;
+ }else{
+ $dbList = DatabaseRoute::getAllSelectDb();
+ foreach ($this->dbMap as $dbname) {
+ if (in_array($dbname, $dbList) ) {
+ $query = Db::connect($dbname)->name($this->table);
+ $query = call_user_func($this->builder, $query);
+ if (method_exists($query, $method)) {
+ $result = call_user_func_array([$query, $method], $args);
+ // find 返回 null,select 返回空数组,count 返回数字
+ $finalResult = $result;
+ $query->getConnection()->close();
+ if ($result instanceof Collection) {
+ if (!$result->isEmpty()) {
+ return $result;
+ }
+ }elseif (is_int($result) && $result != 0) {
+ return $result;
+ } else if ($result) {
+ return $result;
+ }
+ }else {
+ $query->getConnection()->close();
+ }
+ }
+ }
+ }
+ }catch (\Throwable $e) {
+ Log::error("错误信息".$e->getMessage());
+ throw $e;
+ }
+
+
+ return $finalResult;
+ }
+ };
+ }
+
+ public static function getAllSelectDb()
+ {
+ $index = self::getIndex();
+ return ["duanju$index-0_slave", "duanju$index-1_slave", "duanju$index-2_slave", "duanju$index-3_slave", "duanju$index-4_slave"];
+ }
+
+
+ private static function getIndex()
+ {
+ $INDEX = \cache('db_index');
+ if ($INDEX == null) {
+ $INDEX = 0;
+ }
+ $INDEX = ++$INDEX % 4;
+ \cache('db_index', $INDEX);
+ return $INDEX;
+ }
+
+
+ /**
+ * 获取数据库连接
+ * @param string $tableName 表名
+ * @param array $data 数据
+ * @param bool $isWrite 是否为写操作
+ * @return Connection
+ */
+ public static function getConnection($table, $data = [], $isWrite = false)
+ {
+ $routeConfig = config('think-orm.route');
+ $keyField = strpos($table, 'user') !== false || in_array($table, [
+ 'orders', 'course_collect', 'pay_details', 'disc_spinning_record',
+ 'cash_out', 'course_user', 'tb_user', 'task_center_record',
+ 'user_money', 'user_sign_record', 'invite_achievement',
+ 'invite_money', 'user_info', 'sys_user', 'user_money_details', 'sys_user_money_details'
+ ]) ? 'user_id' : 'course_id';
+
+ if (!isset($data[$keyField])) {
+ Log::warning("分库警告: 表={$table}, 数据中缺少 {$keyField} 字段");
+ return $isWrite ? 'duanju_master' : 'duanju_slave';
+ }
+
+ $index = abs($data[$keyField] % 5);
+ $connectionTemplate = $isWrite
+ ? $routeConfig[$table]['master']
+ : $routeConfig[$table]['slave'];
+
+ $connectionName = str_replace("{\${$keyField}%5}", $index, $connectionTemplate);
+ return $connectionName;
+ }
+}
\ No newline at end of file
diff --git a/app/model/Test.php b/app/model/Test.php
index 92d70e3..130d151 100644
--- a/app/model/Test.php
+++ b/app/model/Test.php
@@ -2,7 +2,8 @@
namespace app\model;
-use support\Model;
+use think\model;
+use think\facade\Db;
class Test extends Model
{
@@ -26,4 +27,84 @@ class Test extends Model
* @var bool
*/
public $timestamps = false;
+
+
+
+ public static function checkFreeWatchPayCount($userId)
+ {
+ $count = DatabaseRoute::getDb('orders', $userId)->where([
+ 'status' => 1,
+ 'pay_way' => 9,
+ ['create_time', '>', date('Y-m-d 00:00:00')],
+ ])->count();
+ $needCount = Db::name('common_info')->where([
+ 'type' => 916
+ ])->find();
+ $freeTime = Db::name('common_info')->where([
+ 'type' => 917
+ ])->find();
+ if (!$needCount || !$freeTime) {
+ return false;
+ }
+ if ($count >= intval($needCount['value'])) {
+ $isExpire = false;
+ }else{
+ $isExpire = true;
+ }
+
+ return !$isExpire;
+ }
+
+
+ public static function courseSets($courseId, $isPrice, $wholesalePrice)
+ {
+
+ $db = Db::connect(DatabaseRoute::getConnection('course_details', ['course_id' => $courseId]));
+ $courseDetailsSetVos = $db->name('course_details')
+ ->alias('c')
+ ->field([
+ 'c.course_id' => 'courseId',
+ 'c.course_details_id' => 'courseDetailsId',
+ 'c.course_details_name' => 'courseDetailsName',
+ 'c.video_url' => 'videoUrl',
+ 'c.price' => 'price',
+ 'c.sort' => 'sort',
+ 'c.is_price' => 'isPrice',
+ 'c.title_img' => 'titleImg',
+ 'c.good_num' => 'goodNum',
+ ])
+ ->where('c.course_id', $courseId)
+ ->order('c.sort', 'asc')
+ ->select()
+ ->toArray();
+ foreach ($courseDetailsSetVos as $k => &$v) {
+ $v['courseId'] = (string) $v['courseId'];
+ $v['courseDetailsId'] = (string) $v['courseDetailsId'];
+ if(empty($wholesalePrice)) {
+ $v['wholesalePrice'] = 0;
+ }else {
+ $v['wholesalePrice'] = $wholesalePrice;
+ }
+ if($isPrice != 1) {
+ $v['isPrice'] = 2;
+ }
+ }
+ return $courseDetailsSetVos;
+ }
+ public static function setCourseView($course)
+ {
+ // 1. 更新总播放量
+ if (empty($course['view_counts'])) {
+ $viewCounts = 1;
+ } else {
+ $viewCounts = $course['view_counts'] + 1;
+ }
+
+ $db_name = Db::connect(config('think-orm.z_library'))->name('course');
+ // 4. 执行数据库更新
+ $db_name->where(['course_id' => $course['course_id']])->update([
+ 'view_counts' => $viewCounts,
+ 'week_view' => 999
+ ]);
+ }
}
\ No newline at end of file
diff --git a/composer.json b/composer.json
index d25c083..2a784a9 100644
--- a/composer.json
+++ b/composer.json
@@ -26,7 +26,9 @@
"require": {
"php": ">=8.1",
"workerman/webman-framework": "^2.1",
- "monolog/monolog": "^2.0"
+ "monolog/monolog": "^2.0",
+ "webman/think-orm": "^2.1",
+ "vlucas/phpdotenv": "^5.6"
},
"suggest": {
"ext-event": "For better performance. "
diff --git a/composer.lock b/composer.lock
index 4df1054..441e512 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,77 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "691f538563ac6695008ddc51b7722c80",
+ "content-hash": "31b009f9f2392b9eda909c76dbca259f",
"packages": [
+ {
+ "name": "graham-campbell/result-type",
+ "version": "1.1.x-dev",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/GrahamCampbell/Result-Type.git",
+ "reference": "9d6c1d7ce69a3329936e603617e59ba205ab0a66"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/9d6c1d7ce69a3329936e603617e59ba205ab0a66",
+ "reference": "9d6c1d7ce69a3329936e603617e59ba205ab0a66",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "php": "^7.2.5 || ^8.0",
+ "phpoption/phpoption": "^1.9.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7"
+ },
+ "default-branch": true,
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "GrahamCampbell\\ResultType\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ }
+ ],
+ "description": "An Implementation Of The Result Type",
+ "keywords": [
+ "Graham Campbell",
+ "GrahamCampbell",
+ "Result Type",
+ "Result-Type",
+ "result"
+ ],
+ "support": {
+ "issues": "https://github.com/GrahamCampbell/Result-Type/issues",
+ "source": "https://github.com/GrahamCampbell/Result-Type/tree/1.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-02-09T22:43:44+00:00"
+ },
{
"name": "monolog/monolog",
"version": "2.10.0",
@@ -170,6 +239,87 @@
},
"time": "2018-02-13T20:26:39+00:00"
},
+ {
+ "name": "phpoption/phpoption",
+ "version": "1.9.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/schmittjoh/php-option.git",
+ "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54",
+ "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "php": "^7.2.5 || ^8.0"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.8.2",
+ "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28"
+ },
+ "type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": false
+ },
+ "branch-alias": {
+ "dev-master": "1.9-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpOption\\": "src/PhpOption/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Johannes M. Schmitt",
+ "email": "schmittjoh@gmail.com",
+ "homepage": "https://github.com/schmittjoh"
+ },
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ }
+ ],
+ "description": "Option Type for PHP",
+ "keywords": [
+ "language",
+ "option",
+ "php",
+ "type"
+ ],
+ "support": {
+ "issues": "https://github.com/schmittjoh/php-option/issues",
+ "source": "https://github.com/schmittjoh/php-option/tree/1.9.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-07-20T21:41:07+00:00"
+ },
{
"name": "psr/container",
"version": "2.0.2",
@@ -285,6 +435,673 @@
},
"time": "2024-08-21T13:31:24+00:00"
},
+ {
+ "name": "psr/simple-cache",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/simple-cache.git",
+ "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865",
+ "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\SimpleCache\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interfaces for simple caching",
+ "keywords": [
+ "cache",
+ "caching",
+ "psr",
+ "psr-16",
+ "simple-cache"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/simple-cache/tree/3.0.0"
+ },
+ "time": "2021-10-29T13:26:27+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.31.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-ctype": "*"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-09T11:45:10+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.31.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
+ "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-mbstring": "*"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-09T11:45:10+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php80",
+ "version": "v1.31.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php80.git",
+ "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
+ "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php80\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
+ },
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-09T11:45:10+00:00"
+ },
+ {
+ "name": "topthink/think-container",
+ "version": "v3.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/top-think/think-container.git",
+ "reference": "a24d442a02fb2a4716de232ff1a4f006c178a370"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/top-think/think-container/zipball/a24d442a02fb2a4716de232ff1a4f006c178a370",
+ "reference": "a24d442a02fb2a4716de232ff1a4f006c178a370",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "php": ">=8.0",
+ "psr/container": "^2.0",
+ "topthink/think-helper": "^3.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [],
+ "psr-4": {
+ "think\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "liu21st",
+ "email": "liu21st@gmail.com"
+ }
+ ],
+ "description": "PHP Container & Facade Manager",
+ "support": {
+ "issues": "https://github.com/top-think/think-container/issues",
+ "source": "https://github.com/top-think/think-container/tree/v3.0.1"
+ },
+ "time": "2025-01-07T08:19:23+00:00"
+ },
+ {
+ "name": "topthink/think-helper",
+ "version": "v3.1.11",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/top-think/think-helper.git",
+ "reference": "1d6ada9b9f3130046bf6922fe1bd159c8d88a33c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/top-think/think-helper/zipball/1d6ada9b9f3130046bf6922fe1bd159c8d88a33c",
+ "reference": "1d6ada9b9f3130046bf6922fe1bd159c8d88a33c",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "php": ">=7.1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/helper.php"
+ ],
+ "psr-4": {
+ "think\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "yunwuxin",
+ "email": "448901948@qq.com"
+ }
+ ],
+ "description": "The ThinkPHP6 Helper Package",
+ "support": {
+ "issues": "https://github.com/top-think/think-helper/issues",
+ "source": "https://github.com/top-think/think-helper/tree/v3.1.11"
+ },
+ "time": "2025-04-07T06:55:59+00:00"
+ },
+ {
+ "name": "topthink/think-orm",
+ "version": "v4.0.40",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/top-think/think-orm.git",
+ "reference": "1637860ff736859058f0a5003c7cc719c2068dbc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/top-think/think-orm/zipball/1637860ff736859058f0a5003c7cc719c2068dbc",
+ "reference": "1637860ff736859058f0a5003c7cc719c2068dbc",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "ext-json": "*",
+ "ext-pdo": "*",
+ "php": ">=8.0.0",
+ "psr/log": ">=1.0",
+ "psr/simple-cache": ">=1.0",
+ "topthink/think-helper": "^3.1",
+ "topthink/think-validate": "^3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6|^10"
+ },
+ "suggest": {
+ "ext-mongodb": "provide mongodb support"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/helper.php",
+ "stubs/load_stubs.php"
+ ],
+ "psr-4": {
+ "think\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "liu21st",
+ "email": "liu21st@gmail.com"
+ }
+ ],
+ "description": "the PHP Database&ORM Framework",
+ "keywords": [
+ "database",
+ "orm"
+ ],
+ "support": {
+ "issues": "https://github.com/top-think/think-orm/issues",
+ "source": "https://github.com/top-think/think-orm/tree/v4.0.40"
+ },
+ "time": "2025-05-27T03:32:05+00:00"
+ },
+ {
+ "name": "topthink/think-validate",
+ "version": "v3.0.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/top-think/think-validate.git",
+ "reference": "85063f6d4ef8ed122f17a36179dc3e0949b30988"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/top-think/think-validate/zipball/85063f6d4ef8ed122f17a36179dc3e0949b30988",
+ "reference": "85063f6d4ef8ed122f17a36179dc3e0949b30988",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "php": ">=8.0",
+ "topthink/think-container": ">=3.0"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/helper.php"
+ ],
+ "psr-4": {
+ "think\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "liu21st",
+ "email": "liu21st@gmail.com"
+ }
+ ],
+ "description": "think validate",
+ "support": {
+ "issues": "https://github.com/top-think/think-validate/issues",
+ "source": "https://github.com/top-think/think-validate/tree/v3.0.7"
+ },
+ "time": "2025-06-11T05:51:40+00:00"
+ },
+ {
+ "name": "vlucas/phpdotenv",
+ "version": "v5.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/vlucas/phpdotenv.git",
+ "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2",
+ "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "ext-pcre": "*",
+ "graham-campbell/result-type": "^1.1.3",
+ "php": "^7.2.5 || ^8.0",
+ "phpoption/phpoption": "^1.9.3",
+ "symfony/polyfill-ctype": "^1.24",
+ "symfony/polyfill-mbstring": "^1.24",
+ "symfony/polyfill-php80": "^1.24"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.8.2",
+ "ext-filter": "*",
+ "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2"
+ },
+ "suggest": {
+ "ext-filter": "Required to use the boolean validator."
+ },
+ "type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": false
+ },
+ "branch-alias": {
+ "dev-master": "5.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Dotenv\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Vance Lucas",
+ "email": "vance@vancelucas.com",
+ "homepage": "https://github.com/vlucas"
+ }
+ ],
+ "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
+ "keywords": [
+ "dotenv",
+ "env",
+ "environment"
+ ],
+ "support": {
+ "issues": "https://github.com/vlucas/phpdotenv/issues",
+ "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-07-20T21:52:34+00:00"
+ },
+ {
+ "name": "webman/think-orm",
+ "version": "v2.1.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webman-php/think-orm.git",
+ "reference": "af4a2586177a333983e0da1bf6512ec12f894b29"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webman-php/think-orm/zipball/af4a2586177a333983e0da1bf6512ec12f894b29",
+ "reference": "af4a2586177a333983e0da1bf6512ec12f894b29",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "php": ">=8.1",
+ "topthink/think-container": "^2.0|^3.0",
+ "topthink/think-orm": "^2.0.53 || ^3.0.0 || ^4.0.30 || dev-master",
+ "workerman/webman-framework": "^2.1 || dev-master"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "support\\": "src/support",
+ "Webman\\ThinkOrm\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "support": {
+ "issues": "https://github.com/webman-php/think-orm/issues",
+ "source": "https://github.com/webman-php/think-orm/tree/v2.1.6"
+ },
+ "time": "2025-05-27T13:15:25+00:00"
+ },
{
"name": "workerman/coroutine",
"version": "v1.1.3",
diff --git a/config/bootstrap.php b/config/bootstrap.php
index 95d2e87..ce7bfb2 100644
--- a/config/bootstrap.php
+++ b/config/bootstrap.php
@@ -14,4 +14,5 @@
return [
support\bootstrap\Session::class,
+ Webman\ThinkOrm\ThinkOrm::class,
];
diff --git a/config/think-orm.php b/config/think-orm.php
new file mode 100644
index 0000000..0514e30
--- /dev/null
+++ b/config/think-orm.php
@@ -0,0 +1,284 @@
+ 'duanju_master',
+ 'connections' => [
+ 'duanju_master' => [
+ // 数据库类型
+ 'type' => 'mysql',
+ // 服务器地址
+ 'hostname' => env('HOSTNAME', '127.0.0.1'),
+ // 数据库名
+ 'database' => 'duanju',
+ // 数据库用户名
+ 'username' => env('USERNAME', 'video_user'),
+ // 数据库密码
+ 'password' => env('PASSWORD', 'VideoUser@1'),
+ // 数据库连接端口
+ 'hostport' => env('HOSTPORT', '3306'),
+ // 数据库连接参数
+ 'params' => [
+ // 连接超时3秒
+ \PDO::ATTR_TIMEOUT => 3,
+ ],
+ // 数据库编码默认采用utf8
+ 'charset' => 'utf8mb4',
+ // 数据库表前缀
+ 'prefix' => '',
+ // 断线重连
+ 'break_reconnect' => true,
+ // 自定义分页类
+ 'bootstrap' => '',
+ // 连接池配置
+ 'pool' => [
+ 'max_connections' => 500, // 最大连接数
+ 'min_connections' => 20, // 最小连接数
+ 'wait_timeout' => 3, // 从连接池获取连接等待超时时间
+ 'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收
+ 'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒
+ ],
+ ],
+ 'duanju_slave' => [
+ // 数据库类型
+ 'type' => 'mysql',
+ // 服务器地址
+ 'hostname' => env('SLAVE_HOSTNAME', '127.0.0.1'),
+ // 数据库名
+ 'database' => 'duanju',
+ // 数据库用户名
+ 'username' => env('SLAVE_USERNAME', 'video_user'),
+ // 数据库密码
+ 'password' => env('SLAVE_PASSWORD', 'VideoUser@1'),
+ // 数据库连接端口
+ 'hostport' => env('SLAVE_HOSTPORT', '3306'),
+ // 数据库连接参数
+ 'params' => [
+ // 连接超时3秒
+ \PDO::ATTR_TIMEOUT => 3,
+ ],
+ // 数据库编码默认采用utf8
+ 'charset' => 'utf8mb4',
+ // 数据库表前缀
+ 'prefix' => '',
+ // 断线重连
+ 'break_reconnect' => true,
+ // 自定义分页类
+ 'bootstrap' => '',
+ // 连接池配置
+ 'pool' => [
+ 'max_connections' => 500, // 最大连接数
+ 'min_connections' => 20, // 最小连接数
+ 'wait_timeout' => 3, // 从连接池获取连接等待超时时间
+ 'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收
+ 'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒
+ ],
+ ],
+ 'duanju_slave_0' => [
+ // 数据库类型
+ 'type' => 'mysql',
+ // 服务器地址
+ 'hostname' => env('SLAVE_HOSTNAME', '127.0.0.1'),
+ // 数据库名
+ 'database' => 'duanju-0',
+ // 数据库用户名
+ 'username' => env('SLAVE_USERNAME', 'video_user'),
+ // 数据库密码
+ 'password' => env('SLAVE_PASSWORD', 'VideoUser@1'),
+ // 数据库连接端口
+ 'hostport' => env('SLAVE_HOSTPORT', '3306'),
+ // 数据库连接参数
+ 'params' => [
+ // 连接超时3秒
+ \PDO::ATTR_TIMEOUT => 3,
+ ],
+ // 数据库编码默认采用utf8
+ 'charset' => 'utf8mb4',
+ // 数据库表前缀
+ 'prefix' => '',
+ // 断线重连
+ 'break_reconnect' => true,
+ // 自定义分页类
+ 'bootstrap' => '',
+ // 连接池配置
+ 'pool' => [
+ 'max_connections' => 500, // 最大连接数
+ 'min_connections' => 20, // 最小连接数
+ 'wait_timeout' => 3, // 从连接池获取连接等待超时时间
+ 'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收
+ 'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒
+ ],
+ ],
+
+ 'duanju_slave_1' => [
+ // 数据库类型
+ 'type' => 'mysql',
+ // 服务器地址
+ 'hostname' => env('SLAVE_HOSTNAME', '127.0.0.1'),
+ // 数据库名
+ 'database' => 'duanju-1',
+ // 数据库用户名
+ 'username' => env('SLAVE_USERNAME', 'video_user'),
+ // 数据库密码
+ 'password' => env('SLAVE_PASSWORD', 'VideoUser@1'),
+ // 数据库连接端口
+ 'hostport' => env('SLAVE_HOSTPORT', '3306'),
+ // 数据库连接参数
+ 'params' => [
+ // 连接超时3秒
+ \PDO::ATTR_TIMEOUT => 3,
+ ],
+ // 数据库编码默认采用utf8
+ 'charset' => 'utf8mb4',
+ // 数据库表前缀
+ 'prefix' => '',
+ // 断线重连
+ 'break_reconnect' => true,
+ // 自定义分页类
+ 'bootstrap' => '',
+ // 连接池配置
+ 'pool' => [
+ 'max_connections' => 500, // 最大连接数
+ 'min_connections' => 20, // 最小连接数
+ 'wait_timeout' => 3, // 从连接池获取连接等待超时时间
+ 'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收
+ 'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒
+ ],
+ ],
+
+ 'duanju_slave_2' => [
+ // 数据库类型
+ 'type' => 'mysql',
+ // 服务器地址
+ 'hostname' => env('SLAVE_HOSTNAME', '127.0.0.1'),
+ // 数据库名
+ 'database' => 'duanju-2',
+ // 数据库用户名
+ 'username' => env('SLAVE_USERNAME', 'video_user'),
+ // 数据库密码
+ 'password' => env('SLAVE_PASSWORD', 'VideoUser@1'),
+ // 数据库连接端口
+ 'hostport' => env('SLAVE_HOSTPORT', '3306'),
+ // 数据库连接参数
+ 'params' => [
+ // 连接超时3秒
+ \PDO::ATTR_TIMEOUT => 3,
+ ],
+ // 数据库编码默认采用utf8
+ 'charset' => 'utf8mb4',
+ // 数据库表前缀
+ 'prefix' => '',
+ // 断线重连
+ 'break_reconnect' => true,
+ // 自定义分页类
+ 'bootstrap' => '',
+ // 连接池配置
+ 'pool' => [
+ 'max_connections' => 500, // 最大连接数
+ 'min_connections' => 20, // 最小连接数
+ 'wait_timeout' => 3, // 从连接池获取连接等待超时时间
+ 'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收
+ 'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒
+ ],
+ ],
+ 'duanju_slave_3' => [
+ // 数据库类型
+ 'type' => 'mysql',
+ // 服务器地址
+ 'hostname' => env('SLAVE_HOSTNAME', '127.0.0.1'),
+ // 数据库名
+ 'database' => 'duanju-3',
+ // 数据库用户名
+ 'username' => env('SLAVE_USERNAME', 'video_user'),
+ // 数据库密码
+ 'password' => env('SLAVE_PASSWORD', 'VideoUser@1'),
+ // 数据库连接端口
+ 'hostport' => env('SLAVE_HOSTPORT', '3306'),
+ // 数据库连接参数
+ 'params' => [
+ // 连接超时3秒
+ \PDO::ATTR_TIMEOUT => 3,
+ ],
+ // 数据库编码默认采用utf8
+ 'charset' => 'utf8mb4',
+ // 数据库表前缀
+ 'prefix' => '',
+ // 断线重连
+ 'break_reconnect' => true,
+ // 自定义分页类
+ 'bootstrap' => '',
+ // 连接池配置
+ 'pool' => [
+ 'max_connections' => 500, // 最大连接数
+ 'min_connections' => 20, // 最小连接数
+ 'wait_timeout' => 3, // 从连接池获取连接等待超时时间
+ 'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收
+ 'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒
+ ],
+ ],
+ 'duanju_slave_4' => [
+ // 数据库类型
+ 'type' => 'mysql',
+ // 服务器地址
+ 'hostname' => env('SLAVE_HOSTNAME', '127.0.0.1'),
+ // 数据库名
+ 'database' => 'duanju-4',
+ // 数据库用户名
+ 'username' => env('SLAVE_USERNAME', 'video_user'),
+ // 数据库密码
+ 'password' => env('SLAVE_PASSWORD', 'VideoUser@1'),
+ // 数据库连接端口
+ 'hostport' => env('SLAVE_HOSTPORT', '3306'),
+ // 数据库连接参数
+ 'params' => [
+ // 连接超时3秒
+ \PDO::ATTR_TIMEOUT => 3,
+ ],
+ // 数据库编码默认采用utf8
+ 'charset' => 'utf8mb4',
+ // 数据库表前缀
+ 'prefix' => '',
+ // 断线重连
+ 'break_reconnect' => true,
+ // 自定义分页类
+ 'bootstrap' => '',
+ // 连接池配置
+ 'pool' => [
+ 'max_connections' => 500, // 最大连接数
+ 'min_connections' => 20, // 最小连接数
+ 'wait_timeout' => 3, // 从连接池获取连接等待超时时间
+ 'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收
+ 'heartbeat_interval' => 50, // 心跳检测间隔,需要小于60秒
+ ],
+ ],
+ ],
+ 'db_map' => [
+ 'duanju_slave', 'duanju_slave_0', 'duanju_slave_1', 'duanju_slave_2', 'duanju_slave_3', 'duanju_slave_4',
+ ],
+ // 从主库
+ 'search_library' => 'duanju_slave',
+ 'z_library' => 'duanju_master',
+ // 主主库
+ // 数据库路由配置
+ 'route' => [
+ // user_id分库的表
+ 'user_money_details' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'sys_user_money_details' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'orders' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'course_collect' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'pay_details' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'disc_spinning_record' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'cash_out' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'course_user' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'tb_user' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'task_center_record' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'user_money' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'user_sign_record' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'invite_achievement' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'invite_money' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'user_info' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+ 'sys_user' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$user_id%5}'],
+
+ // course_id分库的表
+ 'course_details' => ['master' => 'duanju_master', 'slave' => 'duanju_slave_{$course_id%5}'],
+ ],
+];