## GitHub 同步说明
| 项 | 内容 |
|:---|:---|
| 仓库 | https://github.com/fnvtk/cunkebao_v3 |
| 分支 | develop |
| 方向 | 本地 → GitHub(单向 push) |
| 是否拉取远程 | 否(未 fetch / pull / merge) |
| 是否改本地文件 | 否(仅 git add/commit,未编辑任何源文件正文) |
| 基准 commit | 0643e78a |
| 变更规模 | 709 files, +26436 / -3407 lines |
## 目录变更统计
| 目录 | 文件数 | 说明 |
|:---|---:|:---|
| 开发文档/ | 404 | 四端进行中/已完成需求、接口文档、官网需求、部署脚本 |
| Server/ | 95 | 后端 API、迁移脚本、触客宝/超管/存客宝服务 |
| Cunkebao/ | 85 | 移动端 H5、设备绑定、客服、转号审批等 |
| Touchkebao/ | 68 | PC 工作台、AI 获客、算力中心、Glass UI |
| SuperAdmin/ | 33 | 超管项目中心、算力计费、内容库 |
| 官网/ | 19 | 新增存客宝官网静态页(index/pricing/solutions 等) |
| .cursor/ | 3 | Cursor 规则与 Skill |
| .obsidian/ | 2 | Obsidian 工作区配置 |
## 重点新增/更新(本地为准)
- 官网/: 完整静态站点(index、pricing、manual、solutions、api)
- 开发文档/1、需求/修改/*_进行中_20260530.md(存客宝/触客宝/AI数智员工)
- 开发文档/1、需求/官网需求.md
- 开发文档/5、接口/开发进度_接口文档.md 等接口文档迭代
- Touchkebao Glass UI 与 P0 收尾、通道获客算力
- SuperAdmin 算力计费规则、项目工作台
## 刻意未上传(本地保留)
- node_modules/
- .DS_Store、.smart-env/
- .开发文档_nested_git_backup/(旧嵌套 git 备份)
- **/__pycache__/
## 验收
GitHub 浏览: https://github.com/fnvtk/cunkebao_v3/tree/develop
Co-authored-by: Cursor <cursoragent@cursor.com>
282 lines
9.0 KiB
PHP
282 lines
9.0 KiB
PHP
<?php
|
||
|
||
namespace app\chukebao\controller;
|
||
|
||
use library\ResponseHelper;
|
||
use think\Db;
|
||
use app\chukebao\model\ChatGroups;
|
||
|
||
class WechatGroupController extends BaseController
|
||
{
|
||
|
||
/**
|
||
* 获取分组列表
|
||
* @return \think\response\Json
|
||
* @throws \Exception
|
||
*/
|
||
public function getList()
|
||
{
|
||
// 公司维度分组,不强制校验 userId
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
$query = ChatGroups::where([
|
||
'companyId' => $companyId,
|
||
'isDel' => 0,
|
||
])
|
||
->order('groupType desc,sort desc,id desc');
|
||
|
||
$total = $query->count();
|
||
$list = $query->select();
|
||
|
||
// 处理每个分组的数据
|
||
$list = is_array($list) ? $list : $list->toArray();
|
||
foreach ($list as $k => &$v) {
|
||
$v['createTime'] = !empty($v['createTime']) ? date('Y-m-d H:i:s', $v['createTime']) : '';
|
||
}
|
||
unset($v);
|
||
|
||
return ResponseHelper::success(['list'=>$list,'total'=>$total]);
|
||
}
|
||
|
||
/**
|
||
* 新增分组
|
||
* @return \think\response\Json
|
||
* @throws \Exception
|
||
*/
|
||
public function create()
|
||
{
|
||
$groupName = $this->request->param('groupName', '');
|
||
$groupMemo = $this->request->param('groupMemo', '');
|
||
$groupType = $this->request->param('groupType', 1);
|
||
$sort = $this->request->param('sort', 0);
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
// 只校验公司维度
|
||
if (empty($companyId)) {
|
||
return ResponseHelper::error('请先登录');
|
||
}
|
||
|
||
if (empty($groupName)) {
|
||
return ResponseHelper::error('分组名称不能为空');
|
||
}
|
||
|
||
// 验证分组类型
|
||
if (!in_array($groupType, [1, 2])) {
|
||
return ResponseHelper::error('无效的分组类型');
|
||
}
|
||
|
||
Db::startTrans();
|
||
try {
|
||
$chatGroup = new ChatGroups();
|
||
$chatGroup->groupName = $groupName;
|
||
$chatGroup->groupMemo = $groupMemo;
|
||
$chatGroup->groupType = $groupType;
|
||
$chatGroup->sort = $sort;
|
||
$chatGroup->userId = $this->getUserInfo('id');
|
||
$chatGroup->companyId = $companyId;
|
||
$chatGroup->createTime = time();
|
||
$chatGroup->isDel = 0;
|
||
$chatGroup->save();
|
||
|
||
Db::commit();
|
||
return ResponseHelper::success(['id' => $chatGroup->id], '创建成功');
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
return ResponseHelper::error('创建失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新分组
|
||
* @return \think\response\Json
|
||
* @throws \Exception
|
||
*/
|
||
public function update()
|
||
{
|
||
$id = $this->request->param('id', 0);
|
||
$groupName = $this->request->param('groupName', '');
|
||
$groupMemo = $this->request->param('groupMemo', '');
|
||
$groupType = $this->request->param('groupType', 1);
|
||
$sort = $this->request->param('sort', 0);
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
if (empty($companyId)) {
|
||
return ResponseHelper::error('请先登录');
|
||
}
|
||
|
||
if (empty($id)) {
|
||
return ResponseHelper::error('参数缺失');
|
||
}
|
||
|
||
if (empty($groupName)) {
|
||
return ResponseHelper::error('分组名称不能为空');
|
||
}
|
||
|
||
// 验证分组类型
|
||
if (!in_array($groupType, [1, 2])) {
|
||
return ResponseHelper::error('无效的分组类型');
|
||
}
|
||
|
||
// 检查分组是否存在
|
||
$chatGroup = ChatGroups::where([
|
||
'id' => $id,
|
||
'companyId' => $companyId,
|
||
'isDel' => 0,
|
||
])->find();
|
||
|
||
if (empty($chatGroup)) {
|
||
return ResponseHelper::error('该分组不存在或已删除');
|
||
}
|
||
|
||
Db::startTrans();
|
||
try {
|
||
$chatGroup->groupName = $groupName;
|
||
$chatGroup->groupMemo = $groupMemo;
|
||
$chatGroup->groupType = $groupType;
|
||
$chatGroup->sort = $sort;
|
||
$chatGroup->save();
|
||
|
||
Db::commit();
|
||
return ResponseHelper::success('', '更新成功');
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
return ResponseHelper::error('更新失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 删除分组(假删除)
|
||
* @return \think\response\Json
|
||
* @throws \Exception
|
||
*/
|
||
public function delete()
|
||
{
|
||
$id = $this->request->param('id', 0);
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
if (empty($companyId)) {
|
||
return ResponseHelper::error('请先登录');
|
||
}
|
||
|
||
if (empty($id)) {
|
||
return ResponseHelper::error('参数缺失');
|
||
}
|
||
|
||
// 检查分组是否存在
|
||
$chatGroup = ChatGroups::where([
|
||
'id' => $id,
|
||
'companyId' => $companyId,
|
||
'isDel' => 0,
|
||
])->find();
|
||
|
||
if (empty($chatGroup)) {
|
||
// 幂等:已软删则视为成功,避免前端缓存重复删报「不存在」
|
||
$alreadyDeleted = ChatGroups::where([
|
||
'id' => $id,
|
||
'companyId' => $companyId,
|
||
'isDel' => 1,
|
||
])->find();
|
||
if (!empty($alreadyDeleted)) {
|
||
return ResponseHelper::success('', '删除成功');
|
||
}
|
||
return ResponseHelper::error('该分组不存在或已删除');
|
||
}
|
||
|
||
Db::startTrans();
|
||
try {
|
||
// 1. 假删除当前分组
|
||
$chatGroup->isDel = 1;
|
||
$chatGroup->deleteTime = time();
|
||
$chatGroup->save();
|
||
|
||
// 2. 重置该分组下所有好友的分组ID(s2_wechat_friend.groupIds -> 0)
|
||
Db::table('s2_wechat_friend')
|
||
->where('groupIds', $id)
|
||
->update(['groupIds' => 0]);
|
||
|
||
// 3. 重置该分组下所有微信群的分组ID(s2_wechat_chatroom.groupIds -> 0)
|
||
Db::table('s2_wechat_chatroom')
|
||
->where('groupIds', $id)
|
||
->update(['groupIds' => 0]);
|
||
|
||
Db::commit();
|
||
return ResponseHelper::success('', '删除成功');
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
return ResponseHelper::error('删除失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 移动分组(将好友或群移动到指定分组)
|
||
* @return \think\response\Json
|
||
* @throws \Exception
|
||
*/
|
||
public function move()
|
||
{
|
||
// type: friend 好友, chatroom 群
|
||
$type = $this->request->param('type', 'friend');
|
||
$targetId = (int)$this->request->param('groupId', 0);
|
||
// 仅支持单个ID移动
|
||
$idParam = $this->request->param('id', 0);
|
||
$companyId = $this->getUserInfo('companyId');
|
||
|
||
if (empty($companyId)) {
|
||
return ResponseHelper::error('请先登录');
|
||
}
|
||
|
||
if (empty($targetId)) {
|
||
return ResponseHelper::error('目标分组ID不能为空');
|
||
}
|
||
|
||
// 仅允许单个 ID,禁止批量
|
||
$moveId = (int)$idParam;
|
||
if (empty($moveId)) {
|
||
return ResponseHelper::error('需要移动的ID不能为空');
|
||
}
|
||
|
||
// 校验目标分组是否存在且属于当前公司
|
||
$targetGroup = ChatGroups::where([
|
||
'id' => $targetId,
|
||
'companyId' => $companyId,
|
||
'isDel' => 0,
|
||
])->find();
|
||
|
||
if (empty($targetGroup)) {
|
||
return ResponseHelper::error('目标分组不存在或已删除');
|
||
}
|
||
|
||
// 校验分组类型与移动对象类型是否匹配
|
||
// groupType: 1=好友分组, 2=群分组
|
||
if ($type === 'friend' && (int)$targetGroup->groupType !== 1) {
|
||
return ResponseHelper::error('目标分组类型错误(需要好友分组)');
|
||
}
|
||
if ($type === 'chatroom' && (int)$targetGroup->groupType !== 2) {
|
||
return ResponseHelper::error('目标分组类型错误(需要群分组)');
|
||
}
|
||
|
||
Db::startTrans();
|
||
try {
|
||
if ($type === 'friend') {
|
||
// 移动单个好友到指定分组:更新 s2_wechat_friend.groupIds
|
||
Db::table('s2_wechat_friend')
|
||
->where('id', $moveId)
|
||
->update(['groupIds' => $targetId]);
|
||
} elseif ($type === 'chatroom') {
|
||
// 移动单个群到指定分组:更新 s2_wechat_chatroom.groupIds
|
||
Db::table('s2_wechat_chatroom')
|
||
->where('id', $moveId)
|
||
->update(['groupIds' => $targetId]);
|
||
} else {
|
||
Db::rollback();
|
||
return ResponseHelper::error('无效的类型参数');
|
||
}
|
||
|
||
Db::commit();
|
||
return ResponseHelper::success('', '移动成功');
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
return ResponseHelper::error('移动失败:' . $e->getMessage());
|
||
}
|
||
}
|
||
} |