feat: 本次提交更新内容如下

保存一下项目
This commit is contained in:
笔记本里的永平
2025-07-17 15:57:20 +08:00
parent 277f57f339
commit 36f72e1948
2 changed files with 151 additions and 61 deletions

View File

@@ -308,4 +308,21 @@ export async function createScenarioPlan(data: any) {
// 编辑计划
export async function updateScenarioPlan(planId: number | string, data: any) {
return await put(`/v1/plan/update?planId=${planId}`, data);
}
}
/**
* 获取计划小程序二维码
* @param taskid 任务ID
* @returns base64二维码
*/
export const getWxMinAppCode = async (taskId: string): Promise<{ code: number; base64?: string; msg?: string }> => {
try {
return await get<{ code: number; base64?: string; msg?: string }>(
`/v1/plan/getWxMinAppCode?taskId=${ taskId }`,
);
} catch (error) {
console.error('获取小程序二维码失败:', error);
return { code: 500, msg: '获取小程序二维码失败' };
}
};

View File

@@ -15,6 +15,7 @@ import {
Code,
Search,
RefreshCw,
QrCode,
} from "lucide-react";
import {
fetchPlanList,
@@ -22,6 +23,7 @@ import {
copyPlan,
deletePlan,
type Task,
getWxMinAppCode,
} from "@/api/scenarios";
import { useToast } from "@/components/ui/toast";
import "@/components/Layout.css";
@@ -65,6 +67,11 @@ export default function ScenarioDetail() {
});
const [searchTerm, setSearchTerm] = useState("");
const [loadingTasks, setLoadingTasks] = useState(false);
// 二维码弹窗相关
const [showQrDialog, setShowQrDialog] = useState(false);
const [qrLoading, setQrLoading] = useState(false);
const [qrImg, setQrImg] = useState("");
const [qrTaskId, setQrTaskId] = useState("");
// 获取渠道中文名称
const getChannelName = (channel: string) => {
@@ -310,6 +317,33 @@ export default function ScenarioDetail() {
navigate(`/scenarios/new/${scenarioId}`);
};
const handleShowQrCode = async (taskId: string) => {
setQrTaskId(taskId);
setShowQrDialog(true);
setQrLoading(true);
setQrImg("");
try {
const data = await getWxMinAppCode(taskId);
if (data && data.base64) {
setQrImg(`data:image/png;base64,${data.base64}`);
} else {
toast({
title: "获取二维码失败",
description: data?.msg || "未知错误",
variant: "destructive",
});
}
} catch (e) {
toast({
title: "获取二维码失败",
description: "网络错误",
variant: "destructive",
});
} finally {
setQrLoading(false);
}
};
const getStatusColor = (status: number) => {
switch (status) {
case 1:
@@ -463,70 +497,75 @@ export default function ScenarioDetail() {
</button>
</div>
) : (
<div className="divide-y">
<div>
{filteredTasks.map((task) => (
<div key={task.id} className="p-4 bg-white">
<div className="flex items-center justify-between">
<div className="flex-1">
<div className="flex items-center mb-2">
<h3 className="font-medium text-gray-900">
{task.name}
</h3>
<span
className={`ml-2 px-2 py-1 text-xs rounded-full ${getStatusColor(
task.status
)}`}
>
{getStatusText(task.status)}
</span>
</div>
<div className="flex items-center text-sm text-gray-500">
<Calendar className="h-4 w-4 mr-1" />
<span>: {task.lastUpdated}</span>
</div>
<div className="flex items-center mt-2 text-sm text-gray-500">
<span>
: {task.stats?.devices || 0} | :{" "}
{task.stats?.acquired || 0} | :{" "}
{task.stats?.added || 0}
</span>
</div>
<div
key={task.id}
className="p-4 mb-4 bg-white rounded-xl shadow-lg border"
>
{/* 头部:标题和状态 */}
<div className="flex items-center justify-between mb-2">
<h3 className="font-medium text-gray-900 text-lg">
{task.name}
</h3>
<span
className={`px-2 py-1 text-xs rounded-full ${getStatusColor(
task.status
)}`}
>
{getStatusText(task.status)}
</span>
</div>
{/* 中部:更新时间和统计 */}
<div className="flex flex-col md:flex-row md:items-center md:justify-between text-sm text-gray-500 mb-2">
<div className="flex items-center mb-1 md:mb-0">
<Calendar className="h-4 w-4 mr-1" />
<span>: {task.lastUpdated}</span>
</div>
<div className="flex items-center space-x-2">
<button
onClick={() => navigate(`/scenarios/edit/${task.id}`)}
className={`p-2 rounded-md ${
task.status === 1
? "text-yellow-600 hover:bg-yellow-50"
: "text-green-600 hover:bg-green-50"
}`}
>
<Edit className="h-4 w-4" />
</button>
<button
onClick={() => handleOpenApiSettings(task.id)}
className="p-2 text-blue-600 hover:bg-blue-50 rounded-md"
>
<Settings className="h-4 w-4" />
</button>
<button
onClick={() => handleCopyPlan(task.id)}
className="p-2 text-gray-600 hover:bg-gray-50 rounded-md"
>
<Copy className="h-4 w-4" />
</button>
<button
onClick={() => handleDeletePlan(task.id)}
className="p-2 text-red-600 hover:bg-red-50 rounded-md"
>
<Trash2 className="h-4 w-4" />
</button>
<div>
: {task.stats?.devices || 0} | :{" "}
{task.stats?.acquired || 0} | :{" "}
{task.stats?.added || 0}
</div>
</div>
{/* 底部:操作按钮 */}
<div className="flex justify-end space-x-2 pt-2 border-t mt-2">
<button
onClick={() => navigate(`/scenarios/edit/${task.id}`)}
className={`p-2 rounded-md ${
task.status === 1
? "text-yellow-600 hover:bg-yellow-50"
: "text-green-600 hover:bg-green-50"
}`}
>
<Edit className="h-4 w-4" />
</button>
<button
onClick={() => handleOpenApiSettings(task.id)}
className="p-2 text-blue-600 hover:bg-blue-50 rounded-md"
>
<Settings className="h-4 w-4" />
</button>
<button
onClick={() => handleCopyPlan(task.id)}
className="p-2 text-gray-600 hover:bg-gray-50 rounded-md"
>
<Copy className="h-4 w-4" />
</button>
<button
onClick={() => handleDeletePlan(task.id)}
className="p-2 text-red-600 hover:bg-red-50 rounded-md"
>
<Trash2 className="h-4 w-4" />
</button>
<button
onClick={() => handleShowQrCode(task.id)}
className="p-2 text-gray-600 hover:bg-gray-50 rounded-md"
title="小程序二维码"
>
<QrCode className="h-4 w-4" />
</button>
</div>
</div>
))}
</div>
@@ -658,6 +697,40 @@ export default function ScenarioDetail() {
</div>
</div>
)}
{/* 二维码弹窗 */}
{showQrDialog && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-xl p-6 max-w-xs w-full flex flex-col items-center relative">
<button
onClick={() => setShowQrDialog(false)}
className="absolute top-2 right-2 p-2 hover:bg-gray-100 rounded-lg transition-colors"
>
<span className="text-2xl">&times;</span>
</button>
<div className="mb-4 flex flex-col items-center">
<QrCode className="h-8 w-8 text-blue-600 mb-2" />
<div className="text-lg font-semibold mb-1"></div>
<div className="text-gray-500 text-xs mb-2">
</div>
</div>
{qrLoading ? (
<div className="flex flex-col items-center justify-center h-40">
<Loader2 className="h-8 w-8 animate-spin text-blue-500 mb-2" />
<div className="text-gray-400">...</div>
</div>
) : qrImg ? (
<img
src={qrImg}
alt="二维码"
className="w-40 h-40 object-contain border rounded"
/>
) : (
<div className="text-red-500"></div>
)}
</div>
</div>
)}
</Layout>
);
}