chore: 添加静态资源文件和版本配置文件

添加大量图片、字体、音频等静态资源文件,包括用户界面图片、模板文件和安装界面素材
添加系统版本配置文件(.version)和常量定义文件(.constant)
更新供应商依赖文件,包括Symfony VarDumper组件和相关许可证文件
添加验证码配置文件(captcha.php)和.gitignore规则
This commit is contained in:
2026-03-06 20:14:23 +08:00
commit c9a98f342c
4485 changed files with 490986 additions and 0 deletions

View File

@@ -0,0 +1,138 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\services\community;
use app\services\BaseServices;
use crmeb\services\CacheService;
class CommunityCacheServices extends BaseServices
{
//帖子点赞
const COMMUNITY_LIKE = 'community_like';
//评论点赞
const COMMUNITY_COMMENT_LIKE = 'community_comment_like';
//浏览
const COMMUNITY_BROWSE = 'community_browse';
//是否关注
const COMMUNITY_INTEREST = 'community_interest';
//最新一条id
const COMMUNITY_NEWEST = 'community_newest';
//话题总数
const COMMUNITY_TOPIC_COUNT = 'community_topic_count';
/**
* 点赞操作
*
* @param int $id 被点赞对象的ID
* @param int $uid 执行点赞操作的用户ID
* @param string $type 点赞类型, 默认为社区点赞
*
* @return mixed 返回点赞操作的结果,通常是受影响的元素数量
* User: liusl
* DateTime: 2024/8/9 17:07
*/
public function setLike(int $id, int $uid, int $status = 1, string $type = self::COMMUNITY_LIKE)
{
$key = $type . '_' . $id;
$status == 1 ? CacheService::redisHandler()->sAdd($key, $uid) : CacheService::redisHandler()->sRem($key, $uid);
return true;
}
/**
* 是否点赞
* @param int $id
* @param int $uid
* @param string $type
* @return mixed
* User: liusl
* DateTime: 2024/8/9 17:07
*/
public function checkUserLike(int $id, int $uid, string $type = self::COMMUNITY_LIKE)
{
$key = $type . '_' . $id;
return CacheService::redisHandler()->sIsMember($key, $uid) ? 1 : 0;
}
/**
* 删除
* @param int $id
* @param int $uid
* @param string $type
* @return mixed
* User: liusl
* DateTime: 2024/8/28 16:35
*/
public function deleteKey(int $id, string $type = self::COMMUNITY_LIKE)
{
$key = $type . '_' . $id;
return CacheService::redisHandler()->del($key);
}
/**
* 多个帖子是否点赞
* @param array $ids
* @param int $uid
* @param string $type
* @return array
* User: liusl
* DateTime: 2024/8/9 17:19
*/
public function checkUserLikeMultiple(array $ids, int $uid, string $type = self::COMMUNITY_LIKE)
{
$userLikes = [];
foreach ($ids as $id) {
$userLikes[$id] = $this->checkUserLike($id, $uid, $type);
}
return $userLikes;
}
/**
* 存用户最新一条帖子
* @param int $uid
* @param int $id
* @return bool
* User: liusl
* DateTime: 2024/9/12 19:42
*/
public function setCommunityNewest(int $uid, int $id)
{
$key = self::COMMUNITY_NEWEST . $uid;
/** @var CacheService $cacheServices */
$cacheServices = app()->make(CacheService::class);
return $cacheServices->set($key, $id,0);
}
/**
* 检查用户是否已读作者最新一条帖子
* @param int $uid
* @param int $author_uid
* @return int
* User: liusl
* DateTime: 2024/9/12 19:58
*/
public function checkCommunityNewest(int $uid, int $author_uid)
{
$key = self::COMMUNITY_NEWEST . $author_uid;
/** @var CacheService $cacheServices */
$cacheServices = app()->make(CacheService::class);
$new_id = $cacheServices->get($key);
if (!$new_id) return 0;
return $this->checkUserLike((int)$new_id, $uid, self::COMMUNITY_BROWSE) ? 0 : 1;
}
}

View File

