代码提交

This commit is contained in:
wong
2025-06-10 09:53:01 +08:00
parent 9d0d552fba
commit 224d89f8e1
5 changed files with 103 additions and 85 deletions

View File

@@ -28,21 +28,44 @@ import Link from "next/link"
import BottomNav from "@/app/components/BottomNav"
import { api } from "@/lib/api"
import { showToast } from "@/lib/toast"
import { Switch } from "@/components/ui/switch"
interface DistributionPlan {
id: string
id: string | number
companyId?: number
name: string
status: "active" | "paused"
source: string
sourceIcon: string
targetGroups: string[]
totalUsers: number
dailyAverage: number
deviceCount: number
poolCount: number
lastUpdated: string
type?: number
status: number // 1: 进行中, 0: 已暂停
autoStart?: number
userId?: number
createTime: string
creator: string
updateTime?: string
config: {
id?: number
workbenchId?: number
distributeType?: number
maxPerDay?: number
timeType?: number
startTime?: string
endTime?: string
account?: string[]
devices: string[]
pools: string[]
createTime?: string
updateTime?: string
lastUpdated?: string
total: {
dailyAverage: number
totalAccounts: number
deviceCount: number
poolCount: number
totalUsers: number
}
}
creatorName?: string
auto_like?: any
moments_sync?: any
group_push?: any
}
interface ApiResponse {
@@ -111,7 +134,7 @@ export default function TrafficDistributionPage() {
const handleDelete = async (planId: string) => {
const loadingToast = showToast("正在删除计划...", "loading", true);
try {
const response = await api.delete<ApiResponse>(`/v1/traffic-distribution/delete?id=${planId}`)
const response = await api.delete<ApiResponse>(`/v1/workbench/delete?id=${planId}`)
if (response.code === 200) {
loadingToast.remove();
@@ -136,24 +159,23 @@ export default function TrafficDistributionPage() {
router.push(`/workspace/traffic-distribution/${planId}`)
}
const togglePlanStatus = async (planId: string, currentStatus: "active" | "paused") => {
const togglePlanStatus = async (planId: string, currentStatus: number) => {
const loadingToast = showToast("正在更新计划状态...", "loading", true);
try {
const response = await api.post<ApiResponse>('/v1/traffic-distribution/update-status', {
const response = await api.post<ApiResponse>('/v1/workbench/update-status', {
id: planId,
status: currentStatus === "active" ? "paused" : "active"
status: currentStatus === 1 ? 0 : 1
})
if (response.code === 200) {
setPlans(plans.map(plan =>
plan.id === planId
? { ...plan, status: currentStatus === "active" ? "paused" : "active" }
? { ...plan, status: currentStatus === 1 ? 0 : 1 }
: plan
))
const newStatus = currentStatus === "active" ? "paused" : "active"
const newStatus = currentStatus === 1 ? 0 : 1
loadingToast.remove();
showToast(response.msg || `计划${newStatus === "active" ? "已启动" : "已暂停"}`, "success")
showToast(response.msg || `计划${newStatus === 1 ? "已启动" : "已暂停"}`, "success")
} else {
loadingToast.remove();
showToast(response.msg || "请稍后再试", "error")
@@ -233,59 +255,52 @@ export default function TrafficDistributionPage() {
<div className="space-y-4 mt-2">
{plans.map((plan) => (
<Card key={plan.id} className="overflow-hidden">
{/* 卡片头部 */}
{/* 卡片头部:全部元素一行排列,间距紧凑 */}
<div className="p-4 bg-white border-b flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="text-2xl">{plan.sourceIcon}</div>
<div>
<h3 className="font-medium text-lg">{plan.name}</h3>
<div className="flex items-center space-x-2 mt-1">
<Badge variant={plan.status == 1 ? "success" : "secondary"}>
{plan.status == 1 ? "进行中" : "已暂停"}
</Badge>
{plan.config.pools.map((group, index) => (
<Badge key={index} variant="outline">
{group}
</Badge>
))}
</div>
</div>
<div className="flex items-center space-x-3 w-full">
<span className="font-medium text-base truncate max-w-[40%]">{plan.name}</span>
<span className={`px-2 py-0.5 rounded-full text-xs font-medium ml-2 ${plan.status === 1 ? "bg-blue-500 text-white" : "bg-gray-300 text-gray-600"}`}>{plan.status === 1 ? "进行中" : "已暂停"}</span>
<Switch
checked={plan.status === 1}
onCheckedChange={() => togglePlanStatus(plan.id.toString(), Number(plan.status))}
className="ml-2"
/>
<div className="flex-1" />
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="h-8 w-8 rounded-full">
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{/* <DropdownMenuItem onClick={() => handleView(plan.id.toString())}>
<Eye className="mr-2 h-4 w-4" />
查看详情
</DropdownMenuItem> */}
<DropdownMenuItem onClick={() => handleEdit(plan.id.toString())}>
<Edit className="mr-2 h-4 w-4" />
</DropdownMenuItem>
<DropdownMenuItem onClick={() => togglePlanStatus(plan.id.toString(), Number(plan.status))}>
{plan.status === 1 ? (
<>
<Pause className="mr-2 h-4 w-4" />
</>
) : (
<>
<Play className="mr-2 h-4 w-4" />
</>
)}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleDelete(plan.id.toString())} className="text-red-600">
<Trash2 className="mr-2 h-4 w-4" />
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="h-8 w-8 rounded-full">
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => handleView(plan.id)}>
<Eye className="mr-2 h-4 w-4" />
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleEdit(plan.id)}>
<Edit className="mr-2 h-4 w-4" />
</DropdownMenuItem>
<DropdownMenuItem onClick={() => togglePlanStatus(plan.id, plan.status)}>
{plan.status === "active" ? (
<>
<Pause className="mr-2 h-4 w-4" />
</>
) : (
<>
<Play className="mr-2 h-4 w-4" />
</>
)}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleDelete(plan.id)} className="text-red-600">
<Trash2 className="mr-2 h-4 w-4" />
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
{/* 卡片内容 - 上3下2布局图标在文字左侧 */}
@@ -312,7 +327,7 @@ export default function TrafficDistributionPage() {
<div className="text-xs text-gray-500 mt-1"></div>
</div>
<div className="p-3 text-center">
<div className="text-lg font-semibold">{plan.config.total.totalUsers}</div>
<div className="text-lg font-semibold">{plan.config.total.totalAccounts}</div>
<div className="text-xs text-gray-500 mt-1"></div>
</div>
</div>

View File

@@ -15,6 +15,7 @@ Route::group('v1', function () {
Route::get('department/list', 'app\\api\\controller\\AccountController@getDepartmentList'); // 获取部门列表 √
Route::post('department/update', 'app\\api\\controller\\AccountController@updateDepartment'); // 更新部门 √
Route::post('department/delete', 'app\\api\\controller\\AccountController@deleteDepartment'); // 删除部门 √
Route::post('department/setPrivileges', 'app\\api\\controller\\AccountController@setPrivileges'); // 设置部门权限 √
});
// Device控制器路由

View File

@@ -520,7 +520,7 @@ class AccountController extends BaseController
* 修改部门权限
* @return \think\response\Json
*/
public function setPrivileges($id = '')
public function setPrivileges($data = [])
{
// 获取授权token
$authorization = trim($this->request->header('authorization', $this->authorization));
@@ -530,23 +530,26 @@ class AccountController extends BaseController
try {
// 获取并验证请求参数
$id = !empty($id) ? $id : $this->request->param('id', 0);
$id = !empty($data['id']) ? $data['id'] : $this->request->param('id', 0);
if (empty($id)) {
return errorJson('部门ID不能为空');
}
$privilegeIds = !empty($data['privilegeIds']) ? $data['privilegeIds'] : '1001,1002,1004,1023,1406,20003,20021,20022,20023,20032,20041,20049,20054,20055,20060,20100,20102,20107';
$privilegeIds = explode(',',$privilegeIds);
// 验证部门是否存在
$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],
'privilegeIds' => $privilegeIds,
'syncPrivilege' => true
];

View File

@@ -307,7 +307,7 @@ class WorkbenchController extends Controller
$day = intval($day);
if($dailyAverage > 0){
if($dailyAverage > 0 && $totalAccounts > 0 && $day > 0){
$dailyAverage = $dailyAverage / $totalAccounts / $day;
}
@@ -706,17 +706,15 @@ class WorkbenchController extends Controller
return json(['code' => 400, 'msg' => '请求方式错误']);
}
$param = $this->request->post();
$id = $this->request->param('id','');
// 验证数据
$validate = new WorkbenchValidate;
if (!$validate->scene('update_status')->check($param)) {
return json(['code' => 400, 'msg' => $validate->getError()]);
if(empty($id)){
return json(['code' => 400, 'msg' => '参数错误']);
}
$workbench = Workbench::where([
['id', '=', $param['id']],
['userId', '=', $this->request->userInfo['id']]
['id', '=', $id],
['companyId', '=', $this->request->userInfo['companyId']]
])->find();
if (empty($workbench)) {

View File

@@ -266,8 +266,9 @@ class CreateCompanyController extends BaseController
*/
protected function setDepartmentPrivileges(array $params): void
{
$params = ArrHelper::getValue('companyId=id,companyId,name,memo,status', $params);
$result = CompanyModel::create($params);
$params = ArrHelper::getValue('companyId', $params);
$accountController = new \app\api\controller\AccountController();
$accountController->setPrivileges(['id' => $params['companyId']]);
}
/**