From 9d0d552fba116800b8f80d775c24175fa77b1dba Mon Sep 17 00:00:00 2001 From: wong <106998207@qq.com> Date: Sat, 7 Jun 2025 17:34:20 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E6=93=8D=E7=9B=98=E6=89=8B=E3=80=91?= =?UTF-8?q?=20=E6=B5=81=E9=87=8F=E5=88=86=E5=8F=91=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E8=B4=A6=E5=8F=B7=E5=88=86=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../traffic-distribution/[id]/edit/page.tsx | 5 +- .../new/components/target-settings-step.tsx | 144 ++++++++++++++-- .../new/components/traffic-pool-step.tsx | 108 +++++++----- .../traffic-distribution/new/page.tsx | 2 + .../api/controller/AccountController.php | 53 ++++++ Server/application/cunkebao/config/route.php | 1 + .../controller/WorkbenchController.php | 156 +++++++++++------- .../device/GetDeviceListV1Controller.php | 2 +- .../cunkebao/validate/Workbench.php | 7 +- .../job/WorkbenchTrafficDistributeJob.php | 12 +- .../company/CreateCompanyController.php | 16 ++ 11 files changed, 389 insertions(+), 117 deletions(-) diff --git a/Cunkebao/app/workspace/traffic-distribution/[id]/edit/page.tsx b/Cunkebao/app/workspace/traffic-distribution/[id]/edit/page.tsx index 3a055ed0..d0a4e056 100644 --- a/Cunkebao/app/workspace/traffic-distribution/[id]/edit/page.tsx +++ b/Cunkebao/app/workspace/traffic-distribution/[id]/edit/page.tsx @@ -28,6 +28,7 @@ interface FormData { targetSettings: { targetGroups: string[] devices: string[] + accounts?: string[] } trafficPool: { poolIds: string[] @@ -105,6 +106,7 @@ export default function EditTrafficDistributionPage({ params }: { params: Promis targetSettings: { targetGroups: data.config?.targetGroups || [], devices: (data.config?.devices || []).map(String), + accounts: (data.config?.account || []).map(String), }, trafficPool: { poolIds: (data.config?.pools || []).map(String), @@ -164,6 +166,7 @@ export default function EditTrafficDistributionPage({ params }: { params: Promis endTime: finalData.basicInfo.endTime, targetGroups: finalData.targetSettings.targetGroups, devices: finalData.targetSettings.devices, + account: finalData.targetSettings.accounts, pools: finalData.trafficPool.poolIds, enabled: true, }) @@ -204,7 +207,7 @@ export default function EditTrafficDistributionPage({ params }: { params: Promis )} diff --git a/Cunkebao/app/workspace/traffic-distribution/new/components/target-settings-step.tsx b/Cunkebao/app/workspace/traffic-distribution/new/components/target-settings-step.tsx index e5d1c18f..c2fc362c 100644 --- a/Cunkebao/app/workspace/traffic-distribution/new/components/target-settings-step.tsx +++ b/Cunkebao/app/workspace/traffic-distribution/new/components/target-settings-step.tsx @@ -6,7 +6,7 @@ import { Card, CardContent } from "@/components/ui/card" import { Checkbox } from "@/components/ui/checkbox" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { Avatar } from "@/components/ui/avatar" -import { Search } from "lucide-react" +import { Search, Users, Smartphone } from "lucide-react" import { Input } from "@/components/ui/input" import { api } from "@/lib/api" import { DeviceSelectionDialog } from "@/app/components/device-selection-dialog" @@ -40,6 +40,14 @@ export default function TargetSettingsStep({ onNext, onBack, initialData = {}, s const [deviceDialogOpen, setDeviceDialogOpen] = useState(false) const [statusFilter, setStatusFilter] = useState("all") + // 账号选择相关状态 + const [accountDialogOpen, setAccountDialogOpen] = useState(false) + const [accountList, setAccountList] = useState([]) + const [selectedAccountIds, setSelectedAccountIds] = useState([]) + const [accountPage, setAccountPage] = useState(1) + const [accountTotal, setAccountTotal] = useState(0) + const [accountLoading, setAccountLoading] = useState(false) + // 每次 initialData.devices 变化时,同步 selectedDeviceIds useEffect(() => { const ids = Array.isArray(initialData.devices) ? initialData.devices.map(String) : []; @@ -53,6 +61,29 @@ export default function TargetSettingsStep({ onNext, onBack, initialData = {}, s }).finally(() => setLoading(false)) }, []) + // 同步初始账号 + useEffect(() => { + const ids = Array.isArray(initialData.accounts) ? initialData.accounts.map(String) : []; + setSelectedAccountIds(ids); + }, [initialData.accounts]) + + // 拉取账号列表 + useEffect(() => { + setAccountLoading(true) + api.get(`/v1/workbench/account-list?page=${accountPage}&size=10`).then((res: any) => { + setAccountList(res.data?.list || []) + setAccountTotal(res.data?.total || 0) + }).finally(() => setAccountLoading(false)) + }, [accountPage]) + + // 账号弹窗每次打开时同步反选 + useEffect(() => { + if (accountDialogOpen) { + const ids = Array.isArray(initialData.accounts) ? initialData.accounts.map(String) : []; + setSelectedAccountIds(ids); + } + }, [accountDialogOpen, initialData.accounts]) + const filteredDevices = deviceList.filter(device => { const matchesSearch = search === "" || @@ -64,7 +95,7 @@ export default function TargetSettingsStep({ onNext, onBack, initialData = {}, s }) const handleSubmit = () => { - onNext({ devices: selectedDeviceIds }) + onNext({ devices: selectedDeviceIds, accounts: selectedAccountIds }) } // 弹窗内确认选择 @@ -75,9 +106,15 @@ export default function TargetSettingsStep({ onNext, onBack, initialData = {}, s setDeviceDialogOpen(false) } + // 账号弹窗确认 + const handleAccountDialogConfirm = () => { + setAccountDialogOpen(false) + } + return (

目标设置

+ {/* 设备选择 */}
@@ -90,16 +127,43 @@ export default function TargetSettingsStep({ onNext, onBack, initialData = {}, s />
-
- {selectedDeviceIds.length === 0 ? ( -
未选择设备
- ) : ( -
已选设备:{selectedDeviceIds.length} 个
- )} + {/* 账号选择 */} +
+
+ + 0 ? `已选择${selectedAccountIds.length}个账号` : ''} + readOnly + className="pl-10 cursor-pointer" + onClick={() => setAccountDialogOpen(true)} + /> +
-
+ {/* 已选账号/设备展示优化 */} +
+
+ + 已选账号: + {selectedAccountIds.length === 0 ? ( + 未选择 + ) : ( + {selectedAccountIds.length} 个 + )} +
+
+ + 已选设备: + {selectedDeviceIds.length === 0 ? ( + 未选择 + ) : ( + {selectedDeviceIds.length} 个 + )} +
+
+
- +
{/* 设备选择弹窗 */} @@ -179,6 +243,66 @@ export default function TargetSettingsStep({ onNext, onBack, initialData = {}, s
+ {/* 账号选择弹窗 */} + + + 选择账号 +
+ {/* 账号列表 */} +
+ {accountLoading ? ( +
加载中...
+ ) : accountList.length === 0 ? ( +
暂无账号
+ ) : ( + accountList.map(account => ( + + )) + )} +
+ {/* 分页 */} +
+ + 第 {accountPage} 页 / 共 {Math.ceil(accountTotal / 10) || 1} 页 + +
+ {/* 确认按钮 */} +
+ +
+
+
+
) } diff --git a/Cunkebao/app/workspace/traffic-distribution/new/components/traffic-pool-step.tsx b/Cunkebao/app/workspace/traffic-distribution/new/components/traffic-pool-step.tsx index be56a8b0..910e0146 100644 --- a/Cunkebao/app/workspace/traffic-distribution/new/components/traffic-pool-step.tsx +++ b/Cunkebao/app/workspace/traffic-distribution/new/components/traffic-pool-step.tsx @@ -27,6 +27,7 @@ interface TrafficPoolStepProps { export default function TrafficPoolStep({ onSubmit, onBack, initialData = {}, devices = [] }: TrafficPoolStepProps) { const [selectedPools, setSelectedPools] = useState(initialData.selectedPools || []) + const [searchInput, setSearchInput] = useState("") const [searchTerm, setSearchTerm] = useState("") const [isSubmitting, setIsSubmitting] = useState(false) const [deviceLabels, setDeviceLabels] = useState<{ label: string; count: number }[]>([]) @@ -34,6 +35,7 @@ export default function TrafficPoolStep({ onSubmit, onBack, initialData = {}, de const [currentPage, setCurrentPage] = useState(1) const pageSize = 10 const [total, setTotal] = useState(0) + const [loading, setLoading] = useState(false) const filteredPools = deviceLabels.filter( (pool) => pool.label && pool.label.toLowerCase().includes(searchTerm.toLowerCase()) @@ -41,7 +43,7 @@ export default function TrafficPoolStep({ onSubmit, onBack, initialData = {}, de const totalPages = Math.ceil(total / pageSize) const pagedPools = filteredPools.slice((currentPage - 1) * pageSize, currentPage * pageSize) - // 监听 devices 变化,请求标签 + // 监听 devices、currentPage、searchTerm 变化,请求标签(后端分页+搜索) useEffect(() => { if (!devices || devices.length === 0) { setDeviceLabels([]) @@ -49,12 +51,13 @@ export default function TrafficPoolStep({ onSubmit, onBack, initialData = {}, de return } const fetchLabels = async () => { + setLoading(true) try { const params = devices.join(",") - const res = await api.get<{ code: number; msg: string; data: { label: string; count: number }[]; total?: number }>(`/v1/workbench/device-labels?deviceIds=${params}`) - if (res.code === 200 && Array.isArray(res.data)) { - setDeviceLabels(res.data) - setTotal(res.total || res.data.length) + const res = await api.get<{ code: number; msg: string; data: { list: { label: string; count: number }[]; total: number } }>(`/v1/workbench/device-labels?deviceIds=${params}&page=${currentPage}&pageSize=${pageSize}&keyword=${encodeURIComponent(searchTerm)}`) + if (res.code === 200 && Array.isArray(res.data?.list)) { + setDeviceLabels(res.data.list) + setTotal(res.data.total || 0) } else { setDeviceLabels([]) setTotal(0) @@ -62,10 +65,18 @@ export default function TrafficPoolStep({ onSubmit, onBack, initialData = {}, de } catch (e) { setDeviceLabels([]) setTotal(0) + } finally { + setLoading(false) } } fetchLabels() - }, [devices]) + }, [devices, currentPage, searchTerm]) + + // 搜索时重置分页并触发搜索 + const handleSearch = () => { + setCurrentPage(1) + setSearchTerm(searchInput) + } // label 到描述的映射 const poolDescMap: Record = { @@ -117,49 +128,58 @@ export default function TrafficPoolStep({ onSubmit, onBack, initialData = {}, de 选择流量池
{/* 搜索栏 */} -
- - setSearchTerm(e.target.value)} - className="pl-10 rounded-lg border-gray-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-100" - /> +
+
+ + setSearchInput(e.target.value)} + className="pl-10 rounded-lg border-gray-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-100" + /> +
+
{/* 流量池列表 */}
- {pagedPools.map((pool) => ( -
togglePool(pool.label)} - > -
-
- -
-
-

{pool.label}

-

{poolDescMap[pool.label] || ""}

+ {loading ? ( +
加载中...
+ ) : filteredPools.length === 0 ? ( +
暂无流量池
+ ) : ( + filteredPools.map((pool) => ( +
togglePool(pool.label)} + > +
+
+ +
+
+

{pool.label}

+

{poolDescMap[pool.label] || ""}

+
+ {pool.count} 人 + { + e.stopPropagation(); + togglePool(pool.label); + }} + onClick={e => e.stopPropagation()} + />
- {pool.count} 人 - { - e.stopPropagation(); - togglePool(pool.label); - }} - onClick={e => e.stopPropagation()} - /> -
- ))} + )) + )}
{/* 分页按钮 */} {totalPages > 1 && ( diff --git a/Cunkebao/app/workspace/traffic-distribution/new/page.tsx b/Cunkebao/app/workspace/traffic-distribution/new/page.tsx index 1db3f045..b62f012f 100644 --- a/Cunkebao/app/workspace/traffic-distribution/new/page.tsx +++ b/Cunkebao/app/workspace/traffic-distribution/new/page.tsx @@ -28,6 +28,7 @@ interface FormData { targetGroups: string[] targets: string[] devices?: string[] + accounts?: string[] } trafficPool: { deviceIds: number[] @@ -114,6 +115,7 @@ export default function NewTrafficDistribution() { endTime: finalData.basicInfo.endTime, targetGroups: finalData.targetSettings.targetGroups, devices: finalData.targetSettings.devices, + account: finalData.targetSettings.accounts, pools: finalData.trafficPool.poolIds, enabled: true, // 默认启用 }) diff --git a/Server/application/api/controller/AccountController.php b/Server/application/api/controller/AccountController.php index c1dbe2ca..0aaecb52 100644 --- a/Server/application/api/controller/AccountController.php +++ b/Server/application/api/controller/AccountController.php @@ -516,6 +516,59 @@ class AccountController extends BaseController } } + /** + * 修改部门权限 + * @return \think\response\Json + */ + public function setPrivileges($id = '') + { + // 获取授权token + $authorization = trim($this->request->header('authorization', $this->authorization)); + if (empty($authorization)) { + return errorJson('缺少授权信息'); + } + + try { + // 获取并验证请求参数 + $id = !empty($id) ? $id : $this->request->param('id', 0); + + if (empty($id)) { + return errorJson('部门ID不能为空'); + } + + + // 验证部门是否存在 + $department = CompanyModel::where('id', $id)->find(); + if (empty($department)) { + return errorJson('部门不存在'); + } + + // 构建请求参数 + $params = [ + 'departmentId' => $id, + 'privilegeIds' => [1001,1002,1004,1023,1406,20003,20021,20022,20023,20032,20041,20049,20054,20055,20060,20100,20102,20107], + 'syncPrivilege' => true + ]; + + // 设置请求头 + $headerData = ['client:system']; + $header = setHeader($headerData, $authorization, 'json'); + + // 发送请求修改部门 + $result = requestCurl($this->baseUrl . 'api/Department/privileges', $params, 'PUT', $header, 'json'); + $response = handleApiResponse($result); + + + return successJson([], '部门权限修改成功'); + } catch (\Exception $e) { + return errorJson('修改部门权限失败:' . $e->getMessage()); + } + } + + + + + /************************ 私有辅助方法 ************************/ /** diff --git a/Server/application/cunkebao/config/route.php b/Server/application/cunkebao/config/route.php index f5349467..8958c616 100644 --- a/Server/application/cunkebao/config/route.php +++ b/Server/application/cunkebao/config/route.php @@ -66,6 +66,7 @@ Route::group('v1/', function () { Route::get('moments-records', 'app\cunkebao\controller\WorkbenchController@getMomentsRecords'); // 获取朋友圈发布记录列表 Route::get('device-labels', 'app\cunkebao\controller\WorkbenchController@getDeviceLabels'); // 获取设备微信好友标签统计 Route::get('group-list', 'app\cunkebao\controller\WorkbenchController@getGroupList'); // 获取群列表 + Route::get('account-list', 'app\cunkebao\controller\WorkbenchController@getAccountList'); // 获取账号列表 }); // 内容库相关 diff --git a/Server/application/cunkebao/controller/WorkbenchController.php b/Server/application/cunkebao/controller/WorkbenchController.php index c088eb3a..872fc754 100644 --- a/Server/application/cunkebao/controller/WorkbenchController.php +++ b/Server/application/cunkebao/controller/WorkbenchController.php @@ -137,6 +137,7 @@ class WorkbenchController extends Controller $config->endTime = $param['endTime']; $config->devices = json_encode($param['devices'], JSON_UNESCAPED_UNICODE); $config->pools = json_encode($param['pools'], JSON_UNESCAPED_UNICODE); + $config->account = json_encode($param['account'], JSON_UNESCAPED_UNICODE); $config->createTime = time(); $config->updateTime = time(); $config->save(); @@ -186,7 +187,7 @@ class WorkbenchController extends Controller $query->field('workbenchId,syncInterval,syncCount,syncType,startTime,endTime,accountType,devices,contentLibraries'); }, 'trafficConfig' => function($query) { - $query->field('workbenchId,distributeType,maxPerDay,timeType,startTime,endTime,devices,pools'); + $query->field('workbenchId,distributeType,maxPerDay,timeType,startTime,endTime,devices,pools,account'); }, 'groupPush' => function($query) { $query->field('workbenchId,pushType,startTime,endTime,maxPerDay,pushOrder,isLoop,status,groups,contentLibraries'); @@ -276,6 +277,7 @@ class WorkbenchController extends Controller $item->config = $item->trafficConfig; $item->config->devices = json_decode($item->config->devices, true); $item->config->pools = json_decode($item->config->pools, true); + $item->config->account = json_decode($item->config->account, true); $config_item = Db::name('workbench_traffic_config_item')->where(['workbenchId' => $item->id])->order('id DESC')->find(); $item->config->lastUpdated = !empty($config_item) ? date('Y-m-d H:i',$config_item['createTime']) : '--'; @@ -296,13 +298,7 @@ class WorkbenchController extends Controller } })->count(); - $totalAccounts = Db::table('s2_company_account') - ->alias('a') - ->where(['a.departmentId' => $item->companyId, 'a.status' => 0]) - ->whereNotLike('a.userName', '%_offline%') - ->whereNotLike('a.userName', '%_delete%') - ->group('a.id') - ->count(); + $totalAccounts = count($item->config->account); $dailyAverage = Db::name('workbench_traffic_config_item') ->where('workbenchId', $item->id) @@ -368,7 +364,7 @@ class WorkbenchController extends Controller $query->field('workbenchId,syncInterval,syncCount,syncType,startTime,endTime,accountType,devices,contentLibraries'); }, 'trafficConfig' => function($query) { - $query->field('workbenchId,distributeType,maxPerDay,timeType,startTime,endTime,devices,pools'); + $query->field('workbenchId,distributeType,maxPerDay,timeType,startTime,endTime,devices,pools,account'); }, 'groupPush' => function($query) { $query->field('workbenchId,pushType,startTime,endTime,maxPerDay,pushOrder,isLoop,status,groups,contentLibraries'); @@ -450,56 +446,54 @@ class WorkbenchController extends Controller }]) ->order('id', 'desc') ->select(); - + // 处理JSON字段 + foreach ($contentLibraryList as &$item) { + $item['sourceFriends'] = json_decode($item['sourceFriends'] ?: '[]', true); + $item['sourceGroups'] = json_decode($item['sourceGroups'] ?: '[]', true); + $item['keywordInclude'] = json_decode($item['keywordInclude'] ?: '[]', true); + $item['keywordExclude'] = json_decode($item['keywordExclude'] ?: '[]', true); + // 添加创建人名称 + $item['creatorName'] = $item['user']['username'] ?? ''; + $item['itemCount'] = Db::name('content_item')->where('libraryId', $item['id'])->count(); - // 处理JSON字段 - foreach ($contentLibraryList as &$item) { - $item['sourceFriends'] = json_decode($item['sourceFriends'] ?: '[]', true); - $item['sourceGroups'] = json_decode($item['sourceGroups'] ?: '[]', true); - $item['keywordInclude'] = json_decode($item['keywordInclude'] ?: '[]', true); - $item['keywordExclude'] = json_decode($item['keywordExclude'] ?: '[]', true); - // 添加创建人名称 - $item['creatorName'] = $item['user']['username'] ?? ''; - $item['itemCount'] = Db::name('content_item')->where('libraryId', $item['id'])->count(); + // 获取好友详细信息 + if (!empty($item['sourceFriends'] && $item['sourceType'] == 1)) { + $friendIds = $item['sourceFriends']; + $friendsInfo = []; - // 获取好友详细信息 - if (!empty($item['sourceFriends'] && $item['sourceType'] == 1)) { - $friendIds = $item['sourceFriends']; - $friendsInfo = []; + if (!empty($friendIds)) { + // 查询好友信息,使用wechat_friendship表 + $friendsInfo = Db::name('wechat_friendship')->alias('wf') + ->field('wf.id,wf.wechatId, wa.nickname, wa.avatar') + ->join('wechat_account wa', 'wf.wechatId = wa.wechatId') + ->whereIn('wf.id', $friendIds) + ->select(); + } - if (!empty($friendIds)) { - // 查询好友信息,使用wechat_friendship表 - $friendsInfo = Db::name('wechat_friendship')->alias('wf') - ->field('wf.id,wf.wechatId, wa.nickname, wa.avatar') - ->join('wechat_account wa', 'wf.wechatId = wa.wechatId') - ->whereIn('wf.id', $friendIds) - ->select(); - } + // 将好友信息添加到返回数据中 + $item['selectedFriends'] = $friendsInfo; + } - // 将好友信息添加到返回数据中 - $item['selectedFriends'] = $friendsInfo; - } + + if (!empty($item['sourceGroups']) && $item['sourceType'] == 2) { + $groupIds = $item['sourceGroups']; + $groupsInfo = []; - - if (!empty($item['sourceGroups']) && $item['sourceType'] == 2) { - $groupIds = $item['sourceGroups']; - $groupsInfo = []; + if (!empty($groupIds)) { + // 查询群组信息 + $groupsInfo = Db::name('wechat_group')->alias('g') + ->field('g.id, g.chatroomId, g.name, g.avatar, g.ownerWechatId') + ->whereIn('g.id', $groupIds) + ->select(); + } - if (!empty($groupIds)) { - // 查询群组信息 - $groupsInfo = Db::name('wechat_group')->alias('g') - ->field('g.id, g.chatroomId, g.name, g.avatar, g.ownerWechatId') - ->whereIn('g.id', $groupIds) - ->select(); - } + // 将群组信息添加到返回数据中 + $item['selectedGroups'] = $groupsInfo; + } - // 将群组信息添加到返回数据中 - $item['selectedGroups'] = $groupsInfo; - } - - unset($item['user']); // 移除关联数据 - } + unset($item['user']); // 移除关联数据 + } $workbench->config->contentLibraryList = $contentLibraryList; unset($workbench->groupPush, $workbench->group_push); @@ -517,6 +511,7 @@ class WorkbenchController extends Controller $workbench->config = $workbench->trafficConfig; $workbench->config->devices = json_decode($workbench->config->devices, true); $workbench->config->pools = json_decode($workbench->config->pools, true); + $workbench->config->account = json_decode($workbench->config->account, true); $config_item = Db::name('workbench_traffic_config_item')->where(['workbenchId' => $workbench->id])->order('id DESC')->find(); $workbench->config->lastUpdated = !empty($config_item) ? date('Y-m-d H:i',$config_item['createTime']) : '--'; @@ -860,6 +855,7 @@ class WorkbenchController extends Controller $newConfig->membersPerGroup = $config->membersPerGroup; $newConfig->devices = $config->devices; $newConfig->targetGroups = $config->targetGroups; + $newConfig->account = $config->account; $newConfig->save(); } break; @@ -1307,6 +1303,9 @@ class WorkbenchController extends Controller { $deviceIds = $this->request->param('deviceIds', ''); $companyId = $this->request->userInfo['companyId']; + $page = $this->request->param('page', 1); + $limit = $this->request->param('limit', 10); + $keyword = $this->request->param('keyword', ''); $where = [ ['wc.companyId', '=', $companyId], @@ -1323,7 +1322,6 @@ class WorkbenchController extends Controller ->where($where) ->field('wa.id,wa.wechatId,wa.nickName,wa.labels') ->select(); - $labels = []; $wechatIds = []; foreach ($wechatAccounts as $account) { @@ -1340,14 +1338,27 @@ class WorkbenchController extends Controller // 去重(只保留一个) $labels = array_values(array_unique($labels)); $wechatIds = array_unique($wechatIds); - + + // 搜索过滤 + if (!empty($keyword)) { + $labels = array_filter($labels, function($label) use ($keyword) { + return mb_stripos($label, $keyword) !== false; + }); + $labels = array_values($labels); // 重新索引数组 + } + + + + // 分页处理 + $labels2 = array_slice($labels, ($page - 1) * $limit, $limit); + // 统计数量 $newLabel = []; - foreach ($labels as $label) { + foreach ($labels2 as $label) { $friendCount = Db::table('s2_wechat_friend') - ->whereIn('ownerWechatId',$wechatIds) - ->where('labels', 'like', '%"'.$label.'"%') - ->count(); + ->whereIn('ownerWechatId',$wechatIds) + ->where('labels', 'like', '%"'.$label.'"%') + ->count(); $newLabel[] = [ 'label' => $label, 'count' => $friendCount @@ -1355,7 +1366,14 @@ class WorkbenchController extends Controller } // 返回结果 - return json(['code' => 200, 'msg' => '获取成功', 'data' => $newLabel,'total'=> count($newLabel)]); + return json([ + 'code' => 200, + 'msg' => '获取成功', + 'data' => [ + 'list' => $newLabel, + 'total' => count($labels), + ] + ]); } @@ -1401,4 +1419,26 @@ class WorkbenchController extends Controller } + public function getAccountList() + { + $companyId = $this->request->userInfo['companyId']; + $page = $this->request->param('page', 1); + $limit = $this->request->param('limit', 10); + $query = Db::table('s2_company_account') + ->alias('a') + ->where(['a.departmentId' => $companyId, 'a.status' => 0]) + ->whereNotLike('a.userName', '%_offline%') + ->whereNotLike('a.userName', '%_delete%'); + + $total = $query->count(); + $list = $query->field('a.id,a.userName,a.realName,a.nickname,a.memo') + ->page($page, $limit) + ->select(); + + + + return json(['code' => 200, 'msg' => '获取成功', 'data' => ['total' => $total,'list' => $list]]); + } + + } \ No newline at end of file diff --git a/Server/application/cunkebao/controller/device/GetDeviceListV1Controller.php b/Server/application/cunkebao/controller/device/GetDeviceListV1Controller.php index 8baf0f02..e01a454d 100644 --- a/Server/application/cunkebao/controller/device/GetDeviceListV1Controller.php +++ b/Server/application/cunkebao/controller/device/GetDeviceListV1Controller.php @@ -77,7 +77,7 @@ class GetDeviceListV1Controller extends BaseController 'l.wechatId', 'a.nickname', 'a.alias', '0 totalFriend' ]) - ->leftJoin('device_wechat_login l', 'd.id = l.deviceId and l.alive =' . DeviceWechatLoginModel::ALIVE_WECHAT_ACTIVE) + ->leftJoin('device_wechat_login l', 'd.id = l.deviceId and l.alive =' . DeviceWechatLoginModel::ALIVE_WECHAT_ACTIVE . ' and l.companyId = d.companyId') ->leftJoin('wechat_account a', 'l.wechatId = a.wechatId') ->order('d.id desc'); diff --git a/Server/application/cunkebao/validate/Workbench.php b/Server/application/cunkebao/validate/Workbench.php index f9f39ea8..f55df5e5 100644 --- a/Server/application/cunkebao/validate/Workbench.php +++ b/Server/application/cunkebao/validate/Workbench.php @@ -55,7 +55,7 @@ class Workbench extends Validate 'timeType' => 'requireIf:type,5|in:1,2', 'startTime' => 'requireIf:type,5|dateFormat:H:i', 'endTime' => 'requireIf:type,5|dateFormat:H:i', - + 'account' => 'requireIf:type,5|array|min:1', // 通用参数 'devices' => 'requireIf:type,1,2,5|array', ]; @@ -141,7 +141,10 @@ class Workbench extends Validate 'devices.require' => '请选择设备', 'devices.array' => '设备格式错误', 'targetGroups.require' => '请选择目标用户组', - 'targetGroups.array' => '目标用户组格式错误' + 'targetGroups.array' => '目标用户组格式错误', + 'account.requireIf' => '流量分发时必须选择分发账号', + 'account.array' => '分发账号格式错误', + 'account.min' => '至少选择一个分发账号', ]; /** diff --git a/Server/application/job/WorkbenchTrafficDistributeJob.php b/Server/application/job/WorkbenchTrafficDistributeJob.php index 730f7031..88c03df9 100644 --- a/Server/application/job/WorkbenchTrafficDistributeJob.php +++ b/Server/application/job/WorkbenchTrafficDistributeJob.php @@ -69,13 +69,18 @@ class WorkbenchTrafficDistributeJob if (!$this->isTimeRange($config) && $config['timeType'] == 2) { return; } - // 获取当天未超额的可用账号 + if(empty($config['account'])){ + Log::error("流量分发工作台 {$workbench->id} 未配置分发的客服"); + return; + } + $accountIds = json_decode($config['account'],true); $todayStart = strtotime(date('Y-m-d 00:00:00')); $todayEnd = strtotime(date('Y-m-d 23:59:59')); $accounts = Db::table('s2_company_account') ->alias('a') ->where(['a.departmentId' => $workbench->companyId, 'a.status' => 0]) + ->whereIn('a.id',$accountIds) ->whereNotLike('a.userName', '%_offline%') ->whereNotLike('a.userName', '%_delete%') ->leftJoin('workbench_traffic_config_item wti', "wti.wechatAccountId = a.id AND wti.workbenchId = {$workbench->id} AND wti.createTime BETWEEN {$todayStart} AND {$todayEnd}") @@ -83,6 +88,11 @@ class WorkbenchTrafficDistributeJob ->group('a.id') ->having('todayCount <= ' . $config['maxPerDay']) ->select(); + + + print_r($accounts); + exit; + $accountNum = count($accounts); if ($accountNum < 1) { Log::info("流量分发工作台 {$workbench->id} 可分配账号少于1个"); diff --git a/Server/application/superadmin/controller/company/CreateCompanyController.php b/Server/application/superadmin/controller/company/CreateCompanyController.php index 7fa4c930..d21e5813 100644 --- a/Server/application/superadmin/controller/company/CreateCompanyController.php +++ b/Server/application/superadmin/controller/company/CreateCompanyController.php @@ -257,6 +257,19 @@ class CreateCompanyController extends BaseController } } + /** + * 设置部门权限 + * + * @param array $params + * @return void + * @throws Exception + */ + protected function setDepartmentPrivileges(array $params): void + { + $params = ArrHelper::getValue('companyId=id,companyId,name,memo,status', $params); + $result = CompanyModel::create($params); + } + /** * 创建新项目 * @@ -276,6 +289,9 @@ class CreateCompanyController extends BaseController // 创建功能账号,不可登录,也非管理员,用户也不可见 $this->createFuncUsers($params); + // 设置部门权限 + $this->setDepartmentPrivileges($params); + Db::commit(); return ResponseHelper::success(); } catch (Exception $e) {