@@ -0,0 +1,413 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\services\community;
use app\dao\community\CommunityCommentDao;
use app\services\BaseServices;
use app\services\user\UserRelationServices;
use app\services\user\UserServices;
use crmeb\basic\BaseModel;
use crmeb\exceptions\AdminException;
use crmeb\services\FormBuilder as Form;
use think\annotation\Inject;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
use think\facade\Db;
use think\facade\Route as Url;
use think\Model;
/**
* 社区评价
* Class CommunityCommentServices
* @package app\services\community
* @mixin CommunityCommentDao
*/
class CommunityCommentServices extends BaseServices
{
/**
* @var CommunityCommentDao
*/
#[Inject]
protected CommunityCommentDao $dao;
/**
* 后台评价列表
* @param array $where
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function sysPage(array $where)
{
$where['is_del'] = 0;
[$page, $limit] = $this->getPageValue();
$list = $this->dao->getList($where, '*', ['communityTitle'], $page, $limit);
$verifyList = [];
if ($where['is_reply'] == 1) {
$verifyIds = array_column($list, 'id');
$verifyList = $this->dao->search(['reply_id' => $verifyIds, 'is_del' => 0])->group('reply_id')->field('count(*) as count,reply_id')->select()->toArray();
$verifyList = array_column($verifyList, 'count', 'reply_id');
}
$commentReplyIds = array_unique(array_filter(array_column($list, 'comment_reply_id')));
$commentReplyList = [];
if ($commentReplyIds) {
$commentReplyList = $this->dao->search(['id' => $commentReplyIds, 'is_del' => 0])->column('content', 'id');
}
/** @var CommunityUserServices $communityUserServices */
$communityUserServices = app()->make(CommunityUserServices::class);
if ($list) {
foreach ($list as &$item) {
//待审核数
$item['verify_count'] = $verifyList[$item['id']] ?? 0;
//回复上级内容
$item['comment_reply_content'] = $commentReplyList[$item['comment_reply_id']] ?? '-';
$userFormat = $communityUserServices->getUserFormat($item['type'], $item['uid'], $item);
$item['author'] = $userFormat['author'];
$item['author_image'] = $userFormat['author_image'];
}
}
$count = $this->dao->count($where);
return compact('list', 'count');
}
/**
* 移动端列表
* @param $where
* @param $field
* @param $with
* @param int $uid
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* User: liusl
* DateTime: 2024/8/29 11:00
*/
public function getList($where, $field = '*', $with = [], int $uid = 0)
{
/** @var CommunityCacheServices $communityCacheServices */
$communityCacheServices = app()->make(CommunityCacheServices::class);
/** @var CommunityUserServices $communityUserServices */
$communityUserServices = app()->make(CommunityUserServices::class);
$order = isset($where['reply_id']) && $where['reply_id'] ? 'add_time ASC' : 'add_time DESC';
$where['author_uid'] = $uid;
//
[$page, $limit] = $this->getPageValue();
$list = $this->dao->getList($where, $field, $with, $page, $limit, $order);
$count = $this->dao->count($where);
foreach ($list as &$item) {
$userFormat = $communityUserServices->getUserFormat($item['type'], $item['uid'], $item);
$item['author'] = $userFormat['author'];
$item['author_image'] = $userFormat['author_image'];
//回复给谁
if ($item['comment_reply_id']) {
$userFormat = $communityUserServices->getUserFormat($item['comment_reply_uid'] == 0 ? 0 : 2, $item['comment_reply_uid']);
$item['comment_author'] = $userFormat['author'] ?? '';
$item['comment_author_image'] = $userFormat['author_image'] ?? '';
}
$item['time_text'] = timeConverter(strtotime($item['add_time']));
if ($uid) {
//是否点赞
$item['isLike'] = $communityCacheServices->checkUserLike($item['id'], $uid, CommunityCacheServices::COMMUNITY_COMMENT_LIKE);
}
}
unset($item);
return compact('list', 'count');
}
/**
* 评论回复表单
* @param int $id
* @param int $is_verify
* @return mixed
*/
public function replayForm(int $id)
{
$f[] = Form::textarea('content', '回复内容:')->required('请输入回复原因');
return create_form('回复内容', $f, Url::buildUrl('/community/comment/reply/' . $id), 'post');
}
/**
* 审核表单
* @param int $id
* @param int $is_verify
* @return mixed
*/
public function verifyForm(int $id, int $is_verify = 1)
{
$f = [];
if ($is_verify == 1) {
$f[] = Form::radio('is_verify', '审核状态:', 1)->options([['value' => 1, 'label' => '通过'], ['value' => -1, 'label' => '拒绝']])->appendControl(-1, [
Form::textarea('refusal', '拒绝原因:')->required('请输入拒绝原因')]);
} else {
$f[] = Form::hidden('is_verify', '-2');
$f[] = Form::textarea('refusal', '下架原因:')->required('请输入下架原因');
}
return create_form($is_verify == 1 ? '评论审核' : '强制下架', $f, Url::buildUrl('/community/comment/set_verify/' . $id), 'post');
}
/**
* 创建虚拟评论表单
* @param int $id
* @param $store_id
* @return mixed
*/
public function createForm(int $id, $store_id = 0)
{
$field[] = Form::hidden('community_id', $id);
$field[] = Form::radio('type', '评论类型:', 0)->options([['value' => 0, 'label' => '商家评论'], ['value' => 3, 'label' => '虚拟评论']])->appendControl(3, [
Form::frameImage('avatar', '用户头像:', Url::buildUrl($store_id ? 'store/widget.images/index' : 'admin/widget.images/index', array('fodder' => 'avatar')))->icon('ios-add')->width('960px')->height('505px')->modal(['footer-hide' => true]),
Form::input('nickname', '用户名称:')->col(24),
Form::dateTime('add_time', '评论时间:', '')->placeholder('请选择评论时间(不选择默认当前添加时间)'),
]);
$field[] = Form::input('content', '评价文字:')->type('textarea');
return create_form('添加虚拟评论', $field, Url::buildUrl('/community/comment/save_fictitious'), 'POST');
}
/**
* 保存评论/回复
* @param int $community_id
* @param array $data
* @param int $id
* @param int $uid
* @return BaseModel|Model
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function saveComment(int $community_id, array $data, int $id = 0, int $uid = 0)
{
/** @var CommunityServices $communityServices */
$communityServices = app()->make(CommunityServices::class);
$community = $communityServices->get($community_id);
if (!$community) {
throw new ValidateException('社区不存在');
}
if ($id) {
//回复回复
$comment = $this->dao->get($id);
if (!$comment) {
throw new ValidateException('评论不存在或已删除');
}
$comment_uid = $comment['uid'];
if ($comment['is_reply'] == 1) {
$data['reply_id'] = $id;
$data['reply_uid'] = $comment_uid;
$comment->comment_num = $comment->comment_num + 1;
$comment->save();
} else {
//回复评论
$reply_comment = $this->dao->get($comment['reply_id']);
if (!$reply_comment) {
throw new ValidateException('评论不存在或已删除');
}
$reply_comment->comment_num = $reply_comment->comment_num + 1;
$reply_comment->save();
$data['reply_id'] = $comment->reply_id;
$data['reply_uid'] = $comment->reply_uid;
$data['comment_reply_id'] = $id;
$data['comment_reply_uid'] = $comment->uid;
}
} else {
$data['is_reply'] = 1;
}
if (isset($data['ip']) && $data['ip']) {
$data['city'] = $this->convertIp($data['ip']);
}
$time = time();
if (isset($data['add_time']) && $data['add_time']) {
$data['add_time'] = strtotime($data['add_time']);
if ($data['add_time'] > $time) {
throw new AdminException('评论时间应小于当前时间');
}
} else {
$data['add_time'] = $time;
}
$data['uid'] = $uid;
$data['community_id'] = $community_id;
$res = $this->dao->save($data);
if (!$res) throw new AdminException('保存评论失败');
event('community.comment.operate', [$res->id, 1]);
return $res;
}
/**
* 获取社区内容评价列表
* @param int $uid
* @param int $id
* @param int $pid
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getVideoCommentList(int $uid, int $id, int $pid = 0)
{
$where = ['community_id' => $id, 'is_del' => 0];
[$page, $limit] = $this->getPageValue();
if ($limit > 20) $limit = 20;
if ($pid) {
$comment = $this->dao->get($pid);
if (!$comment) {
throw new ValidateException('评论不存在或已删除');
}
$where['community_id'] = $comment['community_id'];
}
$where['pid'] = $pid;
$list = $this->dao->getList($where, 'id,pid,community_id,uid,nickname,avatar,content,like_num,city,add_time', ['children' => function ($query) {
$query->field("id,pid")->with(['userVip']);
}, 'userVip'], $page, $limit);
if ($list) {
$userLike = [];
if ($uid) {
$ids = array_column($list, 'id');
/** @var UserRelationServices $userRelationServices */
$userRelationServices = app()->make(UserRelationServices::class);
$userLike = $userRelationServices->getColumn([['uid', '=', $uid], ['relation_id', 'in', $ids], ['category', '=', 'video_comment'], ['type', '=', 'like']], 'id,relation_id', 'relation_id');
}
foreach ($list as &$item) {
// $item['add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : '';
$item['is_like'] = isset($userLike[$item['id']]);
$item['reply'] = [];
$item['reply_count'] = isset($item['children']) ? (int)count($item['children']) : 0;
$item['city'] = $this->addressHandle($item['city'])['city'] ?? '';
unset($item['children']);
}
}
return $list;
}
/**
* 点赞/取消
* @param array $info
* @param int $uid
* @param int $status
* @return void
* User: liusl
* DateTime: 2024/8/21 10:31
*/
public function setCommentLike(array $info, int $uid, int $status)
{
/** @var CommunityRelevanceServices $communityRelevanceServices */
$communityRelevanceServices = app()->make(CommunityRelevanceServices::class);
//是否存在点赞
$check = $communityRelevanceServices->checkHas($uid, $info['id'], CommunityRelevanceServices::TYPE_COMMUNITY_COMMENT_LIKE);
if ($status) {
if ($check) throw new ValidateException('您已经点过赞了~');
$communityRelevanceServices->create($uid, $info['id'], CommunityRelevanceServices::TYPE_COMMUNITY_COMMENT_LIKE, true);
} else {
if (!$check) throw new ValidateException('您还未赞过哦~');
$communityRelevanceServices->destory($uid, $info['id'], CommunityRelevanceServices::TYPE_COMMUNITY_COMMENT_LIKE);
}
event('community.like', [$info, $uid, 2, $status]);
}
/**
* 删除帖子
* @param int $id
* @param int $uid
* @param bool $is_admin
* @return true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* User: liusl
* DateTime: 2024/8/28 16:19
*/
public function commentDelete(int $id, int $uid = 0, bool $is_admin = false)
{
/** @var CommunityServices $communityServices */
$communityServices = app()->make(CommunityServices::class);
$info = $this->dao->get(['id' => $id, 'is_del' => 0]);
if (!$info) {
throw new ValidateException('评论不存在或已删除');
}
if ($info['uid'] != $uid && !$is_admin) {
throw new ValidateException('您无权删除该评论');
}
if ($info['is_reply'] == 1) {//评论帖子
$replyId = $this->dao->getColumn(['reply_id' => $id], 'id');
$replyId = array_merge([$id], $replyId);
//删除评论回复
$this->dao->update(['reply_id' => $id], ['is_del' => 1]);
}
$this->dao->decUpdate(['id' => $info['reply_id']], 'comment_num', 1);
$info->is_del = 1;
$info->save();
event('community.comment.delete', [$replyId ?? $id]);
event('community.comment.operate', [$id]);
return true;
}
/**
* 删除后续事件
* @param $id
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* User: liusl
* DateTime: 2024/8/28 16:47
*/
public function deleteFollow($id)
{
/** @var CommunityRelevanceServices $relevanceServices */
$relevanceServices = app()->make(CommunityRelevanceServices::class);
//删除点赞列表
$relevanceServices->batchDelete($id, CommunityRelevanceServices::TYPE_COMMUNITY_COMMENT_LIKE);
//清理缓存
}
/**
* 评论数量修正
* @param $id
* @return true
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* User: liusl
* DateTime: 2024/9/10 11:02
*/
public function syncCommentNum($id): bool
{
$info = $this->dao->get($id);
if (!$info) {
return true;
}
//帖子评论数量
$reply = $this->dao->count(['community_id' => $info['community_id'], 'is_verify' => 1, 'is_del' => 0]);
/** @var CommunityServices $communityServices */
$communityServices = app()->make(CommunityServices::class);
$communityServices->update(['id' => $info['community_id']], ['comment_num' => $reply ?: 0]);
if ($info['is_reply'] == 0) {
//子帖子数量
$reply = $this->dao->count(['reply_id' => $info['reply_id'], 'is_verify' => 1, 'is_del' => 0]);
$this->dao->update(['id' => $info['reply_id']], ['comment_num' => $reply ?: 0]);
}
return true;
}
}

