feat: 处理语法校验

This commit is contained in:
笔记本里的永平
2025-07-07 14:29:28 +08:00
parent 5b8969f4a6
commit c29fbd1bbb
11 changed files with 11884 additions and 44 deletions

View File

@@ -65,6 +65,21 @@ export function AuthProvider({ children }: AuthProviderProps) {
const [isInitialized, setIsInitialized] = useState(false);
const navigate = useNavigate();
// 先声明handleLogout避免useEffect依赖提前引用
const handleLogout = () => {
// 先清除所有认证相关的状态
safeLocalStorage.removeItem("token");
safeLocalStorage.removeItem("token_expired");
safeLocalStorage.removeItem("s2_accountId");
safeLocalStorage.removeItem("userInfo");
safeLocalStorage.removeItem("user");
setToken(null);
setUser(null);
setIsAuthenticated(false);
// 跳转到登录页面
navigate('/login');
};
// 检查token是否过期
const isTokenExpired = (): boolean => {
const tokenExpired = safeLocalStorage.getItem("token_expired");
@@ -184,22 +199,7 @@ export function AuthProvider({ children }: AuthProviderProps) {
}, 60000); // 每分钟检查一次
return () => clearInterval(checkTokenInterval);
}, [isAuthenticated]);
const handleLogout = () => {
// 先清除所有认证相关的状态
safeLocalStorage.removeItem("token");
safeLocalStorage.removeItem("token_expired");
safeLocalStorage.removeItem("s2_accountId");
safeLocalStorage.removeItem("userInfo");
safeLocalStorage.removeItem("user");
setToken(null);
setUser(null);
setIsAuthenticated(false);
// 跳转到登录页面
navigate('/login');
};
}, [isAuthenticated, handleLogout]);
const login = (newToken: string, userData: User) => {
safeLocalStorage.setItem("token", newToken);

View File

@@ -1,9 +1,9 @@
import React, { useState, useEffect, useRef, useCallback } from 'react';
import React, { useState, useEffect, useRef } from 'react';
import { useParams } from 'react-router-dom';
import PageHeader from '@/components/PageHeader';
import BackButton from '@/components/BackButton';
import { useSimpleBack } from '@/hooks/useBackNavigation';
import { ChevronLeft, Smartphone, Battery, Wifi, MessageCircle, Users, Settings, History, RefreshCw, Loader2 } from 'lucide-react';
import { Smartphone, Battery, Wifi, MessageCircle, Users, Settings, History, RefreshCw, Loader2 } from 'lucide-react';
import { devicesApi, fetchDeviceDetail, fetchDeviceRelatedAccounts, fetchDeviceHandleLogs, updateDeviceTaskConfig } from '@/api/devices';
import { useToast } from '@/components/ui/toast';
@@ -73,7 +73,7 @@ export default function DeviceDetail() {
momentsSync: false,
aiChat: false
});
const [tabChangeLoading, setTabChangeLoading] = useState(false);
const [accountPage, setAccountPage] = useState(1);
const [hasMoreAccounts, setHasMoreAccounts] = useState(true);
const accountsPerPage = 10;
@@ -277,7 +277,7 @@ export default function DeviceDetail() {
return () => {
observer.disconnect();
};
}, [hasMoreLogs, logsLoading]);
}, [hasMoreLogs, logsLoading, loadMoreLogs]);
// 获取任务配置
const fetchTaskConfig = async () => {
@@ -305,7 +305,6 @@ export default function DeviceDetail() {
// 标签页切换处理
const handleTabChange = (value: string) => {
setActiveTab(value);
setTabChangeLoading(true);
setTimeout(() => {
if (value === "accounts" && device && (!device.wechatAccounts || device.wechatAccounts.length === 0)) {
@@ -315,7 +314,6 @@ export default function DeviceDetail() {
setHasMoreLogs(true);
fetchHandleLogs();
}
setTabChangeLoading(false);
}, 100);
};
@@ -421,7 +419,7 @@ export default function DeviceDetail() {
return () => {
observer.disconnect();
};
}, [hasMoreAccounts, accountsLoading]);
}, [hasMoreAccounts, accountsLoading, loadMoreAccounts]);
if (loading) {
return (

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect, useRef, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { Plus, Search, RefreshCw, QrCode, Smartphone, Loader2, AlertTriangle, Trash2, X } from 'lucide-react';
import { Plus, Search, RefreshCw, QrCode, Loader2, AlertTriangle, X } from 'lucide-react';
import { devicesApi } from '@/api';
import { useToast } from '@/components/ui/toast';
import PageHeader from '@/components/PageHeader';
@@ -27,6 +27,7 @@ export default function Devices() {
});
const [searchQuery, setSearchQuery] = useState("");
const [statusFilter, setStatusFilter] = useState("all");
// 恢复分页功能
const [currentPage, setCurrentPage] = useState(1);
const [selectedDeviceId, setSelectedDeviceId] = useState<number | null>(null);
const [isLoading, setIsLoading] = useState(false);

View File

@@ -374,9 +374,9 @@ export default function Login() {
className="text-sm text-gray-600 leading-relaxed cursor-pointer"
>
<a href="#" className="text-blue-500 hover:text-blue-600 mx-1"></a>
<button type="button" className="text-blue-500 hover:text-blue-600 mx-1"></button>
<a href="#" className="text-blue-500 hover:text-blue-600 mx-1"></a>
<button type="button" className="text-blue-500 hover:text-blue-600 mx-1"></button>
</label>
</div>

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { Check, Settings } from 'lucide-react';
import PageHeader from '@/components/PageHeader';
@@ -71,7 +71,7 @@ export default function NewPlan() {
const { toast } = useToast();
const [currentStep, setCurrentStep] = useState(1);
const [loading, setLoading] = useState(false);
const [loadingScenes, setLoadingScenes] = useState(false);
const [formData, setFormData] = useState<FormData>({
planName: "",
@@ -164,8 +164,6 @@ export default function NewPlan() {
// 基础设置步骤
const BasicSettings = () => {
const selectedScenario = scenarioOptions.find(s => s.id === formData.sceneId);
return (
<div className="space-y-6">
<div>

View File

@@ -28,7 +28,6 @@ interface ScenarioData {
export default function ScenarioDetail() {
const { scenarioId } = useParams<{ scenarioId: string }>();
const navigate = useNavigate();
const { goBack } = useSimpleBack('/scenarios');
const [scenario, setScenario] = useState<ScenarioData | null>(null);
const [plans, setPlans] = useState<Plan[]>([]);
const [loading, setLoading] = useState(true);

View File

@@ -81,7 +81,7 @@ export default function GongzhonghaoScenario() {
setError("");
fetchPlanList(channel, page, pageSize)
.then((res) => {
if (res.code === 200 && Array.isArray(res.data?.list)) {
if (res.code === 200 && res.data && Array.isArray(res.data.list)) {
setTasks(res.data.list);
setTotal(res.data.total || 0);
} else {

View File

@@ -12,12 +12,8 @@ import {
Info,
UserPlus,
Search,
Filter,
Tag,
ChevronRight,
Loader2,
AlertCircle,
ArrowRightLeft
Loader2
} from 'lucide-react';
import { useWechatAccount } from '@/contexts/WechatAccountContext';
import { fetchWechatAccountSummary, fetchWechatFriends, fetchWechatFriendDetail } from '@/api/wechat-accounts';
@@ -106,7 +102,6 @@ export default function WechatAccountDetail() {
const [isFriendsEmpty, setIsFriendsEmpty] = useState(false);
const friendsObserver = useRef<IntersectionObserver | null>(null);
const friendsLoadingRef = useRef<HTMLDivElement | null>(null);
const friendsContainerRef = useRef<HTMLDivElement | null>(null);
// 如果没有账号数据,返回上一页
useEffect(() => {

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect, useRef, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { Search, RefreshCw, ArrowRightLeft, AlertCircle, Loader2 } from 'lucide-react';
import { Search, RefreshCw, Loader2 } from 'lucide-react';
import { fetchWechatAccountList, transformWechatAccount } from '@/api/wechat-accounts';
import { useToast } from '@/components/ui/toast';
import { useWechatAccount } from '@/contexts/WechatAccountContext';
@@ -119,7 +119,6 @@ export default function WechatAccounts() {
}
};
const filteredAccounts = accounts;
const totalPages = Math.ceil(totalAccounts / accountsPerPage);
const handleTransferFriends = (account: WechatAccount) => {
@@ -259,7 +258,7 @@ export default function WechatAccounts() {
handleTransferFriends(account);
}}
>
<ArrowRightLeft className="h-4 w-4" />
{/* ArrowRightLeft className="h-4 w-4" */}
</button>
</div>
<div className="mt-2 text-sm text-gray-500 space-y-1">
@@ -274,7 +273,7 @@ export default function WechatAccounts() {
<span></span>
<span className="font-medium">{account.remainingAdds}</span>
<div className="relative group">
<AlertCircle className="h-4 w-4 text-gray-400" />
{/* AlertCircle className="h-4 w-4 text-gray-400" */}
<div className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-2 py-1 text-xs bg-gray-800 text-white rounded opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap">
{account.maxDailyAdds}
</div>

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { useNavigate, Link } from 'react-router-dom';
import { Plus, Filter, Search, RefreshCw, MoreVertical, Clock, Edit, Trash2, Eye, Copy } from 'lucide-react';
import { Plus, Search, RefreshCw, MoreVertical, Clock, Edit, Trash2, Eye, Copy } from 'lucide-react';
import { Card } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
@@ -244,7 +244,7 @@ export default function MomentsSync() {
/>
</div>
<Button variant="outline" size="icon" onClick={handleSearch}>
<Filter className="h-4 w-4" />
{/* <Filter className="h-4 w-4" /> */}
</Button>
<Button variant="outline" size="icon" onClick={fetchTasks} disabled={isLoading}>
<RefreshCw className={`h-4 w-4 ${isLoading ? 'animate-spin' : ''}`} />

11850
nkebao/yarn.lock Normal file

File diff suppressed because it is too large Load Diff