代码提交
This commit is contained in:
@@ -28,21 +28,44 @@ import Link from "next/link"
|
|||||||
import BottomNav from "@/app/components/BottomNav"
|
import BottomNav from "@/app/components/BottomNav"
|
||||||
import { api } from "@/lib/api"
|
import { api } from "@/lib/api"
|
||||||
import { showToast } from "@/lib/toast"
|
import { showToast } from "@/lib/toast"
|
||||||
|
import { Switch } from "@/components/ui/switch"
|
||||||
|
|
||||||
interface DistributionPlan {
|
interface DistributionPlan {
|
||||||
id: string
|
id: string | number
|
||||||
|
companyId?: number
|
||||||
name: string
|
name: string
|
||||||
status: "active" | "paused"
|
type?: number
|
||||||
source: string
|
status: number // 1: 进行中, 0: 已暂停
|
||||||
sourceIcon: string
|
autoStart?: number
|
||||||
targetGroups: string[]
|
userId?: number
|
||||||
totalUsers: number
|
|
||||||
dailyAverage: number
|
|
||||||
deviceCount: number
|
|
||||||
poolCount: number
|
|
||||||
lastUpdated: string
|
|
||||||
createTime: string
|
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 {
|
interface ApiResponse {
|
||||||
@@ -111,7 +134,7 @@ export default function TrafficDistributionPage() {
|
|||||||
const handleDelete = async (planId: string) => {
|
const handleDelete = async (planId: string) => {
|
||||||
const loadingToast = showToast("正在删除计划...", "loading", true);
|
const loadingToast = showToast("正在删除计划...", "loading", true);
|
||||||
try {
|
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) {
|
if (response.code === 200) {
|
||||||
loadingToast.remove();
|
loadingToast.remove();
|
||||||
@@ -136,24 +159,23 @@ export default function TrafficDistributionPage() {
|
|||||||
router.push(`/workspace/traffic-distribution/${planId}`)
|
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);
|
const loadingToast = showToast("正在更新计划状态...", "loading", true);
|
||||||
try {
|
try {
|
||||||
const response = await api.post<ApiResponse>('/v1/traffic-distribution/update-status', {
|
const response = await api.post<ApiResponse>('/v1/workbench/update-status', {
|
||||||
id: planId,
|
id: planId,
|
||||||
status: currentStatus === "active" ? "paused" : "active"
|
status: currentStatus === 1 ? 0 : 1
|
||||||
})
|
})
|
||||||
|
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
setPlans(plans.map(plan =>
|
setPlans(plans.map(plan =>
|
||||||
plan.id === planId
|
plan.id === planId
|
||||||
? { ...plan, status: currentStatus === "active" ? "paused" : "active" }
|
? { ...plan, status: currentStatus === 1 ? 0 : 1 }
|
||||||
: plan
|
: plan
|
||||||
))
|
))
|
||||||
|
const newStatus = currentStatus === 1 ? 0 : 1
|
||||||
const newStatus = currentStatus === "active" ? "paused" : "active"
|
|
||||||
loadingToast.remove();
|
loadingToast.remove();
|
||||||
showToast(response.msg || `计划${newStatus === "active" ? "已启动" : "已暂停"}`, "success")
|
showToast(response.msg || `计划${newStatus === 1 ? "已启动" : "已暂停"}`, "success")
|
||||||
} else {
|
} else {
|
||||||
loadingToast.remove();
|
loadingToast.remove();
|
||||||
showToast(response.msg || "请稍后再试", "error")
|
showToast(response.msg || "请稍后再试", "error")
|
||||||
@@ -233,59 +255,52 @@ export default function TrafficDistributionPage() {
|
|||||||
<div className="space-y-4 mt-2">
|
<div className="space-y-4 mt-2">
|
||||||
{plans.map((plan) => (
|
{plans.map((plan) => (
|
||||||
<Card key={plan.id} className="overflow-hidden">
|
<Card key={plan.id} className="overflow-hidden">
|
||||||
{/* 卡片头部 */}
|
{/* 卡片头部:全部元素一行排列,间距紧凑 */}
|
||||||
<div className="p-4 bg-white border-b flex items-center justify-between">
|
<div className="p-4 bg-white border-b flex items-center justify-between">
|
||||||
<div className="flex items-center space-x-3">
|
<div className="flex items-center space-x-3 w-full">
|
||||||
<div className="text-2xl">{plan.sourceIcon}</div>
|
<span className="font-medium text-base truncate max-w-[40%]">{plan.name}</span>
|
||||||
<div>
|
<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>
|
||||||
<h3 className="font-medium text-lg">{plan.name}</h3>
|
<Switch
|
||||||
<div className="flex items-center space-x-2 mt-1">
|
checked={plan.status === 1}
|
||||||
<Badge variant={plan.status == 1 ? "success" : "secondary"}>
|
onCheckedChange={() => togglePlanStatus(plan.id.toString(), Number(plan.status))}
|
||||||
{plan.status == 1 ? "进行中" : "已暂停"}
|
className="ml-2"
|
||||||
</Badge>
|
/>
|
||||||
{plan.config.pools.map((group, index) => (
|
<div className="flex-1" />
|
||||||
<Badge key={index} variant="outline">
|
<DropdownMenu>
|
||||||
{group}
|
<DropdownMenuTrigger asChild>
|
||||||
</Badge>
|
<Button variant="ghost" size="icon" className="h-8 w-8 rounded-full">
|
||||||
))}
|
<MoreHorizontal className="h-4 w-4" />
|
||||||
</div>
|
</Button>
|
||||||
</div>
|
</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>
|
</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>
|
</div>
|
||||||
|
|
||||||
{/* 卡片内容 - 上3下2布局,图标在文字左侧 */}
|
{/* 卡片内容 - 上3下2布局,图标在文字左侧 */}
|
||||||
@@ -312,7 +327,7 @@ export default function TrafficDistributionPage() {
|
|||||||
<div className="text-xs text-gray-500 mt-1">日均分发量</div>
|
<div className="text-xs text-gray-500 mt-1">日均分发量</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-3 text-center">
|
<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 className="text-xs text-gray-500 mt-1">总流量池数量</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Route::group('v1', function () {
|
|||||||
Route::get('department/list', 'app\\api\\controller\\AccountController@getDepartmentList'); // 获取部门列表 √
|
Route::get('department/list', 'app\\api\\controller\\AccountController@getDepartmentList'); // 获取部门列表 √
|
||||||
Route::post('department/update', 'app\\api\\controller\\AccountController@updateDepartment'); // 更新部门 √
|
Route::post('department/update', 'app\\api\\controller\\AccountController@updateDepartment'); // 更新部门 √
|
||||||
Route::post('department/delete', 'app\\api\\controller\\AccountController@deleteDepartment'); // 删除部门 √
|
Route::post('department/delete', 'app\\api\\controller\\AccountController@deleteDepartment'); // 删除部门 √
|
||||||
|
Route::post('department/setPrivileges', 'app\\api\\controller\\AccountController@setPrivileges'); // 设置部门权限 √
|
||||||
});
|
});
|
||||||
|
|
||||||
// Device控制器路由
|
// Device控制器路由
|
||||||
|
|||||||
@@ -520,7 +520,7 @@ class AccountController extends BaseController
|
|||||||
* 修改部门权限
|
* 修改部门权限
|
||||||
* @return \think\response\Json
|
* @return \think\response\Json
|
||||||
*/
|
*/
|
||||||
public function setPrivileges($id = '')
|
public function setPrivileges($data = [])
|
||||||
{
|
{
|
||||||
// 获取授权token
|
// 获取授权token
|
||||||
$authorization = trim($this->request->header('authorization', $this->authorization));
|
$authorization = trim($this->request->header('authorization', $this->authorization));
|
||||||
@@ -530,23 +530,26 @@ class AccountController extends BaseController
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 获取并验证请求参数
|
// 获取并验证请求参数
|
||||||
$id = !empty($id) ? $id : $this->request->param('id', 0);
|
$id = !empty($data['id']) ? $data['id'] : $this->request->param('id', 0);
|
||||||
|
|
||||||
if (empty($id)) {
|
if (empty($id)) {
|
||||||
return errorJson('部门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();
|
$department = CompanyModel::where('id', $id)->find();
|
||||||
if (empty($department)) {
|
if (empty($department)) {
|
||||||
return errorJson('部门不存在');
|
return errorJson('部门不存在');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 构建请求参数
|
// 构建请求参数
|
||||||
$params = [
|
$params = [
|
||||||
'departmentId' => $id,
|
'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
|
'syncPrivilege' => true
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ class WorkbenchController extends Controller
|
|||||||
$day = intval($day);
|
$day = intval($day);
|
||||||
|
|
||||||
|
|
||||||
if($dailyAverage > 0){
|
if($dailyAverage > 0 && $totalAccounts > 0 && $day > 0){
|
||||||
$dailyAverage = $dailyAverage / $totalAccounts / $day;
|
$dailyAverage = $dailyAverage / $totalAccounts / $day;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -706,17 +706,15 @@ class WorkbenchController extends Controller
|
|||||||
return json(['code' => 400, 'msg' => '请求方式错误']);
|
return json(['code' => 400, 'msg' => '请求方式错误']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$param = $this->request->post();
|
$id = $this->request->param('id','');
|
||||||
|
|
||||||
// 验证数据
|
if(empty($id)){
|
||||||
$validate = new WorkbenchValidate;
|
return json(['code' => 400, 'msg' => '参数错误']);
|
||||||
if (!$validate->scene('update_status')->check($param)) {
|
|
||||||
return json(['code' => 400, 'msg' => $validate->getError()]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$workbench = Workbench::where([
|
$workbench = Workbench::where([
|
||||||
['id', '=', $param['id']],
|
['id', '=', $id],
|
||||||
['userId', '=', $this->request->userInfo['id']]
|
['companyId', '=', $this->request->userInfo['companyId']]
|
||||||
])->find();
|
])->find();
|
||||||
|
|
||||||
if (empty($workbench)) {
|
if (empty($workbench)) {
|
||||||
|
|||||||
@@ -266,8 +266,9 @@ class CreateCompanyController extends BaseController
|
|||||||
*/
|
*/
|
||||||
protected function setDepartmentPrivileges(array $params): void
|
protected function setDepartmentPrivileges(array $params): void
|
||||||
{
|
{
|
||||||
$params = ArrHelper::getValue('companyId=id,companyId,name,memo,status', $params);
|
$params = ArrHelper::getValue('companyId', $params);
|
||||||
$result = CompanyModel::create($params);
|
$accountController = new \app\api\controller\AccountController();
|
||||||
|
$accountController->setPrivileges(['id' => $params['companyId']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user