View File

@@ -0,0 +1,109 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\services\community;
use app\dao\community\CommunityRecordDao;
use app\services\BaseServices;
use think\annotation\Inject;
/**
* 社区记录
* Class CommunityRecordServices
* @package app\services\community
* @mixin CommunityRecordDao
*/
class CommunityRecordServices extends BaseServices
{
/**
* @var CommunityRecordDao
*/
#[Inject]
protected CommunityRecordDao $dao;
//点赞
const SET_TYPE_LIKE = 1;
//评论
const SET_TYPE_COMMENT = 2;
//关注
const SET_TYPE_FOLLOW = 3;
/**
* 获取社区记录列表
* @param array $where 查询条件
* @param string $field 查询字段
* @param int $page 页码
* @param int $limit 每页数量
* @return array
*/
public function getList(array $where, string $field = '*', int $page = 0, int $limit = 0)
{
if (!$limit) {
[$page, $limit] = $this->getPageValue();
}
$list = $this->dao->search($where)
->when($limit && $page, function ($query) use ($page, $limit) {
$query->page($page, $limit);
})
->when($limit && !$page, function ($query) use ($limit) {
$query->limit($limit);
})
->field($field)
->order('add_time DESC')
->select()
->toArray();
$comment_ids = array_unique(array_column($list, 'link_id'));
$communityServices = app()->make(CommunityServices::class);
$communityUserServices = app()->make(CommunityUserServices::class);
$comment_list = $communityServices->getColumn(['id' => $comment_ids], 'image,content_type', 'id', true);
foreach ($list as &$item) {
$item['image'] = $comment_list[$item['link_id']]['image'] ?? '';
$item['content_type'] = $comment_list[$item['link_id']]['content_type'] ?? '';
$userFormat = $communityUserServices->getUserFormat($item['relation_id'] ? 2 : 0, $item['relation_id']);
$item['relation_author'] = $userFormat['author'];
$item['relation_author_image'] = $userFormat['author_image'];
$item['time_text'] = timeConverter($item['add_time']);
}
return $list;
}
/**
* 点赞评论关注是否查看
* @param $uid
* @return bool[]
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* User: liusl
* DateTime: 2025/1/2 上午11:46
*/
public function isViewed($uid)
{
$where = [
'uid' => $uid,
'is_viewed' => 0
];
$likeViewed = $this->dao->get($where + ['type' => self::SET_TYPE_LIKE]);
$commentViewed = $this->dao->get($where + ['type' => self::SET_TYPE_COMMENT]);
$followViewed = $this->dao->get($where + ['type' => self::SET_TYPE_FOLLOW]);
return [
'like' => $likeViewed ? 1 : 0,
'comment' => $commentViewed ? 1 : 0,
'follow' => $followViewed ? 1 : 0
];
}
}

View File

@@ -0,0 +1,52 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\services\community;
use app\dao\community\CommunityRelevanceDao;
use app\services\BaseServices;
use think\annotation\Inject;
use think\exception\ValidateException;
/**
* 社区关联
* Class CommunityRelevanceServices
* @package app\services\community
* @mixin CommunityRelevanceDao
*/
class CommunityRelevanceServices extends BaseServices
{
//社区关联商品
const TYPE_COMMUNITY_PRODUCT = 'community_product';
//社区关联话题
const TYPE_COMMUNITY_TOPIC = 'community_topic';
//社区帖子点赞
const TYPE_COMMUNITY_LIKE = 'community_like';
//帖子浏览
const TYPE_COMMUNITY_BROWSE = 'community_browse';
//社区评论点赞
const TYPE_COMMUNITY_COMMENT_LIKE = 'community_comment_like';
//关注
const TYPE_COMMUNITY_INTEREST = 'community_interest';
/**
* @var CommunityRelevanceDao
*/
#[Inject]
protected CommunityRelevanceDao $dao;
}

View File

@@ -0,0 +1,896 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\services\community;
use app\dao\community\CommunityDao;
use app\services\BaseServices;
use app\services\product\product\StoreProductServices;
use app\services\product\category\StoreProductCategoryServices;
use app\services\user\UserBillServices;
use app\services\user\UserServices;
use app\services\wechat\WechatUserServices;
use crmeb\services\FormBuilder as Form;
use crmeb\services\wechat\MiniProgram;
use think\annotation\Inject;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
use think\facade\Db;
use think\facade\Route as Url;
/**
* 社区
* Class CommunityServices
* @package app\services\community
* @mixin CommunityDao
*/
class CommunityServices extends BaseServices
{
/**
* 移动端社区内容需要默认值
* @var array
*/
protected array $videoDefault = [
'isMore' => false,
'state' => "pause",
'playIng' => false,
'isShowimage' => false,
'isShowProgressBarTime' => false,
'isplay' => true
];
/**
* @var CommunityDao
*/
#[Inject]
protected CommunityDao $dao;
/**
* 获取话题信息(获取不到抛出异常)
* @param int $id
* @param string $field
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getCommunityInfo(int $id, string $field = '*')
{
$videoInfo = $this->dao->getOne(['id' => $id], $field);
if (!$videoInfo) {
throw new ValidateException('获取社区内容信息失败');
}
return $videoInfo->toArray();
}
/**
* 获取社区内容详情
* @param int $id
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getInfo(int $id)
{
$info = $this->dao->get($id);
if (!$info) {
throw new ValidateException('社区内容不存在');
}
$info = $info->toArray();
$site_name = sys_config('site_name');
$site_image = sys_config('wap_login_logo');
$info['author'] = $site_name;
$info['author_image'] = $site_image;
if ($info['type'] == 2) {//用户
/** @var UserServices $userServices */
$userServices = app()->make(UserServices::class);
$userInfo = $userServices->getUserCacheInfo((int)$info['relation_id']);
$info['author'] = $userInfo['nickname'] ?? '';
$info['author_image'] = $userInfo['avatar'] ?? '';
}
$topic = [];
if ($info['topic_id']) {
$info['topic_id'] = is_string($info['topic_id']) ? explode(',', $info['topic_id']) : $info['topic_id'];
/** @var CommunityTopicServices $communityTopicServices */
$communityTopicServices = app()->make(CommunityTopicServices::class);
$topic = $communityTopicServices->getColumn([['id', 'in', $info['topic_id']]], 'id,name');
}
$info['topic'] = $topic;
$productInfo = [];
if ($info['product_id']) {
$info['product_id'] = is_string($info['product_id']) ? explode(',', $info['product_id']) : $info['product_id'];
/** @var StoreProductServices $productServices */
$productServices = app()->make(StoreProductServices::class);
$product_where = ['is_del' => 0, 'is_show' => 1, 'is_verify' => 1];
$productInfo = $productServices->getSearchList($product_where + ['ids' => $info['product_id']], 0, 0, ['id', 'type', 'product_type', 'price', 'image', 'store_name', 'cate_id', 'sales', 'stock'], '', []);
if ($productInfo) {
$cateIds = implode(',', array_column($productInfo, 'cate_id'));
/** @var StoreProductCategoryServices $categoryService */
$categoryService = app()->make(StoreProductCategoryServices::class);
$cateList = $categoryService->getCateParentAndChildName($cateIds);
foreach ($productInfo as $key => &$item) {
$item['cate_name'] = '';
if (isset($item['cate_id']) && $item['cate_id']) {
$cate_ids = explode(',', $item['cate_id']);
$cate_name = $categoryService->getCateName($cate_ids, $cateList);
if ($cate_name) {
$item['cate_name'] = is_array($cate_name) ? implode(',', $cate_name) : '';
}
}
}
}
}
$info['productInfo'] = $productInfo;
return $info;
}
/**
* 社区顶部header
* @param array $where
* @return array[]
* @throws \think\db\exception\DbException
*/
public function getHeader(array $where = [])
{
if (isset($where['store_id']) && $where['store_id']) {
$where['type'] = 1;
$where['relation_id'] = $where['store_id'];
unset($where['store_id']);
}
//已发布
$onPublish = $this->dao->count(['is_verify' => 1] + $where);
//待审核
$unVerify = $this->dao->count(['is_verify' => 0] + $where);
//审核未通过
$verifyFail = $this->dao->count(['is_verify' => -1] + $where);
//强制下架
$remove = $this->dao->count(['is_verify' => -2] + $where);
return [
['is_verify' => 1, 'name' => '已发布', 'count' => $onPublish],
['is_verify' => 0, 'name' => '待审核', 'count' => $unVerify],
['is_verify' => -1, 'name' => '审核未通过', 'count' => $verifyFail],
['is_verify' => -2, 'name' => '强制下架', 'count' => $remove],
];
}
/**
* 社区内容列表
* @param $where
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getList(array $where, array $with = [], string $order = '', int $uid = 0)
{
[$page, $limit] = $this->getPageValue();
$list = $this->dao->getList($where, '*', $page, $limit, $with, $order);
$count = $this->dao->count($where);
$site_name = sys_config('site_name');
$site_image = sys_config('wap_login_logo');
/** @var UserServices $userServices */
$userServices = app()->make(UserServices::class);
$communityTopicServices = app()->make(CommunityTopicServices::class);
$topicList = array_column($list, 'topic');
$topIds = [];
foreach ($topicList as $topic) {
foreach ($topic as $item) {
if (!isset($topIds[$item['right_id']])) {
$topIds[$item['right_id']] = $item['right_id'];
}
}
}
$_topicList = $communityTopicServices->getColumn(['id' => $topIds], 'name', 'id', true);
foreach ($list as &$item) {
$topicName = array_filter(array_map(function ($v) use ($_topicList) {
return $_topicList[$v['right_id']] ?? null;
}, $item['topic']));
$item['topicName'] = implode(',', $topicName);
$item['author'] = $site_name;
$item['author_image'] = $site_image;
if ($item['type'] == 2) {//用户
$userInfo = $userServices->getUserCacheInfo((int)$item['relation_id']);
$item['author'] = $userInfo['nickname'] ?? '';
$item['author_image'] = $userInfo['avatar'] ?? '';
}
}
return compact('list', 'count');
}
/**
* 移动端列表
* @param array $where
* @param $uid
* @return array
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* User: liusl
* DateTime: 2024/8/13 11:46
*/
public function getApiList(array $where, $uid = 0, $order = 'add_time desc')
{
[$page, $limit] = $this->getPageValue();
$order_by_id = [];
if (isset($where['start_id']) && $where['start_id']) {
$start_id = $where['start_id'];
unset($where['start_id']);
$order_by_id = array_merge([(int)$start_id], $this->dao->getIdColumn(array_merge(['notId' => $start_id], $where), 'id', $limit));
}
$list = $this->dao->search($where)
->with(
[
'product' => function ($product) {
$product->with(['product']);
},
'topic' => function ($topic) {
$topic->with(['topic']);
}
]
)->when(true, function ($query) use ($order_by_id, $order) {
if ($order_by_id) {
$query->whereIn('id', $order_by_id)->orderRaw('FIELD(id,' . implode(',', $order_by_id) . ')');
} else {
$query->order($order);
}
})
->page($page, $limit)->select()->toArray();
/** @var CommunityCacheServices $communityCacheServices */
$communityCacheServices = app()->make(CommunityCacheServices::class);
/** @var CommunityUserServices $communityUserServices */
$communityUserServices = app()->make(CommunityUserServices::class);
foreach ($list as &$item) {
$item['time_text'] = timeConverter(strtotime($item['add_time']));
$userFormat = $communityUserServices->getUserFormat($item['type'], $item['relation_id']);
$item['author'] = $userFormat['author'];
$item['author_image'] = $userFormat['author_image'];
if ($item['product']) {
$productList = [];
$productIds = [];
foreach ($item['product'] as $pro) {
if (isset($pro['product']) && $pro['product']) {
$productIds[] = $pro['product']['id'];
$productList[] = $pro['product'];
}
}
$productCount = count($productList);
$item['product'] = $productList;
$item['product_id'] = $productIds;
$item['productCount'] = $productCount;
}
if ($item['topic']) {
$topicList = [];
foreach ($item['topic'] as $top) {
if (isset($top['topic']) && $top['topic']) {
$topicList[] = $top['topic'];
}
}
$item['topic'] = $topicList;
}
if ($uid) {
//是否是自己
$item['is_self'] = $uid == $item['relation_id'] ? 1 : 0;
//是否点赞
$item['is_like'] = $communityCacheServices->checkUserLike($item['id'], $uid);
//是否关注
$item['is_follow'] = $communityCacheServices->checkUserLike($item['relation_id'], $uid, CommunityCacheServices::COMMUNITY_INTEREST);
}
}
return $list;
}
/**
* 移动端详情
* @param $id
* @param int $uid
* @return array
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* User: liusl
* DateTime: 2024/8/13 11:34
*/
public function getDetail(int $id, int $uid = 0, $is_admin = false)
{
/** @var CommunityUserServices $communityUserServices */
$communityUserServices = app()->make(CommunityUserServices::class);
/** @var CommunityCacheServices $communityCacheServices */
$communityCacheServices = app()->make(CommunityCacheServices::class);
$where = [
'id' => $id,
'is_del' => 0
];
$info = $this->dao->search($where)
->with(
[
'product' => function ($product) {
$product->with(['product']);
},
'topic' => function ($topic) {
$topic->with(['topic']);
}
]
)->find();
if (!$info) {
throw new ValidateException('数据不存在');
}
if (($info['is_verify'] != 1 || $info['status'] != 1) && $uid != $info['relation_id'] && !$is_admin) {
throw new ValidateException('数据不存在');
}
$info = $info->toArray();
$userFormat = $communityUserServices->getUserFormat($info['type'], $info['relation_id']);
$info['author'] = $userFormat['author'];
$info['author_image'] = $userFormat['author_image'];
$info['is_self'] = $uid == $info['relation_id'] ? 1 : 0;
if ($info['product']) {
$productList = [];
$productIds = [];
foreach ($info['product'] as $pro) {
if (isset($pro['product']) && $pro['product']) {
$productIds[] = $pro['product']['id'];
$productList[] = $pro['product'];
}
}
$productCount = count($productList);
$info['product'] = $productList;
$info['product_id'] = $productIds;
$info['productCount'] = $productCount;
}
if ($is_admin) {
$communityRelevanceServices = app()->make(CommunityRelevanceServices::class);
$communityTopicServices = app()->make(CommunityTopicServices::class);
$topicIds = $communityRelevanceServices->search(['left_id' => $id, 'type' => CommunityRelevanceServices::TYPE_COMMUNITY_TOPIC])->column('right_id');
$info['topic'] = count($topicIds) ? $communityTopicServices->search(['id' => $topicIds])->field('id,name')->select()->toArray() : [];
} else {
if ($info['topic']) {
$topicList = [];
foreach ($info['topic'] as $top) {
if (isset($top['topic']) && $top['topic']) {
$topicList[] = $top['topic'];
}
}
$info['topic'] = $topicList;
}
}
$info['is_like'] = $info['is_follow'] = 0;
if ($uid) {
//是否点赞
$info['is_like'] = $communityCacheServices->checkUserLike($info['id'], $uid);
//是否关注
$info['is_follow'] = $communityCacheServices->checkUserLike($info['relation_id'], $uid, CommunityCacheServices::COMMUNITY_INTEREST);
}
$this->setBrowse($id, $uid);
return $info;
}
/**
* 增加浏览量
*
* 该方法用于增加特定内容的浏览量,并记录用户的浏览行为。它首先检查是否存在指定的内容,
* 如果内容存在,则增加其浏览量。同时,通过调用缓存服务检查用户是否已经浏览过该内容,
* 如果没有,则记录用户的浏览行为,并通过相关服务创建一条浏览相关的记录。
*
* @param int $id 内容ID,标识要增加浏览量的内容。
* @param int $uid 用户ID,标识正在浏览内容的用户。
*
* @return bool 总是返回true,表示操作成功。
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function setBrowse(int $id, int $uid = 0): bool
{
// 获取内容信息
$info = $this->dao->get($id);
if (!$info) return true;
$info->play_num = $info->play_num + 1;
$info->save();
if (!$uid) return true;
// 浏览记录
/** @var CommunityCacheServices $communityCacheServices */
$communityCacheServices = app()->make(CommunityCacheServices::class);
/** @var CommunityRelevanceServices $communityRelevanceServices */
$communityRelevanceServices = app()->make(CommunityRelevanceServices::class);
// 检查用户是否已经浏览过该内容
if (!$communityCacheServices->checkUserLike($id, $uid, CommunityCacheServices::COMMUNITY_BROWSE)) {
// 如果用户未浏览过,记录用户的浏览行为
$communityCacheServices->setLike($id, $uid, 1, CommunityCacheServices::COMMUNITY_BROWSE);
// 创建一条浏览相关的记录
$communityRelevanceServices->create($uid, $id, CommunityRelevanceServices::TYPE_COMMUNITY_BROWSE, true);
}
return true;
}
/**
* 设置推荐指数表单
* @param int $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function setStarForm(int $id)
{
$info = [];
if ($id) {
$info = $this->getCommunityInfo($id);
}
$field[] = Form::rate('star', '推荐指数:', $info['star'] ?? 1)->allowHalf(false);
return create_form('推荐指数', $field, Url::buildUrl('/community/community/star/' . $id), 'POST');
}
/**
* 商品审核表单
* @param int $id
* @param int $is_verify
* @return mixed
*/
public function verifyForm(int $id, int $is_verify = 1)
{
$f = [];
if ($is_verify == 1) {
$f[] = Form::radio('is_verify', '审核状态:', 1)->options([['value' => 1, 'label' => '通过'], ['value' => -1, 'label' => '拒绝']])->appendControl(-1, [
Form::textarea('refusal', '拒绝原因:')->required('请输入拒绝原因')]);
} else {
$f[] = Form::hidden('is_verify', '-2');
$f[] = Form::textarea('refusal', '下架原因:')->required('请输入下架原因');
}
return create_form($is_verify == 1 ? '内容审核' : '强制下架', $f, Url::buildUrl('/community/community/set_verify/' . $id), 'post');
}
/**
* 添加
* @param array $data
* @param bool $is_admin
* @return void
* User: liusl
* DateTime: 2024/8/7 15:17
*/
public function saveData(array $data, int $id = 0, bool $is_admin = false)
{
$data['type'] = $is_admin ? 0 : 2;
$extractedData = [
'topic_id' => $data['topic_id'],
'topic_name' => $data['topic_name'] ?? [],
'product_id' => $data['product_id']
];
unset($data['topic_id'], $data['product_id']);
//敏感词
// MiniProgram::msgSecCheck($data['title'] . $data['content']);
$id = $this->transaction(function () use ($data, $id, $extractedData) {
if ($id) {
$data['refusal'] = '';
$res = $this->dao->update($id, $data);
$this->extractedDelete($id);
} else {
$data['add_time'] = time();
$res = $this->dao->save($data);
if ($data['is_verify'] == 1) {
/** @var CommunityCacheServices $communityCacheServices */
$communityCacheServices = app()->make(CommunityCacheServices::class);
$communityCacheServices->setCommunityNewest($data['relation_id'], $res->id);
}
}
/** @var CommunityUserServices $communityUserServices */
$communityUserServices = app()->make(CommunityUserServices::class);
if (!$communityUserServices->get(['type' => 0, 'relation_id' => 0])) {
$communityUserServices->save(['type' => 0, 'relation_id' => 0, 'add_time' => time()]);
}
$id = $id ?: $res->id;
$this->extractedFormat($id, $extractedData);
return $id;
});
event('community.operate', [$id, 1]);
return true;
}
/**
* 添加关联
* @param $id
* @param $data
* @return void
* User: liusl
* DateTime: 2024/8/7 16:24
*/
public function extractedFormat($id, $data)
{
/** @var CommunityRelevanceServices $relevanceServices */
$relevanceServices = app()->make(CommunityRelevanceServices::class);
$communityTopicServices = app()->make(CommunityTopicServices::class);
$save = [];
if (count($data['topic_name']) > 0) {
foreach ($data['topic_name'] as $v) {
$topicInfo = $communityTopicServices->get(['name' => $v]);
$topicId = $topicInfo ? $topicInfo['id'] : $communityTopicServices->save([
'name' => $v,
'type' => 2,
'is_del' => -1,
'add_time' => time()
])->id;
$save[] = [
'left_id' => $id,
'right_id' => $topicId,
'type' => CommunityRelevanceServices::TYPE_COMMUNITY_TOPIC
];
}
}
if (count($data['topic_id']) > 0) {
foreach ($data['topic_id'] as $v) {
$save[] = [
'left_id' => $id,
'right_id' => $v,
'type' => CommunityRelevanceServices::TYPE_COMMUNITY_TOPIC
];
}
}
if (count($data['product_id']) > 0) {
foreach ($data['product_id'] as $v) {
$save[] = [
'left_id' => $id,
'right_id' => $v,
'type' => CommunityRelevanceServices::TYPE_COMMUNITY_PRODUCT
];
}
}
if (count($save) > 0) {
$relevanceServices->saveAll($save);
}
}
/**
* 删除关联
* @param $id
* @return void
* User: liusl
* DateTime: 2024/8/7 16:24
*/
public function extractedDelete($id)
{
/** @var CommunityRelevanceServices $relevanceServices */
$relevanceServices = app()->make(CommunityRelevanceServices::class);
$rel_types = [CommunityRelevanceServices::TYPE_COMMUNITY_TOPIC, CommunityRelevanceServices::TYPE_COMMUNITY_PRODUCT];
$relevanceServices->batchDelete($id, $rel_types);
}
/**
* 点赞取消点赞
* @param array $info
* @param int $uid
* @param int $status
* @return void
* User: liusl
* DateTime: 2024/8/13 14:45
*/
public function setCommunityLike(array $info, int $uid, int $status)
{
/** @var CommunityRelevanceServices $communityRelevanceServices */
$communityRelevanceServices = app()->make(CommunityRelevanceServices::class);
//是否存在点赞
$check = $communityRelevanceServices->checkHas($uid, $info['id'], CommunityRelevanceServices::TYPE_COMMUNITY_LIKE);
if ($status) {
if ($check) throw new ValidateException('您已经点过赞了~');
$communityRelevanceServices->create($uid, $info['id'], CommunityRelevanceServices::TYPE_COMMUNITY_LIKE, true);
} else {
if (!$check) throw new ValidateException('您还未赞过哦~');
$communityRelevanceServices->destory($uid, $info['id'], CommunityRelevanceServices::TYPE_COMMUNITY_LIKE);
}
event('community.like', [$info, $uid, 1, $status]);
}
/**
* 点赞列表/商品种草秀
* @param int $uid
* @return array
* @throws \ReflectionException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* User: liusl
* DateTime: 2024/8/24 15:58
*/
public function getJoinCommunityList(array $where = [], int $uid = 0, string $condition = 'right_id', int $limit = 0, string $order = 'r.id DESC')
{
/** @var CommunityRelevanceServices $communityRelevanceServices */
$communityRelevanceServices = app()->make(CommunityRelevanceServices::class);
/** @var CommunityUserServices $communityUserServices */
$communityUserServices = app()->make(CommunityUserServices::class);
/** @var CommunityCacheServices $communityCacheServices */
$communityCacheServices = app()->make(CommunityCacheServices::class);
if (!$limit) {
[$page, $limit] = $this->getPageValue();
}
$list = $communityRelevanceServices->joinCommunityList($where, $page ?? 0, $limit, $condition, $order);
$count = $communityRelevanceServices->joinCommunity($where, $condition)->count();
foreach ($list as &$item) {
if (!($item['c_id'] ?? '')) continue;
$userFormat = $communityUserServices->getUserFormat($item['c_type'], $item['relation_id']);
$item['author'] = $userFormat['author'];
$item['author_image'] = $userFormat['author_image'];
$item['slider_image'] = $item['slider_image'] ? json_decode($item['slider_image'], true) : [];
$item['id'] = $item['c_id'];
$item['is_like'] = $communityCacheServices->checkUserLike($item['id'], $uid);
unset($item['c_id'], $item['left_id'], $item['right_id'], $item['type']);
}
unset($item);
return compact('list', 'count');
}
/**
* 分享
* @param $id
* @param $uid
* @return true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* User: liusl
* DateTime: 2024/8/28 14:10
*/
public function communityShare($id)
{
$info = $this->dao->get(['id' => $id, 'is_del' => 0]);
if (!$info) throw new ValidateException('帖子不存在');
$info->share_num++;
$info->save();
return true;
}
/**
* 帖子删除
* @param $id
* @param $uid
* @param bool $is_admin
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
* User: liusl
* DateTime: 2024/8/28 14:23
*/
public function communityDelete(int $id, int $uid = 0, bool $is_admin = false)
{
$info = $this->dao->get(['id' => $id, 'is_del' => 0]);
if (!$info) throw new ValidateException('帖子不存在');
if (!$is_admin && $info['relation_id'] != $uid) throw new ValidateException('您没有权限删除该帖子');
$info->is_del = 1;
$info->save();
event('community.delete', [$id]);
//帖子操作事件
event('community.operate', [$id]);
}
/**
* 删除后续事件
* @param $id
* @return void
* User: liusl
* DateTime: 2024/8/28 14:24
* @throws \ReflectionException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function deleteFollow($id)
{
/** @var CommunityUserServices $communityUserServices */
$communityUserServices = app()->make(CommunityUserServices::class);
/** @var CommunityCommentServices $communityCommentServices */
$communityCommentServices = app()->make(CommunityCommentServices::class);
/** @var CommunityRelevanceServices $relevanceServices */
$relevanceServices = app()->make(CommunityRelevanceServices::class);
/** @var CommunityCacheServices $communityCacheServices */
$communityCacheServices = app()->make(CommunityCacheServices::class);
$info = $this->dao->get($id);
if (!$info) return;
//帖子评论删除
$communityCommentServices->update(['community_id' => $id], ['is_del' => 1]);
//关联表处理
$rel_types = [
CommunityRelevanceServices::TYPE_COMMUNITY_TOPIC,
CommunityRelevanceServices::TYPE_COMMUNITY_PRODUCT,
CommunityRelevanceServices::TYPE_COMMUNITY_LIKE,
CommunityRelevanceServices::TYPE_COMMUNITY_BROWSE
];
$relevanceServices->batchDelete($id, $rel_types);
//缓存删除
$communityCacheServices->deleteKey($id);
}
/**
* 话题帖子统计缓存
* @param $id
* @return mixed
* User: liusl
* DateTime: 2024/11/11 17:45
*/
public function topicCount(int $id)
{
return $this->dao->cacheTag()->remember(CommunityCacheServices::COMMUNITY_TOPIC_COUNT . $id, function () use ($id) {
return $this->getTopicCount($id);
}, 60 * 60 * 24);
}
/**
* 话题帖子统计
* @param $id
* @return int
* @throws DbException
* User: liusl
* DateTime: 2024/11/11 17:45
*/
public function getTopicCount(int $id)
{
/** @var CommunityRelevanceServices $communityRelevanceServices */
$communityRelevanceServices = app()->make(CommunityRelevanceServices::class);
return $communityRelevanceServices->joinCommunity(['topic_id' => $id], 'left_id')->count();
}
/**
* 话题帖子统计数据矫正
* @param $id
* @return true
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws \ReflectionException
* User: liusl
* DateTime: 2024/11/11 17:57
*/
public function syncTopicNum(int $id)
{
/** @var CommunityRelevanceServices $communityRelevanceServices */
$communityRelevanceServices = app()->make(CommunityRelevanceServices::class);
$list = $communityRelevanceServices->search(['left_id' => $id, 'type' => CommunityRelevanceServices::TYPE_COMMUNITY_TOPIC])->select()->toArray();
foreach ($list as $item) {
$count = $this->getTopicCount($item['right_id']);
$this->dao->cacheTag()->set(CommunityCacheServices::COMMUNITY_TOPIC_COUNT . $item['right_id'], $count);
}
return true;
}
/**
* 发帖审核后奖励积分经验
* @param $id //帖子id
* @return true
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws \ReflectionException
* User: liusl
* DateTime: 2024/12/3 下午2:56
*/
public function giveIncome($id)
{
$info = $this->dao->get($id);
// 经验开关
$communityExp = sys_config('community_exp');
// 积分开关
$communityIntegral = sys_config('community_integral');
// 检查是否启用了经验或积分系统,以及帖子是否审核
if (!$communityExp && !$communityIntegral || !$info || $info['is_verify'] != 1 || !$info['relation_id']) {
return true;
}
// 获取经验限制和每次增加的数量配置
$expRestrict = sys_config('community_exp_restrict');
$expNum = sys_config('community_exp_num');
// 获取积分限制和每次增加的数量配置
$integralNum = sys_config('community_integral_num');
$integralRestrict = sys_config('community_integral_restrict');
// 查询用户当天获得的经验和积分记录
$timestamp = strtotime($info['add_time']);
$startTime = strtotime('today', $timestamp);
$endTime = strtotime('tomorrow', $timestamp);
$userBillServices = app()->make(UserBillServices::class);
$billList = $userBillServices->search(['uid' => $info['relation_id'], 'type' => ['community_add_exp', 'community_add_integral']])
->whereBetween('obtain_time', [$startTime, $endTime])
->field('type,number')
->select()
->toArray();
$maxExpRestrict = $maxIntegralRestrict = 0;
foreach ($billList as $item) {
if ($item['type'] == 'community_add_exp') {
$maxExpRestrict += $item['number'];
} else {
$maxIntegralRestrict += $item['number'];
}
}
$userServices = app()->make(UserServices::class);
$userInfo = $userServices->get($info['relation_id']);
$updateData = [];
// 检查是否需要增加经验,经验开启,且用户今天没有超过限制,有赠送经验,且帖子没有被记录过
if ($communityExp && ($expRestrict == 0 || ($expRestrict > $maxExpRestrict && $expNum && !$userBillServices->get(['type' => 'community_add_exp', 'link_id' => $id])))) {
$updateData['exp'] = bcadd((string)$userInfo['exp'], (string)$expNum, 0);
$userBillServices->income('community_add_exp', $info['relation_id'], (int)$expNum, $updateData['exp'], $id, $timestamp);
}
// 检查是否需要增加积分,积分开启,且用户今天没有超过限制,有赠送积分,且帖子没有被记录过
if ($communityIntegral && ($integralNum != 0 || ($integralRestrict > $maxIntegralRestrict && $integralNum && !$userBillServices->get(['type' => 'community_add_integral', 'link_id' => $id])))) {
$updateData['integral'] = bcadd((string)$userInfo['integral'], (string)$integralNum, 0);
$userBillServices->income('community_add_integral', $info['relation_id'], (int)$integralNum, $updateData['integral'], $id, $timestamp);
}
// 如果有更新数据,则更新用户信息
if (!empty($updateData)) {
$userServices->update($userInfo['uid'], $updateData);
}
return true;
}
/**
* AI批量生成社区内容
* @param array $data AI生成的数据
* @return bool
*/
public function saveAllAiCommunity($data)
{
try {
foreach ($data as $item) {
$saveData = [
'content_type' => 1,
'title' => $item['title'],
'content' => $item['content'],
'image' => 'https://pro.crmeb.net/uploads/thumb_water/0e41012b7d7df9404ca456df1c7625c6.png',
'video_url' => '',
'slider_image' => json_encode(['https://pro.crmeb.net/uploads/thumb_water/0e41012b7d7df9404ca456df1c7625c6.png']),
'topic_id' => [],
'topic_name' => [$item['topic_name']],
'product_id' => [],
'status' => 0,
'is_recommend' => 1,
'star' => 1,
'sort' => 0,
'relation_id' => 0,
'is_verify' => 1,
'verify_time' => time(),
];
$this->saveData($saveData, 0, true);
}
} catch (\Throwable $e) {
}
return true;
}
}

View File

@@ -0,0 +1,129 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\services\community;
use app\dao\community\CommunityTopicDao;
use app\services\BaseServices;
use crmeb\services\FormBuilder as Form;
use think\annotation\Inject;
use think\facade\Route as Url;
/**
* 社区话题
* Class CommunityTopicServices
* @package app\services\community
* @mixin CommunityTopicDao
*/
class CommunityTopicServices extends BaseServices
{
/**
* @var CommunityTopicDao
*/
#[Inject]
protected CommunityTopicDao $dao;
/**
* 获取所有的话题列表
* @param array $where
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getAllTopic(array $where = [], $is_all = false)
{
$where['is_del'] = 0;
$is_community = $where['is_community'] ?? '';
unset($where['is_community']);
[$page, $limit] = $this->getPageValue();
if ($is_all) {
$page = $limit = 0;
}
$list = $this->dao->getList($where, 'id,name', [], $page, $limit);
if ($is_community) {
foreach ($list as &$item) {
$item['community_count'] = app()->make(CommunityServices::class)->topicCount($item['id']);
}
}
return $list;
}
/**
* 话题
* @param array $where
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function sysPage(array $where)
{
$where['is_del'] = 0;
[$page, $limit] = $this->getPageValue();
$list = $this->dao->getList($where, '*', [], $page, $limit);
if ($list) {
/** @var CommunityServices $communityServices */
$communityServices = app()->make(CommunityServices::class);
foreach ($list as &$item) {
$item['add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : '';
$item['community_num'] = $communityServices->count(['topic_id' => $item['id']]);
}
}
$count = $this->dao->count($where);
return compact('list', 'count');
}
/**
* 创建虚拟评论表单
* @param int $video_id
* @param $store_id
* @return mixed
*/
public function createForm(int $id)
{
$topic = [];
if ($id) {
$topic = $this->dao->get($id);
}
$field[] = Form::input('name', '话题名称:', $topic['name'] ?? '')->maxlength(10);
$field[] = Form::number('sort', '排序:', $topic['sort'] ?? 0)->min(0);
$field[] = Form::switches('is_recommend', '推荐:', (string)($topic['is_recommend'] ?? '1'))->falseValue('0')->trueValue('1')->openStr('打开')->closeStr('关闭')->size('large');
$field[] = Form::switches('status', '显示:', (string)($topic['status'] ?? '1'))->falseValue('0')->trueValue('1')->openStr('打开')->closeStr('关闭')->size('large');
return create_form('社区话题', $field, Url::buildUrl('/community/topic/save/' . $id), 'POST');
}
/**
* 修改状态
* @param $id
* @return true
* @throws \ReflectionException
* User: liusl
* DateTime: 2025/1/2 下午4:59\
*/
public function setStatus($id)
{
$info = app()->make(CommunityServices::class)->get($id);
if ($info['is_verify'] != 1) {
return true;
}
$ids = app()->make(CommunityRelevanceServices::class)->search(['left_id' => $id, 'type' => CommunityRelevanceServices::TYPE_COMMUNITY_TOPIC])->column('right_id');
if ($ids) {
$this->dao->search(['id' => $ids, 'is_del' => -1])->update(['is_del' => 0]);
}
return true;
}
}

View File

@@ -0,0 +1,439 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\services\community;
use app\dao\community\CommunityUserDao;
use app\services\agent\AgentLevelServices;
use app\services\BaseServices;
use app\services\user\level\SystemUserLevelServices;
use app\services\user\UserFriendsServices;
use app\services\user\UserServices;
use crmeb\services\CacheService;
use think\annotation\Inject;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
use think\Response;
/**
* 社区用户
* Class CommunityTopicServices
* @package app\services\community
* @mixin CommunityUserDao
*/
class CommunityUserServices extends BaseServices
{
/**
* @var CommunityUserDao
*/
#[Inject]
protected CommunityUserDao $dao;
/**
* 检查用户是否存在
* 此方法用于确认给定的用户ID是否已在社区中存在,如果不存在,则将其标记为存在
* @param int $uid 需要检查的用户ID,默认值为0,表示不特定用户
* @return bool 总是返回true,表示所有用户均被视为存在,特定逻辑处理在方法内部进行
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function hasUser(int $uid = 0)
{
if (!$uid) return true;
$this->cacheTag()->remember('community_is_user_cache_' . $uid, function () use ($uid) {
$info = $this->dao->get(['type' => 2, 'relation_id' => $uid, 'is_del' => 0]);
if (!$info) {
$this->dao->save(['type' => 2, 'relation_id' => $uid, 'add_time' => time()]);
}
return 1;
});
return true;
}
/**
* 主页
* @param int $authorUid //作者ID
* @param int $uid
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* User: liusl
* DateTime: 2024/8/22 12:06
*/
public function getInfo(int $authorUid, int $uid)
{
/** @var UserServices $userServices */
$userServices = app()->make(UserServices::class);
/** @var CommunityCacheServices $communityCacheServices */
$communityCacheServices = app()->make(CommunityCacheServices::class);
$site_name = sys_config('site_name');
$site_image = sys_config('wap_login_logo');
$friend_count = 0;
if ($authorUid == 0) {
$info = $this->dao->get(['type' => 0, 'is_del' => 0]);
} else {
$info = $this->dao->get(['type' => 2, 'relation_id' => $authorUid, 'is_del' => 0]);
$userInfo = app()->make(UserServices::class)->getUserCacheInfo($authorUid);
if (!$userInfo) {
throw new ValidateException('用户不存在~');
}
/** @var UserFriendsServices $userFriendsServices */
$userFriendsServices = app()->make(UserFriendsServices::class);
$friend = $userFriendsServices->getFriendUids($uid);
$friend = array_diff($friend, [$uid]);
$friend_count = count($friend);
}
if (!$info) {
throw new ValidateException('用户不存在~');
}
$info = $info->toArray();
$info['friend_count'] = $friend_count;
$info['author'] = $site_name;
$info['author_image'] = $site_image;
$info['level_name'] = '';
$info['vip_status'] = 0;
$info['is_self'] = 0;
$info['is_follow'] = $communityCacheServices->checkUserLike($authorUid, $uid, CommunityCacheServices::COMMUNITY_INTEREST);
if ($authorUid == $uid) {
$info['is_self'] = 1;
}
if ($authorUid != 0) {
$user = $userServices->get($authorUid);
$info['author'] = $user['nickname'];
$info['author_image'] = $user['avatar'];
$is_open_level = sys_config('member_func_status', 0);
if ($is_open_level && $user['level']) {
/** @var SystemUserLevelServices $levelServices */
$levelServices = app()->make(SystemUserLevelServices::class);
$levelInfo = $levelServices->getOne(['id' => $user['level']], 'id,grade');
$info['level_name'] = $levelInfo['grade'] ?? '';
}
//看付费会员是否开启
$is_open_member = sys_config('member_card_status', 0);
if ($is_open_member) {
if ($user['is_ever_level']) {
$info['vip_status'] = 1;//永久会员
} else {
if ($user['is_money_level'] && $user['overdue_time'] && $user['overdue_time'] > time()) {
$info['vip_status'] = 1;//开通了,没有到期
}
}
}
}
return $info;
}
/**
* 关注/取消关注
* @param int $authorUid
* @param int $uid
* @param int $status
* @return \think\Response|void
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* User: liusl
* DateTime: 2024/8/26 09:35
*/
public function setInterest(int $authorUid, int $uid, int $status)
{
/** @var CommunityRelevanceServices $communityRelevanceServices */
$communityRelevanceServices = app()->make(CommunityRelevanceServices::class);
/** @var CommunityCacheServices $communityCacheServices */
$communityCacheServices = app()->make(CommunityCacheServices::class);
$communityRecordServices = app()->make(CommunityRecordServices::class);
if ($authorUid == 0) {
$info = $this->dao->get(['type' => 0, 'relation_id' => 0]);
} else {
$info = $this->dao->getUserInfo($authorUid);
}
if (!$info)
return app('json')->fail('内容不存在');
//是否存在点赞
$check = $communityRelevanceServices->checkHas($uid, $authorUid, CommunityRelevanceServices::TYPE_COMMUNITY_INTEREST);
if ($status) {
if ($check) throw new ValidateException('您已经关注过了~');
$communityRelevanceServices->create($uid, $authorUid, CommunityRelevanceServices::TYPE_COMMUNITY_INTEREST, true);
//粉丝数量+1
$this->dao->incUpdate(['id' => $info['id']], 'fans_num');
//自己关注数量+1
$this->dao->incUpdate(['relation_id' => $uid], 'follow_num');
$communityRecordServices->save([
'uid' => $authorUid,
'relation_id' => $uid,
'type' => CommunityRecordServices::SET_TYPE_FOLLOW,
'add_time' => time()
]);
} else {
if (!$check) throw new ValidateException('您还未关注哦~');
$communityRelevanceServices->destory($uid, $authorUid, CommunityRelevanceServices::TYPE_COMMUNITY_INTEREST);
//粉丝数量-1
$this->dao->decUpdate(['id' => $info['id']], 'fans_num');
//自己关注数量-1
$this->dao->decUpdate(['relation_id' => $uid], 'follow_num');
}
$communityCacheServices->setLike($authorUid, $uid, $status, CommunityCacheServices::COMMUNITY_INTEREST);
}
/**
* 查询10条关注用户头像,是否发新作品
* @param int $uid
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws \ReflectionException
* User: liusl
* DateTime: 2024/9/13 16:09
*/
public function follow(int $uid)
{
/** @var CommunityRelevanceServices $communityRelevanceServices */
$communityRelevanceServices = app()->make(CommunityRelevanceServices::class);
/** @var CommunityCacheServices $communityCacheServices */
$communityCacheServices = app()->make(CommunityCacheServices::class);
/** @var CommunityUserServices $communityUserServices */
$communityUserServices = app()->make(CommunityUserServices::class);
$where['type'] = CommunityRelevanceServices::TYPE_COMMUNITY_INTEREST;
$where['left_id'] = $uid;
$list = $communityRelevanceServices->search($where)->column('right_id');
if (!$list) return [];
$netFollow = $followIds = [];
foreach ($list as $k => $v) {
if ($communityCacheServices->checkCommunityNewest($uid, $v)) {
$netFollow[] = $v;
unset($list[$k]);
}
}
$remainingCount = 10 - count($netFollow);
if ($remainingCount > 0) {
$followIds = array_slice($list, 0, $remainingCount);
$followIds = array_merge($netFollow, $followIds);
}
$followIds = $followIds ?: $netFollow;
$followList = $communityUserServices->search(['relation_id' => $followIds])->orderRaw('FIELD(relation_id,' . implode(',', $followIds) . ')')->select()->toArray();
$data = [];
foreach ($followList as &$item) {
$userFormat = $this->getUserFormat($item['type'], $item['relation_id']);
$user['author'] = $userFormat['author'];
$user['author_image'] = $userFormat['author_image'];
$user['relation_id'] = $item['relation_id'];
$user['is_new'] = in_array($item['relation_id'], $netFollow) ? 1 : 0;
$data[] = $user;
}
unset($item);
return $data;
}
/**
* 关注/粉丝列表
* @param int $uid
* @param string $type
* @return array|Response
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws \ReflectionException User: liusl
* DateTime: 2024/8/26 10:35
*/
public function followList(int $uid, string $type = 'follow')
{
if (!$uid) {
return app('json')->fail('参数错误');
}
[$page, $limit] = $this->getPageValue();
/** @var CommunityRelevanceServices $communityRelevanceServices */
$communityRelevanceServices = app()->make(CommunityRelevanceServices::class);
/** @var CommunityCacheServices $communityCacheServices */
$communityCacheServices = app()->make(CommunityCacheServices::class);
$where['type'] = CommunityRelevanceServices::TYPE_COMMUNITY_INTEREST;
$with = ['communityUser'];
if ($type == 'follow') {
$where['left_id'] = $uid;
} else {
$where['right_id'] = $uid;
$with = ['communityFans'];
}
$list = $communityRelevanceServices->search($where)->with($with)->page($page, $limit)->order('id desc')->select()->toArray();
$data = [];
foreach ($list as $item) {
$communityUser = $type == 'follow' ? ($item['communityUser'] ?? []) : ($item['communityFans'] ?? []);
$user = [];
if ($communityUser) {
$userFormat = $this->getUserFormat($communityUser['type'], $communityUser['relation_id']);
$user['author'] = $userFormat['author'];
$user['author_image'] = $userFormat['author_image'];
$user['community_num'] = $communityUser['community_num'];
$user['fans_num'] = $communityUser['fans_num'];
$user['relation_id'] = $communityUser['relation_id'];
if ($type == 'follow') {
//我关注对方
$user['is_follow'] = 1;
$user['is_fans'] = $communityCacheServices->checkUserLike($uid, $communityUser['relation_id'], CommunityCacheServices::COMMUNITY_INTEREST);
} else {
$user['is_fans'] = 1;
$user['is_follow'] = $communityCacheServices->checkUserLike($communityUser['relation_id'], $uid, CommunityCacheServices::COMMUNITY_INTEREST);
}
}
$data[] = $user;
}
return $data;
}
/**
* 我的好友
* @param $uid
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* User: liusl
* DateTime: 2024/8/26 12:00
*/
public function userFriend($uid)
{
/** @var UserFriendsServices $services */
$services = app()->make(UserFriendsServices::class);
/** @var CommunityCacheServices $communityCacheServices */
$communityCacheServices = app()->make(CommunityCacheServices::class);
[$page, $limit] = $this->getPageValue();
$uids = $services->getFriendUids($uid);
$uids = array_diff($uids, [$uid]);
if (!$uids) {
return [];
}
$list = $this->dao->getList(['relation_id' => $uids], '*', [], $page, $limit);
foreach ($list as &$item) {
$userFormat = $this->getUserFormat($item['type'], $item['relation_id']);
$item['author'] = $userFormat['author'];
$item['author_image'] = $userFormat['author_image'];
$item['is_fans'] = $communityCacheServices->checkUserLike($uid, $item['relation_id'], CommunityCacheServices::COMMUNITY_INTEREST);
$item['is_follow'] = $communityCacheServices->checkUserLike($item['relation_id'], $uid, CommunityCacheServices::COMMUNITY_INTEREST);
}
unset($item);
return $list;
}
/**
* 用户头像昵称
* @param int $type
* @param int $uid
* @return string[]
* User: liusl
* DateTime: 2024/8/26 10:31
*/
public function getUserFormat(int $type, int $uid, array $info = [])
{
/** @var UserServices $userServices */
$userServices = app()->make(UserServices::class);
if ($type == 2) {//用户
$userInfo = $userServices->getUserCacheInfo(($uid));
$data['author'] = $userInfo['nickname'] ?? '用户已注销';
$data['author_image'] = $userInfo['avatar'] ?? sys_config('h5_avatar');
$data['logout'] = $userInfo ? 0 : 1;
} else if ($type == 3) {//虚拟
$data['author'] = $info['nickname'] ?? '';
$data['author_image'] = $info['avatar'] ?? '';
} else {//平台
$data['author'] = sys_config('site_name');
$data['author_image'] = sys_config('wap_login_logo');
}
return $data;
}
/**
* 推荐
* @param int $uid
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* User: liusl
* DateTime: 2024/8/26 15:44
*/
public function recommendList(int $uid)
{
[$page, $limit] = $this->getPageValue();
/** @var CommunityRelevanceServices $communityRelevanceServices */
$communityRelevanceServices = app()->make(CommunityRelevanceServices::class);
/** @var CommunityCacheServices $communityCacheServices */
$communityCacheServices = app()->make(CommunityCacheServices::class);
$ids = $communityRelevanceServices->getColumn(['left_id' => $uid, 'type' => CommunityRelevanceServices::TYPE_COMMUNITY_INTEREST], 'right_id');
$ids = array_merge($ids, [$uid]);
$list = $this->dao->getList(['not_relation_id' => $ids, 'is_del' => 0, 'status' => 1, 'is_community_num' => 1], 'type,relation_id,community_num,fans_num', ['community'], $page, $limit, 'fans_num desc');
foreach ($list as &$item) {
$userFormat = $this->getUserFormat($item['type'], $item['relation_id']);
$item['author'] = $userFormat['author'];
$item['author_image'] = $userFormat['author_image'];
$item['is_follow'] = $communityCacheServices->checkUserLike($item['relation_id'], $uid, CommunityCacheServices::COMMUNITY_INTEREST);
}
unset($item);
return $list;
}
/**
* 用户发帖数据矫正
* @param $id
* @return void
* User: liusl
* DateTime: 2024/9/9 17:51
*/
public function syncUserNum($id)
{
/** @var CommunityServices $communityServices */
$communityServices = app()->make(CommunityServices::class);
$uid = $communityServices->value(['id' => $id], 'relation_id');
$count = $communityServices->getCount(['relation_id' => $uid, 'status' => 1, 'is_verify' => 1, 'is_del' => 0]);
$this->dao->update(['relation_id' => $uid], ['community_num' => $count]);
}
/**
* 用户注销后续事件
* @param $uid
* @return void
* @throws \ReflectionException
* User: liusl
* DateTime: 2024/12/26 下午4:06
*/
public function logoutAfter($uid)
{
//删除帖子
$communityServices = app()->make(CommunityServices::class);
$communityIds = $communityServices->getColumn(['type' => 2, 'relation_id' => $uid], 'id');
foreach ($communityIds as $communityId) {
event('community.delete', [$communityId]);
//帖子操作事件
event('community.operate', [$communityId]);
}
$communityServices->update(['type' => 2, 'relation_id' => $uid], ['is_del' => 1]);
//清空关注
$communityRelevanceServices = app()->make(CommunityRelevanceServices::class);
$authorUids = $communityRelevanceServices->getColumn(['left_id' => $uid, 'type' => CommunityRelevanceServices::TYPE_COMMUNITY_INTEREST], 'right_id');
$communityRelevanceServices->search(['left_id' => $uid, 'type' => CommunityRelevanceServices::TYPE_COMMUNITY_INTEREST])->delete();
$this->dao->search(['relation_id' => $authorUids])->dec('fans_num', 1)->update();
}
}