接口联调

This commit is contained in:
fengxiangdebaozi committed 2026-05-23 17:23:15 +08:00
1 parent a85f1571a0
commit 87c9986b33
142 files changed
+38111 -73

No files matched your search

@@ -48,6 +48,12 @@ export interface StreamMultiAgentRequest {
signal?: AbortSignal;
/** Fires for every non-status data frame the upstream emits. */
onUpstreamFrame?: (frame: unknown) => void;
/**
* Fires for every AI text chunk parsed out of LangGraph messages-tuple frames.
* `text` is the incremental delta (concatenate to rebuild the message);
* `messageId` is stable per AI message so callers can group deltas.
*/
onTextDelta?: (text: string, messageId: string) => void;
}
export interface StreamMultiAgentResult {
@@ -84,6 +90,41 @@ function isFinalStatusFrame(value: unknown): value is {
return false;
}
/**
* Extract an AI text delta from a LangGraph `messages-tuple` data frame.
* Frames look like `[chunk, metadata]`; an AI text chunk carries `type` in
* {"ai","AIMessageChunk"} and a `content` that is either a string or a list of
* structured content blocks. Returns null when the frame is not an AI text
* chunk (e.g., tool calls, tool results, value snapshots).
*/
function extractAiTextDelta(parsed: unknown): { text: string; id: string } | null {
if (!Array.isArray(parsed) || parsed.length < 1) return null;
const chunk = parsed[0];
if (!chunk || typeof chunk !== "object") return null;
const obj = chunk as Record<string, unknown>;
const type = String(obj.type ?? "").toLowerCase();
// Accept any AI-shaped message chunk LangChain might emit across versions:
// "ai" (older), "AIMessageChunk" (newer streaming), or plain "AIMessage".
if (type !== "ai" && type !== "aimessagechunk" && type !== "aimessage") return null;
const content = obj.content;
let text = "";
if (typeof content === "string") {
text = content;
} else if (Array.isArray(content)) {
for (const item of content) {
if (typeof item === "string") text += item;
else if (item && typeof item === "object") {
const block = item as Record<string, unknown>;
const blockText = block.text;
if (typeof blockText === "string") text += blockText;
}
}
}
if (!text) return null;
const id = typeof obj.id === "string" ? obj.id : "";
return { text, id };
}
/**
* Open an SSE connection to /api/multi-agent/run/stream and resolve once the
* stream completes. The final frame (`{status: ...}`) is interpreted; every
@@ -115,6 +156,17 @@ export async function streamMultiAgent(
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
// Track the last `event:` line so logging can show which event a `data:`
// belongs to. The frontend doesn't actually dispatch by event name — every
// data frame goes through the same parser — but the label is invaluable
// for diagnosing why a sub-agent stream "looks empty".
let lastEvent = "";
let frameSeq = 0;
const debugLabel = `[stream:${req.agentType}:${req.agentName}]`;
const debugEnabled =
typeof window !== "undefined" &&
(window as unknown as { __MULTI_AGENT_DEBUG__?: boolean }).__MULTI_AGENT_DEBUG__ !== false;
const result: StreamMultiAgentResult = { dispatched: [], message: null, content: "", agentName: null };
@@ -128,6 +180,11 @@ export async function streamMultiAgent(
for (const rawLine of lines) {
const line = rawLine.trimEnd();
if (!line) continue;
if (line.startsWith("event:")) {
lastEvent = line.slice(6).trim();
continue;
}
if (!line.startsWith("data:")) continue;
const payload = line.slice(5).trim();
if (!payload) continue;
@@ -136,9 +193,13 @@ export async function streamMultiAgent(
try {
parsed = JSON.parse(payload);
} catch {
if (debugEnabled) console.debug(debugLabel, `bad JSON in event=${lastEvent}:`, payload.slice(0, 200));
continue;
}
frameSeq += 1;
if (debugEnabled) console.debug(debugLabel, `frame#${frameSeq} event=${lastEvent}`, parsed);
if (isFinalStatusFrame(parsed)) {
if (Array.isArray(parsed.status)) {
result.dispatched = parsed.status;
@@ -154,9 +215,19 @@ export async function streamMultiAgent(
continue;
}
const delta = extractAiTextDelta(parsed);
if (delta) {
if (debugEnabled) console.debug(debugLabel, `→ delta (${delta.text.length} chars)`);
req.onTextDelta?.(delta.text, delta.id);
}
req.onUpstreamFrame?.(parsed);
}
}
if (debugEnabled) {
console.debug(debugLabel, `stream ended after ${frameSeq} frames; final content length=${result.content.length}`);
}
return result;
}
@@ -25,8 +25,9 @@ import {
Clock,
Play,
Pause,
ChevronRight,
Settings,
ChevronRight,
ChevronDown,
Settings,
Download,
Share2,
Check,
@@ -200,6 +201,10 @@ export default function RoundtablePlanningPage() {
const [consensusPercentage, setConsensusPercentage] = useState<number>(89.4);
const [selectedAgentId, setSelectedAgentId] = useState<number | null>(null);
const [activeSpeakerId, setActiveSpeakerId] = useState<number | null>(null);
// Multiple speakers can stream in parallel (one bubble per sub-agent). The Set
// tracks every currently-streaming speakerId so the avatar animation lights up
// for each of them concurrently instead of only the most recently set one.
const [activeSpeakerSet, setActiveSpeakerSet] = useState<Set<number>>(new Set());
// Custom presets for agent model, weight, temperature and prompt editors
const [agentConfigs, setAgentConfigs] = useState<{ [key: number]: { model: string; weight: number; prompt: string; temp: number } }>({
@@ -291,6 +296,9 @@ export default function RoundtablePlanningPage() {
const [roundTableSpeed, setRoundTableSpeed] = useState<string>("正常");
const [isRoundTableRunning, setIsRoundTableRunning] = useState<boolean>(true);
const [customAgentInput, setCustomAgentInput] = useState<string>("");
// Whether the roundtable visualizer + constraint console panel is collapsed.
// Collapsing gives the conversation log more vertical space.
const [isUpperPanelCollapsed, setIsUpperPanelCollapsed] = useState<boolean>(false);
// Multi-agent orchestration state (lives only for one step-2 visit).
const [threadIds, setThreadIds] = useState<ThreadIdMap | null>(null);
@@ -300,6 +308,17 @@ export default function RoundtablePlanningPage() {
const [isOrchestrating, setIsOrchestrating] = useState<boolean>(false);
const orchestrationCancelRef = useRef<boolean>(false);
const step2InitRef = useRef<boolean>(false);
// Tracks every AbortController active in this Step 2 visit so the "停止" /
// "挂起协商" button can abort all in-flight stream fetches at once.
const activeAbortersRef = useRef<Set<AbortController>>(new Set());
// Abort every in-flight streaming fetch. Safe to call multiple times.
const abortAllInFlight = useCallback(() => {
activeAbortersRef.current.forEach(ctrl => {
try { ctrl.abort(); } catch { /* noop */ }
});
activeAbortersRef.current.clear();
}, []);
// Toast auto-dismiss logic
useEffect(() => {
@@ -349,7 +368,62 @@ export default function RoundtablePlanningPage() {
]);
}, []);
// Highlight a speaker bubble + flip the role's status label.
// Streaming variant: append a placeholder card and return its id so subsequent
// text deltas can be appended in-place via appendToDialogue.
const appendStreamingDialogue = useCallback((card: {
sender: string;
avatarType: string;
initialContent?: string;
confidence?: string;
}): number => {
const id = Date.now() + Math.random();
setStep2RoundtableDialogues(prev => [
...prev,
{
id,
sender: card.sender,
avatarType: card.avatarType,
content: card.initialContent ?? "",
time: nowTime(),
confidence: card.confidence ?? "正在输出…",
streaming: true,
},
]);
return id;
}, []);
// Append an AI text delta to an existing streaming card (matched by id).
const appendToDialogue = useCallback((id: number, deltaText: string) => {
if (!deltaText) return;
setStep2RoundtableDialogues(prev =>
prev.map(d => (d.id === id ? { ...d, content: (d.content ?? "") + deltaText } : d)),
);
}, []);
// Finalize a streaming card with the official content + final confidence label.
// If the streamed content already matches, we still overwrite with the final
// text (some upstream paths emit trailing whitespace differently).
const finalizeDialogue = useCallback((
id: number,
finalContent: string,
confidence?: string,
) => {
setStep2RoundtableDialogues(prev =>
prev.map(d => {
if (d.id !== id) return d;
const next = finalContent && finalContent.trim().length > 0 ? finalContent : (d.content || "(无文本输出)");
return {
...d,
content: next,
confidence: confidence ?? d.confidence,
streaming: false,
};
}),
);
}, []);
// Highlight a speaker bubble + flip the role's status label. Single-speaker
// mode (used by the leader cycle and the legacy code paths).
const highlightSpeaker = useCallback((speakerId: number | null) => {
setActiveSpeakerId(speakerId);
setRoles(prev =>
@@ -365,6 +439,39 @@ export default function RoundtablePlanningPage() {
);
}, []);
// Add a speaker to the concurrent-streaming set so its avatar lights up
// while a streaming sub-agent run is in flight. Pair with markSpeakerIdle.
const markSpeakerStreaming = useCallback((speakerId: number) => {
setActiveSpeakerSet(prev => {
if (prev.has(speakerId)) return prev;
const next = new Set(prev);
next.add(speakerId);
return next;
});
setRoles(prev =>
prev.map(item => (item.id === speakerId ? { ...item, status: "研讨中" } : item)),
);
}, []);
const markSpeakerIdle = useCallback((speakerId: number) => {
setActiveSpeakerSet(prev => {
if (!prev.has(speakerId)) return prev;
const next = new Set(prev);
next.delete(speakerId);
return next;
});
setRoles(prev =>
prev.map(item => (item.id === speakerId && item.status === "研讨中" ? { ...item, status: "在线" } : item)),
);
}, []);
const clearAllStreamingSpeakers = useCallback(() => {
setActiveSpeakerSet(new Set());
setRoles(prev =>
prev.map(item => (item.status === "研讨中" ? { ...item, status: "在线" } : item)),
);
}, []);
// Pull the consolidated user intent out of step-1 history. Falls back to a
// generic prompt if the user never spoke.
const buildInitialIntent = useCallback(() => {
@@ -393,31 +500,47 @@ export default function RoundtablePlanningPage() {
while (!orchestrationCancelRef.current && safetyCounter < MAX_CYCLES) {
safetyCounter += 1;
highlightSpeaker(2);
appendDialogue({
// Leader bubble — created BEFORE the call so users see "正在输出…" the
// moment the request is in flight, then text fills in as deltas arrive.
const leaderBubbleId = appendStreamingDialogue({
sender: "总控协调",
avatarType: "blue",
content: `🧭 [总控派活] 正在分析当前进展并决定下一步:\n${nextLeaderTask.slice(0, 140)}${nextLeaderTask.length > 140 ? "..." : ""}`,
initialContent: "",
confidence: "调度中",
});
const leaderRes = await streamMultiAgent({
agentType: "leader",
dAgentThreadId: ids,
agentName: coord,
newMessage: nextLeaderTask,
model: DEFAULT_MODEL,
});
// Track this leader call's aborter so the stop button can kill it.
const leaderAborter = new AbortController();
activeAbortersRef.current.add(leaderAborter);
let leaderRes;
try {
leaderRes = await streamMultiAgent({
agentType: "leader",
dAgentThreadId: ids,
agentName: coord,
newMessage: nextLeaderTask,
model: DEFAULT_MODEL,
signal: leaderAborter.signal,
onTextDelta: (text) => appendToDialogue(leaderBubbleId, text),
});
} catch (err) {
activeAbortersRef.current.delete(leaderAborter);
if (leaderAborter.signal.aborted || (err as Error).name === "AbortError") {
finalizeDialogue(leaderBubbleId, "(已停止)", "已停止");
break;
}
throw err;
}
activeAbortersRef.current.delete(leaderAborter);
if (orchestrationCancelRef.current) break;
if (leaderRes.content) {
appendDialogue({
sender: "总结陈述",
avatarType: "blue",
content: leaderRes.content,
confidence: leaderRes.dispatched.length === 0 ? "全案盖印" : "派活说明",
});
}
finalizeDialogue(
leaderBubbleId,
leaderRes.content,
leaderRes.dispatched.length === 0 ? "全案盖印" : "派活说明",
);
if (leaderRes.dispatched.length === 0) {
highlightSpeaker(null);
@@ -427,29 +550,49 @@ export default function RoundtablePlanningPage() {
}
// Dispatch all sub-agents in parallel; per-seat model preference
// overrides the default if the user picked one in the drawer.
// overrides the default if the user picked one in the drawer. Each
// sub-agent gets its own streaming bubble that fills independently.
await Promise.allSettled(
leaderRes.dispatched.map(async ([subName, task]) => {
if (orchestrationCancelRef.current) return;
const meta = AGENT_NAME_TO_ROLE[subName.toLowerCase()];
if (meta) highlightSpeaker(meta.speakerId);
// Add this speaker to the concurrent active set so its avatar
// lights up alongside any other sub-agents streaming in parallel.
if (meta) markSpeakerStreaming(meta.speakerId);
const perSeatModel = meta ? agentConfigs[meta.speakerId]?.model : undefined;
const specRes = await streamMultiAgent({
agentType: "special",
dAgentThreadId: ids,
agentName: subName,
newMessage: task,
model: perSeatModel || DEFAULT_MODEL,
});
if (orchestrationCancelRef.current) return;
appendDialogue({
const subBubbleId = appendStreamingDialogue({
sender: meta?.displayName ?? subName,
avatarType: meta?.avatarType ?? "blue",
content: specRes.content || `(无文本输出)`,
confidence: "子智能体交付",
initialContent: "",
confidence: "正在输出…",
});
const subAborter = new AbortController();
activeAbortersRef.current.add(subAborter);
try {
const specRes = await streamMultiAgent({
agentType: "special",
dAgentThreadId: ids,
agentName: subName,
newMessage: task,
model: perSeatModel || DEFAULT_MODEL,
signal: subAborter.signal,
onTextDelta: (text) => appendToDialogue(subBubbleId, text),
});
if (orchestrationCancelRef.current) return;
finalizeDialogue(subBubbleId, specRes.content, "子智能体交付");
} catch (err) {
if (subAborter.signal.aborted || (err as Error).name === "AbortError") {
finalizeDialogue(subBubbleId, "(已停止)", "已停止");
} else {
console.error(`[special:${subName}] error:`, err);
finalizeDialogue(subBubbleId, `(错误) ${(err as Error).message}`, "调用失败");
}
} finally {
activeAbortersRef.current.delete(subAborter);
if (meta) markSpeakerIdle(meta.speakerId);
}
}),
);
@@ -469,9 +612,18 @@ export default function RoundtablePlanningPage() {
triggerToast(`❌ 研讨异常: ${(err as Error).message}`);
} finally {
highlightSpeaker(null);
clearAllStreamingSpeakers();
setIsOrchestrating(false);
}
}, [appendDialogue, highlightSpeaker, isOrchestrating, agentConfigs]);
}, [appendStreamingDialogue, appendToDialogue, finalizeDialogue, highlightSpeaker, markSpeakerStreaming, markSpeakerIdle, clearAllStreamingSpeakers, isOrchestrating, agentConfigs]);
// Public stop handler used by the pause/stop button and the step-2 teardown.
// Sets the cancel flag and aborts every in-flight stream so the loop can
// unwind immediately (rather than waiting for the current LLM call to finish).
const stopOrchestration = useCallback(() => {
orchestrationCancelRef.current = true;
abortAllInFlight();
}, [abortAllInFlight]);
// On first entry to step 2: init the coordinator + sub-agent threads, then
// fire the first leader cycle. Leaving step 2 resets so re-entering builds
@@ -480,6 +632,7 @@ export default function RoundtablePlanningPage() {
if (currentStep !== 2) {
// tear down: cancel any in-flight orchestration; reset bookkeeping.
orchestrationCancelRef.current = true;
abortAllInFlight();
step2InitRef.current = false;
setIsOrchestrating(false);
return;
@@ -531,12 +684,13 @@ export default function RoundtablePlanningPage() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentStep]);
// Pause/resume button — pausing cancels in-flight stream, resuming kicks off
// another leader cycle to continue the conversation.
// Pause/resume button — pausing aborts every in-flight stream so the run
// halts immediately rather than waiting for the current LLM call to finish.
// Resuming kicks off another leader cycle.
useEffect(() => {
if (currentStep !== 2) return;
if (!isRoundTableRunning) {
orchestrationCancelRef.current = true;
stopOrchestration();
return;
}
if (isOrchestrating || isInitializing || !threadIds || !coordinatorName) return;
@@ -1474,8 +1628,35 @@ export default function RoundtablePlanningPage() {
</div>
</div>
{/* Collapsed handle: when the upper panel is hidden, show a thin
bar at the top of the conversation area so the user can bring
it back. */}
{isUpperPanelCollapsed && (
<div className="shrink-0 px-6 py-2 border-b border-slate-100 bg-white flex items-center justify-center">
<button
onClick={() => setIsUpperPanelCollapsed(false)}
className="flex items-center gap-1.5 text-[11px] font-bold text-slate-500 hover:text-primary hover:bg-slate-50 px-3 py-1 rounded-lg transition cursor-pointer"
title="展开圆桌控制台"
>
<ChevronDown className="w-3.5 h-3.5" />
展开圆桌控制台
</button>
</div>
)}
{/* Split layout: Roundtable visualizer and Interactive Controllers */}
<div className="shrink-0 px-6 py-5 bg-gradient-to-b from-[var(--brand-200)]/10 to-transparent border-b border-slate-100 bg-white">
{!isUpperPanelCollapsed && (
<div className="shrink-0 px-6 py-5 bg-gradient-to-b from-[var(--brand-200)]/10 to-transparent border-b border-slate-100 bg-white relative">
{/* Close button — collapses this whole upper panel so the
conversation log takes the freed vertical space. */}
<button
onClick={() => setIsUpperPanelCollapsed(true)}
className="absolute top-3 right-4 flex items-center gap-1 text-[10px] font-bold text-slate-400 hover:text-primary hover:bg-slate-100 px-2 py-1 rounded-lg transition cursor-pointer z-10"
title="收起圆桌控制台"
>
<X className="w-3.5 h-3.5" />
收起
</button>
<div className="grid grid-cols-1 xl:grid-cols-12 gap-8 items-center max-w-7xl mx-auto">
{/* Left part: Roundtable circle diagram */}
@@ -1497,14 +1678,14 @@ export default function RoundtablePlanningPage() {
{/* Clickable Roundtable Agent Bubbles */}
{/* Role 3: 情报收集 (Top) */}
<button
<button
onClick={() => setSelectedAgentId(3)}
className={`absolute -top-3.5 left-1/2 -translate-x-1/2 transition-transform duration-300 hover:scale-[1.18] active:scale-95 bg-white p-0.5 rounded-full border shadow-md cursor-pointer ${selectedAgentId === 3 || activeSpeakerId === 3 ? 'ring-4 ring-purple-400 scale-[1.12]' : 'border-slate-200'}`}
className={`absolute -top-3.5 left-1/2 -translate-x-1/2 transition-transform duration-300 hover:scale-[1.18] active:scale-95 bg-white p-0.5 rounded-full border shadow-md cursor-pointer ${selectedAgentId === 3 || (activeSpeakerId === 3 || activeSpeakerSet.has(3)) ? 'ring-4 ring-purple-400 scale-[1.12]' : 'border-slate-200'}`}
title="点击配置 情报收集 智能体人设与LLM"
>
<PurpleRobotAvatar size="h-8.5 w-8.5" />
<span className="absolute -bottom-4.5 left-1/2 -translate-x-1/2 text-[8px] bg-purple-900 text-white font-extrabold px-1 rounded whitespace-nowrap shadow-sm">情报收集</span>
{(activeSpeakerId === 3 || selectedAgentId === 3) && (
{((activeSpeakerId === 3 || activeSpeakerSet.has(3)) || selectedAgentId === 3) && (
<span className="absolute -top-1 -right-1 flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-purple-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-purple-500"></span>
@@ -1515,12 +1696,12 @@ export default function RoundtablePlanningPage() {
{/* Role 4: 环境评估 (Top Right) */}
<button
onClick={() => setSelectedAgentId(4)}
className={`absolute top-5 -right-4 transition-transform duration-300 hover:scale-[1.18] active:scale-95 bg-white p-0.5 rounded-full border shadow-md cursor-pointer ${selectedAgentId === 4 || activeSpeakerId === 4 ? 'ring-4 ring-emerald-400 scale-[1.12]' : 'border-slate-200'}`}
className={`absolute top-5 -right-4 transition-transform duration-300 hover:scale-[1.18] active:scale-95 bg-white p-0.5 rounded-full border shadow-md cursor-pointer ${selectedAgentId === 4 || (activeSpeakerId === 4 || activeSpeakerSet.has(4)) ? 'ring-4 ring-emerald-400 scale-[1.12]' : 'border-slate-200'}`}
title="点击配置 环境评估 智能体人设与LLM"
>
<EmeraldRobotAvatar size="h-8.5 w-8.5" />
<span className="absolute -bottom-4.5 left-1/2 -translate-x-1/2 text-[8px] bg-emerald-900 text-white font-extrabold px-1 rounded whitespace-nowrap shadow-sm">环境评估</span>
{(activeSpeakerId === 4 || selectedAgentId === 4) && (
{((activeSpeakerId === 4 || activeSpeakerSet.has(4)) || selectedAgentId === 4) && (
<span className="absolute -top-1 -right-1 flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-emerald-500"></span>
@@ -1531,12 +1712,12 @@ export default function RoundtablePlanningPage() {
{/* Human Participant: 方案设计 (Bottom Right) */}
<button
onClick={() => setSelectedAgentId(5)}
className={`absolute bottom-5 -right-4 transition-transform duration-300 hover:scale-[1.18] active:scale-95 bg-white p-0.5 rounded-full border shadow-md cursor-pointer ${selectedAgentId === 5 || activeSpeakerId === 5 ? 'ring-4 ring-primary/50 scale-[1.12]' : 'border-slate-200'}`}
className={`absolute bottom-5 -right-4 transition-transform duration-300 hover:scale-[1.18] active:scale-95 bg-white p-0.5 rounded-full border shadow-md cursor-pointer ${selectedAgentId === 5 || (activeSpeakerId === 5 || activeSpeakerSet.has(5)) ? 'ring-4 ring-primary/50 scale-[1.12]' : 'border-slate-200'}`}
title="点击查看 方案设计 角色参数"
>
<Man1Avatar size="h-8.5 w-8.5" />
<span className="absolute -bottom-4.5 left-1/2 -translate-x-1/2 text-[8px] bg-[var(--brand-950)] text-white font-extrabold px-1 rounded whitespace-nowrap shadow-sm">方案设计</span>
{(activeSpeakerId === 5 || selectedAgentId === 5) && (
{((activeSpeakerId === 5 || activeSpeakerSet.has(5)) || selectedAgentId === 5) && (
<span className="absolute -top-1 -right-1 flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary/60 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-[var(--brand-200)]0"></span>
@@ -1547,12 +1728,12 @@ export default function RoundtablePlanningPage() {
{/* Role 6: 风险审查 (Bottom) */}
<button
onClick={() => setSelectedAgentId(6)}
className={`absolute -bottom-3.5 left-1/2 -translate-x-1/2 transition-transform duration-300 hover:scale-[1.18] active:scale-95 bg-white p-0.5 rounded-full border shadow-md cursor-pointer ${selectedAgentId === 6 || activeSpeakerId === 6 ? 'ring-4 ring-amber-400 scale-[1.12]' : 'border-slate-200'}`}
className={`absolute -bottom-3.5 left-1/2 -translate-x-1/2 transition-transform duration-300 hover:scale-[1.18] active:scale-95 bg-white p-0.5 rounded-full border shadow-md cursor-pointer ${selectedAgentId === 6 || (activeSpeakerId === 6 || activeSpeakerSet.has(6)) ? 'ring-4 ring-amber-400 scale-[1.12]' : 'border-slate-200'}`}
title="点击配置 风险审查 智能体人设与LLM"
>
<AmberRobotAvatar size="h-8.5 w-8.5" />
<span className="absolute -bottom-4.5 left-1/2 -translate-x-1/2 text-[8px] bg-amber-900 text-white font-extrabold px-1 rounded whitespace-nowrap shadow-sm">风险审查</span>
{(activeSpeakerId === 6 || selectedAgentId === 6) && (
{((activeSpeakerId === 6 || activeSpeakerSet.has(6)) || selectedAgentId === 6) && (
<span className="absolute -top-1 -right-1 flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-amber-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-amber-500"></span>
@@ -1563,12 +1744,12 @@ export default function RoundtablePlanningPage() {
{/* Role 7: 执行规划 (Bottom Left) */}
<button
onClick={() => setSelectedAgentId(7)}
className={`absolute bottom-5 -left-4 transition-transform duration-300 hover:scale-[1.18] active:scale-95 bg-white p-0.5 rounded-full border shadow-md cursor-pointer ${selectedAgentId === 7 || activeSpeakerId === 7 ? 'ring-4 ring-pink-400 scale-[1.12]' : 'border-slate-200'}`}
className={`absolute bottom-5 -left-4 transition-transform duration-300 hover:scale-[1.18] active:scale-95 bg-white p-0.5 rounded-full border shadow-md cursor-pointer ${selectedAgentId === 7 || (activeSpeakerId === 7 || activeSpeakerSet.has(7)) ? 'ring-4 ring-pink-400 scale-[1.12]' : 'border-slate-200'}`}
title="点击配置 执行规划 智能体人设与LLM"
>
<PinkRobotAvatar size="h-8.5 w-8.5" />
<span className="absolute -bottom-4.5 left-1/2 -translate-x-1/2 text-[8px] bg-pink-900 text-white font-extrabold px-1 rounded whitespace-nowrap shadow-sm">执行规划</span>
{(activeSpeakerId === 7 || selectedAgentId === 7) && (
{((activeSpeakerId === 7 || activeSpeakerSet.has(7)) || selectedAgentId === 7) && (
<span className="absolute -top-1 -right-1 flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-pink-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-pink-500"></span>
@@ -1579,12 +1760,12 @@ export default function RoundtablePlanningPage() {
{/* Role 2: 总结陈述 (Top Left) */}
<button
onClick={() => setSelectedAgentId(2)}
className={`absolute top-5 -left-4 transition-transform duration-300 hover:scale-[1.18] active:scale-95 bg-white p-0.5 rounded-full border shadow-md cursor-pointer ${selectedAgentId === 2 || activeSpeakerId === 2 ? 'ring-4 ring-primary/50 scale-[1.12]' : 'border-slate-200'}`}
className={`absolute top-5 -left-4 transition-transform duration-300 hover:scale-[1.18] active:scale-95 bg-white p-0.5 rounded-full border shadow-md cursor-pointer ${selectedAgentId === 2 || (activeSpeakerId === 2 || activeSpeakerSet.has(2)) ? 'ring-4 ring-primary/50 scale-[1.12]' : 'border-slate-200'}`}
title="点击配置 总结陈述 主持人"
>
<RobotAvatar bg="bg-[var(--brand-200)]" headColor="#cf1322" size="h-8.5 w-8.5" />
<span className="absolute -bottom-4.5 left-1/2 -translate-x-1/2 text-[8px] bg-[var(--brand-900)] text-white font-extrabold px-1 rounded whitespace-nowrap shadow-sm">总结陈述</span>
{(activeSpeakerId === 2 || selectedAgentId === 2) && (
{((activeSpeakerId === 2 || activeSpeakerSet.has(2)) || selectedAgentId === 2) && (
<span className="absolute -top-1 -right-1 flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary/60 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-[var(--brand-200)]0"></span>
@@ -1659,6 +1840,7 @@ export default function RoundtablePlanningPage() {
</div>
</div>
)}
{/* Selected Agent Persona Config Drawer / Drawer dialog box */}
{selectedAgentId && (
@@ -1791,9 +1973,9 @@ export default function RoundtablePlanningPage() {
)}
{/* Conversation Log inside Step 2 */}
<div
ref={step2ScrollRef}
className="flex-1 overflow-y-auto p-6 space-y-4 bg-white border-t border-slate-150 border-b border-slate-150 shadow-inner max-h-[350px] min-h-[140px]"
<div
ref={step2ScrollRef}
className="flex-1 min-h-0 overflow-y-auto p-6 space-y-4 bg-white border-t border-slate-150 border-b border-slate-150 shadow-inner"
>
{step2RoundtableDialogues.map((msg) => (
<div
@@ -1813,8 +1995,11 @@ export default function RoundtablePlanningPage() {
</div>
<span className="text-[10px] text-slate-400 font-mono font-medium">{msg.time}</span>
</div>
<p className="text-xs text-slate-700 leading-relaxed font-medium">
<p className="text-xs text-slate-700 leading-relaxed font-medium whitespace-pre-wrap break-words">
{msg.content}
{msg.streaming && (
<span className="inline-block w-1 h-3 ml-0.5 bg-primary align-middle animate-pulse" />
)}
</p>
</div>
</div>
@@ -60,6 +60,10 @@ class AgentsListResponse(BaseModel):
class AgentCreateRequest(BaseModel):
"""Request body for creating a custom agent."""
id: str | None = Field(
default=None,
description="Optional explicit storage id. Must match the storage id pattern. If omitted, a UUID is generated.",
)
name: str = Field(..., description="Display name; Chinese and duplicate names are allowed")
description: str = Field(default="", description="Agent description")
soul: str = Field(default="", description="SOUL.md content - agent personality and behavioral guardrails")
@@ -411,13 +415,19 @@ async def get_agent(agent_id: str, request: Request) -> AgentResponse:
async def create_agent_endpoint(request: AgentCreateRequest, http_request: Request) -> AgentResponse:
_require_agents_api_enabled()
name = _validate_display_name(request.name)
agent_id = uuid4().hex
store = get_agent_store(http_request)
if request.id:
agent_id = _validate_storage_id(request.id)
if await store.get_any(agent_id) is not None:
raise HTTPException(status_code=409, detail=f"Agent id '{agent_id}' already exists")
else:
agent_id = uuid4().hex
agent_dir = get_paths().agent_dir(agent_id)
try:
store = get_agent_store(http_request)
if agent_dir.exists():
raise HTTPException(status_code=409, detail=f"Generated agent id '{agent_id}' already exists")
raise HTTPException(status_code=409, detail=f"Agent id '{agent_id}' already exists")
_write_agent_config(
agent_id,
@@ -69,8 +69,11 @@ async def _create_agent(
model: str | None,
skills: list[str] | None,
soul: str,
agent_id: str | None = None,
) -> tuple[bool, dict[str, Any] | str]:
payload: dict[str, Any] = {"name": name, "description": description, "soul": soul}
if agent_id is not None:
payload["id"] = agent_id
if model is not None:
payload["model"] = model
if skills is not None:
@@ -241,6 +244,7 @@ async def init_multi_agent(request: Request, payload: dict = Body(...)) -> dict[
model=model,
skills=["agent_orchestration"],
soul=soul,
agent_id=main_agent_name,
)
if not ok and isinstance(result, str) and "exists" not in result:
raise HTTPException(status_code=500, detail=f"create coordinator agent failed: {result}")
@@ -425,19 +429,36 @@ async def run_multi_agent_stream(request: Request, payload: dict = Body(...)) ->
async def stream_generator() -> AsyncIterator[str]:
async with httpx.AsyncClient(timeout=None) as client:
if agent_type == "leader":
gen = _leader_run(
client, base, headers, agent_threads, agent_name, new_message, skill_stop_names, model_name,
)
else:
gen = _special_run(
client, base, headers, agent_threads, agent_name, new_message, skill_stop_names, model_name,
)
async for chunk in gen:
if isinstance(chunk, dict):
yield f"data: {json.dumps(chunk, ensure_ascii=False)}\n\n"
try:
if agent_type == "leader":
gen = _leader_run(
client, base, headers, agent_threads, agent_name, new_message, skill_stop_names, model_name,
)
else:
yield chunk if chunk.endswith("\n") else chunk + "\n"
gen = _special_run(
client, base, headers, agent_threads, agent_name, new_message, skill_stop_names, model_name,
)
async for chunk in gen:
if isinstance(chunk, dict):
yield f"data: {json.dumps(chunk, ensure_ascii=False)}\n\n"
else:
yield chunk if chunk.endswith("\n") else chunk + "\n"
except HTTPException as exc:
logger.warning("multi-agent stream HTTPException: %s %s", exc.status_code, exc.detail)
err_frame = {
"status": "error",
"content": f"[{exc.status_code}] {exc.detail}",
"agent_name": agent_name,
}
yield f"data: {json.dumps(err_frame, ensure_ascii=False)}\n\n"
except Exception as exc:
logger.exception("multi-agent stream unexpected failure")
err_frame = {
"status": "error",
"content": f"unexpected: {exc!r}",
"agent_name": agent_name,
}
yield f"data: {json.dumps(err_frame, ensure_ascii=False)}\n\n"
return StreamingResponse(
stream_generator(),
+5 -2
View File
@@ -130,8 +130,11 @@ agents_api:
enabled: true
database:
backend: mysql
mysql_url: $MYSQL_DATABASE_URL
# TODO: 临时切到 SQLite,等 192.168.0.123 MySQL 恢复后改回 backend: mysql
backend: sqlite
sqlite_dir: .deer-flow/data
# backend: mysql
# mysql_url: $MYSQL_DATABASE_URL
pool_size: 10
echo_sql: false
+10
View File
@@ -0,0 +1,10 @@
window.environment = {
b1ConsumerUrl: "http://127.0.0.1:8001/consumer", // http://10.106.71.194:8013/
// b1ConsumerUrl: "http://localhost:8004/consumer", // http://10.106.71.194:8013/
aImagePath: "https://present.a.sit.4.cn/gene", // https://present.a.uat.4.cn present.a.sit.4.cn
g6ImgUrl: "/src/assets",
mapUrl: "https://present.a.sit.4.cn/tiles/{z}/{x}/{y}.jpg",
b1NodeServerUrl: "https://ch1.b.uat.4.cn",
b5ReplyUrl:"https://pg.b.uat.4.cn"
};
@@ -0,0 +1,134 @@
//! moment.js locale configuration
;(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
&& typeof require === 'function' ? factory(require('../moment')) :
typeof define === 'function' && define.amd ? define(['../moment'], factory) :
factory(global.moment)
}(this, (function (moment) { 'use strict';
var symbolMap = {
'1': '١',
'2': '٢',
'3': '٣',
'4': '٤',
'5': '٥',
'6': '٦',
'7': '٧',
'8': '٨',
'9': '٩',
'0': '٠'
}, numberMap = {
'١': '1',
'٢': '2',
'٣': '3',
'٤': '4',
'٥': '5',
'٦': '6',
'٧': '7',
'٨': '8',
'٩': '9',
'٠': '0'
}, pluralForm = function (n) {
return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5;
}, plurals = {
s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'],
m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'],
h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'],
d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'],
M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'],
y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام']
}, pluralize = function (u) {
return function (number, withoutSuffix, string, isFuture) {
var f = pluralForm(number),
str = plurals[u][pluralForm(number)];
if (f === 2) {
str = str[withoutSuffix ? 0 : 1];
}
return str.replace(/%d/i, number);
};
}, months = [
'يناير',
'فبراير',
'مارس',
'أبريل',
'مايو',
'يونيو',
'يوليو',
'أغسطس',
'سبتمبر',
'أكتوبر',
'نوفمبر',
'ديسمبر'
];
var ar = moment.defineLocale('ar', {
months : months,
monthsShort : months,
weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
weekdaysParseExact : true,
longDateFormat : {
LT : 'HH:mm',
LTS : 'HH:mm:ss',
L : 'D/\u200FM/\u200FYYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY HH:mm',
LLLL : 'dddd D MMMM YYYY HH:mm'
},
meridiemParse: /ص|م/,
isPM : function (input) {
return 'م' === input;
},
meridiem : function (hour, minute, isLower) {
if (hour < 12) {
return 'ص';
} else {
return 'م';
}
},
calendar : {
sameDay: '[اليوم عند الساعة] LT',
nextDay: '[غدًا عند الساعة] LT',
nextWeek: 'dddd [عند الساعة] LT',
lastDay: '[أمس عند الساعة] LT',
lastWeek: 'dddd [عند الساعة] LT',
sameElse: 'L'
},
relativeTime : {
future : 'بعد %s',
past : 'منذ %s',
s : pluralize('s'),
ss : pluralize('s'),
m : pluralize('m'),
mm : pluralize('m'),
h : pluralize('h'),
hh : pluralize('h'),
d : pluralize('d'),
dd : pluralize('d'),
M : pluralize('M'),
MM : pluralize('M'),
y : pluralize('y'),
yy : pluralize('y')
},
preparse: function (string) {
return string.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
return numberMap[match];
}).replace(/،/g, ',');
},
postformat: function (string) {
return string.replace(/\d/g, function (match) {
return symbolMap[match];
}).replace(/,/g, '،');
},
week : {
dow : 6, // Saturday is the first day of the week.
doy : 12 // The week that contains Jan 12th is the first week of the year.
}
});
return ar;
})));
@@ -0,0 +1,67 @@
//! moment.js locale configuration
;(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
&& typeof require === 'function' ? factory(require('../moment')) :
typeof define === 'function' && define.amd ? define(['../moment'], factory) :
factory(global.moment)
}(this, (function (moment) { 'use strict';
var sq = moment.defineLocale('sq', {
months : 'Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor'.split('_'),
monthsShort : 'Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj'.split('_'),
weekdays : 'E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë'.split('_'),
weekdaysShort : 'Die_Hën_Mar_Mër_Enj_Pre_Sht'.split('_'),
weekdaysMin : 'D_H_Ma_Më_E_P_Sh'.split('_'),
weekdaysParseExact : true,
meridiemParse: /PD|MD/,
isPM: function (input) {
return input.charAt(0) === 'M';
},
meridiem : function (hours, minutes, isLower) {
return hours < 12 ? 'PD' : 'MD';
},
longDateFormat : {
LT : 'HH:mm',
LTS : 'HH:mm:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY HH:mm',
LLLL : 'dddd, D MMMM YYYY HH:mm'
},
calendar : {
sameDay : '[Sot në] LT',
nextDay : '[Nesër në] LT',
nextWeek : 'dddd [në] LT',
lastDay : '[Dje në] LT',
lastWeek : 'dddd [e kaluar në] LT',
sameElse : 'L'
},
relativeTime : {
future : 'në %s',
past : '%s më parë',
s : 'disa sekonda',
ss : '%d sekonda',
m : 'një minutë',
mm : '%d minuta',
h : 'një orë',
hh : '%d orë',
d : 'një ditë',
dd : '%d ditë',
M : 'një muaj',
MM : '%d muaj',
y : 'një vit',
yy : '%d vite'
},
dayOfMonthOrdinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
doy : 4 // The week that contains Jan 4th is the first week of the year.
}
});
return sq;
})));
@@ -0,0 +1,93 @@
;(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
&& typeof require === 'function' ? factory(require('../moment')) :
typeof define === 'function' && define.amd ? define(['../moment'], factory) :
factory(global.moment)
}(this, (function (moment) { 'use strict';
var suffixes = {
1: '\'inci',
5: '\'inci',
8: '\'inci',
70: '\'inci',
80: '\'inci',
2: '\'nci',
7: '\'nci',
20: '\'nci',
50: '\'nci',
3: '\'üncü',
4: '\'üncü',
100: '\'üncü',
6: '\'ncı',
9: '\'uncu',
10: '\'uncu',
30: '\'uncu',
60: '\'ıncı',
90: '\'ıncı'
};
var tr = moment.defineLocale('tr', {
months : 'Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık'.split('_'),
monthsShort : 'Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara'.split('_'),
weekdays : 'Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi'.split('_'),
weekdaysShort : 'Paz_Pts_Sal_Çar_Per_Cum_Cts'.split('_'),
weekdaysMin : 'Pz_Pt_Sa_Ça_Pe_Cu_Ct'.split('_'),
longDateFormat : {
LT : 'HH:mm',
LTS : 'HH:mm:ss',
L : 'DD.MM.YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY HH:mm',
LLLL : 'dddd, D MMMM YYYY HH:mm'
},
calendar : {
sameDay : '[bugün saat] LT',
nextDay : '[yarın saat] LT',
nextWeek : '[gelecek] dddd [saat] LT',
lastDay : '[dün] LT',
lastWeek : '[geçen] dddd [saat] LT',
sameElse : 'L'
},
relativeTime : {
future : '%s sonra',
past : '%s önce',
s : 'birkaç saniye',
ss : '%d saniye',
m : 'bir dakika',
mm : '%d dakika',
h : 'bir saat',
hh : '%d saat',
d : 'bir gün',
dd : '%d gün',
M : 'bir ay',
MM : '%d ay',
y : 'bir yıl',
yy : '%d yıl'
},
ordinal: function (number, period) {
switch (period) {
case 'd':
case 'D':
case 'Do':
case 'DD':
return number;
default:
if (number === 0) { // special case for zero
return number + '\'ıncı';
}
var a = number % 10,
b = number % 100 - a,
c = number >= 100 ? 100 : null;
return number + (suffixes[a] || suffixes[b] || suffixes[c]);
}
},
week : {
dow : 1, // Monday is the first day of the week.
doy : 7 // The week that contains Jan 7th is the first week of the year.
}
});
return tr;
})));
@@ -0,0 +1 @@
!function(e,a){"object"==typeof exports&&"undefined"!=typeof module?module.exports=a():"function"==typeof define&&define.amd?define(a):e.moment=a()}(this,function(){"use strict";var e,n;function l(){return e.apply(null,arguments)}function _(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function i(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function o(e){return void 0===e}function m(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function u(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function M(e,a){var t,s=[];for(t=0;t<e.length;++t)s.push(a(e[t],t));return s}function h(e,a){return Object.prototype.hasOwnProperty.call(e,a)}function L(e,a){for(var t in a)h(a,t)&&(e[t]=a[t]);return h(a,"toString")&&(e.toString=a.toString),h(a,"valueOf")&&(e.valueOf=a.valueOf),e}function c(e,a,t,s){return Sa(e,a,t,s,!0).utc()}function Y(e){return null==e._pf&&(e._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null,rfc2822:!1,weekdayMismatch:!1}),e._pf}function y(e){if(null==e._isValid){var a=Y(e),t=n.call(a.parsedDateParts,function(e){return null!=e}),s=!isNaN(e._d.getTime())&&a.overflow<0&&!a.empty&&!a.invalidMonth&&!a.invalidWeekday&&!a.weekdayMismatch&&!a.nullInput&&!a.invalidFormat&&!a.userInvalidated&&(!a.meridiem||a.meridiem&&t);if(e._strict&&(s=s&&0===a.charsLeftOver&&0===a.unusedTokens.length&&void 0===a.bigHour),null!=Object.isFrozen&&Object.isFrozen(e))return s;e._isValid=s}return e._isValid}function f(e){var a=c(NaN);return null!=e?L(Y(a),e):Y(a).userInvalidated=!0,a}n=Array.prototype.some?Array.prototype.some:function(e){for(var a=Object(this),t=a.length>>>0,s=0;s<t;s++)if(s in a&&e.call(this,a[s],s,a))return!0;return!1};var d=l.momentProperties=[];function k(e,a){var t,s,n;if(o(a._isAMomentObject)||(e._isAMomentObject=a._isAMomentObject),o(a._i)||(e._i=a._i),o(a._f)||(e._f=a._f),o(a._l)||(e._l=a._l),o(a._strict)||(e._strict=a._strict),o(a._tzm)||(e._tzm=a._tzm),o(a._isUTC)||(e._isUTC=a._isUTC),o(a._offset)||(e._offset=a._offset),o(a._pf)||(e._pf=Y(a)),o(a._locale)||(e._locale=a._locale),0<d.length)for(t=0;t<d.length;t++)o(n=a[s=d[t]])||(e[s]=n);return e}var a=!1;function p(e){k(this,e),this._d=new Date(null!=e._d?e._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)),!1===a&&(a=!0,l.updateOffset(this),a=!1)}function D(e){return e instanceof p||null!=e&&null!=e._isAMomentObject}function T(e){return e<0?Math.ceil(e)||0:Math.floor(e)}function g(e){var a=+e,t=0;return 0!==a&&isFinite(a)&&(t=T(a)),t}function r(e,a,t){var s,n=Math.min(e.length,a.length),d=Math.abs(e.length-a.length),r=0;for(s=0;s<n;s++)(t&&e[s]!==a[s]||!t&&g(e[s])!==g(a[s]))&&r++;return r+d}function w(e){!1===l.suppressDeprecationWarnings&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+e)}function t(n,d){var r=!0;return L(function(){if(null!=l.deprecationHandler&&l.deprecationHandler(null,n),r){for(var e,a=[],t=0;t<arguments.length;t++){if(e="","object"==typeof arguments[t]){for(var s in e+="\n["+t+"] ",arguments[0])e+=s+": "+arguments[0][s]+", ";e=e.slice(0,-2)}else e=arguments[t];a.push(e)}w(n+"\nArguments: "+Array.prototype.slice.call(a).join("")+"\n"+(new Error).stack),r=!1}return d.apply(this,arguments)},d)}var s,v={};function S(e,a){null!=l.deprecationHandler&&l.deprecationHandler(e,a),v[e]||(w(a),v[e]=!0)}function H(e){return e instanceof Function||"[object Function]"===Object.prototype.toString.call(e)}function b(e,a){var t,s=L({},e);for(t in a)h(a,t)&&(i(e[t])&&i(a[t])?(s[t]={},L(s[t],e[t]),L(s[t],a[t])):null!=a[t]?s[t]=a[t]:delete s[t]);for(t in e)h(e,t)&&!h(a,t)&&i(e[t])&&(s[t]=L({},s[t]));return s}function j(e){null!=e&&this.set(e)}l.suppressDeprecationWarnings=!1,l.deprecationHandler=null,s=Object.keys?Object.keys:function(e){var a,t=[];for(a in e)h(e,a)&&t.push(a);return t};var x={};function O(e,a){var t=e.toLowerCase();x[t]=x[t+"s"]=x[a]=e}function P(e){return"string"==typeof e?x[e]||x[e.toLowerCase()]:void 0}function W(e){var a,t,s={};for(t in e)h(e,t)&&(a=P(t))&&(s[a]=e[t]);return s}var A={};function E(e,a){A[e]=a}function F(e,a,t){var s=""+Math.abs(e),n=a-s.length;return(0<=e?t?"+":"":"-")+Math.pow(10,Math.max(0,n)).toString().substr(1)+s}var z=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,J=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,N={},R={};function C(e,a,t,s){var n=s;"string"==typeof s&&(n=function(){return this[s]()}),e&&(R[e]=n),a&&(R[a[0]]=function(){return F(n.apply(this,arguments),a[1],a[2])}),t&&(R[t]=function(){return this.localeData().ordinal(n.apply(this,arguments),e)})}function I(e,a){return e.isValid()?(a=U(a,e.localeData()),N[a]=N[a]||function(s){var e,n,a,d=s.match(z);for(e=0,n=d.lengtLine truncated
+1
View File
@@ -0,0 +1 @@
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.moment=t()}(this,function(){"use strict";var e,i;function c(){return e.apply(null,arguments)}function o(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function u(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function l(e){return void 0===e}function h(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function d(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function f(e,t){var n,s=[];for(n=0;n<e.length;++n)s.push(t(e[n],n));return s}function m(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function _(e,t){for(var n in t)m(t,n)&&(e[n]=t[n]);return m(t,"toString")&&(e.toString=t.toString),m(t,"valueOf")&&(e.valueOf=t.valueOf),e}function y(e,t,n,s){return Tt(e,t,n,s,!0).utc()}function g(e){return null==e._pf&&(e._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null,rfc2822:!1,weekdayMismatch:!1}),e._pf}function v(e){if(null==e._isValid){var t=g(e),n=i.call(t.parsedDateParts,function(e){return null!=e}),s=!isNaN(e._d.getTime())&&t.overflow<0&&!t.empty&&!t.invalidMonth&&!t.invalidWeekday&&!t.weekdayMismatch&&!t.nullInput&&!t.invalidFormat&&!t.userInvalidated&&(!t.meridiem||t.meridiem&&n);if(e._strict&&(s=s&&0===t.charsLeftOver&&0===t.unusedTokens.length&&void 0===t.bigHour),null!=Object.isFrozen&&Object.isFrozen(e))return s;e._isValid=s}return e._isValid}function p(e){var t=y(NaN);return null!=e?_(g(t),e):g(t).userInvalidated=!0,t}i=Array.prototype.some?Array.prototype.some:function(e){for(var t=Object(this),n=t.length>>>0,s=0;s<n;s++)if(s in t&&e.call(this,t[s],s,t))return!0;return!1};var r=c.momentProperties=[];function w(e,t){var n,s,i;if(l(t._isAMomentObject)||(e._isAMomentObject=t._isAMomentObject),l(t._i)||(e._i=t._i),l(t._f)||(e._f=t._f),l(t._l)||(e._l=t._l),l(t._strict)||(e._strict=t._strict),l(t._tzm)||(e._tzm=t._tzm),l(t._isUTC)||(e._isUTC=t._isUTC),l(t._offset)||(e._offset=t._offset),l(t._pf)||(e._pf=g(t)),l(t._locale)||(e._locale=t._locale),0<r.length)for(n=0;n<r.length;n++)l(i=t[s=r[n]])||(e[s]=i);return e}var t=!1;function M(e){w(this,e),this._d=new Date(null!=e._d?e._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)),!1===t&&(t=!0,c.updateOffset(this),t=!1)}function k(e){return e instanceof M||null!=e&&null!=e._isAMomentObject}function S(e){return e<0?Math.ceil(e)||0:Math.floor(e)}function D(e){var t=+e,n=0;return 0!==t&&isFinite(t)&&(n=S(t)),n}function a(e,t,n){var s,i=Math.min(e.length,t.length),r=Math.abs(e.length-t.length),a=0;for(s=0;s<i;s++)(n&&e[s]!==t[s]||!n&&D(e[s])!==D(t[s]))&&a++;return a+r}function Y(e){!1===c.suppressDeprecationWarnings&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+e)}function n(i,r){var a=!0;return _(function(){if(null!=c.deprecationHandler&&c.deprecationHandler(null,i),a){for(var e,t=[],n=0;n<arguments.length;n++){if(e="","object"==typeof arguments[n]){for(var s in e+="\n["+n+"] ",arguments[0])e+=s+": "+arguments[0][s]+", ";e=e.slice(0,-2)}else e=arguments[n];t.push(e)}Y(i+"\nArguments: "+Array.prototype.slice.call(t).join("")+"\n"+(new Error).stack),a=!1}return r.apply(this,arguments)},r)}var s,O={};function T(e,t){null!=c.deprecationHandler&&c.deprecationHandler(e,t),O[e]||(Y(t),O[e]=!0)}function b(e){return e instanceof Function||"[object Function]"===Object.prototype.toString.call(e)}function x(e,t){var n,s=_({},e);for(n in t)m(t,n)&&(u(e[n])&&u(t[n])?(s[n]={},_(s[n],e[n]),_(s[n],t[n])):null!=t[n]?s[n]=t[n]:delete s[n]);for(n in e)m(e,n)&&!m(t,n)&&u(e[n])&&(s[n]=_({},s[n]));return s}function P(e){null!=e&&this.set(e)}c.suppressDeprecationWarnings=!1,c.deprecationHandler=null,s=Object.keys?Object.keys:function(e){var t,n=[];for(t in e)m(e,t)&&n.push(t);return n};var W={};function C(e,t){var n=e.toLowerCase();W[n]=W[n+"s"]=W[t]=e}function H(e){return"string"==typeof e?W[e]||W[e.toLowerCase()]:void 0}function R(e){var t,n,s={};for(n in e)m(e,n)&&(t=H(n))&&(s[t]=e[n]);return s}var U={};function F(e,t){U[e]=t}function L(e,t,n){var s=""+Math.abs(e),i=t-s.length;return(0<=e?n?"+":"":"-")+Math.pow(10,Math.max(0,i)).toString().substr(1)+s}var N=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,G=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,V={},E={};function I(e,t,n,s){var i=s;"string"==typeof s&&(i=function(){return this[s]()}),e&&(E[e]=i),t&&(E[t[0]]=function(){return L(i.apply(this,arguments),t[1],t[2])}),n&&(E[n]=function(){return this.localeData().ordinal(i.apply(this,arguments),e)})}function A(e,t){return e.isValid()?(t=j(t,e.localeData()),V[t]=V[t]||function(s){var e,i,t,r=s.match(N);for(e=0,i=r.lengtLine truncated
@@ -0,0 +1 @@
!function(e,a){"object"==typeof exports&&"undefined"!=typeof module?module.exports=a():"function"==typeof define&&define.amd?define(a):e.moment=a()}(this,function(){"use strict";var e,n;function l(){return e.apply(null,arguments)}function _(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function i(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function o(e){return void 0===e}function m(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function u(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function M(e,a){var t,s=[];for(t=0;t<e.length;++t)s.push(a(e[t],t));return s}function h(e,a){return Object.prototype.hasOwnProperty.call(e,a)}function L(e,a){for(var t in a)h(a,t)&&(e[t]=a[t]);return h(a,"toString")&&(e.toString=a.toString),h(a,"valueOf")&&(e.valueOf=a.valueOf),e}function c(e,a,t,s){return Sa(e,a,t,s,!0).utc()}function Y(e){return null==e._pf&&(e._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null,rfc2822:!1,weekdayMismatch:!1}),e._pf}function y(e){if(null==e._isValid){var a=Y(e),t=n.call(a.parsedDateParts,function(e){return null!=e}),s=!isNaN(e._d.getTime())&&a.overflow<0&&!a.empty&&!a.invalidMonth&&!a.invalidWeekday&&!a.weekdayMismatch&&!a.nullInput&&!a.invalidFormat&&!a.userInvalidated&&(!a.meridiem||a.meridiem&&t);if(e._strict&&(s=s&&0===a.charsLeftOver&&0===a.unusedTokens.length&&void 0===a.bigHour),null!=Object.isFrozen&&Object.isFrozen(e))return s;e._isValid=s}return e._isValid}function f(e){var a=c(NaN);return null!=e?L(Y(a),e):Y(a).userInvalidated=!0,a}n=Array.prototype.some?Array.prototype.some:function(e){for(var a=Object(this),t=a.length>>>0,s=0;s<t;s++)if(s in a&&e.call(this,a[s],s,a))return!0;return!1};var d=l.momentProperties=[];function k(e,a){var t,s,n;if(o(a._isAMomentObject)||(e._isAMomentObject=a._isAMomentObject),o(a._i)||(e._i=a._i),o(a._f)||(e._f=a._f),o(a._l)||(e._l=a._l),o(a._strict)||(e._strict=a._strict),o(a._tzm)||(e._tzm=a._tzm),o(a._isUTC)||(e._isUTC=a._isUTC),o(a._offset)||(e._offset=a._offset),o(a._pf)||(e._pf=Y(a)),o(a._locale)||(e._locale=a._locale),0<d.length)for(t=0;t<d.length;t++)o(n=a[s=d[t]])||(e[s]=n);return e}var a=!1;function p(e){k(this,e),this._d=new Date(null!=e._d?e._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)),!1===a&&(a=!0,l.updateOffset(this),a=!1)}function D(e){return e instanceof p||null!=e&&null!=e._isAMomentObject}function T(e){return e<0?Math.ceil(e)||0:Math.floor(e)}function g(e){var a=+e,t=0;return 0!==a&&isFinite(a)&&(t=T(a)),t}function r(e,a,t){var s,n=Math.min(e.length,a.length),d=Math.abs(e.length-a.length),r=0;for(s=0;s<n;s++)(t&&e[s]!==a[s]||!t&&g(e[s])!==g(a[s]))&&r++;return r+d}function w(e){!1===l.suppressDeprecationWarnings&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+e)}function t(n,d){var r=!0;return L(function(){if(null!=l.deprecationHandler&&l.deprecationHandler(null,n),r){for(var e,a=[],t=0;t<arguments.length;t++){if(e="","object"==typeof arguments[t]){for(var s in e+="\n["+t+"] ",arguments[0])e+=s+": "+arguments[0][s]+", ";e=e.slice(0,-2)}else e=arguments[t];a.push(e)}w(n+"\nArguments: "+Array.prototype.slice.call(a).join("")+"\n"+(new Error).stack),r=!1}return d.apply(this,arguments)},d)}var s,v={};function S(e,a){null!=l.deprecationHandler&&l.deprecationHandler(e,a),v[e]||(w(a),v[e]=!0)}function H(e){return e instanceof Function||"[object Function]"===Object.prototype.toString.call(e)}function b(e,a){var t,s=L({},e);for(t in a)h(a,t)&&(i(e[t])&&i(a[t])?(s[t]={},L(s[t],e[t]),L(s[t],a[t])):null!=a[t]?s[t]=a[t]:delete s[t]);for(t in e)h(e,t)&&!h(a,t)&&i(e[t])&&(s[t]=L({},s[t]));return s}function j(e){null!=e&&this.set(e)}l.suppressDeprecationWarnings=!1,l.deprecationHandler=null,s=Object.keys?Object.keys:function(e){var a,t=[];for(a in e)h(e,a)&&t.push(a);return t};var x={};function O(e,a){var t=e.toLowerCase();x[t]=x[t+"s"]=x[a]=e}function P(e){return"string"==typeof e?x[e]||x[e.toLowerCase()]:void 0}function W(e){var a,t,s={};for(t in e)h(e,t)&&(a=P(t))&&(s[a]=e[t]);return s}var A={};function E(e,a){A[e]=a}function F(e,a,t){var s=""+Math.abs(e),n=a-s.length;return(0<=e?t?"+":"":"-")+Math.pow(10,Math.max(0,n)).toString().substr(1)+s}var z=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,J=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,N={},R={};function C(e,a,t,s){var n=s;"string"==typeof s&&(n=function(){return this[s]()}),e&&(R[e]=n),a&&(R[a[0]]=function(){return F(n.apply(this,arguments),a[1],a[2])}),t&&(R[t]=function(){return this.localeData().ordinal(n.apply(this,arguments),e)})}function I(e,a){return e.isValid()?(a=U(a,e.localeData()),N[a]=N[a]||function(s){var e,n,a,d=s.match(z);for(e=0,n=d.lengtLine truncated
@@ -0,0 +1,2 @@
.vis-time-axis{position:relative;overflow:hidden}.vis-time-axis.vis-foreground{top:0;left:0;width:100%}.vis-time-axis.vis-background{position:absolute;top:0;left:0;width:100%;height:100%}.vis-time-axis .vis-text{position:absolute;color:#4d4d4d;padding:3px;overflow:hidden;box-sizing:border-box;white-space:nowrap}.vis-time-axis .vis-text.vis-measure{position:absolute;padding-left:0;padding-right:0;margin-left:0;margin-right:0;visibility:hidden}.vis-time-axis .vis-grid.vis-vertical{position:absolute;border-left:1px solid}.vis-time-axis .vis-grid.vis-vertical-rtl{position:absolute;border-right:1px solid}.vis-time-axis .vis-grid.vis-minor{border-color:#e5e5e5}.vis-time-axis .vis-grid.vis-major{border-color:#bfbfbf}.vis .overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.vis-active{box-shadow:0 0 10px #86d5f8}.vis-custom-time{background-color:#6e94ff;width:2px;cursor:move;z-index:1}.vis-custom-time>.vis-custom-time-marker{background-color:inherit;color:#fff;font-size:12px;white-space:nowrap;padding:3px 5px;top:0;cursor:auto;z-index:inherit}.vis-current-time{background-color:#ff7f6e;width:2px;z-index:1;pointer-events:none}.vis-rolling-mode-btn{height:40px;width:40px;position:absolute;top:7px;right:20px;border-radius:50%;font-size:28px;cursor:pointer;opacity:.8;color:#fff;font-weight:700;text-align:center;background:#3876c2}.vis-rolling-mode-btn:before{content:"\26F6"}.vis-rolling-mode-btn:hover{opacity:1}.vis-panel{position:absolute;padding:0;margin:0;box-sizing:border-box}.vis-panel.vis-bottom,.vis-panel.vis-center,.vis-panel.vis-left,.vis-panel.vis-right,.vis-panel.vis-top{border:1px #bfbfbf}.vis-panel.vis-center,.vis-panel.vis-left,.vis-panel.vis-right{border-top-style:solid;border-bottom-style:solid;overflow:hidden}.vis-left.vis-panel.vis-vertical-scroll,.vis-right.vis-panel.vis-vertical-scroll{height:100%;overflow-x:hidden;overflow-y:scroll}.vis-left.vis-panel.vis-vertical-scroll{direction:rtl}.vis-left.vis-panel.vis-vertical-scroll .vis-content,.vis-right.vis-panel.vis-vertical-scroll{direction:ltr}.vis-right.vis-panel.vis-vertical-scroll .vis-content{direction:rtl}.vis-panel.vis-bottom,.vis-panel.vis-center,.vis-panel.vis-top{border-left-style:solid;border-right-style:solid}.vis-background{overflow:hidden}.vis-panel>.vis-content{position:relative}.vis-panel .vis-shadow{position:absolute;width:100%;height:1px;box-shadow:0 0 10px rgba(0,0,0,.8)}.vis-panel .vis-shadow.vis-top{top:-1px;left:0}.vis-panel .vis-shadow.vis-bottom{bottom:-1px;left:0}.vis-graph-group0{fill:#4f81bd;fill-opacity:0;stroke-width:2px;stroke:#4f81bd}.vis-graph-group1{fill:#f79646;fill-opacity:0;stroke-width:2px;stroke:#f79646}.vis-graph-group2{fill:#8c51cf;fill-opacity:0;stroke-width:2px;stroke:#8c51cf}.vis-graph-group3{fill:#75c841;fill-opacity:0;stroke-width:2px;stroke:#75c841}.vis-graph-group4{fill:#ff0100;fill-opacity:0;stroke-width:2px;stroke:#ff0100}.vis-graph-group5{fill:#37d8e6;fill-opacity:0;stroke-width:2px;stroke:#37d8e6}.vis-graph-group6{fill:#042662;fill-opacity:0;stroke-width:2px;stroke:#042662}.vis-graph-group7{fill:#00ff26;fill-opacity:0;stroke-width:2px;stroke:#00ff26}.vis-graph-group8{fill:#f0f;fill-opacity:0;stroke-width:2px;stroke:#f0f}.vis-graph-group9{fill:#8f3938;fill-opacity:0;stroke-width:2px;stroke:#8f3938}.vis-timeline .vis-fill{fill-opacity:.1;stroke:none}.vis-timeline .vis-bar{fill-opacity:.5;stroke-width:1px}.vis-timeline .vis-point{stroke-width:2px;fill-opacity:1}.vis-timeline .vis-legend-background{stroke-width:1px;fill-opacity:.9;fill:#fff;stroke:#c2c2c2}.vis-timeline .vis-outline{stroke-width:1px;fill-opacity:1;fill:#fff;stroke:#e5e5e5}.vis-timeline .vis-icon-fill{fill-opacity:.3;stroke:none}.vis-timeline{position:relative;border:1px solid #bfbfbf;overflow:hidden;padding:0;margin:0;box-sizing:border-box}.vis-loading-screen{width:100%;height:100%;position:absolute;top:0;left:0}.vis [class*=span]{min-height:0;width:auto}.vis-item{position:absolute;color:#1a1a1a;border-color:#97b0f8;border-width:1px;background-color:#d5ddf6;display:inline-block;z-index:1}.vis-item.vis-selected{border-color:#ffc200;background-color:#fff785;z-index:2}.vis-editable.vis-selected{cursor:move}.vis-item.vis-point.vis-selected{background-color:#fff785}.vis-item.vis-box{text-align:center;border-style:solid;border-radius:2px}.vis-item.vis-point{background:none}.vis-item.vis-dot{position:absolute;padding:0;border-width:4px;border-style:solid;border-radius:4px}.vis-item.vis-range{border-style:solid;border-radius:2px;box-sizing:border-box}.vis-item.vis-background{border:none;background-color:rgba(213,221,246,.4);box-sizing:border-box;padding:0;margin:0}.vis-item .vis-item-overflow{position:relative;width:100%;height:100%;padding:0;margin:0;overflow:hidden}.vis-item-visible-frame{white-space:nowrap}.vis-item.vis-range .vis-item-content{position:relative;display:inline-block}.vis-item.vis-background .vis-item-content{position:absolute;display:inline-block}.vis-item.vis-line{padding:0;position:absolute;width:0;border-Line truncated
/*# sourceMappingURL=vis-timeline-graph2d.min.css.map */
@@ -0,0 +1,34 @@
/**
* vis-timeline and vis-graph2d
* https://visjs.github.io/vis-timeline/
*
* Create a fully customizable, interactive timeline with items and ranges.
*
* @version 7.5.1
* @date 2022-03-01T18:26:09.239Z
*
* @copyright (c) 2011-2017 Almende B.V, http://almende.com
* @copyright (c) 2017-2019 visjs contributors, https://github.com/visjs
*
* @license
* vis.js is dual licensed under both
*
* 1. The Apache 2.0 License
* http://www.apache.org/licenses/LICENSE-2.0
*
* and
*
* 2. The MIT License
* http://opensource.org/licenses/MIT
*
* vis.js may be distributed under either license.
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).vis=t.vis||{})}(this,(function(t){var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function n(t){throw new Error('Could not dynamically require "'+t+'". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.')}var o={exports:{}};!function(t,e){t.exports=function(){var e,i;function o(){return e.apply(null,arguments)}function r(t){e=t}function s(t){return t instanceof Array||"[object Array]"===Object.prototype.toString.call(t)}function a(t){return null!=t&&"[object Object]"===Object.prototype.toString.call(t)}function l(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function h(t){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(t).length;var e;for(e in t)if(l(t,e))return!1;return!0}function u(t){return void 0===t}function d(t){return"number"==typeof t||"[object Number]"===Object.prototype.toString.call(t)}function c(t){return t instanceof Date||"[object Date]"===Object.prototype.toString.call(t)}function p(t,e){var i,n=[];for(i=0;i<t.length;++i)n.push(e(t[i],i));return n}function f(t,e){for(var i in e)l(e,i)&&(t[i]=e[i]);return l(e,"toString")&&(t.toString=e.toString),l(e,"valueOf")&&(t.valueOf=e.valueOf),t}function m(t,e,i,n){return Xi(t,e,i,n,!0).utc()}function v(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidEra:null,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],era:null,meridiem:null,rfc2822:!1,weekdayMismatch:!1}}function g(t){return null==t._pf&&(t._pf=v()),t._pf}function y(t){if(null==t._isValid){var e=g(t),n=i.call(e.parsedDateParts,(function(t){return null!=t})),o=!isNaN(t._d.getTime())&&e.overflow<0&&!e.empty&&!e.invalidEra&&!e.invalidMonth&&!e.invalidWeekday&&!e.weekdayMismatch&&!e.nullInput&&!e.invalidFormat&&!e.userInvalidated&&(!e.meridiem||e.meridiem&&n);if(t._strict&&(o=o&&0===e.charsLeftOver&&0===e.unusedTokens.length&&void 0===e.bigHour),null!=Object.isFrozen&&Object.isFrozen(t))return o;t._isValid=o}return t._isValid}function b(t){var e=m(NaN);return null!=t?f(g(e),t):g(e).userInvalidated=!0,e}i=Array.prototype.some?Array.prototype.some:function(t){var e,i=Object(this),n=i.length>>>0;for(e=0;e<n;e++)if(e in i&&t.call(this,i[e],e,i))return!0;return!1};var _=o.momentProperties=[],w=!1;function k(t,e){var i,n,o;if(u(e._isAMomentObject)||(t._isAMomentObject=e._isAMomentObject),u(e._i)||(t._i=e._i),u(e._f)||(t._f=e._f),u(e._l)||(t._l=e._l),u(e._strict)||(t._strict=e._strict),u(e._tzm)||(t._tzm=e._tzm),u(e._isUTC)||(t._isUTC=e._isUTC),u(e._offset)||(t._offset=e._offset),u(e._pf)||(t._pf=g(e)),u(e._locale)||(t._locale=e._locale),_.length>0)for(i=0;i<_.length;i++)u(o=e[n=_[i]])||(t[n]=o);return t}function x(t){k(this,t),this._d=new Date(null!=t._d?t._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)),!1===w&&(w=!0,o.updateOffset(this),w=!1)}function D(t){return t instanceof x||null!=t&&null!=t._isAMomentObject}function S(t){!1===o.suppressDeprecationWarnings&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+t)}function C(t,e){var i=!0;return f((function(){if(null!=o.deprecationHandler&&o.deprecationHandler(null,t),i){var n,r,s,a=[];for(r=0;r<arguments.length;r++){if(n="","object"==typeof arguments[r]){for(s in n+="\n["+r+"] ",arguments[0])l(arguments[0],s)&&(n+=s+": "+arguments[0][s]+", ");n=n.slice(0,-2)}else n=arguments[r];a.push(n)}S(t+"\nArguments: "+Array.prototype.slice.call(a).join("")+"\n"+(new Error).stack),i=!1}return e.apply(this,arguments)}),e)}var T,M={};function O(t,e){null!=o.deprecationHandler&&o.deprecationHandler(t,e),M[t]||(S(e),M[t]=!0)}function E(t){return"undefined"!=typeof Function&&t instanceof Function||"[object Function]"===Object.prototype.toString.call(t)}function P(t){var e,i;for(i in t)l(t,i)&&(E(e=t[i])?this[i]=e:this["_"+i]=e);this._config=t,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)}function A(t,e){var i,n=f({},t);for(i in e)l(e,i)&&(a(t[i])&&a(e[i])?(n[i]={},f(n[i],t[i]),f(n[i],e[i])):null!=e[i]?n[i]=e[i]:delete n[i]);for(i in t)l(t,i)&&!l(e,i)&&a(t[i])&&(n[i]=f({},n[i]));return n}function I(t){null!=t&&this.set(t)}o.suppressDeprecationWarnings=!1,o.deprecationHandler=null,T=Object.keys?Object.keys:function(t){var e,i=[];for(e in t)l(t,e)&&i.push(e);return i};var L={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"};function N(t,e,i){var n=this._calendar[t]||this._calendar.sameElse;return E(n)?n.call(e,i):n}function F(t,e,i){var n=""+Math.abs(t),o=e-n.Line truncated
o.version="2.29.1",r(qi),o.fn=hr,o.min=Ji,o.max=Qi,o.now=tn,o.utc=m,o.unix=ur,o.months=gr,o.isDate=c,o.locale=fi,o.invalid=b,o.duration=Mn,o.isMoment=D,o.weekdays=br,o.parseZone=dr,o.localeData=gi,o.isDuration=an,o.monthsShort=yr,o.weekdaysMin=wr,o.defineLocale=mi,o.updateLocale=vi,o.locales=yi,o.weekdaysShort=_r,o.normalizeUnits=ot,o.relativeTimeRounding=os,o.relativeTimeThreshold=rs,o.calendarFormat=zn,o.prototype=hr,o.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},o}()}(o);var r=o.exports;!function(t){function e(t,e,i,n){var o={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[t+" Tage",t+" Tagen"],w:["eine Woche","einer Woche"],M:["ein Monat","einem Monat"],MM:[t+" Monate",t+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[t+" Jahre",t+" Jahren"]};return e?o[i][0]:o[i][1]}t.defineLocale("de",{months:"Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",ss:"%d Sekunden",m:e,mm:"%d Minuten",h:e,hh:"%d Stunden",d:e,dd:e,w:e,ww:"%d Wochen",M:e,MM:e,y:e,yy:e},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(o.exports),function(t){var e="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),i="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),n=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],o=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;t.defineLocale("es",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(t,n){return t?/-MMM-/.test(n)?i[t.month()]:e[t.month()]:e},monthsRegex:o,monthsShortRegex:o,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:n,longMonthsParse:n,shortMonthsParse:n,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4},invalidDate:"Fecha inválida"})}(o.exports),function(t){var e=/(janv\.?|févr\.?|mars|avr\.?|mai|juin|juil\.?|août|sept\.?|oct\.?|nov\.?|déc\.?|janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)/i,i=[/^janv/i,/^févr/i,/^mars/i,/^avr/i,/^mai/i,/^juin/i,/^juil/i,/^août/i,/^sept/i,/^oct/i,/^nov/i,/^déc/i];t.defineLocale("fr",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsRegex:e,monthsShortRegex:e,monthsStrictRegex:/^(janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)/i,monthsShortStrictRegex:/(janv\.?|févr\.?|mars|avr\.?|mai|juin|juil\.?|août|sept\.?|oct\.?|nov\.?|déc\.?)/i,monthsParse:i,longMonthsParse:i,shortMonthsParse:i,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_saLine truncated
/*! Hammer.JS - v2.0.17-rc - 2019-12-16
* http://naver.github.io/egjs
*
* Forked By Naver egjs
* Copyright (c) hammerjs
* Licensed under the MIT license */function Gf(){return(Gf=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t}).apply(this,arguments)}function Bf(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,t.__proto__=e}function Wf(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}var Vf,Uf="function"!=typeof Object.assign?function(t){if(null==t)throw new TypeError("Cannot convert undefined or null to object");for(var e=Object(t),i=1;i<arguments.length;i++){var n=arguments[i];if(null!=n)for(var o in n)n.hasOwnProperty(o)&&(e[o]=n[o])}return e}:Object.assign,Xf=["","webkit","Moz","MS","ms","o"],qf="undefined"==typeof document?{style:{}}:document.createElement("div"),Zf=Math.round,$f=Math.abs,Kf=Date.now;function Jf(t,e){for(var i,n,o=e[0].toUpperCase()+e.slice(1),r=0;r<Xf.length;){if((n=(i=Xf[r])?i+o:e)in t)return n;r++}}Vf="undefined"==typeof window?{}:window;var Qf=Jf(qf.style,"touchAction"),tm=void 0!==Qf;var em="compute",im="auto",nm="manipulation",om="none",rm="pan-x",sm="pan-y",am=function(){if(!tm)return!1;var t={},e=Vf.CSS&&Vf.CSS.supports;return["auto","manipulation","pan-y","pan-x","pan-x pan-y","none"].forEach((function(i){return t[i]=!e||Vf.CSS.supports("touch-action",i)})),t}(),lm="ontouchstart"in Vf,hm=void 0!==Jf(Vf,"PointerEvent"),um=lm&&/mobile|tablet|ip(ad|hone|od)|android/i.test(navigator.userAgent),dm="touch",cm="mouse",pm=16,fm=24,mm=["x","y"],vm=["clientX","clientY"];function gm(t,e,i){var n;if(t)if(t.forEach)t.forEach(e,i);else if(void 0!==t.length)for(n=0;n<t.length;)e.call(i,t[n],n,t),n++;else for(n in t)t.hasOwnProperty(n)&&e.call(i,t[n],n,t)}function ym(t,e){return"function"==typeof t?t.apply(e&&e[0]||void 0,e):t}function bm(t,e){return t.indexOf(e)>-1}var _m=function(){function t(t,e){this.manager=t,this.set(e)}var e=t.prototype;return e.set=function(t){t===em&&(t=this.compute()),tm&&this.manager.element.style&&am[t]&&(this.manager.element.style[Qf]=t),this.actions=t.toLowerCase().trim()},e.update=function(){this.set(this.manager.options.touchAction)},e.compute=function(){var t=[];return gm(this.manager.recognizers,(function(e){ym(e.options.enable,[e])&&(t=t.concat(e.getTouchAction()))})),function(t){if(bm(t,om))return om;var e=bm(t,rm),i=bm(t,sm);return e&&i?om:e||i?e?rm:sm:bm(t,nm)?nm:im}(t.join(" "))},e.preventDefaults=function(t){var e=t.srcEvent,i=t.offsetDirection;if(this.manager.session.prevented)e.preventDefault();else{var n=this.actions,o=bm(n,om)&&!am.none,r=bm(n,sm)&&!am["pan-y"],s=bm(n,rm)&&!am["pan-x"];if(o){var a=1===t.pointers.length,l=t.distance<2,h=t.deltaTime<250;if(a&&l&&h)return}if(!s||!r)return o||r&&6&i||s&&i&fm?this.preventSrc(e):void 0}},e.preventSrc=function(t){this.manager.session.prevented=!0,t.preventDefault()},t}();function wm(t,e){for(;t;){if(t===e)return!0;t=t.parentNode}return!1}function km(t){var e=t.length;if(1===e)return{x:Zf(t[0].clientX),y:Zf(t[0].clientY)};for(var i=0,n=0,o=0;o<e;)i+=t[o].clientX,n+=t[o].clientY,o++;return{x:Zf(i/e),y:Zf(n/e)}}function xm(t){for(var e=[],i=0;i<t.pointers.length;)e[i]={clientX:Zf(t.pointers[i].clientX),clientY:Zf(t.pointers[i].clientY)},i++;return{timeStamp:Kf(),pointers:e,center:km(e),deltaX:t.deltaX,deltaY:t.deltaY}}function Dm(t,e,i){i||(i=mm);var n=e[i[0]]-t[i[0]],o=e[i[1]]-t[i[1]];return Math.sqrt(n*n+o*o)}function Sm(t,e,i){i||(i=mm);var n=e[i[0]]-t[i[0]],o=e[i[1]]-t[i[1]];return 180*Math.atan2(o,n)/Math.PI}function Cm(t,e){return t===e?1:$f(t)>=$f(e)?t<0?2:4:e<0?8:pm}function Tm(t,e,i){return{x:e/t||0,y:i/t||0}}function Mm(t,e){var i=t.session,n=e.pointers,o=n.length;i.firstInput||(i.firstInput=xm(e)),o>1&&!i.firstMultiple?i.firstMultiple=xm(e):1===o&&(i.firstMultiple=!1);var r=i.firstInput,s=i.firstMultiple,a=s?s.center:r.center,l=e.center=km(n);e.timeStamp=Kf(),e.deltaTime=e.timeStamp-r.timeStamp,e.angle=Sm(a,l),e.distance=Dm(a,l),function(t,e){var i=e.center,n=t.offsetDelta||{},o=t.prevDelta||{},r=t.prevInput||{};1!==e.eventType&&4!==r.eventType||(o=t.prevDelta={x:r.deltaX||0,y:r.deltaY||0},n=t.offsetDelta={x:i.x,y:i.y}),e.deltaX=o.x+(i.x-n.x),e.deltaY=o.y+(i.y-n.y)}(i,e),e.offsetDirection=Cm(e.deltaX,e.deltaY);var h,u,d=Tm(e.deltaTime,e.deltaX,e.deltaY);e.overallVelocityX=d.x,e.overallVelocityY=d.y,e.overallVelocity=$f(d.x)>$f(d.y)?d.x:d.y,e.scale=s?(h=s.pointers,Dm((u=n)[0],u[1],vm)/Dm(h[0],h[1],vm)):1,e.rotation=s?function(t,e){return Sm(e[1],e[0],vm)+Sm(t[1],t[0],vm)}(s.pointers,n):0,e.maxPointers=i.prevInput?e.pointers.length>i.prevInput.maxPointers?e.pointers.length:i.prevInput.maxPointers:e.pointers.length,function(t,e){var i,n,o,r,s=t.lastInterval||e,a=e.timeStamp-s.timeStamp;if(8!==e.eventType&&(a>25||void 0===s.velocity)){var l=e.deltaX-s.deltaX,h=e.deltaY-s.deltaY,u=Tm(a,l,h);n=u.x,o=u.y,i=$f(u.x)>$f(u.y)?u.x:u.y,r=Cm(l,h),t.lastInterval=e}else i=s.velocity,n=s.velocityX,o=s.velocityY,r=s.direction;e.velocityLine truncated
//# sourceMappingURL=vis-timeline-graph2d.min.js.map
File diff suppressed because it is too large. Load diff
+47
View File
@@ -0,0 +1,47 @@
/**
* vis.js
* https://github.com/almende/vis
*
* A dynamic, browser-based visualization library.
*
* @version 4.20.1-SNAPSHOT
* @date 2017-10-12
*
* @license
* Copyright (C) 2011-2017 Almende B.V, http://almende.com
*
* Vis.js is dual licensed under both
*
* * The Apache 2.0 License
* http://www.apache.org/licenses/LICENSE-2.0
*
* and
*
* * The MIT License
* http://opensource.org/licenses/MIT
*
* Vis.js may be distributed under either license.
*/
"use strict";!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.vis=e():t.vis=e()}(this,function(){return function(t){function e(o){if(i[o])return i[o].exports;var n=i[o]={i:o,l:!1,exports:{}};return t[o].call(n.exports,n,n.exports,e),n.l=!0,n.exports}var i={};return e.m=t,e.c=i,e.d=function(t,i,o){e.o(t,i)||Object.defineProperty(t,i,{configurable:!1,enumerable:!0,get:o})},e.n=function(t){var i=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(i,"a",i),i},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=123)}([function(t,e,i){e.__esModule=!0,e.default=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}},function(t,e,i){e.__esModule=!0;var o=i(169),n=function(t){return t&&t.__esModule?t:{default:t}}(o);e.default=function(){function t(t,e){for(var i=0;i<e.length;i++){var o=e[i];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),(0,n.default)(t,o.key,o)}}return function(e,i,o){return i&&t(e.prototype,i),o&&t(e,o),e}}()},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}function n(t,e,i,o){var n=!1;!0===o&&(n=null===e[i]&&void 0!==t[i]),n?delete t[i]:t[i]=e[i]}var s=i(77),r=o(s),a=i(29),h=o(a),d=i(8),l=o(d),u=i(6),c=o(u),p=i(9),f=i(157);e.isNumber=function(t){return t instanceof Number||"number"==typeof t},e.recursiveDOMDelete=function(t){if(t)for(;!0===t.hasChildNodes();)e.recursiveDOMDelete(t.firstChild),t.removeChild(t.firstChild)},e.giveRange=function(t,e,i,o){if(e==t)return.5;var n=1/(e-t);return Math.max(0,(o-t)*n)},e.isString=function(t){return t instanceof String||"string"==typeof t},e.isDate=function(t){if(t instanceof Date)return!0;if(e.isString(t)){if(m.exec(t))return!0;if(!isNaN(Date.parse(t)))return!0}return!1},e.randomUUID=function(){return f.v4()},e.assignAllKeys=function(t,e){for(var i in t)t.hasOwnProperty(i)&&"object"!==(0,c.default)(t[i])&&(t[i]=e)},e.fillIfDefined=function(t,i){var o=arguments.length>2&&void 0!==arguments[2]&&arguments[2];for(var s in t)void 0!==i[s]&&(null===i[s]||"object"!==(0,c.default)(i[s])?n(t,i,s,o):"object"===(0,c.default)(t[s])&&e.fillIfDefined(t[s],i[s],o))},e.extend=function(t,e){for(var i=1;i<arguments.length;i++){var o=arguments[i];for(var n in o)o.hasOwnProperty(n)&&(t[n]=o[n])}return t},e.selectiveExtend=function(t,e,i){if(!Array.isArray(t))throw new Error("Array with property names expected as first argument");for(var o=2;o<arguments.length;o++)for(var n=arguments[o],s=0;s<t.length;s++){var r=t[s];n&&n.hasOwnProperty(r)&&(e[r]=n[r])}return e},e.selectiveDeepExtend=function(t,i,o){var s=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if(Array.isArray(o))throw new TypeError("Arrays are not supported by deepExtend");for(var r=0;r<t.length;r++){var a=t[r];if(o.hasOwnProperty(a))if(o[a]&&o[a].constructor===Object)void 0===i[a]&&(i[a]={}),i[a].constructor===Object?e.deepExtend(i[a],o[a],!1,s):n(i,o,a,s);else{if(Array.isArray(o[a]))throw new TypeError("Arrays are not supported by deepExtend");n(i,o,a,s)}}return i},e.selectiveNotDeepExtend=function(t,i,o){var s=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if(Array.isArray(o))throw new TypeError("Arrays are not supported by deepExtend");for(var r in o)if(o.hasOwnProperty(r)&&-1===t.indexOf(r))if(o[r]&&o[r].constructor===Object)void 0===i[r]&&(i[r]={}),i[r].constructor===Object?e.deepExtend(i[r],o[r]):n(i,o,r,s);else if(Array.isArray(o[r])){i[r]=[];for(var a=0;a<o[r].length;a++)i[r].push(o[r][a])}else n(i,o,r,s);return i},e.deepExtend=function(t,i){var o=arguments.length>2&&void 0!==arguments[2]&&arguments[2],s=arguments.length>3&&void 0!==arguments[3]&&arguments[3];for(var r in i)if(i.hasOwnProperty(r)||!0===o)if(i[r]&&i[r].constructor===Object)void 0===t[r]&&(t[r]={}),t[r].constructor===Object?e.deepExtend(t[r],i[r],o):n(t,i,r,s);else if(Array.isArray(i[r])){t[r]=[];for(var a=0;a<i[r].length;a++)t[r].push(i[r][a])}else n(t,i,r,s);return t},e.equalArray=function(t,e){if(t.length!=e.length)return!1;for(var i=0,o=t.length;i<o;i++)if(t[i]!=e[i])return!1;return!0},e.convert=function(t,i){var o;if(void 0!==t){if(null===t)return null;if(!i)return t;if("string"!=typeof i&&!(i instanceof String))throw new Error("Type must be a string");switch(i){case"boolean":case"Boolean":return Boolean(t);case"number":case"Number":return e.isString(t)&&!isNaN(Date.parse(t))?p(t).valueOf():Number(t.valueOf());case"string":case"String":return String(t);case"Date":if(e.isNumber(t))return new Date(t);if(t instanceof Date)return new Date(t.valueOf());if(p.isMoment(t))return new Date(t.valueOf());if(e.isString(t))return o=m.exec(t),o?new Date(Number(o[1])):p(new Date(t)).toDate();throw new Error("Cannot convert object of type "+e.getType(t)+" to type Date");case"Moment":if(e.isNumber(t))return p(t);if(t instanceof Date)return p(t.valueOf());if(p.isMoment(t))return p(t);ifLine truncated
;r=void 0!==n.indexMatch?" in "+t.printLocation(n.path,e,"")+'Perhaps it was incomplete? Did you mean: "'+n.indexMatch+'"?\n\n':s.distance<=4&&n.distance>s.distance?" in "+t.printLocation(n.path,e,"")+"Perhaps it was misplaced? Matching option found at: "+t.printLocation(s.path,s.closestMatch,""):n.distance<=8?'. Did you mean "'+n.closestMatch+'"?'+t.printLocation(n.path,e):". Did you mean one of these: "+t.print((0,d.default)(i))+t.printLocation(o,e),console.log('%cUnknown option detected: "'+e+'"'+r,g),m=!0}},{key:"findInOptions",value:function(e,i,o){var n=arguments.length>3&&void 0!==arguments[3]&&arguments[3],s=1e9,r="",a=[],h=e.toLowerCase(),d=void 0;for(var l in i){var u=void 0;if(void 0!==i[l].__type__&&!0===n){var c=t.findInOptions(e,i[l],f.copyAndExtendArray(o,l));s>c.distance&&(r=c.closestMatch,a=c.path,s=c.distance,d=c.indexMatch)}else-1!==l.toLowerCase().indexOf(h)&&(d=l),u=t.levenshteinDistance(e,l),s>u&&(r=l,a=f.copyArray(o),s=u)}return{closestMatch:r,path:a,distance:s,indexMatch:d}}},{key:"printLocation",value:function(t,e){for(var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"Problem value found at: \n",o="\n\n"+i+"options = {\n",n=0;n<t.length;n++){for(var s=0;s<n+1;s++)o+=" ";o+=t[n]+": {\n"}for(var r=0;r<t.length+1;r++)o+=" ";o+=e+"\n";for(var a=0;a<t.length+1;a++){for(var h=0;h<t.length-a;h++)o+=" ";o+="}\n"}return o+"\n\n"}},{key:"print",value:function(t){return(0,s.default)(t).replace(/(\")|(\[)|(\])|(,"__type__")/g,"").replace(/(\,)/g,", ")}},{key:"levenshteinDistance",value:function(t,e){if(0===t.length)return e.length;if(0===e.length)return t.length;var i,o=[];for(i=0;i<=e.length;i++)o[i]=[i];var n;for(n=0;n<=t.length;n++)o[0][n]=n;for(i=1;i<=e.length;i++)for(n=1;n<=t.length;n++)e.charAt(i-1)==t.charAt(n-1)?o[i][n]=o[i-1][n-1]:o[i][n]=Math.min(o[i-1][n-1]+1,Math.min(o[i][n-1]+1,o[i-1][n]+1));return o[e.length][t.length]}}]),t}();e.default=y,e.printStyle=g},function(t,e,i){function o(t,e){this.options=null,this.props=null}var n=i(2);o.prototype.setOptions=function(t){t&&n.extend(this.options,t)},o.prototype.redraw=function(){return!1},o.prototype.destroy=function(){},o.prototype._isResized=function(){var t=this.props._previousWidth!==this.props.width||this.props._previousHeight!==this.props.height;return this.props._previousWidth=this.props.width,this.props._previousHeight=this.props.height,t},t.exports=o},function(t,e,i){var o=i(18),n=i(7),s=i(80),r=i(26),a=function(t,e,i){var h,d,l,u=t&a.F,c=t&a.G,p=t&a.S,f=t&a.P,m=t&a.B,v=t&a.W,g=c?n:n[e]||(n[e]={}),y=g.prototype,b=c?o:p?o[e]:(o[e]||{}).prototype;c&&(i=e);for(h in i)(d=!u&&b&&void 0!==b[h])&&h in g||(l=d?b[h]:i[h],g[h]=c&&"function"!=typeof b[h]?i[h]:m&&d?s(l,o):v&&b[h]==l?function(t){var e=function(e,i,o){if(this instanceof t){switch(arguments.length){case 0:return new t;case 1:return new t(e);case 2:return new t(e,i)}return new t(e,i,o)}return t.apply(this,arguments)};return e.prototype=t.prototype,e}(l):f&&"function"==typeof l?s(Function.call,l):l,f&&((g.virtual||(g.virtual={}))[h]=l,t&a.R&&y&&!y[h]&&r(y,h,l)))};a.F=1,a.G=2,a.S=4,a.P=8,a.B=16,a.W=32,a.U=64,a.R=128,t.exports=a},function(t,e){var i=t.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=i)},function(t,e,i){t.exports={default:i(160),__esModule:!0}},function(t,e,i){var o=i(27),n=i(81),s=i(53),r=Object.defineProperty;e.f=i(21)?Object.defineProperty:function(t,e,i){if(o(t),e=s(e,!0),o(i),n)try{return r(t,e,i)}catch(t){}if("get"in i||"set"in i)throw TypeError("Accessors not supported!");return"value"in i&&(t[e]=i.value),t}},function(t,e,i){t.exports=!i(28)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(t,e){var i={}.hasOwnProperty;t.exports=function(t,e){return i.call(t,e)}},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(6),s=o(n),r=i(0),a=o(r),h=i(1),d=o(h),l=function(){function t(e,i,o){(0,a.default)(this,t),this.body=i,this.labelModule=o,this.setOptions(e),this.top=void 0,this.left=void 0,this.height=void 0,this.width=void 0,this.radius=void 0,this.margin=void 0,this.refreshNeeded=!0,this.boundingBox={top:0,left:0,right:0,bottom:0}}return(0,d.default)(t,[{key:"setOptions",value:function(t){this.options=t}},{key:"_setMargins",value:function(t){this.margin={},this.options.margin&&("object"==(0,s.default)(this.options.margin)?(this.margin.top=this.options.margin.top,this.margin.right=this.options.margin.right,this.margin.bottom=this.options.margin.bottom,this.margin.left=this.options.margin.left):(this.margin.top=this.options.margin,this.margin.right=this.options.margin,this.margin.bottom=this.options.margin,this.margin.left=this.options.margin)),t.adjustSizes(this.margin)}},{key:"_distanceToBorder",value:function(t,e){var i=this.options.borderWidth;return this.resize(t),Math.min(Math.abs(this.width/2/Math.cos(e)),Math.abs(thiLine truncated
;var s=this.options.showMinorLabels&&"none"!==this.options.orientation.axis,r=this.options.showMajorLabels&&"none"!==this.options.orientation.axis;t.minorLabelHeight=s?t.minorCharHeight:0,t.majorLabelHeight=r?t.majorCharHeight:0,t.height=t.minorLabelHeight+t.majorLabelHeight,t.width=e.offsetWidth,t.minorLineHeight=this.body.domProps.root.height-t.majorLabelHeight-("top"==this.options.orientation.axis?this.body.domProps.bottom.height:this.body.domProps.top.height),t.minorLineWidth=1,t.majorLineHeight=t.minorLineHeight+t.majorLabelHeight,t.majorLineWidth=1;var a=e.nextSibling,h=i.nextSibling;return e.parentNode&&e.parentNode.removeChild(e),i.parentNode&&i.parentNode.removeChild(i),e.style.height=this.props.height+"px",this._repaintLabels(),a?o.insertBefore(e,a):o.appendChild(e),h?this.body.dom.backgroundVertical.insertBefore(i,h):this.body.dom.backgroundVertical.appendChild(i),this._isResized()||n},o.prototype._repaintLabels=function(){var t=this.options.orientation.axis,e=r.convert(this.body.range.start,"Number"),i=r.convert(this.body.range.end,"Number"),o=this.body.util.toTime((this.props.minorCharWidth||10)*this.options.maxMinorChars).valueOf(),n=o-d.getHiddenDurationBefore(this.options.moment,this.body.hiddenDates,this.body.range,o);n-=this.body.util.toTime(0).valueOf();var s=new h(new Date(e),new Date(i),n,this.body.hiddenDates,this.options);s.setMoment(this.options.moment),this.options.format&&s.setFormat(this.options.format),this.options.timeAxis&&s.setScale(this.options.timeAxis),this.step=s;var a=this.dom;a.redundant.lines=a.lines,a.redundant.majorTexts=a.majorTexts,a.redundant.minorTexts=a.minorTexts,a.lines=[],a.majorTexts=[],a.minorTexts=[];var l,c,p,f,m,v,g,y,b,_=0,w=void 0,x=0;for(s.start(),l=s.getCurrent(),p=this.body.util.toScreen(l);s.hasNext()&&x<1e3;){switch(x++,f=s.isMajor(),b=s.getClassName(),y=s.getLabelMinor(),l,c=p,s.next(),l=s.getCurrent(),s.isMajor(),p=this.body.util.toScreen(l),v=_,_=p-c,s.scale){case"week":m=!0;break;default:m=_>=.4*v}if(this.options.showMinorLabels&&m){var k=this._repaintMinorText(c,y,t,b);k.style.width=_+"px"}f&&this.options.showMajorLabels?(c>0&&(void 0==w&&(w=c),k=this._repaintMajorText(c,s.getLabelMajor(),t,b)),g=this._repaintMajorLine(c,_,t,b)):m?g=this._repaintMinorLine(c,_,t,b):g&&(g.style.width=parseInt(g.style.width)+_+"px")}if(1e3!==x||u||(console.warn("Something is wrong with the Timeline scale. Limited drawing of grid lines to 1000 lines."),u=!0),this.options.showMajorLabels){var S=this.body.util.toTime(0),D=s.getLabelMajor(S),M=D.length*(this.props.majorCharWidth||10)+10;(void 0==w||M<w)&&this._repaintMajorText(0,D,t,b)}r.forEach(this.dom.redundant,function(t){for(;t.length;){var e=t.pop();e&&e.parentNode&&e.parentNode.removeChild(e)}})},o.prototype._repaintMinorText=function(t,e,i,o){var n=this.dom.redundant.minorTexts.shift();if(!n){var s=document.createTextNode("");n=document.createElement("div"),n.appendChild(s),this.dom.foreground.appendChild(n)}return this.dom.minorTexts.push(n),n.innerHTML=e,n.style.top="top"==i?this.props.majorLabelHeight+"px":"0",this.options.rtl?(n.style.left="",n.style.right=t+"px"):n.style.left=t+"px",n.className="vis-text vis-minor "+o,n},o.prototype._repaintMajorText=function(t,e,i,o){var n=this.dom.redundant.majorTexts.shift();if(!n){var s=document.createElement("div");n=document.createElement("div"),n.appendChild(s),this.dom.foreground.appendChild(n)}return n.childNodes[0].innerHTML=e,n.className="vis-text vis-major "+o,n.style.top="top"==i?"0":this.props.minorLabelHeight+"px",this.options.rtl?(n.style.left="",n.style.right=t+"px"):n.style.left=t+"px",this.dom.majorTexts.push(n),n},o.prototype._repaintMinorLine=function(t,e,i,o){var n=this.dom.redundant.lines.shift();n||(n=document.createElement("div"),this.dom.background.appendChild(n)),this.dom.lines.push(n);var s=this.props;return n.style.top="top"==i?s.majorLabelHeight+"px":this.body.domProps.top.height+"px",n.style.height=s.minorLineHeight+"px",this.options.rtl?(n.style.left="",n.style.right=t-s.minorLineWidth/2+"px",n.className="vis-grid vis-vertical-rtl vis-minor "+o):(n.style.left=t-s.minorLineWidth/2+"px",n.className="vis-grid vis-vertical vis-minor "+o),n.style.width=e+"px",n},o.prototype._repaintMajorLine=function(t,e,i,o){var n=this.dom.redundant.lines.shift();n||(n=document.createElement("div"),this.dom.background.appendChild(n)),this.dom.lines.push(n);var s=this.props;return n.style.top="top"==i?"0":this.body.domProps.top.height+"px",this.options.rtl?(n.style.left="",n.style.right=t-s.majorLineWidth/2+"px",n.className="vis-grid vis-vertical-rtl vis-major "+o):(n.style.left=t-s.majorLineWidth/2+"px",n.className="vis-grid vis-vertical vis-major "+o),n.style.height=s.majorLineHeight+"px",n.style.width=e+"px",n},o.prototype._calculateCharSize=function(){this.dom.measureCharMinor||(this.dom.measureCharMinor=document.createElement("DIV"),this.dom.measureCharMinor.className="vis-text vis-minor vis-measure",this.dom.measureCharMinor.style.position="absolute",thiLine truncated
;var d=m.snapAwayFromHidden(this.body.hiddenDates,a,i,!0),l=m.snapAwayFromHidden(this.body.hiddenDates,h,-i,!0);d==a&&l==h||(a=d,h=l);var u={animation:!1,byUser:!0,event:o};this.setRange(a,h,u),this.startToFront=!1,this.endToFront=!0},n.prototype.move=function(t){var e=this.end-this.start,i=this.start+e*t,o=this.end+e*t;this.start=i,this.end=o},n.prototype.moveTo=function(t){var e=(this.start+this.end)/2,i=e-t,o=this.start-i,n=this.end-i,s={animation:!1,byUser:!0,event:null};this.setRange(o,n,s)},t.exports=n},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}function n(){}var s=i(19),r=o(s),a=i(6),h=o(a),d=i(44),l=i(10),u=i(37),c=i(2),p=i(45),f=i(97),m=i(36),v=i(46);d(n.prototype),n.prototype._create=function(t){function e(t){this.isActive()&&this.emit("mousewheel",t);var e=0,i=0;if("detail"in t&&(i=-1*t.detail),"wheelDelta"in t&&(i=t.wheelDelta),"wheelDeltaY"in t&&(i=t.wheelDeltaY),"wheelDeltaX"in t&&(e=-1*t.wheelDeltaX),"axis"in t&&t.axis===t.HORIZONTAL_AXIS&&(e=-1*i,i=0),"deltaY"in t&&(i=-1*t.deltaY),"deltaX"in t&&(e=t.deltaX),this.options.zoomKey&&!t[this.options.zoomKey])if(t.preventDefault(),this.options.verticalScroll&&Math.abs(i)>=Math.abs(e)){var o=this.props.scrollTop,n=o+i;this.isActive()&&(this._setScrollTop(n),this._redraw(),this.emit("scroll",t))}else if(this.options.horizontalScroll){var s=Math.abs(e)>=Math.abs(i)?e:i,r=s/120*(this.range.end-this.range.start)/20,a=this.range.start+r,h=this.range.end+r,d={animation:!1,byUser:!0,event:t};this.range.setRange(a,h,d)}}function i(t){if(s.options.verticalScroll&&(t.preventDefault(),s.isActive())){var e=-t.target.scrollTop;s._setScrollTop(e),s._redraw(),s.emit("scrollSide",t)}}function o(t){if(t.preventDefault&&t.preventDefault(),!(!t.target.className.indexOf("vis")>-1||a))return t.dataTransfer.dropEffect="move",a=!0,!1}function n(t){t.preventDefault&&t.preventDefault(),t.stopPropagation&&t.stopPropagation();try{var e=JSON.parse(t.dataTransfer.getData("text"));if(!e||!e.content)return}catch(t){return!1}return a=!1,t.center={x:t.clientX,y:t.clientY},"item"!==e.target?s.itemSet._onAddItem(t):s.itemSet._onDropObjectOnItem(t),s.emit("drop",s.getEventProperties(t)),!1}this.dom={},this.dom.container=t,this.dom.root=document.createElement("div"),this.dom.background=document.createElement("div"),this.dom.backgroundVertical=document.createElement("div"),this.dom.backgroundHorizontal=document.createElement("div"),this.dom.centerContainer=document.createElement("div"),this.dom.leftContainer=document.createElement("div"),this.dom.rightContainer=document.createElement("div"),this.dom.center=document.createElement("div"),this.dom.left=document.createElement("div"),this.dom.right=document.createElement("div"),this.dom.top=document.createElement("div"),this.dom.bottom=document.createElement("div"),this.dom.shadowTop=document.createElement("div"),this.dom.shadowBottom=document.createElement("div"),this.dom.shadowTopLeft=document.createElement("div"),this.dom.shadowBottomLeft=document.createElement("div"),this.dom.shadowTopRight=document.createElement("div"),this.dom.shadowBottomRight=document.createElement("div"),this.dom.rollingModeBtn=document.createElement("div"),this.dom.root.className="vis-timeline",this.dom.background.className="vis-panel vis-background",this.dom.backgroundVertical.className="vis-panel vis-background vis-vertical",this.dom.backgroundHorizontal.className="vis-panel vis-background vis-horizontal",this.dom.centerContainer.className="vis-panel vis-center",this.dom.leftContainer.className="vis-panel vis-left",this.dom.rightContainer.className="vis-panel vis-right",this.dom.top.className="vis-panel vis-top",this.dom.bottom.className="vis-panel vis-bottom",this.dom.left.className="vis-content",this.dom.center.className="vis-content",this.dom.right.className="vis-content",this.dom.shadowTop.className="vis-shadow vis-top",this.dom.shadowBottom.className="vis-shadow vis-bottom",this.dom.shadowTopLeft.className="vis-shadow vis-top",this.dom.shadowBottomLeft.className="vis-shadow vis-bottom",this.dom.shadowTopRight.className="vis-shadow vis-top",this.dom.shadowBottomRight.className="vis-shadow vis-bottom",this.dom.rollingModeBtn.className="vis-rolling-mode-btn",this.dom.root.appendChild(this.dom.background),this.dom.root.appendChild(this.dom.backgroundVertical),this.dom.root.appendChild(this.dom.backgroundHorizontal),this.dom.root.appendChild(this.dom.centerContainer),this.dom.root.appendChild(this.dom.leftContainer),this.dom.root.appendChild(this.dom.rightContainer),this.dom.root.appendChild(this.dom.top),this.dom.root.appendChild(this.dom.bottom),this.dom.root.appendChild(this.dom.bottom),this.dom.root.appendChild(this.dom.rollingModeBtn),this.dom.centerContainer.appendChild(this.dom.center),this.dom.leftContainer.appendChild(this.dom.left),this.dom.rightContainer.appendChild(this.dom.right),this.dom.centerContainer.appendChild(this.dom.shadowTop),this.dom.centerContainer.appendChild(this.dom.shadowBottom),this.dom.leftContainer.appendCLine truncated
h.push(t(r.date()-1));break;case"week":h.push("vis-week"+r.format("w")),h.push(i(r)),h.push(t(r.week()));break;case"month":h.push("vis-"+r.format("MMMM").toLowerCase()),h.push(o(r)),h.push(t(r.month()));break;case"year":h.push("vis-year"+r.year()),h.push(function(t){return t.isSame(new Date,"year")?" vis-current-year":""}(r)),h.push(t(r.year()))}return h.filter(String).join(" ")},t.exports=o},function(t,e,i){function o(t,e){this.body=t,this.defaultOptions={rtl:!1,showCurrentTime:!0,moment:r,locales:a,locale:"en"},this.options=n.extend({},this.defaultOptions),this.offset=0,this._create(),this.setOptions(e)}var n=i(2),s=i(16),r=i(9),a=i(98);o.prototype=new s,o.prototype._create=function(){var t=document.createElement("div");t.className="vis-current-time",t.style.position="absolute",t.style.top="0px",t.style.height="100%",this.bar=t},o.prototype.destroy=function(){this.options.showCurrentTime=!1,this.redraw(),this.body=null},o.prototype.setOptions=function(t){t&&n.selectiveExtend(["rtl","showCurrentTime","moment","locale","locales"],this.options,t)},o.prototype.redraw=function(){if(this.options.showCurrentTime){var t=this.body.dom.backgroundVertical;this.bar.parentNode!=t&&(this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar),t.appendChild(this.bar),this.start());var e=this.options.moment((new Date).valueOf()+this.offset),i=this.body.util.toScreen(e),o=this.options.locales[this.options.locale];o||(this.warned||(console.log("WARNING: options.locales['"+this.options.locale+"'] not found. See http://visjs.org/docs/timeline/#Localization"),this.warned=!0),o=this.options.locales.en);var n=o.current+" "+o.time+": "+e.format("dddd, MMMM Do YYYY, H:mm:ss");n=n.charAt(0).toUpperCase()+n.substring(1),this.options.rtl?this.bar.style.right=i+"px":this.bar.style.left=i+"px",this.bar.title=n}else this.bar.parentNode&&this.bar.parentNode.removeChild(this.bar),this.stop();return!1},o.prototype.start=function(){function t(){e.stop();var i=e.body.range.conversion(e.body.domProps.center.width).scale,o=1/i/10;o<30&&(o=30),o>1e3&&(o=1e3),e.redraw(),e.body.emitter.emit("currentTimeTick"),e.currentTimeTimer=setTimeout(t,o)}var e=this;t()},o.prototype.stop=function(){void 0!==this.currentTimeTimer&&(clearTimeout(this.currentTimeTimer),delete this.currentTimeTimer)},o.prototype.setCurrentTime=function(t){var e=n.convert(t,"Date").valueOf(),i=(new Date).valueOf();this.offset=e-i,this.redraw()},o.prototype.getCurrentTime=function(){return new Date((new Date).valueOf()+this.offset)},t.exports=o},function(t,e,i){function o(t,e,i){if(this.groupId=t,this.subgroups={},this.subgroupStack={},this.subgroupStackAll=!1,this.doInnerStack=!1,this.subgroupIndex=0,this.subgroupOrderer=e&&e.subgroupOrder,this.itemSet=i,this.isVisible=null,this.stackDirty=!0,e&&e.nestedGroups&&(this.nestedGroups=e.nestedGroups,0==e.showNested?this.showNested=!1:this.showNested=!0),e&&e.subgroupStack)if("boolean"==typeof e.subgroupStack)this.doInnerStack=e.subgroupStack,this.subgroupStackAll=e.subgroupStack;else for(var o in e.subgroupStack)this.subgroupStack[o]=e.subgroupStack[o],this.doInnerStack=this.doInnerStack||e.subgroupStack[o];this.nestedInGroup=null,this.dom={},this.props={label:{width:0,height:0}},this.className=null,this.items={},this.visibleItems=[],this.itemsInRange=[],this.orderedItems={byStart:[],byEnd:[]},this.checkRangedItems=!1;var n=this;this.itemSet.body.emitter.on("checkRangedItems",function(){n.checkRangedItems=!0}),this._create(),this.setData(e)}var n=i(8),s=function(t){return t&&t.__esModule?t:{default:t}}(n),r=i(2),a=i(100);o.prototype._create=function(){var t=document.createElement("div");this.itemSet.options.groupEditable.order?t.className="vis-label draggable":t.className="vis-label",this.dom.label=t;var e=document.createElement("div");e.className="vis-inner",t.appendChild(e),this.dom.inner=e;var i=document.createElement("div");i.className="vis-group",i["timeline-group"]=this,this.dom.foreground=i,this.dom.background=document.createElement("div"),this.dom.background.className="vis-group",this.dom.axis=document.createElement("div"),this.dom.axis.className="vis-group",this.dom.marker=document.createElement("div"),this.dom.marker.style.visibility="hidden",this.dom.marker.style.position="absolute",this.dom.marker.innerHTML="",this.dom.background.appendChild(this.dom.marker)},o.prototype.setData=function(t){var e,i;if(this.itemSet.options&&this.itemSet.options.groupTemplate?(i=this.itemSet.options.groupTemplate.bind(this),e=i(t,this.dom.inner)):e=t&&t.content,e instanceof Element){for(this.dom.inner.appendChild(e);this.dom.inner.firstChild;)this.dom.inner.removeChild(this.dom.inner.firstChild);this.dom.inner.appendChild(e)}else e instanceof Object?i(t,this.dom.inner):this.dom.inner.innerHTML=void 0!==e&&null!==e?e:this.groupId||"";if(this.dom.label.title=t&&t.title||"",this.dom.inner.firstChild?r.removeClassName(this.dom.inner,"vis-hidden"):r.addClassName(this.dom.inner,"vis-hidden"),t&&t.nestedGroups){this.nestedGroups&&this.nestedGroLine truncated
styles:e.styles||t.options.drawPoints.styles,size:e.size||t.options.drawPoints.size,className:e.className||t.className}}function s(t,e){var i=void 0;return t.options&&t.options.drawPoints&&t.options.drawPoints.onRender&&"function"==typeof t.options.drawPoints.onRender&&(i=t.options.drawPoints.onRender),e.group.options&&e.group.options.drawPoints&&e.group.options.drawPoints.onRender&&"function"==typeof e.group.options.drawPoints.onRender&&(i=e.group.options.drawPoints.onRender),i}var r=i(6),a=function(t){return t&&t.__esModule?t:{default:t}}(r),h=i(14);o.draw=function(t,e,i,o){o=o||0;for(var r=s(i,e),d=0;d<t.length;d++)if(r){var l=r(t[d],e);!0!==l&&"object"!==(void 0===l?"undefined":(0,a.default)(l))||h.drawPoint(t[d].screen_x+o,t[d].screen_y,n(e,l),i.svgElements,i.svg,t[d].label)}else h.drawPoint(t[d].screen_x+o,t[d].screen_y,n(e),i.svgElements,i.svg,t[d].label)},o.drawIcon=function(t,e,i,o,s,r){var a=.5*s,d=h.getSVGElement("rect",r.svgElements,r.svg);d.setAttributeNS(null,"x",e),d.setAttributeNS(null,"y",i-a),d.setAttributeNS(null,"width",o),d.setAttributeNS(null,"height",2*a),d.setAttributeNS(null,"class","vis-outline"),h.drawPoint(e+.5*o,i,n(t),r.svgElements,r.svg)},t.exports=o},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(3),s=o(n),r=i(0),a=o(r),h=i(1),d=o(h),l=i(4),u=o(l),c=i(5),p=o(c),f=i(23),m=o(f),v=function(t){function e(t,i,o){(0,a.default)(this,e);var n=(0,u.default)(this,(e.__proto__||(0,s.default)(e)).call(this,t,i,o));return n.labelOffset=0,n.selected=!1,n}return(0,p.default)(e,t),(0,d.default)(e,[{key:"setOptions",value:function(t,e,i){this.options=t,void 0===e&&void 0===i||this.setImages(e,i)}},{key:"setImages",value:function(t,e){e&&this.selected?(this.imageObj=e,this.imageObjAlt=t):(this.imageObj=t,this.imageObjAlt=e)}},{key:"switchImages",value:function(t){var e=t&&!this.selected||!t&&this.selected;if(this.selected=t,void 0!==this.imageObjAlt&&e){var i=this.imageObj;this.imageObj=this.imageObjAlt,this.imageObjAlt=i}}},{key:"_resizeImage",value:function(){var t,e;if(!1===this.options.shapeProperties.useImageSize){var i=1,o=1;this.imageObj.width&&this.imageObj.height&&(this.imageObj.width>this.imageObj.height?i=this.imageObj.width/this.imageObj.height:o=this.imageObj.height/this.imageObj.width),t=2*this.options.size*i,e=2*this.options.size*o}else t=this.imageObj.width,e=this.imageObj.height;this.width=t,this.height=e,this.radius=.5*this.width}},{key:"_drawRawCircle",value:function(t,e,i,o){this.initContextForDraw(t,o),t.circle(e,i,o.size),this.performFill(t,o)}},{key:"_drawImageAtPosition",value:function(t,e){if(0!=this.imageObj.width){t.globalAlpha=1,this.enableShadow(t,e);var i=1;!0===this.options.shapeProperties.interpolation&&(i=this.imageObj.width/this.width/this.body.view.scale),this.imageObj.drawImageAtPosition(t,i,this.left,this.top,this.width,this.height),this.disableShadow(t,e)}}},{key:"_drawImageLabel",value:function(t,e,i,o,n){var s,r=0;if(void 0!==this.height){r=.5*this.height;var a=this.labelModule.getTextSize(t,o,n);a.lineCount>=1&&(r+=a.height/2)}s=i+r,this.options.label&&(this.labelOffset=r),this.labelModule.draw(t,e,s,o,n,"hanging")}}]),e}(m.default);e.default=v},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(19),s=o(n),r=i(6),a=o(r),h=i(29),d=o(h),l=i(0),u=o(l),c=i(1),p=o(c),f=i(2),m=i(117).default,v=i(48).default,g=i(215).default,y=i(217).default,b=i(218).default,_=i(219).default,w=function(){function t(e,i,o,n){if((0,u.default)(this,t),void 0===i)throw new Error("No body provided");this.options=f.bridgeObject(o),this.globalOptions=o,this.defaultOptions=n,this.body=i,this.id=void 0,this.fromId=void 0,this.toId=void 0,this.selected=!1,this.hover=!1,this.labelDirty=!0,this.baseWidth=this.options.width,this.baseFontSize=this.options.font.size,this.from=void 0,this.to=void 0,this.edgeType=void 0,this.connected=!1,this.labelModule=new m(this.body,this.options,!0),this.setOptions(e)}return(0,p.default)(t,[{key:"setOptions",value:function(e){if(e){t.parseOptions(this.options,e,!0,this.globalOptions),void 0!==e.id&&(this.id=e.id),void 0!==e.from&&(this.fromId=e.from),void 0!==e.to&&(this.toId=e.to),void 0!==e.title&&(this.title=e.title),void 0!==e.value&&(e.value=parseFloat(e.value));var i=[e,this.options,this.defaultOptions];this.chooser=v.choosify("edge",i),this.updateLabelModule(e);var o=this.updateEdgeType();return this._setInteractionWidths(),this.connect(),void 0===e.hidden&&void 0===e.physics||(o=!0),o}}},{key:"getFormattingValues",value:function(){var t=!0===this.options.arrows.to||!0===this.options.arrows.to.enabled,e=!0===this.options.arrows.from||!0===this.options.arrows.from.enabled,i=!0===this.options.arrows.middle||!0===this.options.arrows.middle.enabled,o=this.options.color.inherit,n={toArrow:t,toArrowScale:this.options.arrows.to.scaleFactor,toArrowType:this.options.arrows.to.type,middleArrow:i,middleArrowScalLine truncated
o.prototype.getArmLength=function(){return this.armLength},o.prototype.getCameraLocation=function(){return this.cameraLocation},o.prototype.getCameraRotation=function(){return this.cameraRotation},o.prototype.calculateCameraOrientation=function(){this.cameraLocation.x=this.armLocation.x-this.armLength*Math.sin(this.armRotation.horizontal)*Math.cos(this.armRotation.vertical),this.cameraLocation.y=this.armLocation.y-this.armLength*Math.cos(this.armRotation.horizontal)*Math.cos(this.armRotation.vertical),this.cameraLocation.z=this.armLocation.z+this.armLength*Math.sin(this.armRotation.vertical),this.cameraRotation.x=Math.PI/2-this.armRotation.vertical,this.cameraRotation.y=0,this.cameraRotation.z=-this.armRotation.horizontal;var t=this.cameraRotation.x,e=this.cameraRotation.z,i=this.cameraOffset.x,o=this.cameraOffset.y,n=Math.sin,s=Math.cos;this.cameraLocation.x=this.cameraLocation.x+i*s(e)+o*-n(e)*s(t),this.cameraLocation.y=this.cameraLocation.y+i*n(e)+o*s(e)*s(t),this.cameraLocation.z=this.cameraLocation.z+o*n(t)},t.exports=o},function(t,e,i){function o(t,e,i){this.dataGroup=t,this.column=e,this.graph=i,this.index=void 0,this.value=void 0,this.values=t.getDistinctValues(this.column),this.values.length>0&&this.selectValue(0),this.dataPoints=[],this.loaded=!1,this.onLoadCallback=void 0,i.animationPreload?(this.loaded=!1,this.loadInBackground()):this.loaded=!0}var n=i(12);o.prototype.isLoaded=function(){return this.loaded},o.prototype.getLoadedProgress=function(){for(var t=this.values.length,e=0;this.dataPoints[e];)e++;return Math.round(e/t*100)},o.prototype.getLabel=function(){return this.graph.filterLabel},o.prototype.getColumn=function(){return this.column},o.prototype.getSelectedValue=function(){if(void 0!==this.index)return this.values[this.index]},o.prototype.getValues=function(){return this.values},o.prototype.getValue=function(t){if(t>=this.values.length)throw new Error("Index out of range");return this.values[t]},o.prototype._getDataPoints=function(t){if(void 0===t&&(t=this.index),void 0===t)return[];var e;if(this.dataPoints[t])e=this.dataPoints[t];else{var i={};i.column=this.column,i.value=this.values[t];var o=new n(this.dataGroup.getDataSet(),{filter:function(t){return t[i.column]==i.value}}).get();e=this.dataGroup._getDataPoints(o),this.dataPoints[t]=e}return e},o.prototype.setOnLoadCallback=function(t){this.onLoadCallback=t},o.prototype.selectValue=function(t){if(t>=this.values.length)throw new Error("Index out of range");this.index=t,this.value=this.values[t]},o.prototype.loadInBackground=function(t){void 0===t&&(t=0);var e=this.graph.frame;if(t<this.values.length){void 0===e.progress&&(e.progress=document.createElement("DIV"),e.progress.style.position="absolute",e.progress.style.color="gray",e.appendChild(e.progress));var i=this.getLoadedProgress();e.progress.innerHTML="Loading animation... "+i+"%",e.progress.style.bottom="60px",e.progress.style.left="10px";var o=this;setTimeout(function(){o.loadInBackground(t+1)},10),this.loaded=!1}else this.loaded=!0,void 0!==e.progress&&(e.removeChild(e.progress),e.progress=void 0),this.onLoadCallback&&this.onLoadCallback()},t.exports=o},function(t,e,i){function o(t){this.active=!1,this.dom={container:t},this.dom.overlay=document.createElement("div"),this.dom.overlay.className="vis-overlay",this.dom.container.appendChild(this.dom.overlay),this.hammer=a(this.dom.overlay),this.hammer.on("tap",this._onTapOverlay.bind(this));var e=this;["tap","doubletap","press","pinch","pan","panstart","panmove","panend"].forEach(function(t){e.hammer.on(t,function(t){t.stopPropagation()})}),document&&document.body&&(this.onClick=function(i){n(i.target,t)||e.deactivate()},document.body.addEventListener("click",this.onClick)),void 0!==this.keycharm&&this.keycharm.destroy(),this.keycharm=s(),this.escListener=this.deactivate.bind(this)}function n(t,e){for(;t;){if(t===e)return!0;t=t.parentNode}return!1}var s=i(35),r=i(44),a=i(10),h=i(2);r(o.prototype),o.current=null,o.prototype.destroy=function(){this.deactivate(),this.dom.overlay.parentNode.removeChild(this.dom.overlay),this.onClick&&document.body.removeEventListener("click",this.onClick),this.hammer.destroy(),this.hammer=null},o.prototype.activate=function(){o.current&&o.current.deactivate(),o.current=this,this.active=!0,this.dom.overlay.style.display="none",h.addClassName(this.dom.container,"vis-active"),this.emit("change"),this.emit("activate"),this.keycharm.bind("esc",this.escListener)},o.prototype.deactivate=function(){this.active=!1,this.dom.overlay.style.display="",h.removeClassName(this.dom.container,"vis-active"),this.keycharm.unbind("esc",this.escListener),this.emit("change"),this.emit("deactivate")},o.prototype._onTapOverlay=function(t){this.activate(),t.stopPropagation()},t.exports=o},function(t,e,i){e.en={current:"current",time:"time"},e.en_EN=e.en,e.en_US=e.en,e.it={current:"attuale",time:"tempo"},e.it_IT=e.it,e.it_CH=e.it,e.nl={current:"huidige",time:"tijd"},e.nl_NL=e.nl,e.nl_BE=e.nl,e.de={current:"Aktuelle",time:"ZeiLine truncated
var i=this.options.multiselect?this.getSelection():[];if((t.srcEvent&&t.srcEvent.shiftKey||!1)&&this.options.multiselect){var o=this.itemsData.get(e.id).group,s=void 0;this.options.multiselectPerGroup&&i.length>0&&(s=this.itemsData.get(i[0]).group),this.options.multiselectPerGroup&&void 0!=s&&s!=o||i.push(e.id);var r=n._getItemRange(this.itemsData.get(i,this.itemOptions));if(!this.options.multiselectPerGroup||s==o){i=[];for(var a in this.items)if(this.items.hasOwnProperty(a)){var h=this.items[a],d=h.data.start,l=void 0!==h.data.end?h.data.end:d;!(d>=r.min&&l<=r.max)||this.options.multiselectPerGroup&&s!=this.itemsData.get(h.id).group||h instanceof _||i.push(h.id)}}}else{var u=i.indexOf(e.id);-1==u?i.push(e.id):i.splice(u,1)}this.setSelection(i),this.body.emitter.emit("select",{items:this.getSelection(),event:t})}}},n._getItemRange=function(t){var e=null,i=null;return t.forEach(function(t){(null==i||t.start<i)&&(i=t.start),void 0!=t.end?(null==e||t.end>e)&&(e=t.end):(null==e||t.start>e)&&(e=t.start)}),{min:i,max:e}},n.prototype.itemFromElement=function(t){for(var e=t;e;){if(e.hasOwnProperty("timeline-item"))return e["timeline-item"];e=e.parentNode}return null},n.prototype.itemFromTarget=function(t){return this.itemFromElement(t.target)},n.prototype.itemFromRelatedTarget=function(t){return this.itemFromElement(t.relatedTarget)},n.prototype.groupFromTarget=function(t){var e=t.center?t.center.y:t.clientY,i=this.groupIds;i.length<=0&&this.groupsData&&(i=this.groupsData.getIds({order:this.options.groupOrder}));for(var o=0;o<i.length;o++){var n=i[o],s=this.groups[n],r=s.dom.foreground,a=l.getAbsoluteTop(r);if(e>a&&e<a+r.offsetHeight)return s;if("top"===this.options.orientation.item){if(o===this.groupIds.length-1&&e>a)return s}else if(0===o&&e<a+r.offset)return s}return null},n.itemSetFromTarget=function(t){for(var e=t.target;e;){if(e.hasOwnProperty("timeline-itemset"))return e["timeline-itemset"];e=e.parentNode}return null},n.prototype._cloneItemData=function(t,e){var i=l.extend({},t);return e||(e=this.itemsData.getDataSet()._options.type),void 0!=i.start&&(i.start=l.convert(i.start,e&&e.start||"Date")),void 0!=i.end&&(i.end=l.convert(i.end,e&&e.end||"Date")),i},t.exports=n},function(t,e,i){e.orderByStart=function(t){t.sort(function(t,e){return t.data.start-e.data.start})},e.orderByEnd=function(t){t.sort(function(t,e){return("end"in t.data?t.data.end:t.data.start)-("end"in e.data?e.data.end:e.data.start)})},e.stack=function(t,i,o){if(o)for(var n=0;n<t.length;n++)t[n].top=null;for(var n=0;n<t.length;n++){var s=t[n];if(s.stack&&null===s.top){s.top=i.axis;do{for(var r=null,a=0,h=t.length;a<h;a++){var d=t[a];if(null!==d.top&&d!==s&&d.stack&&e.collision(s,d,i.item,d.options.rtl)){r=d;break}}null!=r&&(s.top=r.top+r.height+i.item.vertical)}while(r)}}},e.substack=function(t,i,o){for(var n=0;n<t.length;n++)t[n].top=null;var s=o.height;for(n=0;n<t.length;n++){var r=t[n];if(r.stack&&null===r.top){r.top=r.baseTop;do{for(var a=null,h=0,d=t.length;h<d;h++){var l=t[h];if(null!==l.top&&l!==r&&e.collision(r,l,i.item,l.options.rtl)){a=l;break}}null!=a&&(r.top=a.top+a.height+i.item.vertical),r.top+r.height>s&&(s=r.top+r.height)}while(a)}}o.height=s-o.top+.5*i.item.vertical},e.nostack=function(t,i,o,n){for(var s=0;s<t.length;s++)if(void 0==t[s].data.subgroup)t[s].top=i.item.vertical;else if(void 0!==t[s].data.subgroup&&n){var r=0;for(var a in o)o.hasOwnProperty(a)&&1==o[a].visible&&o[a].index<o[t[s].data.subgroup].index&&(r+=o[a].height,o[t[s].data.subgroup].top=r);t[s].top=r+.5*i.item.vertical}n||e.stackSubgroups(t,i,o)},e.stackSubgroups=function(t,i,o){for(var n in o)if(o.hasOwnProperty(n)){o[n].top=0;do{var s=null;for(var r in o)if(null!==o[r].top&&r!==n&&o[n].index>o[r].index&&e.collisionByTimes(o[n],o[r])){s=o[r];break}null!=s&&(o[n].top=s.top+s.height)}while(s)}for(var a=0;a<t.length;a++)void 0!==t[a].data.subgroup&&(t[a].top=o[t[a].data.subgroup].top+.5*i.item.vertical)},e.stackSubgroupsWithInnerStack=function(t,i,o){var n=!1,s=[];for(var r in o)o[r].hasOwnProperty("index")?s[o[r].index]=r:s.push(r);for(var a=0;a<s.length;a++)if(r=s[a],o.hasOwnProperty(r)){n=n||o[r].stack,o[r].top=0;for(var h in o)o[h].visible&&o[r].index>o[h].index&&(o[r].top+=o[h].height);for(var d=t[r],l=0;l<d.length;l++)void 0!==d[l].data.subgroup&&(d[l].top=o[d[l].data.subgroup].top+.5*i.item.vertical,o[r].stack&&(d[l].baseTop=d[l].top));n&&o[r].stack&&e.substack(t[r],i,o[r])}},e.collision=function(t,e,i,o){return o?t.right-i.horizontal+.001<e.right+e.width&&t.right+t.width+i.horizontal-.001>e.right&&t.top-i.vertical+.001<e.top+e.height&&t.top+t.height+i.vertical-.001>e.top:t.left-i.horizontal+.001<e.left+e.width&&t.left+t.width+i.horizontal-.001>e.left&&t.top-i.vertical+.001<e.top+e.height&&t.top+t.height+i.vertical-.001>e.top},e.collisionByTimes=function(t,e){return t.start<=e.start&&t.end>=e.start&&t.top<e.top+e.height&&t.top+t.height>e.top||e.start<=t.start&&e.end>=t.start&&e.top<t.top+t.height&&e.top+e.height>t.top}},function(t,e,i){function o(t,e,iLine truncated
f[n]=d[n];var m=i[l].length-a[l]--;i[l][m]=f}for(l in this.groups)this.groups.hasOwnProperty(l)&&(i.hasOwnProperty(l)||(i[l]=new Array(0)));for(l in i)if(i.hasOwnProperty(l))if(0==i[l].length)this.groups.hasOwnProperty(l)&&this._removeGroup(l);else{var v=void 0;void 0!=this.groupsData&&(v=this.groupsData.get(l)),void 0==v&&(v={id:l,content:this.options.defaultGroup+l}),this._updateGroup(v,l),this.groups[l].setItems(i[l])}this.forceGraphUpdate=!0,this.body.emitter.emit("_change",{queue:!0})}},o.prototype.redraw=function(){var t=!1;this.props.width=this.dom.frame.offsetWidth,this.props.height=this.body.domProps.centerContainer.height-this.body.domProps.border.top-this.body.domProps.border.bottom,t=this._isResized()||t;var e=this.body.range.end-this.body.range.start,i=e!=this.lastVisibleInterval;if(this.lastVisibleInterval=e,1==t&&(this.svg.style.width=r.option.asSize(3*this.props.width),this.svg.style.left=r.option.asSize(-this.props.width),-1==(this.options.height+"").indexOf("%")&&1!=this.updateSVGheightOnResize||(this.updateSVGheight=!0)),1==this.updateSVGheight?(this.options.graphHeight!=this.props.height+"px"&&(this.options.graphHeight=this.props.height+"px",this.svg.style.height=this.props.height+"px"),this.updateSVGheight=!1):this.svg.style.height=(""+this.options.graphHeight).replace("px","")+"px",1==t||1==i||1==this.abortedGraphUpdate||1==this.forceGraphUpdate)t=this._updateGraph()||t,this.forceGraphUpdate=!1;else if(0!=this.lastStart){var o=this.body.range.start-this.lastStart,n=this.body.range.end-this.body.range.start;if(0!=this.props.width){var s=this.props.width/n,a=o*s;this.svg.style.left=-this.props.width-a+"px"}}return this.legendLeft.redraw(),this.legendRight.redraw(),t},o.prototype._getSortedGroupIds=function(){var t=[];for(var e in this.groups)if(this.groups.hasOwnProperty(e)){var i=this.groups[e];1!=i.visible||void 0!==this.options.groups.visibility[e]&&1!=this.options.groups.visibility[e]||t.push({id:e,zIndex:i.options.zIndex})}r.insertSort(t,function(t,e){var i=t.zIndex,o=e.zIndex;return void 0===i&&(i=0),void 0===o&&(o=0),i==o?0:i<o?-1:1});for(var o=new Array(t.length),n=0;n<t.length;n++)o[n]=t[n].id;return o},o.prototype._updateGraph=function(){if(a.prepareElements(this.svgElements),0!=this.props.width&&null!=this.itemsData){var t,e,i={},o=this.body.util.toGlobalTime(-this.body.domProps.root.width),n=this.body.util.toGlobalTime(2*this.body.domProps.root.width),s=this._getSortedGroupIds();if(s.length>0){var r={};for(this._getRelevantData(s,r,o,n),this._applySampling(s,r),e=0;e<s.length;e++)this._convertXcoordinates(r[s[e]]);if(this._getYRanges(s,r,i),1==this._updateYAxis(s,i))return a.cleanupElements(this.svgElements),this.abortedGraphUpdate=!0,!0;this.abortedGraphUpdate=!1;var h=void 0;for(e=0;e<s.length;e++)t=this.groups[s[e]],!0===this.options.stack&&"line"===this.options.style&&(void 0!=t.options.excludeFromStacking&&t.options.excludeFromStacking||(void 0!=h&&(this._stack(r[t.id],r[h.id]),1==t.options.shaded.enabled&&"group"!==t.options.shaded.orientation&&("top"==t.options.shaded.orientation&&"group"!==h.options.shaded.orientation?(h.options.shaded.orientation="group",h.options.shaded.groupId=t.id):(t.options.shaded.orientation="group",t.options.shaded.groupId=h.id))),h=t)),this._convertYcoordinates(r[s[e]],t);var d={};for(e=0;e<s.length;e++)if(t=this.groups[s[e]],"line"===t.options.style&&1==t.options.shaded.enabled){var l=r[s[e]];if(null==l||0==l.length)continue;if(d.hasOwnProperty(s[e])||(d[s[e]]=m.calcPath(l,t)),"group"===t.options.shaded.orientation){var u=t.options.shaded.groupId;if(-1===s.indexOf(u)){console.log(t.id+": Unknown shading group target given:"+u);continue}d.hasOwnProperty(u)||(d[u]=m.calcPath(r[u],this.groups[u])),m.drawShading(d[s[e]],t,d[u],this.framework)}else m.drawShading(d[s[e]],t,void 0,this.framework)}for(f.draw(s,r,this.framework),e=0;e<s.length;e++)if(t=this.groups[s[e]],r[s[e]].length>0)switch(t.options.style){case"line":d.hasOwnProperty(s[e])||(d[s[e]]=m.calcPath(r[s[e]],t)),m.draw(d[s[e]],t,this.framework);case"point":case"points":"point"!=t.options.style&&"points"!=t.options.style&&1!=t.options.drawPoints.enabled||v.draw(r[s[e]],t,this.framework)}}}return a.cleanupElements(this.svgElements),!1},o.prototype._stack=function(t,e){var i,o,n,s,r;i=0;for(var a=0;a<t.length;a++){s=void 0,r=void 0;for(var h=i;h<e.length;h++){if(e[h].x===t[a].x){s=e[h],r=e[h],i=h;break}if(e[h].x>t[a].x){r=e[h],s=0==h?r:e[h-1],i=h;break}}void 0===r&&(s=e[e.length-1],r=e[e.length-1]),o=r.x-s.x,n=r.y-s.y,t[a].y=0==o?t[a].orginalY+r.y:t[a].orginalY+n/o*(t[a].x-s.x)+s.y}},o.prototype._getRelevantData=function(t,e,i,o){var n,s,a,h;if(t.length>0)for(s=0;s<t.length;s++){n=this.groups[t[s]];var d=n.getItems();if(1==n.options.sort){var l=function(t,e){return t.getTime()==e.getTime()?0:t<e?-1:1},u=Math.max(0,r.binarySearchValue(d,i,"x","before",l)),c=Math.min(d.length,r.binarySearchValue(d,o,"x","after",l)+1);c<=0&&(c=d.length);var p=new Array(c-u);for(a=u;a<c;a++)h=n.itemsData[a],pLine truncated
d=Math.sqrt(Math.pow(o.screen_x-n.screen_x,2)+Math.pow(o.screen_y-n.screen_y,2)),l=Math.sqrt(Math.pow(n.screen_x-s.screen_x,2)+Math.pow(n.screen_y-s.screen_y,2)),u=Math.sqrt(Math.pow(s.screen_x-r.screen_x,2)+Math.pow(s.screen_y-r.screen_y,2)),v=Math.pow(u,i),y=Math.pow(u,2*i),g=Math.pow(l,i),b=Math.pow(l,2*i),w=Math.pow(d,i),_=Math.pow(d,2*i),c=2*_+3*w*g+b,p=2*y+3*v*g+b,f=3*w*(w+g),f>0&&(f=1/f),m=3*v*(v+g),m>0&&(m=1/m),a={screen_x:(-b*o.screen_x+c*n.screen_x+_*s.screen_x)*f,screen_y:(-b*o.screen_y+c*n.screen_y+_*s.screen_y)*f},h={screen_x:(y*n.screen_x+p*s.screen_x-b*r.screen_x)*m,screen_y:(y*n.screen_y+p*s.screen_y-b*r.screen_y)*m},0==a.screen_x&&0==a.screen_y&&(a=n),0==h.screen_x&&0==h.screen_y&&(h=s),x.push([a.screen_x,a.screen_y]),x.push([h.screen_x,h.screen_y]),x.push([s.screen_x,s.screen_y]);return x},o._linear=function(t){for(var e=[],i=0;i<t.length;i++)e.push([t[i].screen_x,t[i].screen_y]);return e},t.exports=o},function(t,e,i){function o(t,e,i,o){this.body=t,this.defaultOptions={enabled:!1,icons:!0,iconSize:20,iconSpacing:6,left:{visible:!0,position:"top-left"},right:{visible:!0,position:"top-right"}},this.side=i,this.options=r.extend({},this.defaultOptions),this.linegraphOptions=o,this.svgElements={},this.dom={},this.groups={},this.amountOfGroups=0,this._create(),this.framework={svg:this.svg,svgElements:this.svgElements,options:this.options,groups:this.groups},this.setOptions(e)}var n=i(8),s=function(t){return t&&t.__esModule?t:{default:t}}(n),r=i(2),a=i(14),h=i(16);o.prototype=new h,o.prototype.clear=function(){this.groups={},this.amountOfGroups=0},o.prototype.addGroup=function(t,e){1!=e.options.excludeFromLegend&&(this.groups.hasOwnProperty(t)||(this.groups[t]=e),this.amountOfGroups+=1)},o.prototype.updateGroup=function(t,e){this.groups[t]=e},o.prototype.removeGroup=function(t){this.groups.hasOwnProperty(t)&&(delete this.groups[t],this.amountOfGroups-=1)},o.prototype._create=function(){this.dom.frame=document.createElement("div"),this.dom.frame.className="vis-legend",this.dom.frame.style.position="absolute",this.dom.frame.style.top="10px",this.dom.frame.style.display="block",this.dom.textArea=document.createElement("div"),this.dom.textArea.className="vis-legend-text",this.dom.textArea.style.position="relative",this.dom.textArea.style.top="0px",this.svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.svg.style.position="absolute",this.svg.style.top="0px",this.svg.style.width=this.options.iconSize+5+"px",this.svg.style.height="100%",this.dom.frame.appendChild(this.svg),this.dom.frame.appendChild(this.dom.textArea)},o.prototype.hide=function(){this.dom.frame.parentNode&&this.dom.frame.parentNode.removeChild(this.dom.frame)},o.prototype.show=function(){this.dom.frame.parentNode||this.body.dom.center.appendChild(this.dom.frame)},o.prototype.setOptions=function(t){var e=["enabled","orientation","icons","left","right"];r.selectiveDeepExtend(e,this.options,t)},o.prototype.redraw=function(){var t=0,e=(0,s.default)(this.groups);e.sort(function(t,e){return t<e?-1:1});for(var i=0;i<e.length;i++){var o=e[i];1!=this.groups[o].visible||void 0!==this.linegraphOptions.visibility[o]&&1!=this.linegraphOptions.visibility[o]||t++}if(0==this.options[this.side].visible||0==this.amountOfGroups||0==this.options.enabled||0==t)this.hide();else{if(this.show(),"top-left"==this.options[this.side].position||"bottom-left"==this.options[this.side].position?(this.dom.frame.style.left="4px",this.dom.frame.style.textAlign="left",this.dom.textArea.style.textAlign="left",this.dom.textArea.style.left=this.options.iconSize+15+"px",this.dom.textArea.style.right="",this.svg.style.left="0px",this.svg.style.right=""):(this.dom.frame.style.right="4px",this.dom.frame.style.textAlign="right",this.dom.textArea.style.textAlign="right",this.dom.textArea.style.right=this.options.iconSize+15+"px",this.dom.textArea.style.left="",this.svg.style.right="0px",this.svg.style.left=""),"top-left"==this.options[this.side].position||"top-right"==this.options[this.side].position)this.dom.frame.style.top=4-Number(this.body.dom.center.style.top.replace("px",""))+"px",this.dom.frame.style.bottom="";else{var n=this.body.domProps.center.height-this.body.domProps.centerContainer.height;this.dom.frame.style.bottom=4+n+Number(this.body.dom.center.style.top.replace("px",""))+"px",this.dom.frame.style.top=""}0==this.options.icons?(this.dom.frame.style.width=this.dom.textArea.offsetWidth+10+"px",this.dom.textArea.style.right="",this.dom.textArea.style.left="",this.svg.style.width="0px"):(this.dom.frame.style.width=this.options.iconSize+15+this.dom.textArea.offsetWidth+10+"px",this.drawLegendIcons());var r="";for(i=0;i<e.length;i++)o=e[i],1!=this.groups[o].visible||void 0!==this.linegraphOptions.visibility[o]&&1!=this.linegraphOptions.visibility[o]||(r+=this.groups[o].content+"<br />");this.dom.textArea.innerHTML=r,this.dom.textArea.style.lineHeight=.75*this.options.iconSize+this.options.iconSpacing+"px"}},o.prototype.drawLegendIcons=function(){if(thLine truncated
value:function(t,e,i,o,n){this.enableShadow(t,e),t.beginPath(),t.arc(i,o,n,0,2*Math.PI,!1),t.stroke(),this.disableShadow(t,e)}},{key:"getDistanceToEdge",value:function(t,e,i,o,n,r,a,h){var d=0;if(this.from!=this.to)d=this._getDistanceToEdge(t,e,i,o,n,r,a);else{var l=this._getCircleData(void 0),u=(0,s.default)(l,3),c=u[0],p=u[1],f=u[2],m=c-n,v=p-r;d=Math.abs(Math.sqrt(m*m+v*v)-f)}return d}},{key:"_getDistanceToLine",value:function(t,e,i,o,n,s){var r=i-t,a=o-e,h=r*r+a*a,d=((n-t)*r+(s-e)*a)/h;d>1?d=1:d<0&&(d=0);var l=t+d*r,u=e+d*a,c=l-n,p=u-s;return Math.sqrt(c*c+p*p)}},{key:"getArrowData",value:function(t,e,i,o,n,r){var a=void 0,h=void 0,d=void 0,l=void 0,u=void 0,c=void 0,p=void 0,f=r.width;if("from"===e?(d=this.from,l=this.to,u=.1,c=r.fromArrowScale,p=r.fromArrowType):"to"===e?(d=this.to,l=this.from,u=-.1,c=r.toArrowScale,p=r.toArrowType):(d=this.to,l=this.from,c=r.middleArrowScale,p=r.middleArrowType),d!=l)if("middle"!==e)if(!0===this.options.smooth.enabled){h=this.findBorderPosition(d,t,{via:i});var m=this.getPoint(Math.max(0,Math.min(1,h.t+u)),i);a=Math.atan2(h.y-m.y,h.x-m.x)}else a=Math.atan2(d.y-l.y,d.x-l.x),h=this.findBorderPosition(d,t);else a=Math.atan2(d.y-l.y,d.x-l.x),h=this.getPoint(.5,i);else{var v=this._getCircleData(t),g=(0,s.default)(v,3),y=g[0],b=g[1],_=g[2];"from"===e?(h=this.findBorderPosition(this.from,t,{x:y,y:b,low:.25,high:.6,direction:-1}),a=-2*h.t*Math.PI+1.5*Math.PI+.1*Math.PI):"to"===e?(h=this.findBorderPosition(this.from,t,{x:y,y:b,low:.6,high:1,direction:1}),a=-2*h.t*Math.PI+1.5*Math.PI-1.1*Math.PI):(h=this._pointOnCircle(y,b,_,.175),a=3.9269908169872414)}"middle"===e&&c<0&&(f*=-1);var w=15*c+3*f;return{point:h,core:{x:h.x-.9*w*Math.cos(a),y:h.y-.9*w*Math.sin(a)},angle:a,length:w,type:p}}},{key:"drawArrowHead",value:function(t,e,i,o,n){t.strokeStyle=this.getColor(t,e,i,o),t.fillStyle=t.strokeStyle,t.lineWidth=e.width,u.draw(t,n),this.enableShadow(t,e),t.fill(),this.disableShadow(t,e)}},{key:"enableShadow",value:function(t,e){!0===e.shadow&&(t.shadowColor=e.shadowColor,t.shadowBlur=e.shadowSize,t.shadowOffsetX=e.shadowX,t.shadowOffsetY=e.shadowY)}},{key:"disableShadow",value:function(t,e){!0===e.shadow&&(t.shadowColor="rgba(0,0,0,0)",t.shadowBlur=0,t.shadowOffsetX=0,t.shadowOffsetY=0)}}]),t}();e.default=c},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(3),s=o(n),r=i(4),a=o(r),h=i(5),d=o(h),l=i(0),u=o(l),c=i(1),p=o(c),f=function(){function t(){(0,u.default)(this,t)}return(0,p.default)(t,null,[{key:"transform",value:function(t,e){t instanceof Array||(t=[t]);for(var i=e.point.x,o=e.point.y,n=e.angle,s=e.length,r=0;r<t.length;++r){var a=t[r],h=a.x*Math.cos(n)-a.y*Math.sin(n),d=a.x*Math.sin(n)+a.y*Math.cos(n);a.x=i+s*h,a.y=o+s*d}}},{key:"drawPath",value:function(t,e){t.beginPath(),t.moveTo(e[0].x,e[0].y);for(var i=1;i<e.length;++i)t.lineTo(e[i].x,e[i].y);t.closePath()}}]),t}(),m=function(t){function e(){return(0,u.default)(this,e),(0,a.default)(this,(e.__proto__||(0,s.default)(e)).apply(this,arguments))}return(0,d.default)(e,t),(0,p.default)(e,null,[{key:"draw",value:function(t,e){var i=[{x:0,y:0},{x:-1,y:.3},{x:-.9,y:0},{x:-1,y:-.3}];f.transform(i,e),f.drawPath(t,i)}}]),e}(f),v=function(){function t(){(0,u.default)(this,t)}return(0,p.default)(t,null,[{key:"draw",value:function(t,e){var i={x:-.4,y:0};f.transform(i,e),t.circle(i.x,i.y,.4*e.length)}}]),t}(),g=function(){function t(){(0,u.default)(this,t)}return(0,p.default)(t,null,[{key:"draw",value:function(t,e){var i=[{x:0,y:.5},{x:0,y:-.5},{x:-.15,y:-.5},{x:-.15,y:.5}];f.transform(i,e),f.drawPath(t,i)}}]),t}(),y=function(){function t(){(0,u.default)(this,t)}return(0,p.default)(t,null,[{key:"draw",value:function(t,e){var i;switch(e.type&&(i=e.type.toLowerCase()),i){case"circle":v.draw(t,e);break;case"bar":g.draw(t,e);break;case"arrow":default:m.draw(t,e)}}}]),t}();e.default=y},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(0),s=o(n),r=i(1),a=o(r),h=function(){function t(e,i,o){(0,s.default)(this,t),this.body=e,this.physicsBody=i,this.barnesHutTree,this.setOptions(o),this.randomSeed=5}return(0,a.default)(t,[{key:"setOptions",value:function(t){this.options=t,this.thetaInversed=1/this.options.theta,this.overlapAvoidanceFactor=1-Math.max(0,Math.min(1,this.options.avoidOverlap))}},{key:"seededRandom",value:function(){var t=1e4*Math.sin(this.randomSeed++);return t-Math.floor(t)}},{key:"solve",value:function(){if(0!==this.options.gravitationalConstant&&this.physicsBody.physicsNodeIndices.length>0){var t=void 0,e=this.body.nodes,i=this.physicsBody.physicsNodeIndices,o=i.length,n=this._formBarnesHutTree(e,i);this.barnesHutTree=n;for(var s=0;s<o;s++)t=e[i[s]],t.options.mass>0&&this._getForceContributions(n.root,t)}}},{key:"_getForceContributions",value:function(t,e){this._getForceContribution(t.children.NW,e),this._getForceContribution(t.children.NE,e),this._getForceContribution(t.children.SW,Line truncated
;for(var a in arguments[0])n+=a+": "+arguments[0][a]+", ";n=n.slice(0,-2)}else n=arguments[r];s.push(n)}x(t+"\nArguments: "+Array.prototype.slice.call(s).join("")+"\n"+(new Error).stack),o=!1}return i.apply(this,arguments)},i)}function S(t,i){null!=e.deprecationHandler&&e.deprecationHandler(t,i),Po[t]||(x(i),Po[t]=!0)}function D(t){return t instanceof Function||"[object Function]"===Object.prototype.toString.call(t)}function M(t){var e,i;for(i in t)e=t[i],D(e)?this[i]=e:this["_"+i]=e;this._config=t,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)}function C(t,e){var i,n=l({},t);for(i in e)d(e,i)&&(o(t[i])&&o(e[i])?(n[i]={},l(n[i],t[i]),l(n[i],e[i])):null!=e[i]?n[i]=e[i]:delete n[i]);for(i in t)d(t,i)&&!d(e,i)&&o(t[i])&&(n[i]=l({},n[i]));return n}function O(t){null!=t&&this.set(t)}function E(t,e,i){var o=this._calendar[t]||this._calendar.sameElse;return D(o)?o.call(e,i):o}function T(t){var e=this._longDateFormat[t],i=this._longDateFormat[t.toUpperCase()];return e||!i?e:(this._longDateFormat[t]=i.replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t])}function P(){return this._invalidDate}function I(t){return this._ordinal.replace("%d",t)}function N(t,e,i,o){var n=this._relativeTime[i];return D(n)?n(t,e,i,o):n.replace(/%d/i,t)}function R(t,e){var i=this._relativeTime[t>0?"future":"past"];return D(i)?i(e):i.replace(/%s/i,e)}function A(t,e){var i=t.toLowerCase();Lo[i]=Lo[i+"s"]=Lo[e]=t}function z(t){return"string"==typeof t?Lo[t]||Lo[t.toLowerCase()]:void 0}function L(t){var e,i,o={};for(i in t)d(t,i)&&(e=z(i))&&(o[e]=t[i]);return o}function F(t,e){Fo[t]=e}function B(t){var e=[];for(var i in t)e.push({unit:i,priority:Fo[i]});return e.sort(function(t,e){return t.priority-e.priority}),e}function j(t,e,i){var o=""+Math.abs(t),n=e-o.length;return(t>=0?i?"+":"":"-")+Math.pow(10,Math.max(0,n)).toString().substr(1)+o}function H(t,e,i,o){var n=o;"string"==typeof o&&(n=function(){return this[o]()}),t&&(Wo[t]=n),e&&(Wo[e[0]]=function(){return j(n.apply(this,arguments),e[1],e[2])}),i&&(Wo[i]=function(){return this.localeData().ordinal(n.apply(this,arguments),t)})}function W(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function Y(t){var e,i,o=t.match(Bo);for(e=0,i=o.length;e<i;e++)Wo[o[e]]?o[e]=Wo[o[e]]:o[e]=W(o[e]);return function(e){var n,s="";for(n=0;n<i;n++)s+=D(o[n])?o[n].call(e,t):o[n];return s}}function G(t,e){return t.isValid()?(e=V(e,t.localeData()),Ho[e]=Ho[e]||Y(e),Ho[e](t)):t.localeData().invalidDate()}function V(t,e){function i(t){return e.longDateFormat(t)||t}var o=5;for(jo.lastIndex=0;o>=0&&jo.test(t);)t=t.replace(jo,i),jo.lastIndex=0,o-=1;return t}function U(t,e,i){an[t]=D(e)?e:function(t,o){return t&&i?i:e}}function q(t,e){return d(an,t)?an[t](e._strict,e._locale):new RegExp(X(t))}function X(t){return Z(t.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,i,o,n){return e||i||o||n}))}function Z(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function K(t,e){var i,o=e;for("string"==typeof t&&(t=[t]),r(e)&&(o=function(t,i){i[e]=_(t)}),i=0;i<t.length;i++)hn[t[i]]=o}function J(t,e){K(t,function(t,i,o,n){o._w=o._w||{},e(t,o._w,o,n)})}function $(t,e,i){null!=e&&d(hn,t)&&hn[t](e,i._a,i,t)}function Q(t){return tt(t)?366:365}function tt(t){return t%4==0&&t%100!=0||t%400==0}function et(){return tt(this.year())}function it(t,i){return function(o){return null!=o?(nt(this,t,o),e.updateOffset(this,i),this):ot(this,t)}}function ot(t,e){return t.isValid()?t._d["get"+(t._isUTC?"UTC":"")+e]():NaN}function nt(t,e,i){t.isValid()&&!isNaN(i)&&("FullYear"===e&&tt(t.year())?t._d["set"+(t._isUTC?"UTC":"")+e](i,t.month(),ht(i,t.month())):t._d["set"+(t._isUTC?"UTC":"")+e](i))}function st(t){return t=z(t),D(this[t])?this[t]():this}function rt(t,e){if("object"==typeof t){t=L(t);for(var i=B(t),o=0;o<i.length;o++)this[i[o].unit](t[i[o].unit])}else if(t=z(t),D(this[t]))return this[t](e);return this}function at(t,e){return(t%e+e)%e}function ht(t,e){if(isNaN(t)||isNaN(e))return NaN;var i=at(e,12);return t+=(e-i)/12,1===i?tt(t)?29:28:31-i%7%2}function dt(t,e){return t?i(this._months)?this._months[t.month()]:this._months[(this._months.isFormat||_n).test(e)?"format":"standalone"][t.month()]:i(this._months)?this._months:this._months.standalone}function lt(t,e){return t?i(this._monthsShort)?this._monthsShort[t.month()]:this._monthsShort[_n.test(e)?"format":"standalone"][t.month()]:i(this._monthsShort)?this._monthsShort:this._monthsShort.standalone}function ut(t,e,i){var o,n,s,r=t.toLocaleLowerCase();if(!this._monthsParse)for(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],o=0;o<12;++o)s=u([2e3,o]),this._shortMonthsParse[o]=this.monthsShort(s,"").toLocaleLowerCase(),this._longMonthsParse[o]=this.months(s,"").toLocaleLowerCase();return i?"MMM"===e?(n=yn.call(this._shortMonthsParse,r),-1!==n?n:null):(n=yn.call(this._longMonthsParse,r),-1!==n?n:null):"MMMLine truncated
r-=ho(co(n)),o=b(a/12),a%=12,h.days=r,h.months=a,h.years=o,this}function uo(t){return 4800*t/146097}function co(t){return 146097*t/4800}function po(t){if(!this.isValid())return NaN;var e,i,o=this._milliseconds;if("month"===(t=z(t))||"year"===t)return e=this._days+o/864e5,i=this._months+uo(e),"month"===t?i:i/12;switch(e=this._days+Math.round(co(this._months)),t){case"week":return e/7+o/6048e5;case"day":return e+o/864e5;case"hour":return 24*e+o/36e5;case"minute":return 1440*e+o/6e4;case"second":return 86400*e+o/1e3;case"millisecond":return Math.floor(864e5*e)+o;default:throw new Error("Unknown unit "+t)}}function fo(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*_(this._months/12):NaN}function mo(t){return function(){return this.as(t)}}function vo(){return Ke(this)}function go(t){return t=z(t),this.isValid()?this[t+"s"]():NaN}function yo(t){return function(){return this.isValid()?this._data[t]:NaN}}function bo(){return b(this.days()/7)}function _o(t,e,i,o,n){return n.relativeTime(e||1,!!i,t,o)}function wo(t,e,i){var o=Ke(t).abs(),n=Ds(o.as("s")),s=Ds(o.as("m")),r=Ds(o.as("h")),a=Ds(o.as("d")),h=Ds(o.as("M")),d=Ds(o.as("y")),l=n<=Ms.ss&&["s",n]||n<Ms.s&&["ss",n]||s<=1&&["m"]||s<Ms.m&&["mm",s]||r<=1&&["h"]||r<Ms.h&&["hh",r]||a<=1&&["d"]||a<Ms.d&&["dd",a]||h<=1&&["M"]||h<Ms.M&&["MM",h]||d<=1&&["y"]||["yy",d];return l[2]=e,l[3]=+t>0,l[4]=i,_o.apply(null,l)}function xo(t){return void 0===t?Ds:"function"==typeof t&&(Ds=t,!0)}function ko(t,e){return void 0!==Ms[t]&&(void 0===e?Ms[t]:(Ms[t]=e,"s"===t&&(Ms.ss=e-1),!0))}function So(t){if(!this.isValid())return this.localeData().invalidDate();var e=this.localeData(),i=wo(this,!t,e);return t&&(i=e.pastFuture(+this,i)),e.postformat(i)}function Do(t){return(t>0)-(t<0)||+t}function Mo(){if(!this.isValid())return this.localeData().invalidDate();var t,e,i,o=Cs(this._milliseconds)/1e3,n=Cs(this._days),s=Cs(this._months);t=b(o/60),e=b(t/60),o%=60,t%=60,i=b(s/12),s%=12;var r=i,a=s,h=n,d=e,l=t,u=o?o.toFixed(3).replace(/\.?0+$/,""):"",c=this.asSeconds();if(!c)return"P0D";var p=c<0?"-":"",f=Do(this._months)!==Do(c)?"-":"",m=Do(this._days)!==Do(c)?"-":"",v=Do(this._milliseconds)!==Do(c)?"-":"";return p+"P"+(r?f+r+"Y":"")+(a?f+a+"M":"")+(h?m+h+"D":"")+(d||l||u?"T":"")+(d?v+d+"H":"")+(l?v+l+"M":"")+(u?v+u+"S":"")}var Co,Oo;Oo=Array.prototype.some?Array.prototype.some:function(t){for(var e=Object(this),i=e.length>>>0,o=0;o<i;o++)if(o in e&&t.call(this,e[o],o,e))return!0;return!1};var Eo=e.momentProperties=[],To=!1,Po={};e.suppressDeprecationWarnings=!1,e.deprecationHandler=null;var Io;Io=Object.keys?Object.keys:function(t){var e,i=[];for(e in t)d(t,e)&&i.push(e);return i};var No={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},Ro={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},Ao=/\d{1,2}/,zo={future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Lo={},Fo={},Bo=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,jo=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Ho={},Wo={},Yo=/\d/,Go=/\d\d/,Vo=/\d{3}/,Uo=/\d{4}/,qo=/[+-]?\d{6}/,Xo=/\d\d?/,Zo=/\d\d\d\d?/,Ko=/\d\d\d\d\d\d?/,Jo=/\d{1,3}/,$o=/\d{1,4}/,Qo=/[+-]?\d{1,6}/,tn=/\d+/,en=/[+-]?\d+/,on=/Z|[+-]\d\d:?\d\d/gi,nn=/Z|[+-]\d\d(?::?\d\d)?/gi,sn=/[+-]?\d+(\.\d{1,3})?/,rn=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,an={},hn={},dn=0,ln=1,un=2,cn=3,pn=4,fn=5,mn=6,vn=7,gn=8;H("Y",0,0,function(){var t=this.year();return t<=9999?""+t:"+"+t}),H(0,["YY",2],0,function(){return this.year()%100}),H(0,["YYYY",4],0,"year"),H(0,["YYYYY",5],0,"year"),H(0,["YYYYYY",6,!0],0,"year"),A("year","y"),F("year",1),U("Y",en),U("YY",Xo,Go),U("YYYY",$o,Uo),U("YYYYY",Qo,qo),U("YYYYYY",Qo,qo),K(["YYYYY","YYYYYY"],dn),K("YYYY",function(t,i){i[dn]=2===t.length?e.parseTwoDigitYear(t):_(t)}),K("YY",function(t,i){i[dn]=e.parseTwoDigitYear(t)}),K("Y",function(t,e){e[dn]=parseInt(t,10)}),e.parseTwoDigitYear=function(t){return _(t)+(_(t)>68?1900:2e3)};var yn,bn=it("FullYear",!0);yn=Array.prototype.indexOf?Array.prototype.indexOf:function(t){var e;for(e=0;e<this.length;++e)if(this[e]===t)return e;return-1},H("M",["MM",2],"Mo",function(){return this.month()+1}),H("MMM",0,0,function(t){return this.localeData().monthsShort(this,t)}),H("MMMM",0,0,function(t){return this.localeData().months(this,t)}),A("month","M"),F("month",8),U("M",Xo),U("MM",Xo,Go),U("MMM",function(t,e){return e.monthsShortRegex(t)}),U("MMMM",function(t,e){return e.monthsRegex(t)}),K(["M","MM"],function(t,e){e[ln]=_(t)-1}),K(["MMM","MMMM"],function(t,e,i,o){var nLine truncated
;Math.cos(2*o)>0?(t.textAlign="center",t.textBaseline="top",s.y+=n):Math.sin(2*o)<0?(t.textAlign="right",t.textBaseline="middle"):(t.textAlign="left",t.textBaseline="middle"),t.fillStyle=this.axisColor,t.fillText(i,s.x,s.y)},o.prototype.drawAxisLabelY=function(t,e,i,o,n){void 0===n&&(n=0);var s=this._convert3Dto2D(e);Math.cos(2*o)<0?(t.textAlign="center",t.textBaseline="top",s.y+=n):Math.sin(2*o)>0?(t.textAlign="right",t.textBaseline="middle"):(t.textAlign="left",t.textBaseline="middle"),t.fillStyle=this.axisColor,t.fillText(i,s.x,s.y)},o.prototype.drawAxisLabelZ=function(t,e,i,o){void 0===o&&(o=0);var n=this._convert3Dto2D(e);t.textAlign="right",t.textBaseline="middle",t.fillStyle=this.axisColor,t.fillText(i,n.x-o,n.y)},o.prototype._line3d=function(t,e,i,o){var n=this._convert3Dto2D(e),s=this._convert3Dto2D(i);this._line(t,n,s,o)},o.prototype._redrawAxis=function(){var t,e,i,o,n,s,r,a,h,d,c,f=this._getContext();f.font=24/this.camera.getArmLength()+"px arial";var m,v=.025/this.scale.x,g=.025/this.scale.y,y=5/this.camera.getArmLength(),b=this.camera.getArmRotation().horizontal,_=new u(Math.cos(b),Math.sin(b)),w=this.xRange,x=this.yRange,k=this.zRange;for(f.lineWidth=1,o=void 0===this.defaultXStep,i=new p(w.min,w.max,this.xStep,o),i.start(!0);!i.end();){var S=i.getCurrent();if(this.showGrid?(t=new l(S,x.min,k.min),e=new l(S,x.max,k.min),this._line3d(f,t,e,this.gridColor)):this.showXAxis&&(t=new l(S,x.min,k.min),e=new l(S,x.min+v,k.min),this._line3d(f,t,e,this.axisColor),t=new l(S,x.max,k.min),e=new l(S,x.max-v,k.min),this._line3d(f,t,e,this.axisColor)),this.showXAxis){r=_.x>0?x.min:x.max,m=new l(S,r,k.min);var D=" "+this.xValueLabel(S)+" ";this.drawAxisLabelX(f,m,D,b,y)}i.next()}for(f.lineWidth=1,o=void 0===this.defaultYStep,i=new p(x.min,x.max,this.yStep,o),i.start(!0);!i.end();){var M=i.getCurrent();if(this.showGrid?(t=new l(w.min,M,k.min),e=new l(w.max,M,k.min),this._line3d(f,t,e,this.gridColor)):this.showYAxis&&(t=new l(w.min,M,k.min),e=new l(w.min+g,M,k.min),this._line3d(f,t,e,this.axisColor),t=new l(w.max,M,k.min),e=new l(w.max-g,M,k.min),this._line3d(f,t,e,this.axisColor)),this.showYAxis){s=_.y>0?w.min:w.max,m=new l(s,M,k.min);var C=" "+this.yValueLabel(M)+" ";this.drawAxisLabelY(f,m,C,b,y)}i.next()}if(this.showZAxis){for(f.lineWidth=1,o=void 0===this.defaultZStep,i=new p(k.min,k.max,this.zStep,o),i.start(!0),s=_.x>0?w.min:w.max,r=_.y<0?x.min:x.max;!i.end();){var O=i.getCurrent(),E=new l(s,r,O),T=this._convert3Dto2D(E);e=new u(T.x-y,T.y),this._line(f,T,e,this.axisColor);var P=this.zValueLabel(O)+" ";this.drawAxisLabelZ(f,E,P,5),i.next()}f.lineWidth=1,t=new l(s,r,k.min),e=new l(s,r,k.max),this._line3d(f,t,e,this.axisColor)}if(this.showXAxis){var I,N;f.lineWidth=1,I=new l(w.min,x.min,k.min),N=new l(w.max,x.min,k.min),this._line3d(f,I,N,this.axisColor),I=new l(w.min,x.max,k.min),N=new l(w.max,x.max,k.min),this._line3d(f,I,N,this.axisColor)}this.showYAxis&&(f.lineWidth=1,t=new l(w.min,x.min,k.min),e=new l(w.min,x.max,k.min),this._line3d(f,t,e,this.axisColor),t=new l(w.max,x.min,k.min),e=new l(w.max,x.max,k.min),this._line3d(f,t,e,this.axisColor));var R=this.xLabel;R.length>0&&this.showXAxis&&(c=.1/this.scale.y,s=(w.max+3*w.min)/4,r=_.x>0?x.min-c:x.max+c,n=new l(s,r,k.min),this.drawAxisLabelX(f,n,R,b));var A=this.yLabel;A.length>0&&this.showYAxis&&(d=.1/this.scale.x,s=_.y>0?w.min-d:w.max+d,r=(x.max+3*x.min)/4,n=new l(s,r,k.min),this.drawAxisLabelY(f,n,A,b));var z=this.zLabel;z.length>0&&this.showZAxis&&(h=30,s=_.x>0?w.min:w.max,r=_.y<0?x.min:x.max,a=(k.max+3*k.min)/4,n=new l(s,r,a),this.drawAxisLabelZ(f,n,z,h))},o.prototype._hsv2rgb=function(t,e,i){var o,n,s,r,a,h;switch(r=i*e,a=Math.floor(t/60),h=r*(1-Math.abs(t/60%2-1)),a){case 0:o=r,n=h,s=0;break;case 1:o=h,n=r,s=0;break;case 2:o=0,n=r,s=h;break;case 3:o=0,n=h,s=r;break;case 4:o=h,n=0,s=r;break;case 5:o=r,n=0,s=h;break;default:o=0,n=0,s=0}return"RGB("+parseInt(255*o)+","+parseInt(255*n)+","+parseInt(255*s)+")"},o.prototype._getStrokeWidth=function(t){return void 0!==t?this.showPerspective?1/-t.trans.z*this.dataColor.strokeWidth:-this.eye.z/this.camera.getArmLength()*this.dataColor.strokeWidth:this.dataColor.strokeWidth},o.prototype._redrawBar=function(t,e,i,o,n,s){var r,a=this,h=e.point,d=this.zRange.min,u=[{point:new l(h.x-i,h.y-o,h.z)},{point:new l(h.x+i,h.y-o,h.z)},{point:new l(h.x+i,h.y+o,h.z)},{point:new l(h.x-i,h.y+o,h.z)}],c=[{point:new l(h.x-i,h.y-o,d)},{point:new l(h.x+i,h.y-o,d)},{point:new l(h.x+i,h.y+o,d)},{point:new l(h.x-i,h.y+o,d)}];u.forEach(function(t){t.screen=a._convert3Dto2D(t.point)}),c.forEach(function(t){t.screen=a._convert3Dto2D(t.point)});var p=[{corners:u,center:l.avg(c[0].point,c[2].point)},{corners:[u[0],u[1],c[1],c[0]],center:l.avg(c[1].point,c[0].point)},{corners:[u[1],u[2],c[2],c[1]],center:l.avg(c[2].point,c[1].point)},{corners:[u[2],u[3],c[3],c[2]],center:l.avg(c[3].point,c[2].point)},{corners:[u[3],u[0],c[0],c[3]],center:l.avg(c[0].point,c[3].point)}];e.surfaces=p;for(var f=0;f<p.length;f++){r=p[f];var m=this._conveLine truncated
function tt(t){return t&ve?"cancel":t&fe?"end":t&pe?"move":t&ce?"start":""}function et(t){return t==Lt?"down":t==zt?"up":t==Rt?"left":t==At?"right":""}function it(t,e){var i=e.manager;return i?i.get(t):t}function ot(){Q.apply(this,arguments)}function nt(){ot.apply(this,arguments),this.pX=null,this.pY=null}function st(){ot.apply(this,arguments)}function rt(){Q.apply(this,arguments),this._timer=null,this._input=null}function at(){ot.apply(this,arguments)}function ht(){ot.apply(this,arguments)}function dt(){Q.apply(this,arguments),this.pTime=!1,this.pCenter=!1,this._timer=null,this._input=null,this.count=0}function lt(t,e){return e=e||{},e.recognizers=m(e.recognizers,lt.defaults.preset),new ut(t,e)}function ut(t,e){this.options=ft({},lt.defaults,e||{}),this.options.inputTarget=this.options.inputTarget||t,this.handlers={},this.session={},this.recognizers=[],this.oldCssProps={},this.element=t,this.input=O(this),this.touchAction=new J(this,this.options.touchAction),ct(this,!0),l(this.options.recognizers,function(t){var e=this.add(new t[0](t[1]));t[2]&&e.recognizeWith(t[2]),t[3]&&e.requireFailure(t[3])},this)}function ct(t,e){var i=t.element;if(i.style){var o;l(t.options.cssProps,function(n,s){o=S(i.style,s),e?(t.oldCssProps[o]=i.style[o],i.style[o]=n):i.style[o]=t.oldCssProps[o]||""}),e||(t.oldCssProps={})}}function pt(t,e){var i=s.createEvent("Event");i.initEvent(t,!0,!0),i.gesture=e,e.target.dispatchEvent(i)}var ft,mt=["","webkit","Moz","MS","ms","o"],vt=s.createElement("div"),gt="function",yt=Math.round,bt=Math.abs,_t=Date.now;ft="function"!=typeof Object.assign?function(t){if(t===a||null===t)throw new TypeError("Cannot convert undefined or null to object");for(var e=Object(t),i=1;i<arguments.length;i++){var o=arguments[i];if(o!==a&&null!==o)for(var n in o)o.hasOwnProperty(n)&&(e[n]=o[n])}return e}:Object.assign;var wt=u(function(t,e,i){for(var o=Object.keys(e),n=0;n<o.length;)(!i||i&&t[o[n]]===a)&&(t[o[n]]=e[o[n]]),n++;return t},"extend","Use `assign`."),xt=u(function(t,e){return wt(t,e,!0)},"merge","Use `assign`."),kt=1,St=/mobile|tablet|ip(ad|hone|od)|android/i,Dt="ontouchstart"in n,Mt=S(n,"PointerEvent")!==a,Ct=Dt&&St.test(navigator.userAgent),Ot=25,Et=1,Tt=2,Pt=4,It=8,Nt=1,Rt=2,At=4,zt=8,Lt=16,Ft=Rt|At,Bt=zt|Lt,jt=Ft|Bt,Ht=["x","y"],Wt=["clientX","clientY"];C.prototype={handler:function(){},init:function(){this.evEl&&v(this.element,this.evEl,this.domHandler),this.evTarget&&v(this.target,this.evTarget,this.domHandler),this.evWin&&v(M(this.element),this.evWin,this.domHandler)},destroy:function(){this.evEl&&g(this.element,this.evEl,this.domHandler),this.evTarget&&g(this.target,this.evTarget,this.domHandler),this.evWin&&g(M(this.element),this.evWin,this.domHandler)}};var Yt={mousedown:Et,mousemove:Tt,mouseup:Pt},Gt="mousedown",Vt="mousemove mouseup";c(H,C,{handler:function(t){var e=Yt[t.type];e&Et&&0===t.button&&(this.pressed=!0),e&Tt&&1!==t.which&&(e=Pt),this.pressed&&(e&Pt&&(this.pressed=!1),this.callback(this.manager,e,{pointers:[t],changedPointers:[t],pointerType:"mouse",srcEvent:t}))}});var Ut={pointerdown:Et,pointermove:Tt,pointerup:Pt,pointercancel:It,pointerout:It},qt={2:"touch",3:"pen",4:"mouse",5:"kinect"},Xt="pointerdown",Zt="pointermove pointerup pointercancel";n.MSPointerEvent&&!n.PointerEvent&&(Xt="MSPointerDown",Zt="MSPointerMove MSPointerUp MSPointerCancel"),c(W,C,{handler:function(t){var e=this.store,i=!1,o=t.type.toLowerCase().replace("ms",""),n=Ut[o],s=qt[t.pointerType]||t.pointerType,r="touch"==s,a=w(e,t.pointerId,"pointerId");n&Et&&(0===t.button||r)?a<0&&(e.push(t),a=e.length-1):n&(Pt|It)&&(i=!0),a<0||(e[a]=t,this.callback(this.manager,n,{pointers:e,changedPointers:[t],pointerType:s,srcEvent:t}),i&&e.splice(a,1))}});var Kt={touchstart:Et,touchmove:Tt,touchend:Pt,touchcancel:It},Jt="touchstart",$t="touchstart touchmove touchend touchcancel";c(Y,C,{handler:function(t){var e=Kt[t.type];if(e===Et&&(this.started=!0),this.started){var i=G.call(this,t,e);e&(Pt|It)&&i[0].length-i[1].length==0&&(this.started=!1),this.callback(this.manager,e,{pointers:i[0],changedPointers:i[1],pointerType:"touch",srcEvent:t})}}});var Qt={touchstart:Et,touchmove:Tt,touchend:Pt,touchcancel:It},te="touchstart touchmove touchend touchcancel";c(V,C,{handler:function(t){var e=Qt[t.type],i=U.call(this,t,e);i&&this.callback(this.manager,e,{pointers:i[0],changedPointers:i[1],pointerType:"touch",srcEvent:t})}});var ee=2500,ie=25;c(q,C,{handler:function(t,e,i){var o="touch"==i.pointerType,n="mouse"==i.pointerType;if(!(n&&i.sourceCapabilities&&i.sourceCapabilities.firesTouchEvents)){if(o)X.call(this,e,i);else if(n&&K.call(this,i))return;this.callback(t,e,i)}},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var oe=S(vt.style,"touchAction"),ne=oe!==a,se="auto",re="manipulation",ae="none",he="pan-x",de="pan-y",le=function(){if(!ne)return!1;var t={},e=n.CSS&&n.CSS.supports;return["auto","manipulation","pan-y","pan-x","pan-x pan-y","none"].forEach(function(i){t[i]=!e||n.CSS.supports("touch-action",i)}),t}();J.protoLine truncated
;this.pixelRatio=(window.devicePixelRatio||1)/(t.webkitBackingStorePixelRatio||t.mozBackingStorePixelRatio||t.msBackingStorePixelRatio||t.oBackingStorePixelRatio||t.backingStorePixelRatio||1),this.colorPickerCanvas.getContext("2d").setTransform(this.pixelRatio,0,0,this.pixelRatio,0,0)}else{var e=document.createElement("DIV");e.style.color="red",e.style.fontWeight="bold",e.style.padding="10px",e.innerHTML="Error: your browser does not support HTML canvas",this.colorPickerCanvas.appendChild(e)}this.colorPickerDiv.className="vis-color",this.opacityDiv=document.createElement("div"),this.opacityDiv.className="vis-opacity",this.brightnessDiv=document.createElement("div"),this.brightnessDiv.className="vis-brightness",this.arrowDiv=document.createElement("div"),this.arrowDiv.className="vis-arrow",this.opacityRange=document.createElement("input");try{this.opacityRange.type="range",this.opacityRange.min="0",this.opacityRange.max="100"}catch(t){}this.opacityRange.value="100",this.opacityRange.className="vis-range",this.brightnessRange=document.createElement("input");try{this.brightnessRange.type="range",this.brightnessRange.min="0",this.brightnessRange.max="100"}catch(t){}this.brightnessRange.value="100",this.brightnessRange.className="vis-range",this.opacityDiv.appendChild(this.opacityRange),this.brightnessDiv.appendChild(this.brightnessRange);var i=this;this.opacityRange.onchange=function(){i._setOpacity(this.value)},this.opacityRange.oninput=function(){i._setOpacity(this.value)},this.brightnessRange.onchange=function(){i._setBrightness(this.value)},this.brightnessRange.oninput=function(){i._setBrightness(this.value)},this.brightnessLabel=document.createElement("div"),this.brightnessLabel.className="vis-label vis-brightness",this.brightnessLabel.innerHTML="brightness:",this.opacityLabel=document.createElement("div"),this.opacityLabel.className="vis-label vis-opacity",this.opacityLabel.innerHTML="opacity:",this.newColorDiv=document.createElement("div"),this.newColorDiv.className="vis-new-color",this.newColorDiv.innerHTML="new",this.initialColorDiv=document.createElement("div"),this.initialColorDiv.className="vis-initial-color",this.initialColorDiv.innerHTML="initial",this.cancelButton=document.createElement("div"),this.cancelButton.className="vis-button vis-cancel",this.cancelButton.innerHTML="cancel",this.cancelButton.onclick=this._hide.bind(this,!1),this.applyButton=document.createElement("div"),this.applyButton.className="vis-button vis-apply",this.applyButton.innerHTML="apply",this.applyButton.onclick=this._apply.bind(this),this.saveButton=document.createElement("div"),this.saveButton.className="vis-button vis-save",this.saveButton.innerHTML="save",this.saveButton.onclick=this._save.bind(this),this.loadButton=document.createElement("div"),this.loadButton.className="vis-button vis-load",this.loadButton.innerHTML="load last",this.loadButton.onclick=this._loadLast.bind(this),this.frame.appendChild(this.colorPickerDiv),this.frame.appendChild(this.arrowDiv),this.frame.appendChild(this.brightnessLabel),this.frame.appendChild(this.brightnessDiv),this.frame.appendChild(this.opacityLabel),this.frame.appendChild(this.opacityDiv),this.frame.appendChild(this.newColorDiv),this.frame.appendChild(this.initialColorDiv),this.frame.appendChild(this.cancelButton),this.frame.appendChild(this.applyButton),this.frame.appendChild(this.saveButton),this.frame.appendChild(this.loadButton)}},{key:"_bindHammer",value:function(){var t=this;this.drag={},this.pinch={},this.hammer=new l(this.colorPickerCanvas),this.hammer.get("pinch").set({enable:!0}),u.onTouch(this.hammer,function(e){t._moveSelector(e)}),this.hammer.on("tap",function(e){t._moveSelector(e)}),this.hammer.on("panstart",function(e){t._moveSelector(e)}),this.hammer.on("panmove",function(e){t._moveSelector(e)}),this.hammer.on("panend",function(e){t._moveSelector(e)})}},{key:"_generateHueCircle",value:function(){if(!1===this.generated){var t=this.colorPickerCanvas.getContext("2d");void 0===this.pixelRation&&(this.pixelRatio=(window.devicePixelRatio||1)/(t.webkitBackingStorePixelRatio||t.mozBackingStorePixelRatio||t.msBackingStorePixelRatio||t.oBackingStorePixelRatio||t.backingStorePixelRatio||1)),t.setTransform(this.pixelRatio,0,0,this.pixelRatio,0,0);var e=this.colorPickerCanvas.clientWidth,i=this.colorPickerCanvas.clientHeight;t.clearRect(0,0,e,i);var o=void 0,n=void 0,s=void 0,r=void 0;this.centerCoordinates={x:.5*e,y:.5*i},this.r=.49*e;var a=2*Math.PI/360,h=1/this.r,d=void 0;for(s=0;s<360;s++)for(r=0;r<this.r;r++)o=this.centerCoordinates.x+r*Math.sin(a*s),n=this.centerCoordinates.y+r*Math.cos(a*s),d=c.HSVToRGB(s*(1/360),r*h,1),t.fillStyle="rgb("+d.r+","+d.g+","+d.b+")",t.fillRect(o-.5,n-.5,2,2);t.strokeStyle="rgba(0,0,0,1)",t.circle(this.centerCoordinates.x,this.centerCoordinates.y,this.r),t.stroke(),this.hueCircle=t.getImageData(0,0,e,i)}this.generated=!0}},{key:"_moveSelector",value:function(t){var e=this.colorPickerDiv.getBoundingClientRect(),i=t.center.x-e.left,o=t.center.y-Line truncated
function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(0),s=o(n),r=i(1),a=o(r),h=i(2),d=function(){function t(){(0,s.default)(this,t),this.clear(),this.defaultIndex=0,this.groupsArray=[],this.groupIndex=0,this.defaultGroups=[{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"},hover:{border:"#2B7CE9",background:"#D2E5FF"}},{border:"#FFA500",background:"#FFFF00",highlight:{border:"#FFA500",background:"#FFFFA3"},hover:{border:"#FFA500",background:"#FFFFA3"}},{border:"#FA0A10",background:"#FB7E81",highlight:{border:"#FA0A10",background:"#FFAFB1"},hover:{border:"#FA0A10",background:"#FFAFB1"}},{border:"#41A906",background:"#7BE141",highlight:{border:"#41A906",background:"#A1EC76"},hover:{border:"#41A906",background:"#A1EC76"}},{border:"#E129F0",background:"#EB7DF4",highlight:{border:"#E129F0",background:"#F0B3F5"},hover:{border:"#E129F0",background:"#F0B3F5"}},{border:"#7C29F0",background:"#AD85E4",highlight:{border:"#7C29F0",background:"#D3BDF0"},hover:{border:"#7C29F0",background:"#D3BDF0"}},{border:"#C37F00",background:"#FFA807",highlight:{border:"#C37F00",background:"#FFCA66"},hover:{border:"#C37F00",background:"#FFCA66"}},{border:"#4220FB",background:"#6E6EFD",highlight:{border:"#4220FB",background:"#9B9BFD"},hover:{border:"#4220FB",background:"#9B9BFD"}},{border:"#FD5A77",background:"#FFC0CB",highlight:{border:"#FD5A77",background:"#FFD1D9"},hover:{border:"#FD5A77",background:"#FFD1D9"}},{border:"#4AD63A",background:"#C2FABC",highlight:{border:"#4AD63A",background:"#E6FFE3"},hover:{border:"#4AD63A",background:"#E6FFE3"}},{border:"#990000",background:"#EE0000",highlight:{border:"#BB0000",background:"#FF3333"},hover:{border:"#BB0000",background:"#FF3333"}},{border:"#FF6000",background:"#FF6000",highlight:{border:"#FF6000",background:"#FF6000"},hover:{border:"#FF6000",background:"#FF6000"}},{border:"#97C2FC",background:"#2B7CE9",highlight:{border:"#D2E5FF",background:"#2B7CE9"},hover:{border:"#D2E5FF",background:"#2B7CE9"}},{border:"#399605",background:"#255C03",highlight:{border:"#399605",background:"#255C03"},hover:{border:"#399605",background:"#255C03"}},{border:"#B70054",background:"#FF007E",highlight:{border:"#B70054",background:"#FF007E"},hover:{border:"#B70054",background:"#FF007E"}},{border:"#AD85E4",background:"#7C29F0",highlight:{border:"#D3BDF0",background:"#7C29F0"},hover:{border:"#D3BDF0",background:"#7C29F0"}},{border:"#4557FA",background:"#000EA1",highlight:{border:"#6E6EFD",background:"#000EA1"},hover:{border:"#6E6EFD",background:"#000EA1"}},{border:"#FFC0CB",background:"#FD5A77",highlight:{border:"#FFD1D9",background:"#FD5A77"},hover:{border:"#FFD1D9",background:"#FD5A77"}},{border:"#C2FABC",background:"#74D66A",highlight:{border:"#E6FFE3",background:"#74D66A"},hover:{border:"#E6FFE3",background:"#74D66A"}},{border:"#EE0000",background:"#990000",highlight:{border:"#FF3333",background:"#BB0000"},hover:{border:"#FF3333",background:"#BB0000"}}],this.options={},this.defaultOptions={useDefaultGroups:!0},h.extend(this.options,this.defaultOptions)}return(0,a.default)(t,[{key:"setOptions",value:function(t){var e=["useDefaultGroups"];if(void 0!==t)for(var i in t)if(t.hasOwnProperty(i)&&-1===e.indexOf(i)){var o=t[i];this.add(i,o)}}},{key:"clear",value:function(){this.groups={},this.groupsArray=[]}},{key:"get",value:function(t){var e=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],i=this.groups[t];if(void 0===i&&e)if(!1===this.options.useDefaultGroups&&this.groupsArray.length>0){var o=this.groupIndex%this.groupsArray.length;this.groupIndex++,i={},i.color=this.groups[this.groupsArray[o]],this.groups[t]=i}else{var n=this.defaultIndex%this.defaultGroups.length;this.defaultIndex++,i={},i.color=this.defaultGroups[n],this.groups[t]=i}return i}},{key:"add",value:function(t,e){return this.groups[t]=e,this.groupsArray.push(t),e}}]),t}();e.default=d},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(0),s=o(n),r=i(1),a=o(r),h=i(2),d=i(11),l=i(12),u=i(47).default,c=function(){function t(e,i,o,n){var r=this;if((0,s.default)(this,t),this.body=e,this.images=i,this.groups=o,this.layoutEngine=n,this.body.functions.createNode=this.create.bind(this),this.nodesListeners={add:function(t,e){r.add(e.items)},update:function(t,e){r.update(e.items,e.data,e.oldData)},remove:function(t,e){r.remove(e.items)}},this.defaultOptions={borderWidth:1,borderWidthSelected:2,brokenImage:void 0,color:{border:"#2B7CE9",background:"#97C2FC",highlight:{border:"#2B7CE9",background:"#D2E5FF"},hover:{border:"#2B7CE9",background:"#D2E5FF"}},fixed:{x:!1,y:!1},font:{color:"#343434",size:14,face:"arial",background:"none",strokeWidth:0,strokeColor:"#ffffff",align:"center",vadjust:0,multi:!1,bold:{mod:"bold"},boldital:{mod:"bold italic"},ital:{mod:"italic"},mono:{mod:"",size:15,face:"monospace",vadjust:2}},group:void 0,hidden:!1,icon:{face:"FontAwesome",code:void 0,size:50,color:"#Line truncated
}]),e}(m.default);e.default=v},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(3),s=o(n),r=i(0),a=o(r),h=i(1),d=o(h),l=i(4),u=o(l),c=i(5),p=o(c),f=i(24),m=o(f),v=function(t){function e(t,i,o){return(0,a.default)(this,e),(0,u.default)(this,(e.__proto__||(0,s.default)(e)).call(this,t,i,o))}return(0,p.default)(e,t),(0,d.default)(e,[{key:"draw",value:function(t,e,i,o,n,s){this._drawShape(t,"square",2,e,i,o,n,s)}},{key:"distanceToBorder",value:function(t,e){return this._distanceToBorder(t,e)}}]),e}(m.default);e.default=v},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(3),s=o(n),r=i(0),a=o(r),h=i(1),d=o(h),l=i(4),u=o(l),c=i(5),p=o(c),f=i(24),m=o(f),v=function(t){function e(t,i,o){return(0,a.default)(this,e),(0,u.default)(this,(e.__proto__||(0,s.default)(e)).call(this,t,i,o))}return(0,p.default)(e,t),(0,d.default)(e,[{key:"draw",value:function(t,e,i,o,n,s){this._drawShape(t,"hexagon",4,e,i,o,n,s)}},{key:"distanceToBorder",value:function(t,e){return this._distanceToBorder(t,e)}}]),e}(m.default);e.default=v},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(3),s=o(n),r=i(0),a=o(r),h=i(1),d=o(h),l=i(4),u=o(l),c=i(5),p=o(c),f=i(24),m=o(f),v=function(t){function e(t,i,o){return(0,a.default)(this,e),(0,u.default)(this,(e.__proto__||(0,s.default)(e)).call(this,t,i,o))}return(0,p.default)(e,t),(0,d.default)(e,[{key:"draw",value:function(t,e,i,o,n,s){this._drawShape(t,"star",4,e,i,o,n,s)}},{key:"distanceToBorder",value:function(t,e){return this._distanceToBorder(t,e)}}]),e}(m.default);e.default=v},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(3),s=o(n),r=i(0),a=o(r),h=i(1),d=o(h),l=i(4),u=o(l),c=i(5),p=o(c),f=i(23),m=o(f),v=function(t){function e(t,i,o){(0,a.default)(this,e);var n=(0,u.default)(this,(e.__proto__||(0,s.default)(e)).call(this,t,i,o));return n._setMargins(o),n}return(0,p.default)(e,t),(0,d.default)(e,[{key:"resize",value:function(t,e,i){this.needsRefresh(e,i)&&(this.textSize=this.labelModule.getTextSize(t,e,i),this.width=this.textSize.width+this.margin.right+this.margin.left,this.height=this.textSize.height+this.margin.top+this.margin.bottom,this.radius=.5*this.width)}},{key:"draw",value:function(t,e,i,o,n,s){this.resize(t,o,n),this.left=e-this.width/2,this.top=i-this.height/2,this.enableShadow(t,s),this.labelModule.draw(t,this.left+this.textSize.width/2+this.margin.left,this.top+this.textSize.height/2+this.margin.top,o,n),this.disableShadow(t,s),this.updateBoundingBox(e,i,t,o,n)}},{key:"distanceToBorder",value:function(t,e){return this._distanceToBorder(t,e)}}]),e}(m.default);e.default=v},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(3),s=o(n),r=i(0),a=o(r),h=i(1),d=o(h),l=i(4),u=o(l),c=i(5),p=o(c),f=i(24),m=o(f),v=function(t){function e(t,i,o){return(0,a.default)(this,e),(0,u.default)(this,(e.__proto__||(0,s.default)(e)).call(this,t,i,o))}return(0,p.default)(e,t),(0,d.default)(e,[{key:"draw",value:function(t,e,i,o,n,s){this._drawShape(t,"triangle",3,e,i,o,n,s)}},{key:"distanceToBorder",value:function(t,e){return this._distanceToBorder(t,e)}}]),e}(m.default);e.default=v},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(3),s=o(n),r=i(0),a=o(r),h=i(1),d=o(h),l=i(4),u=o(l),c=i(5),p=o(c),f=i(24),m=o(f),v=function(t){function e(t,i,o){return(0,a.default)(this,e),(0,u.default)(this,(e.__proto__||(0,s.default)(e)).call(this,t,i,o))}return(0,p.default)(e,t),(0,d.default)(e,[{key:"draw",value:function(t,e,i,o,n,s){this._drawShape(t,"triangleDown",3,e,i,o,n,s)}},{key:"distanceToBorder",value:function(t,e){return this._distanceToBorder(t,e)}}]),e}(m.default);e.default=v},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(0),s=o(n),r=i(1),a=o(r),h=i(2),d=i(11),l=i(12),u=i(74).default,c=function(){function t(e,i,o){var n=this;(0,s.default)(this,t),this.body=e,this.images=i,this.groups=o,this.body.functions.createEdge=this.create.bind(this),this.edgesListeners={add:function(t,e){n.add(e.items)},update:function(t,e){n.update(e.items)},remove:function(t,e){n.remove(e.items)}},this.options={},this.defaultOptions={arrows:{to:{enabled:!1,scaleFactor:1,type:"arrow"},middle:{enabled:!1,scaleFactor:1,type:"arrow"},from:{enabled:!1,scaleFactor:1,type:"arrow"}},arrowStrikethrough:!0,color:{color:"#848484",highlight:"#848484",hover:"#848484",inherit:"from",opacity:1},dashes:!1,font:{color:"#343434",size:14,face:"arial",background:"none",strokeWidth:2,strokeColor:"#ffffff",align:"horizontal",multi:!1,vadjust:0,bold:{mod:"bold"},boldital:{mod:"bold italic"},ital:{mod:"italic"},mono:{mod:"",size:15,face:"courier nLine truncated
;s=i<p?-Math.pow(.05*i,2)+Math.pow(.05*p,2):0,0===i?i=.01:s/=i,o=t*s,n=e*s,c[r.id].x-=o,c[r.id].y-=n,c[a.id].x+=o,c[a.id].y+=n}}}]),t}();e.default=h},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(0),s=o(n),r=i(1),a=o(r),h=function(){function t(e,i,o){(0,s.default)(this,t),this.body=e,this.physicsBody=i,this.setOptions(o)}return(0,a.default)(t,[{key:"setOptions",value:function(t){this.options=t}},{key:"solve",value:function(){for(var t=void 0,e=void 0,i=this.physicsBody.physicsEdgeIndices,o=this.body.edges,n=void 0,s=void 0,r=void 0,a=0;a<i.length;a++)e=o[i[a]],!0===e.connected&&e.toId!==e.fromId&&void 0!==this.body.nodes[e.toId]&&void 0!==this.body.nodes[e.fromId]&&(void 0!==e.edgeType.via?(t=void 0===e.options.length?this.options.springLength:e.options.length,n=e.to,s=e.edgeType.via,r=e.from,this._calculateSpringForce(n,s,.5*t),this._calculateSpringForce(s,r,.5*t)):(t=void 0===e.options.length?1.5*this.options.springLength:e.options.length,this._calculateSpringForce(e.from,e.to,t)))}},{key:"_calculateSpringForce",value:function(t,e,i){var o=t.x-e.x,n=t.y-e.y,s=Math.max(Math.sqrt(o*o+n*n),.01),r=this.options.springConstant*(i-s)/s,a=o*r,h=n*r;void 0!==this.physicsBody.forces[t.id]&&(this.physicsBody.forces[t.id].x+=a,this.physicsBody.forces[t.id].y+=h),void 0!==this.physicsBody.forces[e.id]&&(this.physicsBody.forces[e.id].x-=a,this.physicsBody.forces[e.id].y-=h)}}]),t}();e.default=h},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(0),s=o(n),r=i(1),a=o(r),h=function(){function t(e,i,o){(0,s.default)(this,t),this.body=e,this.physicsBody=i,this.setOptions(o)}return(0,a.default)(t,[{key:"setOptions",value:function(t){this.options=t}},{key:"solve",value:function(){for(var t,e,i,o,n,s,r,a,h=this.body.edges,d=this.physicsBody.physicsEdgeIndices,l=this.physicsBody.physicsNodeIndices,u=this.physicsBody.forces,c=0;c<l.length;c++){var p=l[c];u[p].springFx=0,u[p].springFy=0}for(var f=0;f<d.length;f++)e=h[d[f]],!0===e.connected&&(t=void 0===e.options.length?this.options.springLength:e.options.length,i=e.from.x-e.to.x,o=e.from.y-e.to.y,a=Math.sqrt(i*i+o*o),a=0===a?.01:a,r=this.options.springConstant*(t-a)/a,n=i*r,s=o*r,e.to.level!=e.from.level?(void 0!==u[e.toId]&&(u[e.toId].springFx-=n,u[e.toId].springFy-=s),void 0!==u[e.fromId]&&(u[e.fromId].springFx+=n,u[e.fromId].springFy+=s)):(void 0!==u[e.toId]&&(u[e.toId].x-=.5*n,u[e.toId].y-=.5*s),void 0!==u[e.fromId]&&(u[e.fromId].x+=.5*n,u[e.fromId].y+=.5*s)));r=1;for(var m,v,g=0;g<l.length;g++){var y=l[g];m=Math.min(r,Math.max(-r,u[y].springFx)),v=Math.min(r,Math.max(-r,u[y].springFy)),u[y].x+=m,u[y].y+=v}for(var b=0,_=0,w=0;w<l.length;w++){var x=l[w];b+=u[x].x,_+=u[x].y}for(var k=b/l.length,S=_/l.length,D=0;D<l.length;D++){var M=l[D];u[M].x-=k,u[M].y-=S}}}]),t}();e.default=h},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(3),s=o(n),r=i(0),a=o(r),h=i(1),d=o(h),l=i(4),u=o(l),c=i(5),p=o(c),f=i(120),m=o(f),v=function(t){function e(t,i,o){return(0,a.default)(this,e),(0,u.default)(this,(e.__proto__||(0,s.default)(e)).call(this,t,i,o))}return(0,p.default)(e,t),(0,d.default)(e,[{key:"_calculateForces",value:function(t,e,i,o,n){0===t&&(t=.1*Math.random(),e=t),this.overlapAvoidanceFactor<1&&o.shape.radius&&(t=Math.max(.1+this.overlapAvoidanceFactor*o.shape.radius,t-o.shape.radius));var s=o.edges.length+1,r=this.options.gravitationalConstant*n.mass*o.options.mass*s/Math.pow(t,2),a=e*r,h=i*r;this.physicsBody.forces[o.id].x+=a,this.physicsBody.forces[o.id].y+=h}}]),e}(m.default);e.default=v},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(3),s=o(n),r=i(0),a=o(r),h=i(1),d=o(h),l=i(4),u=o(l),c=i(5),p=o(c),f=i(121),m=o(f),v=function(t){function e(t,i,o){return(0,a.default)(this,e),(0,u.default)(this,(e.__proto__||(0,s.default)(e)).call(this,t,i,o))}return(0,p.default)(e,t),(0,d.default)(e,[{key:"_calculateForces",value:function(t,e,i,o,n){if(t>0){var s=n.edges.length+1,r=this.options.centralGravity*s*n.options.mass;o[n.id].x=e*r,o[n.id].y=i*r}}}]),e}(m.default);e.default=v},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(8),s=o(n),r=i(6),a=o(r),h=i(0),d=o(h),l=i(1),u=o(l),c=i(2),p=i(76).default,f=i(228).default,m=i(74).default,v=i(47).default,g=function(){function t(e){var i=this;(0,d.default)(this,t),this.body=e,this.clusteredNodes={},this.clusteredEdges={},this.options={},this.defaultOptions={},c.extend(this.options,this.defaultOptions),this.body.emitter.on("_resetData",function(){i.clusteredNodes={},i.clusteredEdges={}})}return(0,u.default)(t,[{key:"clusterByHubsize",value:function(t,e){void 0===t?t=this._getHubSize():"object"===(void 0===t?"undefined":(0,a.default)(t))&&(e=this._checkOptions(t),t=this._getHubSiLine truncated
this.frame.canvas.width!==r&&(this.frame.canvas.width=r,i=!0),this.frame.canvas.height!==a&&(this.frame.canvas.height=a,i=!0)}return!0===i&&(this.body.emitter.emit("resize",{width:Math.round(this.frame.canvas.width/this.pixelRatio),height:Math.round(this.frame.canvas.height/this.pixelRatio),oldWidth:Math.round(o/this.pixelRatio),oldHeight:Math.round(n/this.pixelRatio)}),this._setCameraState()),this.initialized=!0,i}},{key:"getContext",value:function(){return this.frame.canvas.getContext("2d")}},{key:"_determinePixelRatio",value:function(){var t=this.getContext();if(void 0===t)throw new Error("Could not get canvax context");var e=1;return"undefined"!=typeof window&&(e=window.devicePixelRatio||1),e/(t.webkitBackingStorePixelRatio||t.mozBackingStorePixelRatio||t.msBackingStorePixelRatio||t.oBackingStorePixelRatio||t.backingStorePixelRatio||1)}},{key:"_setPixelRatio",value:function(){this.pixelRatio=this._determinePixelRatio()}},{key:"setTransform",value:function(){var t=this.getContext();if(void 0===t)throw new Error("Could not get canvax context");t.setTransform(this.pixelRatio,0,0,this.pixelRatio,0,0)}},{key:"_XconvertDOMtoCanvas",value:function(t){return(t-this.body.view.translation.x)/this.body.view.scale}},{key:"_XconvertCanvasToDOM",value:function(t){return t*this.body.view.scale+this.body.view.translation.x}},{key:"_YconvertDOMtoCanvas",value:function(t){return(t-this.body.view.translation.y)/this.body.view.scale}},{key:"_YconvertCanvasToDOM",value:function(t){return t*this.body.view.scale+this.body.view.translation.y}},{key:"canvasToDOM",value:function(t){return{x:this._XconvertCanvasToDOM(t.x),y:this._YconvertCanvasToDOM(t.y)}}},{key:"DOMtoCanvas",value:function(t){return{x:this._XconvertDOMtoCanvas(t.x),y:this._YconvertDOMtoCanvas(t.y)}}}]),t}();e.default=u},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(0),s=o(n),r=i(1),a=o(r),h=i(2),d=i(76).default,l=function(){function t(e,i){var o=this;(0,s.default)(this,t),this.body=e,this.canvas=i,this.animationSpeed=1/this.renderRefreshRate,this.animationEasingFunction="easeInOutQuint",this.easingTime=0,this.sourceScale=0,this.targetScale=0,this.sourceTranslation=0,this.targetTranslation=0,this.lockedOnNodeId=void 0,this.lockedOnNodeOffset=void 0,this.touchTime=0,this.viewFunction=void 0,this.body.emitter.on("fit",this.fit.bind(this)),this.body.emitter.on("animationFinished",function(){o.body.emitter.emit("_stopRendering")}),this.body.emitter.on("unlockNode",this.releaseNode.bind(this))}return(0,a.default)(t,[{key:"setOptions",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.options=t}},{key:"fit",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{nodes:[]},e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=void 0,o=void 0;if(void 0!==t.nodes&&0!==t.nodes.length||(t.nodes=this.body.nodeIndices),!0===e){var n=0;for(var s in this.body.nodes)if(this.body.nodes.hasOwnProperty(s)){var r=this.body.nodes[s];!0===r.predefinedPosition&&(n+=1)}if(n>.5*this.body.nodeIndices.length)return void this.fit(t,!1);i=d.getRange(this.body.nodes,t.nodes);o=12.662/(this.body.nodeIndices.length+7.4147)+.0964822;o*=Math.min(this.canvas.frame.canvas.clientWidth/600,this.canvas.frame.canvas.clientHeight/600)}else{this.body.emitter.emit("_resizeNodes"),i=d.getRange(this.body.nodes,t.nodes);var a=1.1*Math.abs(i.maxX-i.minX),h=1.1*Math.abs(i.maxY-i.minY),l=this.canvas.frame.canvas.clientWidth/a,u=this.canvas.frame.canvas.clientHeight/h;o=l<=u?l:u}o>1?o=1:0===o&&(o=1);var c=d.findCenter(i),p={position:c,scale:o,animation:t.animation};this.moveTo(p)}},{key:"focus",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(void 0!==this.body.nodes[t]){var i={x:this.body.nodes[t].x,y:this.body.nodes[t].y};e.position=i,e.lockedOnNode=t,this.moveTo(e)}else console.log("Node: "+t+" cannot be found.")}},{key:"moveTo",value:function(t){if(void 0===t)return void(t={});void 0===t.offset&&(t.offset={x:0,y:0}),void 0===t.offset.x&&(t.offset.x=0),void 0===t.offset.y&&(t.offset.y=0),void 0===t.scale&&(t.scale=this.body.view.scale),void 0===t.position&&(t.position=this.getViewPosition()),void 0===t.animation&&(t.animation={duration:0}),!1===t.animation&&(t.animation={duration:0}),!0===t.animation&&(t.animation={}),void 0===t.animation.duration&&(t.animation.duration=1e3),void 0===t.animation.easingFunction&&(t.animation.easingFunction="easeInOutQuad"),this.animateView(t)}},{key:"animateView",value:function(t){if(void 0!==t){this.animationEasingFunction=t.animation.easingFunction,this.releaseNode(),!0===t.locked&&(this.lockedOnNodeId=t.lockedOnNode,this.lockedOnNodeOffset=t.offset),0!=this.easingTime&&this._transitionRedraw(!0),this.sourceScale=this.body.view.scale,this.sourceTranslation=this.body.view.translation,this.targetScale=t.scale,this.body.view.scale=this.targetScale;var e=this.canvas.DOMtoCanvas({x:.5*this.canvas.frame.cLine truncated
;if((e.unselectAll||void 0===e.unselectAll)&&this.unselectAll(),t.nodes)for(i=0;i<t.nodes.length;i++){o=t.nodes[i];var n=this.body.nodes[o];if(!n)throw new RangeError('Node with id "'+o+'" not found');this.selectObject(n,e.highlightEdges)}if(t.edges)for(i=0;i<t.edges.length;i++){o=t.edges[i];var s=this.body.edges[o];if(!s)throw new RangeError('Edge with id "'+o+'" not found');this.selectObject(s)}this.body.emitter.emit("_requestRedraw")}},{key:"selectNodes",value:function(t){var e=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];if(!t||void 0===t.length)throw"Selection must be an array with ids";this.setSelection({nodes:t},{highlightEdges:e})}},{key:"selectEdges",value:function(t){if(!t||void 0===t.length)throw"Selection must be an array with ids";this.setSelection({edges:t})}},{key:"updateSelection",value:function(){for(var t in this.selectionObj.nodes)this.selectionObj.nodes.hasOwnProperty(t)&&(this.body.nodes.hasOwnProperty(t)||delete this.selectionObj.nodes[t]);for(var e in this.selectionObj.edges)this.selectionObj.edges.hasOwnProperty(e)&&(this.body.edges.hasOwnProperty(e)||delete this.selectionObj.edges[e])}},{key:"getClickedItems",value:function(t){for(var e=this.canvas.DOMtoCanvas(t),i=[],o=this.body.nodeIndices,n=this.body.nodes,s=o.length-1;s>=0;s--){var r=n[o[s]],a=r.getItemsOnPoint(e);i.push.apply(i,a)}for(var h=this.body.edgeIndices,d=this.body.edges,l=h.length-1;l>=0;l--){var u=d[h[l]],c=u.getItemsOnPoint(e);i.push.apply(i,c)}return i}}]),t}();e.default=u},function(t,e,i){function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var n=i(30),s=o(n),r=i(6),a=o(r),h=i(8),d=o(h),l=i(0),u=o(l),c=i(1),p=o(c),f=i(2),m=i(76).default,v=i(236),g=v.HorizontalStrategy,y=v.VerticalStrategy,b=function(){function t(){(0,u.default)(this,t),this.childrenReference={},this.parentReference={},this.trees={},this.distributionOrdering={},this.levels={},this.distributionIndex={},this.isTree=!1,this.treeIndex=-1}return(0,p.default)(t,[{key:"addRelation",value:function(t,e){void 0===this.childrenReference[t]&&(this.childrenReference[t]=[]),this.childrenReference[t].push(e),void 0===this.parentReference[e]&&(this.parentReference[e]=[]),this.parentReference[e].push(t)}},{key:"checkIfTree",value:function(){for(var t in this.parentReference)if(this.parentReference[t].length>1)return void(this.isTree=!1);this.isTree=!0}},{key:"numTrees",value:function(){return this.treeIndex+1}},{key:"setTreeIndex",value:function(t,e){void 0!==e&&void 0===this.trees[t.id]&&(this.trees[t.id]=e,this.treeIndex=Math.max(e,this.treeIndex))}},{key:"ensureLevel",value:function(t){void 0===this.levels[t]&&(this.levels[t]=0)}},{key:"getMaxLevel",value:function(t){var e=this,i={};return function t(o){if(void 0!==i[o])return i[o];var n=e.levels[o];if(e.childrenReference[o]){var s=e.childrenReference[o];if(s.length>0)for(var r=0;r<s.length;r++)n=Math.max(n,t(s[r]))}return i[o]=n,n}(t)}},{key:"levelDownstream",value:function(t,e){void 0===this.levels[e.id]&&(void 0===this.levels[t.id]&&(this.levels[t.id]=0),this.levels[e.id]=this.levels[t.id]+1)}},{key:"setMinLevelToZero",value:function(t){var e=1e9;for(var i in t)t.hasOwnProperty(i)&&void 0!==this.levels[i]&&(e=Math.min(this.levels[i],e));for(var o in t)t.hasOwnProperty(o)&&void 0!==this.levels[o]&&(this.levels[o]-=e)}},{key:"getTreeSize",value:function(t,e){var i=1e9,o=-1e9,n=1e9,s=-1e9;for(var r in this.trees)if(this.trees.hasOwnProperty(r)&&this.trees[r]===e){var a=t[r];i=Math.min(a.x,i),o=Math.max(a.x,o),n=Math.min(a.y,n),s=Math.max(a.y,s)}return{min_x:i,max_x:o,min_y:n,max_y:s}}},{key:"hasSameParent",value:function(t,e){var i=this.parentReference[t.id],o=this.parentReference[e.id];if(void 0===i||void 0===o)return!1;for(var n=0;n<i.length;n++)for(var s=0;s<o.length;s++)if(i[n]==o[s])return!0;return!1}},{key:"inSameSubNetwork",value:function(t,e){return this.trees[t.id]===this.trees[e.id]}},{key:"getLevels",value:function(){return(0,d.default)(this.distributionOrdering)}},{key:"addToOrdering",value:function(t,e){void 0===this.distributionOrdering[e]&&(this.distributionOrdering[e]=[]);var i=!1,o=this.distributionOrdering[e];for(var n in o)if(o[n]===t){i=!0;break}i||(this.distributionOrdering[e].push(t),this.distributionIndex[t.id]=this.distributionOrdering[e].length-1)}}]),t}(),_=function(){function t(e){(0,u.default)(this,t),this.body=e,this.initialRandomSeed=Math.round(1e6*Math.random()),this.randomSeed=this.initialRandomSeed,this.setPhysics=!1,this.options={},this.optionsBackup={physics:{}},this.defaultOptions={randomSeed:void 0,improvedLayout:!0,hierarchical:{enabled:!1,levelSeparation:150,nodeSpacing:100,treeSpacing:200,blockShifting:!0,edgeMinimization:!0,parentCentralization:!0,direction:"UD",sortMethod:"hubsize"}},f.extend(this.options,this.defaultOptions),this.bindEventListeners()}return(0,p.default)(t,[{key:"bindEventListeners",value:function(){var t=this;this.body.emitter.on("_dataChanged",function(){t.setupHierarchicalLayout()}),this.boLine truncated
;if(2!==o.length)throw new Error("The function for delete does not support two arguments (data, callback)");o(s,function(e){null!==e&&void 0!==e&&"delete"===t.inMode?(t.body.data.edges.getDataSet().remove(e.edges),t.body.data.nodes.getDataSet().remove(e.nodes),t.body.emitter.emit("startSimulation"),t.showManipulatorToolbar()):(t.body.emitter.emit("startSimulation"),t.showManipulatorToolbar())})}else this.body.data.edges.getDataSet().remove(i),this.body.data.nodes.getDataSet().remove(e),this.body.emitter.emit("startSimulation"),this.showManipulatorToolbar()}},{key:"_setup",value:function(){!0===this.options.enabled?(this.guiEnabled=!0,this._createWrappers(),!1===this.editMode?this._createEditButton():this.showManipulatorToolbar()):(this._removeManipulationDOM(),this.guiEnabled=!1)}},{key:"_createWrappers",value:function(){void 0===this.manipulationDiv&&(this.manipulationDiv=document.createElement("div"),this.manipulationDiv.className="vis-manipulation",!0===this.editMode?this.manipulationDiv.style.display="block":this.manipulationDiv.style.display="none",this.canvas.frame.appendChild(this.manipulationDiv)),void 0===this.editModeDiv&&(this.editModeDiv=document.createElement("div"),this.editModeDiv.className="vis-edit-mode",!0===this.editMode?this.editModeDiv.style.display="none":this.editModeDiv.style.display="block",this.canvas.frame.appendChild(this.editModeDiv)),void 0===this.closeDiv&&(this.closeDiv=document.createElement("div"),this.closeDiv.className="vis-close",this.closeDiv.style.display=this.manipulationDiv.style.display,this.canvas.frame.appendChild(this.closeDiv))}},{key:"_getNewTargetNode",value:function(t,e){var i=f.deepExtend({},this.options.controlNodeStyle);i.id="targetNode"+f.randomUUID(),i.hidden=!1,i.physics=!1,i.x=t,i.y=e;var o=this.body.functions.createNode(i);return o.shape.boundingBox={left:t,right:t,top:e,bottom:e},o}},{key:"_createEditButton",value:function(){this._clean(),this.manipulationDOM={},f.recursiveDOMDelete(this.editModeDiv);var t=this.options.locales[this.options.locale],e=this._createButton("editMode","vis-button vis-edit vis-edit-mode",t.edit||this.options.locales.en.edit);this.editModeDiv.appendChild(e),this._bindHammerToDiv(e,this.toggleEditMode.bind(this))}},{key:"_clean",value:function(){this.inMode=!1,!0===this.guiEnabled&&(f.recursiveDOMDelete(this.editModeDiv),f.recursiveDOMDelete(this.manipulationDiv),this._cleanManipulatorHammers()),this._cleanupTemporaryNodesAndEdges(),this._unbindTemporaryUIs(),this._unbindTemporaryEvents(),this.body.emitter.emit("restorePhysics")}},{key:"_cleanManipulatorHammers",value:function(){if(0!=this.manipulationHammers.length){for(var t=0;t<this.manipulationHammers.length;t++)this.manipulationHammers[t].destroy();this.manipulationHammers=[]}}},{key:"_removeManipulationDOM",value:function(){this._clean(),f.recursiveDOMDelete(this.manipulationDiv),f.recursiveDOMDelete(this.editModeDiv),f.recursiveDOMDelete(this.closeDiv),this.manipulationDiv&&this.canvas.frame.removeChild(this.manipulationDiv),this.editModeDiv&&this.canvas.frame.removeChild(this.editModeDiv),this.closeDiv&&this.canvas.frame.removeChild(this.closeDiv),this.manipulationDiv=void 0,this.editModeDiv=void 0,this.closeDiv=void 0}},{key:"_createSeperator",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1;this.manipulationDOM["seperatorLineDiv"+t]=document.createElement("div"),this.manipulationDOM["seperatorLineDiv"+t].className="vis-separator-line",this.manipulationDiv.appendChild(this.manipulationDOM["seperatorLineDiv"+t])}},{key:"_createAddNodeButton",value:function(t){var e=this._createButton("addNode","vis-button vis-add",t.addNode||this.options.locales.en.addNode);this.manipulationDiv.appendChild(e),this._bindHammerToDiv(e,this.addNodeMode.bind(this))}},{key:"_createAddEdgeButton",value:function(t){var e=this._createButton("addEdge","vis-button vis-connect",t.addEdge||this.options.locales.en.addEdge);this.manipulationDiv.appendChild(e),this._bindHammerToDiv(e,this.addEdgeMode.bind(this))}},{key:"_createEditNodeButton",value:function(t){var e=this._createButton("editNode","vis-button vis-edit",t.editNode||this.options.locales.en.editNode);this.manipulationDiv.appendChild(e),this._bindHammerToDiv(e,this.editNode.bind(this))}},{key:"_createEditEdgeButton",value:function(t){var e=this._createButton("editEdge","vis-button vis-edit",t.editEdge||this.options.locales.en.editEdge);this.manipulationDiv.appendChild(e),this._bindHammerToDiv(e,this.editEdgeMode.bind(this))}},{key:"_createDeleteButton",value:function(t){var e;e=this.options.rtl?"vis-button vis-delete-rtl":"vis-button vis-delete";var i=this._createButton("delete",e,t.del||this.options.locales.en.del);this.manipulationDiv.appendChild(i),this._bindHammerToDiv(i,this.deleteSelected.bind(this))}},{key:"_createBackButton",value:function(t){var e=this._createButton("back","vis-button vis-back",t.back||this.options.locales.en.back);this.manipulationDiv.appendChild(e),this._bindHammerToDiv(e,this.shLine truncated
//# sourceMappingURL=vis.map
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+24
View File
@@ -0,0 +1,24 @@
<template>
<router-view />
</template>
<script setup>
// import autofit from '../src/assets/js/autofit'
document.documentElement.setAttribute('theme-mode', 'dark');
// if (typeof autofit !== 'undefined') {
// autofit.init();
// console.log('autofit初始化');
// }
</script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
overflow: hidden;
}
</style>
+21
View File
@@ -0,0 +1,21 @@
import request from './request'
export const getUserList = () => {
return request.get('/users')
}
export const getUserById = (id) => {
return request.get(`/users/${id}`)
}
export const createUser = (data) => {
return request.post('/users', data)
}
export const updateUser = (id, data) => {
return request.put(`/users/${id}`, data)
}
export const deleteUser = (id) => {
return request.delete(`/users/${id}`)
}
@@ -0,0 +1,7 @@
export default {
0: "待签收",
10: "待分析",
20: "CEH中",
25: "CEH完成",
23: '已终止',
};
@@ -0,0 +1,12 @@
export const deepCopy = (data) => {
return JSON.parse(JSON.stringify(data));
}
export const uniqueById = (array) => {
return array.reduce((acc, item) => {
if (!acc.find(x => x.id === item.id)) {
acc.push(item);
}
return acc;
}, []);
};
@@ -0,0 +1,4 @@
export default {
0: "本系统创建",
1: "来自于B3",
};
@@ -0,0 +1,5 @@
export default {
1: "一般",
2: "紧急",
3: "加急",
};
@@ -0,0 +1,16 @@
export default {
0: "待签收",
10: "待分析",
20: "分析中",
25: "分析完成已提交",
30: "已分析待审核",
40: "分析审核通过",
50: "分析审核未通过",
60: "行动已下发待签收",
70: "行动已签收待策划",
80: "行动策划已提交",
90: "作战方案已提交",
100: "作战方案待审核",
110: "作战方案已审核",
120: "作战方案未通过",
};
@@ -0,0 +1,36 @@
<template>
<div class="AIChatExtract">
<div class="box">
AIChatExtract
</div>
</div>
</template>
<script>
export default {
data() {
return {
};
},
methods: {
},
watch: {
},
};
</script>
<style lang="less">
.AIChatExtract {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 1001;
background-color: rgba(0, 0, 0, .2);
.box {
color: #fff;
}
}
</style>
@@ -0,0 +1,702 @@
<template>
<div class="action-overview">
<t-loading :loading="loading" show-overlay>
<t-layout>
<t-aside width="568px"></t-aside>
<t-layout>
<div class="overview-head"></div>
<div class="overview-body">
<div v-if="!loading" ref="graphRef" class="graph-container"></div>
</div>
</t-layout>
<t-aside width="562px">
<div class="graph-map-content">
<div class="collapse-content collapse-content-right flex-center-center cursor-pointer"
v-if="expandRightShow" @click="expandRightChange">
<img src="@/assets/map-icon/expand-logo.svg" alt="" />
</div>
<div class="expand-content" :class="{ 'expand-hidden': expandRightShow }">
<div class="graph-map">
<div class="list-content">
<div class="expand-logo cursor-pointer" @click="expandRightChange">
<img src="../assets/map-icon/expand-logo.svg" alt="" />
</div>
<div class="list-item" v-for="(item, index) in graphList" :key="index">
<div class="item-logo">
<img :src="item.imgUrl" alt="" />
</div>
<div class="item-title">{{ item.title }}</div>
</div>
</div>
</div>
</div>
</div>
</t-aside>
</t-layout>
</t-loading>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, watch } from 'vue';
import { Graph, Quadratic, register, ExtensionCategory, Circle } from '@antv/g6'
import { requestAxiosService } from '@/service/request-axios-service';
import { deepCopy, uniqueById } from '@/common/chatData';
const props = defineProps({
msg: String,
actionData: Object,
actionId: [String, Number, Object, Boolean, Array]
})
const count = ref(0);
let graph = null;
const graphRef = ref(null);
let treeMapData = {
nodes: [],
edges: [],
}
const service = requestAxiosService;
const loading = ref(false);
import xdLogo from "@/assets/map-icon/xd-logo.svg"
import xdLogoPng from "@/assets/map-icon/xd-logo.png"
import bcLogo from "@/assets/map-icon/boci-logo.svg"
import bcLogoPng from "@/assets/map-icon/boci-logo.png"
import characterLogo from "@/assets/map-icon/character-logo.svg"
import characterLogoPng from "@/assets/map-icon/character-logo.png"
import userSpreadLogo from "@/assets/map-icon/user-spread-logo.svg"
import userSpreadLogoPng from "@/assets/map-icon/user-spread-logo.png"
import audienceLogo from "@/assets/map-icon/audience-logo.svg"
import audienceLogoPng from "@/assets/map-icon/audience-logo.png"
import strategyLogo from "@/assets/map-icon/strategy-logo.png"
const graphList = [
{ imgUrl: xdLogo, title: 'XD' },
{ imgUrl: bcLogo, title: '波次' },
{ imgUrl: characterLogo, title: '人设' },
{ imgUrl: userSpreadLogo, title: '关键传播节点' },
{ imgUrl: audienceLogo, title: '受众群体' },
// { imgUrl: `${environment['g6ImgUrl'] || '/src/assets'}/map-icon/user-logo.svg`, title: '受众目标' },
]
const expandRightShow = ref(false);
onMounted(() => {
// initGraph()
})
const expandRightChange = () => {
expandRightShow.value = !expandRightShow.value;
}
// 查询关键传播节点-未完成
const copRelationingSearch = async (actionId) => {
const parmy = {
actionId,
}
loading.value = true;
const res = await service.get(`${environment['b1ConsumerUrl']}/cop/copRelationing`, parmy);
loading.value = false;
console.log(res);
treeMapData.nodes = [];
treeMapData.edges = [];
let result = res.data;
treeMapData.nodes.push({
id: actionId,
data: {
type: 'action',
bgColor: '#cf1322',
name: '行动'
},
size: 30
});
result?.designs?.forEach((item) => {
treeMapData.nodes.push({
id: item.designId,
data: { type: 'audience', bgColor: '#1569ef', name: item.targetAudience, item: deepCopy(item) },
size: 25
});
treeMapData.edges.push({
source: actionId, target: item.designId, data: { type: 'audience', lineColor: '#23D0FF', name: item.targetAudience }
});
item.designAccount.forEach((aItem) => {
//添加受众目标
// treeMapData.nodes.push({
// id: aItem.id,
// data: { type: 'userList', bgColor: '#1eb07f', name: aItem.accountName, item: deepCopy(aItem) },
// size: 25
// });
// treeMapData.edges.push({
// source: item.designId, target: aItem.id, data: { type: 'userList', lineColor: '#8263FF', name: aItem.accountName }
// });
});
// if (item.strategy) {
// item.strategy.forEach((cItem) => {
// try {
// cItem.extendInfo = JSON.parse(cItem.extendInfo);
// console.log('策略详细信息', cItem.extendInfo)
// } catch (error) {
// console.log('error',error)
// // cItem.namme
// }
// treeMapData.nodes.push({
// id: cItem.id,
// data: { type: 'strategy', bgColor: '#ac77e8', name: cItem.topic, item: deepCopy(cItem) },
// size: 25
// });
// treeMapData.edges.push({
// source: item.designId, target: cItem.id, data: { type: 'strategy', lineColor: '#ac77e8', name: cItem.topic }
// });
// })
// }
});
result?.pathway?.forEach((item) => {
treeMapData.nodes.push({
id: item.pathwayId,
data: { type: 'userSpread', bgColor: '#1eb07f', name: item.accountName, item: deepCopy(item) },
size: 25
});
treeMapData.edges.push({
source: actionId, target: item.pathwayId, data: { type: 'userSpread', lineColor: '#B0DC00', name: item.accountName }
});
// if (item.strategy) {
// item.strategy.forEach((aItem) => {
// treeMapData.nodes.push({
// id: aItem.id,
// data: { type: 'strategy', bgColor: '#ac77e8', name: aItem.topic, item: deepCopy(aItem) },
// size: 25
// });
// treeMapData.edges.push({
// source: item.pathwayId, target: aItem.id, data: { type: 'strategy', lineColor: '#ac77e8', name: aItem.topic }
// });
// })
// }
})
// await graph.value?.clear();
setTimeout(async () => {
await initGraph();
}, 10)
}
// 查询关键传播节点关系图-已完成
const copRelationSearch = async (actionId) => {
console.log('actionData', props.actionData);
const parmy = {
actionId,
}
loading.value = true;
const res = await service.get(`${environment['b1ConsumerUrl']}/cop/copRelations`, parmy);
loading.value = false;
console.log('查询关系图', res);
let result = res.data;
treeMapData.nodes = [];
treeMapData.edges = [];
treeMapData.nodes.push({
id: actionId,
data: {
type: 'action',
bgColor: '#cf1322',
name: '行动'
},
size: 30
})
result.bocis.forEach((item) => {
treeMapData.nodes.push({
id: item.bociId,
data: { type: 'boci', bgColor: '#fff6ea', name: item.bociName, item: deepCopy(item) },
size: 25
})
treeMapData.edges.push({
source: actionId, target: item.bociId, data: { type: 'action', lineColor: '#3683FF', name: item.bociName }
})
item.strategies.forEach((aItem) => {
// treeMapData.nodes.push({
// id: aItem.strategyId,
// data: { type: 'strategy', bgColor: '#ac77e8', name: aItem.targetAudience, item: deepCopy(aItem) },
// size: 25
// })
// treeMapData.edges.push({
// source: item.bociId, target: aItem.strategyId, data: { type: 'strategy', lineColor: '#ac77e8', name: aItem.targetAudience }
// })
aItem.personas.forEach((bItem, bIndex) => {
treeMapData.nodes.push({
id: 'persona' + bIndex + bItem.persona,
data: { type: 'character', bgColor: '#fff6ea', name: bItem.persona, item: deepCopy(bItem) },
size: 25
})
treeMapData.edges.push({
source: item.bociId, target: 'persona' + bIndex + bItem.persona, data: { type: 'character', lineColor: '#8263FF', name: bItem.persona }
})
bItem.pathwayRelations.forEach((cItem) => {
treeMapData.nodes.push({
id: cItem.pathwayId,
data: { type: 'userSpread', bgColor: '#1eb07f', name: cItem.pathwayAccountName, item: deepCopy(cItem) },
size: 25
})
treeMapData.edges.push({
source: 'persona' + bIndex + bItem.persona, target: cItem.pathwayId, data: { type: 'userSpread', lineColor: '#B0DC00', name: cItem.pathwayAccountName }
})
})
bItem.designRelations.forEach((dItem) => {
treeMapData.nodes.push({
id: dItem.designId,
data: { type: 'audience', bgColor: '#1569ef', name: dItem.targetAudience, item: deepCopy(dItem) },
size: 25
})
treeMapData.edges.push({
source: 'persona' + bIndex + bItem.persona, target: dItem.designId, data: { type: 'audience', lineColor: '#23D0FF', name: dItem.targetAudience }
})
})
})
})
});
treeMapData.nodes = uniqueById(treeMapData.nodes)
console.log('查询关系处理', treeMapData);
// await graph.value?.clear();
setTimeout(async () => {
await initGraph();
}, 10)
}
watch(() => props.actionData, (newVal, oldVal) => {
console.log('count changed from-------------', oldVal, 'to', newVal);
if (newVal) {
if (newVal.actionStatus === 25) {
copRelationSearch(newVal.id);
} else if (newVal.actionStatus === 20) {
copRelationingSearch(newVal.id)
}
}
}, { immediate: true });
// 渲染关系图
const initGraph = () => {
console.log('environment', environment)
// 自定义边
class AntLine extends Quadratic {
onCreate() {
const shape = this.shapeMap.key;
shape.animate([{ lineDashOffset: 20 }, { lineDashOffset: 0 }], { // 添加动画
duration: 500,
iterations: Infinity,
})
}
}
register(ExtensionCategory.EDGE, 'ant-line', AntLine);
// 定义自定义节点
class CustomImageCircleNode extends Circle {
render(attributes = this.parsedAttributes, container) {
super.render(attributes, container); // 渲染圆形节点
const [width, height] = this.getSize(attributes);
// 获取节点数据中的图片源
const { type, platform } = attributes;
// console.log('attributes', attributes);
// 如果有图片源,则添加图片元素
if (type === 'action') { // 当节点类型为行动
// console.log('imgUrl', imgUrl, width);
this.upsert(
'node-image',
'image',
{
x: -width / 2, // 图片的x坐标,使其居中
y: -height / 2, // 图片的y坐标,使其居中
width: width, // 图片宽度略小于圆形节点
height: height, // 图片高度略小于圆形节点
src: xdLogoPng,
},
container
);
this.upsert('subtitle', 'text', {
x: 0,
y: 0, // 节点中心
text: '行动',
fontSize: 16,
fill: '#fff',
textAlign: 'center',
textBaseline: 'middle',
fontWeight: 'bold' // 设置字体加粗
}, container)
} else if (type === 'boci') { // 节点类型为波次
// this.upsert(
// 'node-circle',
// 'rect',
// {
// x: -width / 2, // 图片的x坐标,使其居中
// y: -height / 2, // 图片的y坐标,使其居中
// width: width - 2, // 图片宽度略小于圆形节点
// height: height - 2, // 图片高度略小于圆形节点
// fill: 'transparent',
// stroke: '#fc5',
// lineWidth: 5,
// radius: 50,
// labelBackground: true,
// },
// container
// );
this.upsert(
'node-image',
'image',
{
x: -width / 2, // 图片的x坐标,使其居中
y: -height / 2, // 图片的y坐标,使其居中
width: width, // 图片宽度略小于圆形节点
height: height, // 图片高度略小于圆形节点
src: bcLogoPng,
},
container
);
this.upsert('subtitle', 'text', {
x: 10,
y: 0, // 节点中心
text: '波次',
fontSize: 16,
fill: '#fff',
textAlign: 'center',
textBaseline: 'middle',
fontWeight: 'bold' // 设置字体加粗
}, container)
} else if (type === 'character') { // 节点类型为人设
this.upsert(
'node-image',
'image',
{
x: -width / 2, // 图片的x坐标,使其居中
y: -height / 2, // 图片的y坐标,使其居中
width: width, // 图片宽度略小于圆形节点
height: height, // 图片高度略小于圆形节点
src: characterLogoPng,
},
container
);
} else if (type === 'userSpread') { // 节点类型为关键传播节点
this.upsert(
'node-image',
'image',
{
x: -width / 2, // 图片的x坐标,使其居中
y: -height / 2, // 图片的y坐标,使其居中
width: width, // 图片宽度略小于圆形节点
height: height, // 图片高度略小于圆形节点
src: userSpreadLogoPng,
},
container
);
} else if (type === 'audience') { // 节点类型为受众群体
this.upsert(
'node-image',
'image',
{
x: -width / 2, // 图片的x坐标,使其居中
y: -height / 2, // 图片的y坐标,使其居中
width: width, // 图片宽度略小于圆形节点
height: height, // 图片高度略小于圆形节点
src: audienceLogoPng,
},
container
);
} else if (type === 'userList') { // 节点类型为受众目标
this.upsert(
'node-image',
'image',
{
x: -width / 2, // 图片的x坐标,使其居中
y: -height / 2, // 图片的y坐标,使其居中
width: width, // 图片宽度略小于圆形节点
height: height, // 图片高度略小于圆形节点
src: userSpreadLogoPng,
},
container
);
} else if (type === 'strategy') {
this.upsert(
'node-image',
'image',
{
x: -width / 2, // 图片的x坐标,使其居中
y: -height / 2, // 图片的y坐标,使其居中
width: width, // 图片宽度略小于圆形节点
height: height, // 图片高度略小于圆形节点
src: strategyLogo,
},
container
);
}
}
}
// 2. 注册自定义节点
register(ExtensionCategory.NODE, 'custom-image-circle', CustomImageCircleNode);
const data = {
nodes: [
{ id: 'node1', data: { type: 'action', bgColor: '#cf1322', name: '行动1' }, size: 30 },
{ id: 'node2', data: { type: 'boci', bgColor: '#fff6ea', name: '波次1' }, size: 25 },
{ id: 'node3', data: { type: 'boci', bgColor: '#fff6ea', name: '波次2' }, size: 25 },
{ id: 'node4', data: { type: 'boci', bgColor: '#fff6ea', name: '波次3' }, size: 25 },
{ id: 'node5', data: { type: 'character', bgColor: '#fff6ea', name: '人设01' }, size: 25 },
{ id: 'node6', data: { type: 'character', bgColor: '#fff6ea', name: '人设02' }, size: 20 },
{ id: 'node7', data: { type: 'character', bgColor: '#fff6ea', name: '人设03' }, size: 25 },
{ id: 'node8', data: { type: 'character', bgColor: '#fff6ea', name: '人设04' }, size: 20 },
{ id: 'node9', data: { type: 'character', lineColor: '#fff6ea', name: '人设05' }, size: 25 },
{ id: 'node10', data: { type: 'character', bgColor: '#fff6ea', name: '人设06' }, size: 20 },
{ id: 'node11', data: { type: 'userSpread', platform: 'facebook', bgColor: '#1eb07f', name: '关键传播节点01' }, size: 20 },
{ id: 'node12', data: { type: 'userSpread', platform: 'facebook', bgColor: '#1eb07f', name: '关键传播节点01' }, size: 20 },
{ id: 'node13', data: { type: 'userSpread', platform: 'facebook', bgColor: '#1eb07f', name: '关键传播节点01' }, size: 20 },
{ id: 'node14', data: { type: 'userSpread', platform: 'facebook', bgColor: '#1eb07f', name: '关键传播节点01' }, size: 20 },
{ id: 'node15', data: { type: 'userSpread', platform: 'facebook', bgColor: '#1eb07f', name: '关键传播节点01' }, size: 20 },
{ id: 'node16', data: { type: 'userSpread', platform: 'facebook', bgColor: '#1eb07f', name: '关键传播节点01' }, size: 20 },
{ id: 'node17', data: { type: 'userSpread', platform: 'facebook', bgColor: '#1eb07f', name: '关键传播节点01' }, size: 20 },
{ id: 'node18', data: { type: 'audience', platform: 'facebook', bgColor: '#1569ef', name: '关键传播节点01' }, size: 20 },
{ id: 'node19', data: { type: 'audience', platform: 'facebook', bgColor: '#1569ef', name: '关键传播节点01' }, size: 20 },
{ id: 'node20', data: { type: 'audience', platform: 'facebook', bgColor: '#1569ef', name: '关键传播节点01' }, size: 20 },
{ id: 'node21', data: { type: 'audience', platform: 'facebook', bgColor: '#1569ef', name: '关键传播节点01' }, size: 20 },
{ id: 'node22', data: { type: 'audience', platform: 'facebook', bgColor: '#1569ef', name: '关键传播节点01' }, size: 20 },
{ id: 'node23', data: { type: 'audience', platform: 'facebook', bgColor: '#1569ef', name: '关键传播节点01' }, size: 20 },
{ id: 'node24', data: { type: 'audience', platform: 'facebook', bgColor: '#1569ef', name: '关键传播节点01' }, size: 20 },
],
edges: [
{ source: 'node1', target: 'node2', data: { type: 'action', lineColor: '#cf1322', name: '行动1' } },
{ source: 'node2', target: 'node5', data: { type: 'boci', lineColor: '#dd8717', name: '波次1' } },
{ source: 'node5', target: 'node11', data: { type: 'character', lineColor: '#fff6ea', name: '人设01' } },
{ source: 'node11', target: 'node18', data: { type: 'userSpread', platform: 'facebook', lineColor: '#1eb07f', name: '关键传播节点01' } },
{ source: 'node2', target: 'node6', data: { type: 'audience', platform: 'facebook', lineColor: '#1569ef', name: '关键传播节点01' } },
{ source: 'node6', target: 'node12', data: { type: 'character', lineColor: '#fff6ea', name: '人设01' } },
{ source: 'node12', target: 'node19', data: { type: 'userSpread', platform: 'facebook', lineColor: '#1eb07f', name: '关键传播节点01' } },
{ source: 'node1', target: 'node3', data: { type: 'action', lineColor: '#cf1322', name: '行动1' } },
{ source: 'node3', target: 'node7', data: { type: 'boci', lineColor: '#dd8717', name: '波次1' } },
{ source: 'node7', target: 'node13', data: { type: 'character', lineColor: '#fff6ea', name: '人设01' } },
{ source: 'node13', target: 'node20', data: { type: 'userSpread', platform: 'facebook', lineColor: '#1eb07f', name: '关键传播节点01' } },
{ source: 'node3', target: 'node8', data: { type: 'audience', platform: 'facebook', lineColor: '#1569ef', name: '关键传播节点01' } },
{ source: 'node8', target: 'node14', data: { type: 'character', lineColor: '#fff6ea', name: '人设01' } },
{ source: 'node14', target: 'node21', data: { type: 'userSpread', platform: 'facebook', lineColor: '#1eb07f', name: '关键传播节点01' } },
{ source: 'node1', target: 'node4', data: { type: 'action', lineColor: '#cf1322', name: '行动1' } },
{ source: 'node4', target: 'node9', data: { type: 'boci', lineColor: '#dd8717', name: '波次1' } },
{ source: 'node9', target: 'node15', data: { type: 'character', lineColor: '#fff6ea', name: '人设01' } },
{ source: 'node15', target: 'node22', data: { type: 'userSpread', platform: 'facebook', lineColor: '#1eb07f', name: '关键传播节点01' } },
{ source: 'node4', target: 'node10', data: { type: 'audience', platform: 'facebook', lineColor: '#1569ef', name: '关键传播节点01' } },
{ source: 'node10', target: 'node16', data: { type: 'character', lineColor: '#fff6ea', name: '人设01' } },
{ source: 'node16', target: 'node23', data: { type: 'userSpread', platform: 'facebook', lineColor: '#1eb07f', name: '关键传播节点01' } },
{ source: 'node10', target: 'node17', data: { type: 'character', lineColor: '#fff6ea', name: '人设01' } },
{ source: 'node17', target: 'node24', data: { type: 'audience', platform: 'facebook', lineColor: '#1569ef', name: '关键传播节点01' } },
]
}
// const size = (node) => Math.max(...node.style.size);
graph = new Graph({
container: graphRef.value,
// width: 800,
// height: 600,
data: treeMapData,
modes: {
default: ['drag-canvas', 'zoom-canvas', 'drag-node']
},
node: {
type: 'custom-image-circle', // 使用自定义节点类型
style: {
label: true,
labelText: (d) => d.data?.name,
labelFill: '#fff',
labelBackground: false,
// fill: (d) => d.data.bgColor || '#fc5',
fill: 'transparent',
type: (d) => d.data.type,
platform: (d) => d.data.platform,
size: (d) => {
if (d.data.type === 'action') {
return [120, 60]
} else if (d.data.type === 'boci') {
return [130, 40]
} else {
return [60, 70]
}
}
}
},
edge: {
type: 'ant-line',
style: {
label: false,
// labelText: (d) => d.data?.type,
labelBackground: true,
stroke: (d) => d.data?.lineColor || '#fc5', // 边的颜色,可以根据需要调整
lineWidth: 2.5, // 边的宽度,可以根据需要调整
lineDash: [10, 10],
endArrow: true, // 添加箭头
arrowSize: 6, // 箭头大小
},
},
layout: {
// type: 'radial',
// unitRadius: 220,
// linkDistance: 200,
// type: 'd3-force',
// link: 200,
// // collide: { radius: (node) => size(node) },
// // manyBody: { strength: (node) => -4 * size(node) }
animation: false,
// preventOverlap: true
type: 'd3-force',
preventOverlap: true,
nodeSize: 100,
link: {
distance: 200,
strength: 2
},
collide: { radius: 100 },
manyBody: {
strangth: (d) => {
if (d.isLeaf) {
return -50;
}
return -10;
}
}
},
autoFit: 'view',
behaviors: ['drag-canvas', 'drag-element', 'zoom-canvas',]
})
graph.render();
graph.on('node:click', (event) => {
const nodeItem = event.item; // 节点实例
console.log(event.target.id);
const model = graph.getNodeData(event.target.id);
console.log('节点数据:', model.data);
// const model = nodeItem.getModel(); // 数据模型
// console.log('点击了节点:', model.id);
});
// window.addPanel((gui) => {
// const config = {
// lineDash: 10,
// }
// gui.add(config,'lineDash',1,20,1).onChange((lineDash) => {
// graph.setEdge({
// type: 'ant-line',
// style: {
// lineDash: [lineDash,lineDash]
// }
// })
// })
// graph.draw()
// })
}
</script>
<style scoped lang="less">
.action-overview {
z-index: 500;
color: #fff;
position: relative;
.overview-head {
width: 100%;
height: 115px;
}
.overview-body {
// width: 100%;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: calc(100vh - 115px);
.graph-container {
width: 100%;
height: 100%;
}
}
.graph-map-content {
z-index: 500;
position: fixed;
bottom: 100px;
right: 20px;
.graph-map {
width: 202px;
background: rgba(3, 38, 80, 0.8);
border: 1px solid;
border-color: rgba(43, 143, 254, 0.6);
z-index: 500;
border-radius: 4px;
padding: 10px 15px;
padding-top: 30px;
.list-content {
position: relative;
.expand-logo {
width: 20px;
height: 11px;
position: absolute;
top: -27px;
right: -8px;
img {
width: 100%;
}
}
.list-item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
.item-logo {
width: 62px;
height: 28px;
img {
height: 28px;
}
}
.item-title {
flex: 1;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: 18px;
}
}
}
}
}
.collapse-content {
width: 30px;
height: 40px;
background: #032650cc;
border: 1px solid;
border-color: #2b8ffe99;
border-radius: 4px 0 0 4px;
z-index: 500;
position: absolute;
top: 0;
img {
width: 16px;
}
}
.collapse-content-right {
right: 0;
}
.expand-hidden {
width: 0px !important;
border: 0px !important;
overflow: hidden;
}
.expand-content {
width: 100%;
transition: all 0.5s ease;
float: right;
}
.expand-content-right {
float: right;
}
}
</style>
@@ -0,0 +1,448 @@
<template>
<div class="action-planning">
<!-- 任务详情 -->
<div class="task-details" v-if="flag">
<div class="task-title">
{{ taskData.taskName }}
</div>
<div class="task-content">
<span class="item-label">任务时间:</span>
<span class="item-value">{{
dayjs(taskData.createTime).format("YYYY-MM-DD HH:mm:ss")
}}</span>
<span class="item-tab tab-yellow" style="margin-left: 10px">{{
taskLevel[taskData.taskLevel]
}}</span>
</div>
<div class="task-footer" :class="{ 'text-ellipsis ellipsis3': !allShow }">
<span class="item-label">任务简介:</span> {{ taskData.overview }}
</div>
<div class="allShow" @click="allShow = !allShow">
{{ allShow ? "收起" : "查看全文" }}
</div>
</div>
<!-- 任务行动 -->
<div class="title-content-item margin-bottom-10">任务行动</div>
<div class="action-content">
<div class="action-list">
<div
class="list-item"
:class="{ 'item-active': item.id === actionId }"
v-for="(item, index) in actionList"
:key="index"
@click="actionDataChange(item)"
>
<div :class="'action-status-logo ' + handleBg(item.actionStatus)">
{{ actionStatus[item.actionStatus] }}
</div>
<!-- <div class="item-title">
{{ item.title }}
</div> -->
<div class="item-content text-ellipsis ellipsis2">
{{ item.actionName }}
</div>
<div class="item-footer">
<span class="item-label">行动时间:</span>
<span class="item-value">{{
dayjs(item.createTime).format("YYYY-MM-DD HH:mm:ss")
}}</span>
</div>
</div>
</div>
</div>
<t-dialog
v-model:visible="visible"
header="行动详情"
width="700"
:confirm-on-enter="true"
:on-cancel="handleCancel"
:on-close="handleCancel"
:on-confirm="handleOk"
>
<t-space direction="vertical" style="width: 100%">
<div class="action-details">
<div class="item-head">桃色与军纪舆论裂变攻台军形象</div>
<div class="item-card">
支撑性目的:利用桃色新闻与军纪涣散议题,瓦解台军社会形象与民众支持基础,引发线上网红、大V等对台军……
</div>
<!-- 顶部标签页 -->
<TabsContent
:tabIndex="tabIndex"
:tabsList="tabsList"
:tabStyle="{
textAlign: 'left',
borderBottom: '1px solid rgba(0, 98, 217, 0.4)',
}"
@tabsDataC="tabDataChange"
/>
<div class="narrate-list" v-if="tabIndex === 'narrate'">
<div
class="item-card"
v-for="(item, index) in narrateList"
:key="index"
>
<span class="item-index">{{ index + 1 }}</span
>. {{ item.title }}
</div>
</div>
<div class="behavior-list">
<div
class="item-card"
v-for="(item, index) in behaviorList"
:key="index"
>
<div class="item-title">行为体:{{ item.actor }}</div>
<div class="item-content">预期行为:{{ item.behavior }}</div>
</div>
</div>
</div>
</t-space>
</t-dialog>
</div>
</template>
<script setup>
import { ref, reactive, watch, onUnmounted } from "vue";
import TabsContent from "./views/TabsContent.vue";
import taskStatus from "@/common/taskStatus";
import taskLevel from "@/common/taskLevel";
import sourceTypeDict from "@/common/sourceType";
import actionStatus from "@/common/actionStatus";
import dayjs from "dayjs";
import { requestAxiosService } from "@/service/request-axios-service";
import { useStore } from "vuex";
const flag = ref(false);
const props = defineProps({
msg: String,
taskData: Object,
});
const allShow = ref(false);
const actionList = ref([
{
title: "行动01",
content: "军购透明化对比民生缺口,激青年声讨",
actionStatus: "CEH完成",
actionLogo: "action-completed",
},
{
title: "行动01",
content: "军购透明化对比民生缺口,激青年声讨",
actionStatus: "CEH中",
actionLogo: "action-uncompleted",
},
{
title: "行动01",
content: "军购透明化对比民生缺口,激青年声讨",
actionStatus: "待分析",
actionLogo: "action-pendinganalysis",
},
{
title: "行动01",
content: "军购透明化对比民生缺口,激青年声讨",
actionStatus: "已终止",
actionLogo: "action-failed",
},
{
title: "行动01",
content: "军购透明化对比民生缺口,激青年声讨",
actionStatus: "CEH完成",
actionLogo: "action-completed",
},
]); // 行动列表
const visible = ref(false); // 对话框
const tabIndex = ref("narrate"); // narrate 叙事主题 behavior 预期行为
const tabsList = ref([
{ label: "叙事主题", value: "narrate" },
{ label: "预期行为", value: "behavior" },
]);
const narrateList = ref([
{ title: "台军桃色丑闻频发暴露军纪涣散" },
{ title: "飞行事故频发揭穿台军装备老旧与训练造假" },
]);
const behaviorList = ref([
{
actor: "台军各军种单位",
behavior:
"通过社交媒体或媒体渠道揭露上级贪腐、性丑闻等(如陆军109旅贩毒案后内部爆料)",
},
]);
const actionId = ref(null);
const service = requestAxiosService;
// 获取 Vuex store
const store = useStore();
const emit = defineEmits(["actionDataC"]); // 定义子组件发送给父组件的函数
const actionShowChange = (item) => {
// visible.value = true;
};
const handleOk = () => {
visible.value = false;
};
const handleCancel = () => {
visible.value = false;
};
// 接收tabs页切换
const tabDataChange = (value) => {
tabIndex.value = value;
console.log("tabs", tabIndex.value);
};
const handleBg = (d) => {
const colorList = {
10: "action-pendinganalysis",
20: "action-uncompleted",
25: "action-completed",
23: "action-failed",
};
return colorList[d] || "action-completed";
};
// 查询行动略表
const taskActionSearch = async (taskId) => {
const parmy = {
taskId,
};
const res = await service.get(
`${environment["b1ConsumerUrl"]}/cop/copTaskActions`,
parmy
);
console.log("查询行动列表", res);
let result = res.data;
actionList.value = result.actions;
};
// 查询行动概览
const actionSummarySearch = async () => {
const parmy = {
actionId: actionId.value,
};
const res = await service.get(
`${environment["b1ConsumerUrl"]}/cop/copActionSummary`,
parmy
);
console.log("行动概览", res);
let result = res.data;
store.commit("setActionOverview", result);
};
// cop/queryOverview
const queryOverview = async () => {
const res = await service.get(
`${environment["b1ConsumerUrl"]}/cop/queryOverview`,
""
);
console.log("概览", res);
};
const actionDataChange = async (item) => {
console.log(item);
actionId.value = item.id;
store.commit("setActionOverview", null);
if (item.actionStatus === 25) {
await actionSummarySearch();
}
emit("actionDataC", item);
};
onUnmounted(() => {
store.commit("setActionOverview", null);
});
watch(
props.taskData,
(newVal, oldVal) => {
// console.log('count changed from', oldVal, 'to', newVal);
if (newVal) {
queryOverview();
taskActionSearch(newVal.id);
}
},
{ immediate: true }
);
</script>
<style scoped lang="less">
.action-planning {
z-index: 500;
color: #fff;
padding: 10px;
box-sizing: border-box;
// 任务详情样式
.task-details {
padding: 10px;
.task-title {
font-size: 20px;
font-weight: 500;
font-family: "Noto Sans S Chinese";
}
.task-content {
margin: 5px 0;
font-family: "Noto Sans S Chinese";
}
.task-footer {
font-family: "Noto Sans S Chinese";
}
}
// 行动列表样式
.action-content {
.action-list {
.list-item {
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
padding: 10px;
margin-bottom: 15px;
position: relative;
cursor: pointer;
overflow: hidden;
&:hover {
background: rgba(0, 98, 217, 0.4);
border-color: #0062d9;
}
.item-title {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #ffffff;
font-size: var(--titleSize);
margin-bottom: 5px;
}
.item-content {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSize);
margin-bottom: 5px;
}
.item-footer {
font-family: Noto Sans S Chinese;
font-weight: 300;
color: rgba(255, 255, 255, 0.8);
font-size: 15px;
}
.action-status-logo {
width: 132px;
height: 30px;
transform: rotate(45deg);
position: absolute;
top: 12px;
text-align: center;
line-height: 30px;
right: -36px;
}
.action-completed {
background: linear-gradient(
134.57deg,
#05b89f 14.74%,
#007f73 84.95%
);
}
.action-uncompleted {
background: linear-gradient(
134.57deg,
#d09a14 14.74%,
#a76e12 84.95%
);
}
.action-pendinganalysis {
background: linear-gradient(
134.57deg,
#117dff 14.74%,
#0057b8 84.95%
);
}
.action-failed {
background: linear-gradient(
134.57deg,
#838383 14.74%,
#5e5e5e 84.95%
);
}
}
.item-active {
background: rgba(0, 98, 217, 0.4);
border-color: #0062d9;
}
}
}
.item-label {
font-family: "Noto Sans S Chinese";
font-size: 15px;
margin-right: 5px;
}
.item-value {
font-family: "DDIN";
}
.item-tab {
font-size: var(--fontSizes);
font-family: "Noto Sans S Chinese";
padding: 2px 10px;
border: 1px solid;
border-radius: 4px;
}
}
// 详情弹窗页面
.action-details {
.item-head {
font-size: var(--fontSize);
font-family: "Noto Sans S Chinese";
padding: 10px;
}
.item-card {
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
padding: 10px;
margin-top: 10px;
margin-bottom: 15px;
.item-index {
font-family: "Noto Sans S Chinese";
font-weight: 500;
}
.item-title {
// font-size: var(--fontSize);
font-family: "Noto Sans S Chinese";
// font-weight: 500;
margin-bottom: 5px;
}
}
}
.allShow {
margin-top: 10px;
max-width: 100px;
padding: 5px;
border-radius: 3px;
cursor: pointer;
line-height: 20px;
border: 1px solid #2b8ffe99 !important;
text-align: center;
}
</style>
@@ -0,0 +1,242 @@
<template>
<div class="performance-evaluation">
<!-- 六度量样式 -->
<div class="six-metrics">
<t-row :gutter="16">
<t-col :span="4">
<div class="item-left">
<div class="metrices-item item-completed" style="margin-left: 50px;">
<div class="item-value">
108<i>个</i>
</div>
<div class="item-label">
大V转发
</div>
</div>
<div class="metrices-item item-completed" style="margin-left: 10px;">
<div class="item-value">
387<i>家</i>
</div>
<div class="item-label">
媒体报道
</div>
</div>
<div class="metrices-item item-completed" style="margin-left: 50px;">
<div class="item-value">
16<i>个</i>
</div>
<div class="item-label">
传播平台
</div>
</div>
</div>
</t-col>
<t-col :span="3">
<div class="item-center">
<div class="level-content">
<div class="metrices-item item-center-bg">
<div class="level-text">
五级
</div>
<div class="level-list">
<span class="list-item" v-for="(item, index) in levelList" :class="{ 'item-active': item.checked }"
:key="index">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" style="">
<path fill="currentColor"
d="M313.6 924.48a70.4 70.4 0 0 1-74.152-5.365 70.4 70.4 0 0 1-27.992-68.875l37.888-220.928L88.96 472.96a70.4 70.4 0 0 1 3.788-104.225A70.4 70.4 0 0 1 128 352.896l221.76-32.256 99.2-200.96a70.4 70.4 0 0 1 100.246-28.595 70.4 70.4 0 0 1 25.962 28.595l99.2 200.96 221.824 32.256a70.4 70.4 0 0 1 39.04 120.064L774.72 629.376l37.888 220.928a70.4 70.4 0 0 1-102.144 74.24L512 820.096l-198.4 104.32z">
</path>
</svg>
</span>
</div>
<div class="item-label">
评估等级
</div>
</div>
</div>
</div>
</t-col>
<t-col :span="5">
<div class="item-right">
<div class="metrices-item item-incomplete">
<div class="item-value">
0<i>个</i>
</div>
<div class="item-label">
线下活动
</div>
</div>
<div class="metrices-item item-completed" style="margin-left: 50px;">
<div class="item-value">
6<i>个</i>
</div>
<div class="item-label">
官方回应
</div>
</div>
<div class="metrices-item item-completed">
<div class="item-value">
5<i>个</i>
</div>
<div class="item-label" style="padding-left: 5px;">
关键节点
</div>
</div>
</div>
</t-col>
</t-row>
</div>
<!-- tab标签页 -->
<TabsContent :tabIndex="tabIndex" :tabsList="tabsList" @taskDetailsC="taskDetailsChange"/>
</div>
</template>
<script setup>
import { ref } from 'vue';
import TabsContent from '../views/TabsContent.vue';
defineProps({
msg: String,
})
const levelList = ref([
{ title: 1, checked: true },
{ title: 1, checked: true },
{ title: 1, checked: true },
{ title: 1, checked: true },
{ title: 1, checked: true },
{ title: 1, checked: false },
])
const tabIndex = ref('cognition'); // cognition 认知影响 spread 传播效果 action 行动脉络
const tabsList = ref([
{ label: '认知影响', value: 'cognition' },
{ label: '传播效果', value: 'spread' },
{ label: '行动脉络', value: 'action' },
])
// 标签页切换
const taskDetailsChange = (value) => {
tabIndex.value = value;
}
</script>
<style scoped lang="less">
.performance-evaluation {
z-index: 500;
color: #fff;
padding: 10px;
.six-metrics {
width: 100%;
padding-top: 15px;
margin-bottom: 25px;
.item-left {
width: 100%;
height: 100%;
}
.item-center {
width: 100%;
height: 100%;
position: relative;
.level-content {
padding-left: 15px;
position: absolute;
top: 50px;
left: 50%;
transform: translateX(-50%);
}
}
.item-right {
width: 100%;
height: 100%;
}
.metrices-item {
width: 100px;
height: 62px;
padding-top: 7px;
text-align: center;
}
.item-value {
color: #01e1e9;
font-size: var(--titleSize);
font-family: 'DDINBold';
font-weight: 700;
line-height: var(--fontSize);
i {
font-size: 12px;
font-style: normal;
color: #fff;
font-weight: 300;
margin-left: 5px;
}
}
.item-label {
font-family: Noto Sans S Chinese;
}
.level-text {
font-size: 24px;
font-family: Noto Sans S Chinese;
font-weight: 700;
padding-top: 5px;
animation: levelBreath 2s ease-in-out infinite;
}
.level-list {
width: 120px;
margin-top: 25px;
.list-item {
svg {
width: 20px;
color: #05727a;
}
}
.item-active {
svg {
color: #00ffff !important;
}
}
}
.item-completed {
background: url('../../assets/icon/tj-blue.png') no-repeat;
background-size: cover;
}
.item-incomplete {
background: url('../../assets/icon/tj-grey.png') no-repeat;
background-size: cover;
}
.item-center-bg {
background: url('../../assets/icon/cen-top.png') no-repeat;
background-size: cover;
}
}
}
// 级别动画
@keyframes levelBreath {
0% {
text-shadow: 0 0 0 #f90;
}
50% {
text-shadow: 0 0 25px #f90;
}
100% {
text-shadow: 0 0 0 #f90;
}
}
</style>
@@ -0,0 +1,43 @@
<script setup>
import { ref } from 'vue'
defineProps({
msg: String,
})
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p>
Learn more about IDE Support for Vue in the
<a
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
target="_blank"
>Vue Docs Scaling up Guide</a
>.
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>
@@ -0,0 +1,549 @@
<template>
<!-- @click="getChatInfo()" -->
<div class="frame">
<div class="opentiong">
<div class="isShowBtn" @click="getChatInfo()">
<img src="@/assets/icon/刷新.svg" alt="" />
</div>
<div class="isShowBtn" @click="quanpingModel = !quanpingModel">
<img src="@/assets/icon/流式输出.svg" alt="" />
</div>
<div class="isShowBtn" @click="isShow = !isShow">
<img src="@/assets/map-icon/expand-logo.svg" alt="" />
</div>
</div>
<div class="huakuai" v-if="isShow" @mousedown.prevent="startSplitting" @mouseup.prevent="endSplitting">
</div>
<div class="InfoChatView" ref="chatList"
:style="isShow ? { width: currentWidth + 'px' } : { width: '0px', border: 'none' }">
<t-collapse :default-value="[1]" @change="handlePanelChange" default-expand-all>
<t-collapse-panel header="思考过程"> <t-collapse default-expand-all>
<template v-for="(item, index) in chatList">
<t-collapse-panel header="思考过程" v-if="item.type === 'show_text'">
<CodeData :markdown="item.text"></CodeData>
</t-collapse-panel>
<t-collapse-panel header="分析报告" v-if="item.type === 'summary'">
<CodeData :markdown="item.text"></CodeData>
</t-collapse-panel>
<template v-if="item.type === 'google_search' && item.data['q']">
<div class="search" v-if="index === chatList.length - 1">
<t-loading text="搜索中..." size="small"></t-loading>{{
item.data['q'] }}
</div>
</template>
<t-collapse-panel :header="chatList[index - 1].data['q'] || '思考过程'"
v-if="item.type === 'google_search' && item.data['result']">
<div class="resultList">
<div class="item" @click="openDetails(item)"
v-for="(item, i) in JSON.parse(item.data['result']).organic">
<div class="eventTitle text-ellipsis ellipsis1">
<span class="num"> {{ i + 1 }} </span> {{ item.title }}
</div>
<div class="eventContent text-ellipsis ellipsis3">
{{ item.content }}
</div>
</div>
</div>
</t-collapse-panel>
</template>
</t-collapse></t-collapse-panel>
</t-collapse>
<div class="summary">
<CodeData :markdown="summary"></CodeData>
</div>
<t-loading v-if="loading" :loading="loading" show-overlay></t-loading>
</div>
</div>
<t-dialog v-model:visible="detailModel" header="详情" :zIndex="2000" width="1000" :footer='false'>
<t-space direction=" vertical" style="width: 100%">
<div class="detailModel">
<div class="title">
{{ detailData.title }}
</div>
<!-- <a class="link" target="_blank"> 原文链接</a> -->
<t-link hover="color"
:href="'http://chlib.b.uat.4.cn/knowlibrary/#/knowledge/mid-detail?recUuid=' + detailData.recUuid"
target="_blank">
<template #suffix-icon>
<jump-icon />
</template>
跳转链接
</t-link>
<div class="content">
<CodeData :markdown="detailData.content" />
</div>
</div>
</t-space>
</t-dialog>
<t-dialog v-model:visible="quanpingModel" header="详情" width="1600" :footer='false'>
<t-space direction=" vertical" style="width: 100%">
<div style="display: flex;flex-direction: column;gap: 10px;">
<t-collapse :default-value="[1]" @change="handlePanelChange" default-expand-all>
<t-collapse-panel header="思考过程"> <t-collapse default-expand-all>
<template v-for="(item, index) in chatList">
<t-collapse-panel header="思考过程" v-if="item.type === 'show_text'">
<CodeData :markdown="item.text"></CodeData>
</t-collapse-panel>
<t-collapse-panel header="分析报告" v-if="item.type === 'summary'">
<CodeData :markdown="item.text"></CodeData>
</t-collapse-panel>
<template v-if="item.type === 'google_search' && item.data['q']">
<div class="search" v-if="index === chatList.length - 1">
<t-loading text="搜索中..." size="small"></t-loading>{{
item.data['q'] }}
</div>
</template>
<t-collapse-panel :header="chatList[index - 1].data['q'] || '思考过程'"
v-if="item.type === 'google_search' && item.data['result']">
<div class="resultList">
<div class="item" @click="openDetails(item)"
v-for="(item, i) in JSON.parse(item.data['result']).organic">
<div class="eventTitle text-ellipsis ellipsis1">
<span class="num"> {{ i + 1 }} </span> {{ item.title }}
</div>
<div class="eventContent text-ellipsis ellipsis3">
{{ item.content }}
</div>
</div>
</div>
</t-collapse-panel>
</template>
</t-collapse></t-collapse-panel>
</t-collapse>
<div class="summary">
<CodeData :markdown="summary"></CodeData>
</div>
<t-loading v-if="loading" :loading="loading" show-overlay></t-loading>
</div>
</t-space>
</t-dialog>
</template>
<script>
import { requestAxiosService } from "@/service/request-axios-service"; // 引入发送异步请求方法
import CodeData from '../markdown/CodeData.vue'
import { MessagePlugin } from 'tdesign-vue-next';
import { LinkIcon, JumpIcon } from 'tdesign-icons-vue-next';
export default {
data() {
return {
rawData: [],
chatList: [],
quanpingModel: false,
loading: false,
isShow: true,
service: requestAxiosService,
abortController: null,
MessagePlugin: MessagePlugin,
isResizing: false,
currentWidth: 320,
startX: 0, //开始的X坐标
startWidth: 0, //开始的宽度
detailModel: false,
detailData: {},
summary: '', //总结
};
},
props: ['prompt', 'generate', 'taskId', 'taskChatList', 'taskSummary'],
components: { CodeData, JumpIcon },
computed: {
},
methods: {
openDetails(d) {
console.log(d);
this.detailData = d
this.detailModel = true
},
startSplitting(e) {
this.isResizing = true
this.startX = e.pageX;
this.startWidth = this.currentWidth
console.log(document);
document.addEventListener('mousemove', this.handleMouseMove);
document.addEventListener('mouseup', this.endResizing);
},
handleMouseMove(e) {
if (!this.isResizing) return;
const deltaX = this.startX - e.pageX;
const newWidth = this.startWidth + deltaX;
// 设置宽度限制
const minWidth = 320;
const maxWidth = 800;
this.currentWidth = Math.max(minWidth, Math.min(newWidth, maxWidth));
console.log(this.currentWidth);
},
endResizing() {
this.isResizing = false;
document.removeEventListener('mousemove', this.handleMouseMove);
document.removeEventListener('mouseup', this.endResizing);
},
dataHandl() {
console.log(this.rawData);
console.log(this.chatList);
this.service
.post(
`${environment["b1ConsumerUrl"]}/cop/batchEnemyElement`,
{
"data": [JSON.stringify(this.chatList), this.summary, ...this.rawData],
"taskId": this.taskId,
}
)
.then((res) => {
console.log("热点事件", res);
this.$emit('upDataInfo')
});
},
async getChatInfo() {
if (this.loading) {
this.MessagePlugin.warning('正在生成中,请稍后!')
return
}
this.loading = true
this.chatList = []
this.summary = ''
this.abortController = new AbortController();
try {
const response = await fetch(`https://ch1.b.uat.4.cn/qq_b1_chat/generate_qq`, {
// const response = await fetch(`http://localhost:8095/generate_qq`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
prompt: this.prompt
}),
// signal: this.abortController.signal
});
// console.log(response);
if (!response.ok) {
const errorData = await response.json().catch(() => ({ detail: 'Unknown error' }));
throw new Error(errorData.detail || `HTTP error ${response.status}`);
}
if (!response.body) {
throw new Error('Response body is null');
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
console.log(done, value);
if (done) {
this.loading = false
this.dataHandl()
break;
}
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
const lastLine = lines.pop();
buffer = lastLine || '';
console.log(lines);
for (let line of lines) {
if (!line.startsWith('data: ')) continue;
this.rawData.push(line.slice(6))
try {
// 解析SSE数据
// line = line.replace(/'/g, '"').trim();
const parsedData = JSON.parse(line.slice(6));
const { event, data } = parsedData;
// 处理不同类型的事件
switch (event) {
case 'task_created': {
// taskIdRef.current = data.task_id;
break;
}
case 'tool_call': {
this.handleToolCall(data);
break;
}
case 'message': {
// 处理消息事件
break;
}
case 'done': {
break;
}
case 'references': {
break;
}
default:
console.log(`未知事件类型: ${event}`, data);
}
} catch (error) {
console.error('JSON解析错误:', error);
console.log('原始数据:', line.slice(6));
}
}
}
} catch (err) {
this.loading = false
console.error('JSON解析错误:', err);
console.log('接口中断');
setTimeout(() => {
this.MessagePlugin.warning('数据异常中断,开始重试!')
this.getChatInfo()
}, 1000)
}
},
handleToolCall(d) {
console.log(d);
switch (d.tool_name) {
case 'show_text': {
const chatText = d.tool_input.text || '';
console.log(chatText);
if (chatText.includes('<think>')) {
// 添加新的思考过程
const thinkContent = chatText.replace('<think>', '').replace('</think>', '');
this.chatList.push({
text: thinkContent,
type: d.tool_name,
});
} else {
this.summary += chatText;
// 更新总结回答
}
break;
}
case 'google_search': {
this.chatList.push({
type: d.tool_name,
data: d.tool_input
})
}
}
this.$nextTick(() => {
this.scrollToBottom()
})
},
scrollToBottom() {
const container = this.$refs.chatList
// 平滑滚动
if (container && container.scrollTo) {
container.scrollTo({
top: container.scrollHeight,
behavior: 'smooth'
})
}
}
},
watch: {
generate(v) {
if (v) {
this.getChatInfo()
}
},
taskChatList(v) {
console.log(v);
if (v) {
this.chatList = v
}
},
taskSummary(d) {
if (d) {
this.summary = d
}
}
},
mounted() {
// this.getChatInfo()
},
};
</script>
<style lang="less" scoped>
.detailModel {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
.title {
color: #fff;
font-size: 32px;
line-height: 40px;
font-weight: 700;
text-align: center;
}
.link {
color: #fff;
text-align: center;
}
.content {
color: #fff;
font-size: 14px;
}
}
.huakuai {
width: 8px;
height: 50px;
background-color: #075176;
border: 1px solid #05244f;
border-radius: 3px;
position: absolute;
left: 0;
top: 50%;
z-index: 1001;
cursor: pointer;
}
:deep(.t-collapse-panel__body) {
background: rgba(3, 38, 80, 0.8);
}
:deep(.t-collapse) {
background-color: transparent;
}
.hidden {
height: 0 !important;
padding: 0 !important;
border: 0 !important;
}
.frame {
display: flex;
flex-direction: column;
gap: 10px;
top: 230px;
position: absolute;
align-items: end;
.opentiong {
display: flex;
align-items: center;
gap: 10px;
}
.isShowBtn {
cursor: pointer;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
background: #032650cc;
border: 1px solid;
border-color: #2b8ffe99;
border-radius: 4px 0 0 4px;
}
}
.InfoChatView {
z-index: 1000;
display: flex;
gap: 10px;
flex-direction: column;
// transition: width 0.3s ease;
overflow-y: auto;
width: 319px;
padding: 20px 0;
height: calc(100vh - 360px);
background: rgba(3, 38, 80, 0.8);
border: 1px solid;
border-color: rgba(43, 143, 254, 0.6);
border-radius: 4px;
backdrop-filter: blur(10px);
// 滚动条样式
&::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #f8f8f8;
}
&::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #aaa;
}
}
.chatItem {
.search {
color: #fff;
}
.think {
padding: 10px;
border: 1px solid;
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
}
}
.resultList {
display: flex;
flex-direction: column;
gap: 10px;
.item {
cursor: pointer;
.eventTitle {
color: #fff;
font-size: 20px;
font-weight: 600;
.num {
width: 16px;
height: 16px;
border-radius: 50%;
font-size: 14px;
display: inline-block;
text-align: center;
background-color: var(--bg-color);
}
}
.eventContent {
color: #fff;
}
}
}
.summary {
padding: 10px;
}
</style>
@@ -0,0 +1,206 @@
<template>
<div class="Overview">
<div class="title">
<span>ZZ任务</span>
<img src="@/assets/map-icon/down-logo.svg" alt="" />
</div>
<div class="content">
<div class="taskName">
任务名称任务名称任务名称任务名称任务名称任务名称任务名称任务名称任务名称任务名称任务名称任务名称任务名称任务名称任务名称
</div>
</div>
<div class="task-details">
<div class="task-line-bg task-line-top"></div>
<div class="" style="margin-top: 5px;">
<!-- {{ taskData.overview }} -->
</div>
<div class="task-line-bg task-line-bottom"></div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
};
},
methods: {
},
watch: {
},
};
</script>
<style lang="less">
.Overview {
position: fixed;
top: 60px;
left: 50%;
transform: translateX(-50%);
z-index: 1000;
.title {
width: 160px;
height: 30px;
line-height: 33px;
margin: auto;
background: url(/src/assets/map-icon/task-content-logo.svg) no-repeat;
background-size: cover;
color: #ffffff;
text-align: center;
}
.content {
.taskName {
background: linear-gradient(90.02deg,
rgba(3, 38, 80, 0) 0%,
rgba(25, 84, 154, 0.8) 32.88%,
rgba(21, 76, 141, 0.8) 67.83%,
rgba(3, 38, 80, 0) 99.46%);
margin-top: 10px;
font-family: Noto Sans S Chinese;
line-height: 30px;
font-weight: 300;
padding-top: 6px;
color: #ffffff;
font-size: var(--titleSize);
text-align: center;
padding-bottom: 10px;
position: relative;
}
}
// 顶部任务信息样式
.task-content {
width: 701px;
position: absolute;
top: 60px;
left: 50%;
transform: translateX(-50%);
z-index: 550;
.task-title {
width: 160px;
height: 30px;
line-height: 33px;
margin: auto;
background: url(/src/assets/map-icon/task-content-logo.svg) no-repeat;
background-size: cover;
color: #ffffff;
text-align: center;
img {
width: 12px;
margin-left: 10px;
}
}
.task-details {
width: 701px;
// height: 75px;
background: linear-gradient(90.02deg,
rgba(3, 38, 80, 0) 0%,
rgba(25, 84, 154, 0.8) 32.88%,
rgba(21, 76, 141, 0.8) 67.83%,
rgba(3, 38, 80, 0) 99.46%);
margin-top: 10px;
font-family: Noto Sans S Chinese;
line-height: 30px;
font-weight: 300;
padding-top: 6px;
color: #ffffff;
font-size: var(--titleSize);
text-align: center;
padding-bottom: 10px;
position: relative;
.task-line-bg {
width: 100%;
height: 2px;
background: linear-gradient(90deg,
rgba(33, 99, 171, 0) -0.82%,
#0079fe 48.95%,
rgba(33, 99, 171, 0) 100%);
position: absolute;
}
.task-line-top {
top: 0;
}
.task-line-bottom {
bottom: 0;
}
}
}
// 顶部行动信息样式
.action-content {
width: 1000px;
position: absolute;
top: 60px;
left: 50%;
transform: translateX(-50%);
z-index: 550;
.action-title {
width: 160px;
height: 30px;
line-height: 33px;
margin: auto;
background: url(/src/assets/map-icon/task-content-logo.svg) no-repeat;
background-size: cover;
color: #ffffff;
text-align: center;
img {
width: 12px;
margin-left: 10px;
}
}
.action-list {
width: 1000px;
margin-top: 20px;
display: flex;
justify-content: space-between;
.action-item {
width: 255px;
padding: 0 10px;
background: linear-gradient(90.07deg, rgba(3, 38, 80, 0) 0%, rgba(15, 63, 120, 0.34) 11.02%, rgba(25, 84, 154, 0.64) 27.47%, rgba(14, 92, 185, 0.64) 50.34%, rgba(21, 76, 141, 0.64) 75.5%, rgba(13, 58, 113, 0.34) 89.24%, rgba(3, 38, 80, 0) 99.43%);
text-align: center;
.action-line {
width: 100%;
height: 2px;
background: linear-gradient(90deg, rgba(33, 99, 171, 0) -0.82%, rgba(0, 121, 254, 0.8) 48.95%, rgba(33, 99, 171, 0) 100%);
}
.item-title {
font-family: Noto Sans S Chinese;
color: #ffffff;
font-size: 18px;
margin-top: 10px;
.item-label {
font-family: DS-Digital;
font-weight: 700;
color: rgba(255, 255, 255, 0.8);
font-size: 30px;
margin-left: 10px;
margin-right: 5px;
}
.item-value {
font-family: Noto Sans S Chinese;
color: #ffffff;
font-size: 16px;
}
}
}
}
}
}
</style>
@@ -0,0 +1,132 @@
<template>
<div class="setiment-analysis">
<div class="setiment-head">
<!-- 任务筛选 -->
<div class="margin-bottom-10">
<t-row :gutter="16">
<t-col :span="7">
<div>
<t-input v-model="inputValue" placeholder="请输入内容搜索" @enter="onEnter" />
</div>
</t-col>
<t-col :span="5">
<t-select>
<t-option key="待分析" label="待分析" value="待分析" />
<t-option key="分析中" label="分析中" value="分析中" />
<t-option key="已完成" label="已完成" value="已完成" />
</t-select>
</t-col>
</t-row>
</div>
<div>
<t-row :gutter="16">
<t-col :span="8">
<div>
<t-date-range-picker v-model="range" :presets="presets" enable-time-picker />
</div>
</t-col>
<t-col :span="4">
<div class="tabs-box">
<span class="sortBtn" :class="{ 'sort-active': taskRadioValue === 'all' }"
@click="taskChange('all')">全部</span>
<span class="sortBtn" :class="{ 'sort-active': taskRadioValue === 'me' }"
@click="taskChange('me')">我的</span>
</div>
</t-col>
</t-row>
</div>
</div>
<div class="setiment-body">
<TaskList :taskList="taskList" @taskDetailsC="taskDataChange" />
</div>
</div>
</template>
<script setup>
import { ref, defineEmits, onMounted } from 'vue';
import TaskList from './TaskAnalysis/TaskDataList.vue';
import { requestAxiosService } from '../service/request-axios-service'; // 引入发送异步请求方法
import dayjs from 'dayjs';
defineProps({
msg: String,
})
const inputValue = ref(''); // 输入款内容
const taskStatus = ref('a'); // 任务状态
const taskRadioValue = ref('all') // 任务类型选择
const presets = ref({
最近7天: [dayjs().subtract(6, 'day').toDate(), dayjs().toDate()],
最近3天: [dayjs().subtract(2, 'day').toDate(), dayjs().toDate()],
今天: [dayjs().toDate(), dayjs().toDate()],
});
const taskList = ref([
{ title: '任务01', taskStatus: '已完成', taskLogo: 'task-completed' },
{ title: '任务01', taskStatus: '分析中', taskLogo: 'task-uncompleted' },
{ title: '任务01', taskStatus: '待分析', taskLogo: 'task-pendinganalysis' },
{ title: '任务01', taskStatus: '未通过', taskLogo: 'task-failed' },
{ title: '任务01', taskStatus: '已完成', taskLogo: 'task-completed' },
])
const range = ref([]); // 日期时间筛选框
const service = requestAxiosService;
const emit = defineEmits(['taskDetailsC']) // 定义子组件发送给父组件的函数
onMounted(() => {
taskSearch();
})
// 发送请求
const taskSearch = () => {
const parmy = {
orderBy: 'createTime',
orderByType: 'desc',
keyword: '',
pageNo: 1,
pageSize: 10,
taskStatus: '25,30,40,60,70,80,90,100,110'
}
service.get(`${environment['b1ConsumerUrl']}/taskAnalyseSearch/getTaskSearch`, parmy).then((res) => {
console.log('任务检索', res);
})
}
// 回车搜索
const onEnter = () => {
}
// 任务类型选择
const taskChange = (value) => {
taskRadioValue.value = value
}
const taskDataChange = (value) => { // 任务点击
console.log(value)
emit('taskDetailsC', value); // 给父组件传参
}
</script>
<style scoped lang="less">
.setiment-analysis {
width: 100%;
height: 100%;
z-index: 500;
color: #fff;
display: flex;
flex-direction: column;
/* 垂直排列子元素 */
.setiment-head {
padding: 10px;
}
.setiment-body {
padding: 10px;
// flex-grow: 1; /* 让 div 填充剩余空间 */
height: calc(100vh - 225px);
box-sizing: border-box;
overflow-y: auto;
}
}
.sortBtn {
padding: 8px 10px;
}
</style>
@@ -0,0 +1,359 @@
<template>
<div class="assessment-content">
<t-loading :loading="loading" show-overlay>
<div class="item-card margin-bottom-15">
<div class="item-title">
<img src="/src/assets/icon/zf-logo.png" alt="" />
上级意图领会
</div>
<div class="item-content">
{{ situationData['上级意图领会'] || '暂无数据' }}
</div>
</div>
<t-row :gutter="16">
<t-col :span="6">
<div class="item-card" v-if="situationData['口径指导与限制']">
<div class="item-title" style="margin-bottom: 10px;">
<img src="/src/assets/icon/theme-logo.png" alt="" />
口径指导与限制
</div>
<div class="item-border-card tab-red">
<div class="item-blue-card">
{{ situationData['口径指导与限制']['关键口径总结'] || '暂无数据' }}
</div>
<div class="item-title color-blue margin-top-15">
观点分布
</div>
<div class="viewpoint-item" v-for="(item, index) in consistencyList" :key="index">
<span :class="'item-tag ' + item.color">{{ item.type }}</span>
{{ item.title }}
</div>
</div>
</div>
</t-col>
<t-col :span="6">
<div class="item-card" v-if="situationData['可用资源与力量']">
<div class="item-title" style="margin-bottom: 10px;">
<img src="/src/assets/icon/theme-logo.png" alt="" />
可用资源与力量
</div>
<div class="item-border-card tab-orange">
<t-row :gutter="16">
<t-col :span="6">
<div class="assessment-item">
<span class="font-weight-bold">我方账号:</span>{{ situationData['可用资源与力量']['我方账号情况'] || '暂无数据' }}
</div>
</t-col>
<t-col :span="6">
<div ref="userPieRef" class="item-pie"></div>
</t-col>
</t-row>
</div>
<div class="item-border-card tab-orange">
<t-row :gutter="16">
<t-col :span="6">
<div class="assessment-item">
<span class="font-weight-bold">媒资数量不足:</span>{{ situationData['可用资源与力量']['媒资数量情况'] || '暂无数据' }}
</div>
</t-col>
<t-col :span="6">
<div ref="mediaPieRef" class="item-pie"></div>
</t-col>
</t-row>
</div>
<div class="item-border-card tab-orange">
<t-row :gutter="16">
<t-col :span="7">
<div class="assessment-item">
<span class="font-weight-bold">目标触达率较高:</span>{{ situationData['可用资源与力量']['目标触达率情况'] || '暂无数据' }}
</div>
</t-col>
<t-col :span="5">
<div class="assessment-item">
<span class="item-tag tag-lightblue" style="margin-right: 10px;">CBW1触达:</span>XXX、XXX
</div>
<div class="assessment-item">
<span class="item-tag tag-green" style="margin-right: 10px;">CBW2触达:</span>XXX、XXX
</div>
</t-col>
</t-row>
</div>
</div>
</t-col>
</t-row>
</t-loading>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import store from '@/store';
import * as echarts from 'echarts';
import { requestAxiosService } from '@/service/request-axios-service';
defineProps({
msg: String,
})
const consistencyList = ref([
{ title: '通过“坚决反对”和“强烈谴责”的表述,坚决反对美对台军售', type: '外交部', color: 'tag-lightblue' },
{ title: '以“要求停止武装台湾”划清红线,结合争取和平统一前景', type: '国台办', color: 'tag-green' },
{ title: '以“警告台独分裂势力”传递不承诺放弃使用武力的信号', type: '东部战区', color: 'tag-blue' },
]);
const userPieRef = ref(null);
const mediaPieRef = ref(null);
const situationData = ref({})
const loading = ref(false);
const taskData = store.state.taskData;
const service = requestAxiosService;
onMounted(() => {
ownSituationSearch();
})
// 查询我情判定
const ownSituationSearch = async () => {
const parmy = {
query: taskData.overview || ''
}
loading.value = true;
const res = await service.get(`${environment['b1ConsumerUrl']}/cop/copOwnSituation`, parmy);
loading.value = false;
console.log('我情判定', res);
let result = res.data;
situationData.value = result;
consistencyList.value[0].title = result['口径指导与限制']['核心口径']['外交部'] || '暂无数据';
consistencyList.value[1].title = result['口径指导与限制']['核心口径']['国台办'] || '暂无数据';
consistencyList.value[2].title = result['口径指导与限制']['核心口径']['东部战区'] || '暂无数据';
setTimeout(() => {
userPieChart();
mediaPieChart();
}, 100);
}
// 我方账号饼状图
const userPieChart = () => {
let chartPie = echarts.init(userPieRef.value);
const option = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'right',
top: 'center',
data: ['文本', '图片', '音频', '视频'],
textStyle: {
color: '#fff'
}
},
series: [
{
name: '数据类型',
type: 'pie',
radius: '75%',
center: ['40%', '50%'],
label: {
show: false
},
labelLine: {
show: false // 隐藏标签线
},
data: [
{ value: 134, name: '文本' },
{ value: 42, name: '图片' },
{ value: 33, name: '音频' },
{ value: 14, name: '视频' }
],
}
]
};
chartPie.setOption(option)
}
// 媒资饼状图
const mediaPieChart = () => {
let chartPie = echarts.init(mediaPieRef.value);
const option = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'right',
top: 'center',
data: ['政治学家人设', '地缘政治', '政治评论员', '绿营支持者'],
textStyle: {
color: '#fff'
}
},
series: [
{
name: '数据类型',
type: 'pie',
radius: '75%',
center: ['40%', '50%'],
label: {
show: false
},
labelLine: {
show: false // 隐藏标签线
},
data: [
{ value: 134, name: '政治学家人设' },
{ value: 149, name: '地缘政治' },
{ value: 112, name: '政治评论员' },
{ value: 124, name: '绿营支持者' }
],
}
]
};
chartPie.setOption(option)
}
</script>
<style scoped lang="less">
.assessment-content {
z-index: 500;
color: #fff;
padding: 15px 10px;
}
.item-card {
padding: 15px;
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
.item-title {
font-size: var(--fontSize);
font-family: 'Noto Sans S Chinese';
font-weight: 700;
margin-bottom: 5px;
display: flex;
align-items: center;
img {
width: var(--fontSize);
margin-right: 5px;
}
}
.item-content {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
}
.item-border-card {
border-left: 5px solid;
border-radius: 5px;
padding: 15px;
margin-bottom: 15px;
.item-title {
font-size: var(--fontSize);
font-family: 'Noto Sans S Chinese';
font-weight: 700;
margin-bottom: 5px;
display: flex;
align-items: center;
img {
width: var(--fontSize);
margin-right: 5px;
}
}
.item-content {
padding: 10px;
}
.ul li {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
}
.item-blue-card {
border: 1px solid;
border-radius: 5px;
border-color: rgba(85, 166, 254, 0.1);
padding: 15px;
margin-bottom: 15px;
background: rgba(0, 98, 217, 0.3);
}
.viewpoint-item {
padding: 10px;
border-radius: 4px;
background: rgba(0, 140, 119, 0.1);
margin-bottom: 10px;
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
.assessment-item {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
.item-tag {
display: inline-block;
color: #fff;
font-size: var(--fontSizes);
padding: 2px 10px;
border-radius: 4px;
margin: 5px;
}
.item-pie {
width: 230px;
height: 100px;
}
.tag-lightblue {
background: #169bd5;
}
.tag-green {
background: #008080;
}
.tag-blue {
background: #015478;
}
.color-blue {
color: #0062d9;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.color-green {
color: #1eb07f;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.color-orange {
color: #d97b00;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.tab-red {
background: rgba(207, 19, 34, 0.2);
}
.tab-orange {
border-color: #d97b00 !important;
background: #a6895f80;
.item-blue-card {
background: rgb(8 67 137);
}
}
</style>
@@ -0,0 +1,358 @@
<template>
<t-loading :loading="loading" show-overlay>
<div class="battlefield-environment">
<div class="margin-bottom-15">
<t-row :gutter="16">
<t-col :span="6">
<div class="item-card">
<div class="item-title" style="margin-bottom: 10px;">
<img src="/src/assets/icon/theme-logo.png" alt="" />
法理环境分析
</div>
<div class="item-border-card tab-blue" v-if="battlefieldEnvironmentData['法理环境分析']">
<div class="item-blue-card">
{{ battlefieldEnvironmentData['法理环境分析']['总结'] }}
</div>
<div class="analysis-content">
<ul>
<template v-for="(value, key) in battlefieldEnvironmentData['法理环境分析']" :key="key">
<li v-if="key !== '总结'">
{{ key }}: {{ value }}
</li>
</template>
</ul>
</div>
</div>
<t-empty v-if="!battlefieldEnvironmentData['法理环境分析']"/>
</div>
</t-col>
<t-col :span="6">
<div class="item-card" v-if="battlefieldEnvironmentData['人文环境分析']">
<div class="item-title" style="margin-bottom: 10px;">
<img src="/src/assets/icon/theme-logo.png" alt="" />
人文环境分析
</div>
<div class="item-border-card tab-blue">
<div class="item-blue-card">
{{ battlefieldEnvironmentData['人文环境分析']['总结'] }}
</div>
<div class="analysis-content">
<ul>
<template v-for="(value, key) in battlefieldEnvironmentData['人文环境分析']" :key="key">
<li v-if="key !== '总结'">
{{ key }}: {{ value }}
</li>
</template>
</ul>
</div>
</div>
</div>
<t-empty v-if="!battlefieldEnvironmentData['人文环境分析']"/>
</t-col>
</t-row>
</div>
<div class="margin-bottom-15">
<t-row :gutter="16">
<t-col :span="6">
<div class="item-card" v-if="battlefieldEnvironmentData['信息环境分析']">
<div class="item-title" style="margin-bottom: 10px;">
<img src="/src/assets/icon/theme-logo.png" alt="" />
信息环境分析
</div>
<div class="item-border-card tab-blue">
<div class="item-blue-card">
{{ battlefieldEnvironmentData['信息环境分析']['总结'] }}
</div>
<!-- <div class="analysis-content">
<div ref="informationPieRef" class="item-pie"></div>
</div> -->
<div class="analysis-content">
<ul>
<template v-for="(value, key) in battlefieldEnvironmentData['信息环境分析']" :key="key">
<li v-if="key !== '总结'">
{{ key }}: {{ value }}
</li>
</template>
</ul>
</div>
</div>
</div>
<t-empty v-if="!battlefieldEnvironmentData['信息环境分析']"/>
</t-col>
<t-col :span="6">
<div class="item-card" v-if="battlefieldEnvironmentData['国际舆论分析']">
<div class="item-title" style="margin-bottom: 10px;">
<img src="/src/assets/icon/theme-logo.png" alt="" />
国际舆论分析
</div>
<div class="item-border-card tab-blue">
<div class="item-blue-card">
{{ battlefieldEnvironmentData['国际舆论分析']['总结'] }}
</div>
<div class="analysis-content">
<ul>
<template v-for="(value, key) in battlefieldEnvironmentData['国际舆论分析']" :key="key">
<li v-if="key !== '总结'">
{{ key }}: {{ value }}
</li>
</template>
</ul>
</div>
</div>
</div>
<t-empty v-if="!battlefieldEnvironmentData['国际舆论分析']"/>
</t-col>
</t-row>
</div>
</div>
</t-loading>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import * as echarts from 'echarts';
import { requestAxiosService } from '@/service/request-axios-service';
import store from '@/store';
defineProps({
msg: String,
})
const legalList = ref([
{ title: '美国军售违背《联合国宪章》尊重主权原则,以及中美三个联合公报(特别是“八·一七”公报),该公报明确要求美国逐步减少对台军售。' },
{ title: '美国试图以《台湾关系法》和“六项保证”为军售辩护[[19][27]],但国际社会多数国家承认一个中国原则' },
{ title: '我国通过《反分裂国家法》等国内法,将台湾问题定位为内政,任何外部军售均属违法' },
])
const humList = ref([
{ title: '赖当局将海马斯军售包装为“守护民主自由”,鼓吹“同岛一命”的分裂文化。' },
{ title: '台军演习(如“云台操演”)融入海马斯元素,试图塑造“台湾主体意识”。' },
{ title: '我国通过《反分裂国家法》等国内法,将台湾问题定位为内政,任何外部军售均属违法' },
])
const opinionList = ref([
{ title: '赖当局将海马斯军售包装为“守护民主自由”,鼓吹“同岛一命”的分裂文化。' },
{ title: '台军演习(如“云台操演”)融入海马斯元素,试图塑造“台湾主体意识”。' },
{ title: '我国通过《反分裂国家法》等国内法,将台湾问题定位为内政,任何外部军售均属违法' },
]);
const loading = ref(false);
const taskData = store.state.taskData;
const service = requestAxiosService;
const battlefieldEnvironmentData = ref({});
onMounted(() => {
copBattlefieldEnvironmentSearch();
// informationPieChart();
})
// 战场环境
const copBattlefieldEnvironmentSearch = async () => {
const parmy = {
query: taskData.overview || ''
}
loading.value = true;
const res = await service.get(`${environment['b1ConsumerUrl']}/cop/copBattlefieldEnvironment`, parmy);
loading.value = false;
console.log('战场环境', res);
let result = res.data;
battlefieldEnvironmentData.value = result;
}
const informationPieRef = ref(null);
// 信息分析饼状图
const informationPieChart = () => {
let chartPie = echarts.init(informationPieRef.value);
const option = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'right',
top: 'center',
data: ['facebook', 'ppt', 'youtube', 'threads', '伊莉论坛'],
textStyle: {
color: '#fff'
}
},
series: [
{
name: '数据类型',
type: 'pie',
radius: '75%',
center: ['40%', '50%'],
label: {
show: false
},
labelLine: {
show: false // 隐藏标签线
},
data: [
{ value: 65, name: 'facebook' },
{ value: 14, name: 'ppt' },
{ value: 12, name: 'youtube' },
{ value: 10, name: 'threads' },
{ value: 9, name: '伊莉论坛' },
],
}
]
};
chartPie.setOption(option)
}
</script>
<style scoped lang="less">
.battlefield-environment {
z-index: 500;
color: #fff;
padding: 15px 10px;
}
.item-card {
padding: 15px;
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
.item-title {
font-size: var(--fontSize);
font-family: 'Noto Sans S Chinese';
font-weight: 700;
margin-bottom: 5px;
display: flex;
align-items: center;
img {
width: var(--fontSize);
margin-right: 5px;
}
}
.item-content {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
}
.item-border-card {
border-left: 5px solid;
border-radius: 5px;
padding: 15px;
margin-bottom: 15px;
.item-title {
font-size: var(--fontSize);
font-family: 'Noto Sans S Chinese';
font-weight: 700;
margin-bottom: 5px;
display: flex;
align-items: center;
img {
width: var(--fontSize);
margin-right: 5px;
}
}
.item-content {
padding: 10px;
}
.ul li {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
}
.analysis-content {
padding: 10px 25px;
.ul li {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
margin-bottom: 5px;
}
}
.item-blue-card {
border: 1px solid;
border-radius: 5px;
border-color: rgba(85, 166, 254, 0.1);
padding: 15px;
margin-bottom: 15px;
background: rgba(0, 98, 217, 0.3);
}
.viewpoint-item {
padding: 10px;
border-radius: 4px;
background: rgba(0, 140, 119, 0.1);
margin-bottom: 10px;
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
.assessment-item {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
.item-tag {
display: inline-block;
color: #fff;
font-size: var(--fontSizes);
padding: 2px 10px;
border-radius: 4px;
margin: 5px;
}
.item-pie {
width: 435px;
height: 200px;
}
.tag-lightblue {
background: #169bd5;
}
.tag-green {
background: #008080;
}
.tag-blue {
background: #015478;
}
.color-blue {
color: #0062d9;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.color-green {
color: #1eb07f;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.color-orange {
color: #d97b00;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.tab-red {
background: rgba(207, 19, 34, 0.2);
}
.tab-orange {
border-color: #d97b00 !important;
background: #a6895f80;
.item-blue-card {
background: rgb(8 67 137);
}
}
</style>
@@ -0,0 +1,544 @@
<template>
<div class="determination-content">
<t-loading :loading="loading" show-overlay>
<t-row :gutter="16">
<t-col :span="7">
<t-dialog
v-model:visible="GJZQModel"
attach="body"
header="关键战情详情"
width="1000"
:confirm-on-enter="true"
:on-confirm="addModelConfig"
>
<div>
<div
style="
font-size: 26px;
font-weight: 800px;
color: #fff;
margin-bottom: 20px;
text-align: center;
"
>
{{
GJZQData["矛盾名称"] ||
GJZQData["优势名称"] ||
GJZQData["战机名称"]
}}
</div>
<div
style="
font-size: 18px;
font-weight: 600px;
color: #fff;
margin-bottom: 10px;
"
>
简介描述:
{{
GJZQData["矛盾简介"] ||
GJZQData["优势简介"] ||
GJZQData["战机简介"]
}}
</div>
<div class="item-content">
<div
class="item-label"
style="
font-size: 18px;
font-weight: 600px;
color: #fff;
margin-bottom: 10px;
"
>
关联方:<span
class="item-tag tag-lightblue"
v-for="(values, keys) in GJZQData['关联方']"
:key="keys"
>{{ keys }}:{{ values }}</span
>
</div>
</div>
<div class="item-content flex-between-center">
<span
class="item-value"
style="
font-size: 18px;
font-weight: 600px;
color: #fff;
margin-bottom: 10px;
"
>战场:{{ GJZQData["战场"] }}</span
>
</div>
<div
v-if="GJZQData['总结']"
style="
font-size: 18px;
font-weight: 600px;
color: #fff;
margin-bottom: 10px;
"
>
总结: {{ GJZQData["总结"] }}
</div>
<div
v-if="GJZQData['分析依据']"
style="
font-size: 18px;
font-weight: 600px;
color: #fff;
margin-bottom: 10px;
"
>
分析依据: {{ GJZQData["分析依据"] }}
</div>
</div>
</t-dialog>
<t-dialog
v-model:visible="modelStatus"
attach="body"
header="决心建议"
width="1000"
:confirm-on-enter="true"
:on-confirm="addModelConfig"
>
<CodeData :markdown="handleData['md']" />
</t-dialog>
<div v-if="determinationData['关键战情']">
<div class="title-content-item margin-bottom-10">关键战情</div>
<template v-for="(value, key) in determinationData['关键战情']">
<div
class="item-card"
v-for="(v, i) in value"
@click="
GJZQData = v;
GJZQModel = true;
"
>
<div class="item-title">
<span
class="item-tag tab-green"
:class="{
'tab-green': key === '核心矛盾',
'tab-yellow': key === '战机',
'tab-yellow': key === '优势',
}"
>{{ key }}{{ i + 1 }}</span
>
{{ v["优势名称"] || v["战机名称"] || v["矛盾名称"] }}
</div>
<!-- <div class="item-content">
<span class="item-label">
{{ key }}名称:
{{ v['矛盾名称'] || v['优势名称'] || v['战机名称'] }}
</span>
</div>
<div class="item-content">
<span class="item-label">
{{ key }}简介:
{{ v['矛盾简介'] || v['优势简介'] || v['战机简介'] }}
</span>
</div> -->
<!-- <div class="item-content">
<div class="item-label">
关联方:<span class="item-tag tag-lightblue" v-for="(values, keys) in v['关联方']" :key="keys">{{ keys
}}:{{
values
}}</span>
</div>
</div>
<div class="item-content flex-between-center">
<span class="item-value">{{ v['战场'] }}</span>
</div> -->
</div>
</template>
</div>
<div v-else>
<t-empty />
</div>
</t-col>
<t-col :span="5">
<div v-if="determinationData['决心建议']">
<div
class="title-content-item margin-bottom-10 cursor-pointer"
@click="
modelStatus = true;
handleData = determinationData;
"
>
决心建议
</div>
<div class="item-card">
<div class="item-title">本级任务</div>
<div class="item-content">
<div class="title">
{{ determinationData["决心建议"]["任务标题"] }}
</div>
{{ determinationData["决心建议"]["任务简介"] }}
<AddTaskDialog
:taskSuperiorFlag="1"
:taskId="taskData.id"
:overview="determinationData['决心建议']['任务简介']"
:taskName="determinationData['决心建议']['任务标题']"
>
<div class="btn" v-if="taskData.ifCreateTask !== 0">
下发任务
</div>
</AddTaskDialog>
</div>
</div>
<div class="item-card">
<div class="item-title">作战目的</div>
<div class="item-content">
<ul>
<li
v-for="(item, index) in determinationData['决心建议'][
'作战目的'
]"
:key="index"
>
{{ index + 1 }}.<span class="font-weight-bold">{{
item
}}</span>
</li>
</ul>
</div>
</div>
<!-- <div class="item-card">
<div class="item-title">
实施要点
</div>
<div class="item-content">
<ul>
<li v-for="(item, index) in determinationData['实施要点']" :key="index">{{ index + 1 }}.<span
class="font-weight-bold">{{ item }}</span></li>
</ul>
</div>
</div> -->
<div class="title-content-item margin-bottom-10">打击目标</div>
<div class="item-card">
<t-dialog
v-model:visible="DJTergetModel"
attach="body"
header="打击目标详情"
width="600"
:confirm-on-enter="true"
:on-confirm="addModelConfig"
>
<div>
<div
style="
font-size: 18px;
font-weight: 600px;
color: #fff;
margin-bottom: 10px;
"
>
目标名称: {{ DJTergetData["目标名称"] }}
</div>
<div
style="
font-size: 18px;
font-weight: 600px;
color: #fff;
margin-bottom: 10px;
"
>
目标描述: {{ DJTergetData["目标描述"] }}
</div>
<div
style="
font-size: 18px;
font-weight: 600px;
color: #fff;
margin-bottom: 10px;
"
>
选择理由: {{ DJTergetData["选择理由"] }}
</div>
<div
style="
font-size: 18px;
font-weight: 600px;
color: #fff;
margin-bottom: 10px;
"
>
推荐依据: {{ DJTergetData["推荐依据"] }}
</div>
</div>
</t-dialog>
<div class="item-content">
<div class="title">
<!-- <span class="item-tag tag-yellow" :key="index">{{ item['优先级'] }}</span> {{ item['目标名称'] }} -->
<span
class="item-tag tag-yellow"
@click="
DJTergetData = item;
DJTergetModel = true;
"
v-for="(item, index) in determinationData['决心建议'][
'打击目标'
]"
:key="index"
>
{{ item["目标名称"] }}</span
>
</div>
<!-- <div>
目标描述: {{ item['目标描述'] }}
</div>
<div>
选择理由: {{ item['选择理由'] }}
</div> -->
<!-- <div>
目标类型: {{ item['目标类型'] }}
</div>
<div>
选择理由: {{ item['选择理由'] }}
</div> -->
</div>
</div>
<div class="title-content-item margin-bottom-10">决心建议总结</div>
<div class="item-card">
<div class="item-content">
{{ determinationData["决心建议总结"] || "暂无数据" }}
</div>
</div>
<!-- <div class="title-content-item margin-bottom-10">叙事建议</div>
<div class="item-card">
<div class="item-title">
叙事反转
</div>
<div class="item-content">
{{ determinationData['叙事反转'] }}
</div>
</div>
<div class="item-card">
<div class="item-title">
数据反制
</div>
<div class="item-content">
{{ determinationData['数据反制'] }}
</div>
</div>
<div class="item-card">
<div class="item-title">
群体分化
</div>
<div class="item-content">
{{ determinationData['群体分化'] }}
</div>
</div> -->
<!-- <div class="item-card">
<div class="item-title">
总结
</div>
<div class="item-content">
{{ determinationData['决心建议总结'] }}
</div>
</div> -->
<!-- <t-radio-group variant="primary-filled" :value="taskRadioValue" @change="onChange">
<t-radio-button value="a">任务</t-radio-button>
<t-radio-button value="b">原则与限制</t-radio-button>
<t-radio-button value="c">兵力使用</t-radio-button>
<t-radio-button value="d">终止条件</t-radio-button>
</t-radio-group> -->
</div>
</t-col>
</t-row>
</t-loading>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from "vue";
import { requestAxiosService } from "@/service/request-axios-service";
import AddTaskDialog from "@/components/dialog/addTaskDialog.vue";
import store from "@/store";
import CodeData from "../markdown/CodeData.vue";
import { MessagePlugin } from "tdesign-vue-next";
const props = defineProps({
msg: String,
updateKey: Number,
});
watch(
() => props.updateKey,
(v) => {
copDecisionRecommendationSearch(true);
}
);
const addModelConfig = () => {};
const taskRadioValue = ref("a");
const loading = ref(false);
const taskData = store.state.taskData;
const service = requestAxiosService;
const determinationData = ref({});
const DJTergetModel = ref(false);
const DJTergetData = ref({});
const GJZQModel = ref(false);
const GJZQData = ref({});
const handleData = ref({});
const modelStatus = ref(false);
// 决心建议
const copDecisionRecommendationSearch = async (status = false) => {
// wxq让去掉query: taskData.overview || "",
const parmy = {
taskId: taskData.id,
refresh: status,
};
loading.value = true;
try {
const res = await service.get(
`${environment["b1ConsumerUrl"]}/cop/copDecisionRecommendation`,
parmy
);
console.log("决心建议", res);
let result = res.data;
determinationData.value = result;
loading.value = false;
} catch (error) {
MessagePlugin.error("决心建议数据获取失败!");
loading.value = false;
} finally {
loading.value = false;
}
};
onMounted(() => {
copDecisionRecommendationSearch();
});
const onChange = (value) => {
taskRadioValue.value = value;
};
</script>
<style scoped lang="less">
.determination-content {
z-index: 500;
color: #fff;
padding: 10px;
position: relative;
.item-card {
width: 100%;
background: rgba(0, 238, 255, 0.2);
border-radius: 4px;
padding: 10px 15px;
margin-bottom: 15px;
box-sizing: border-box;
.item-title {
font-size: var(--fontSize);
font-family: "Noto Sans S Chinese";
font-weight: 500;
margin-bottom: 10px;
}
.item-content {
font-size: var(--fontSizes);
font-family: "Noto Sans S Chinese";
overflow: hidden;
.title {
font-size: 18px;
font-weight: 700;
}
.item-value {
text-decoration: underline;
}
ul {
margin: 0 25px;
li {
margin-bottom: 10px;
}
}
}
}
}
.item-tag {
font-size: var(--fontSizes);
cursor: pointer;
display: inline-block;
white-space: nowrap;
padding: 2px 10px;
border-radius: 4px;
margin: 5px;
}
// 标签样式
// 蓝色标签
.tag-blue {
border-color: #aad2ff !important;
color: #0062d9 !important;
background-color: #eaf4ff !important;
}
// 黄色标签
.tag-yellow {
border-color: #d95e00 !important;
color: #fff !important;
background-color: #dd8717;
}
// 红色标签
.tag-red {
border-color: #fcb5b9 !important;
color: #fff !important;
background-color: #cf1322;
}
// 绿色标签
.tag-green {
border-color: #baf1dd !important;
color: #ffffff !important;
background-color: #1eb07f;
}
// 紫色标签
.tag-purple {
border-color: #cec0fc !important;
color: #fff !important;
background-color: #6353cc;
}
// 浅蓝色标签
.tag-lightblue {
border-color: #c1ebfb !important;
color: #ffffff !important;
background-color: #2f9acc;
}
// 灰色标签
.tag-gray {
border-color: #d6d7db !important;
background-color: #ffffff;
color: #575a61;
}
.btn {
padding: 0 5px;
background-color: #0e597f;
width: 100px;
text-align: center;
cursor: pointer;
line-height: 26px;
border-radius: 5px;
float: right;
}
</style>
@@ -0,0 +1,424 @@
<template>
<div class="enemy-assessmen">
<t-loading :loading="loading" show-overlay>
<div class="item-card margin-bottom-15">
<div class="item-title">
<img src="/src/assets/icon/zf-logo.png" alt="" />
对手核心企图
</div>
<div class="item-cotnent">
{{ enemyData['对手核心企图'] || '暂无数据'}}
</div>
</div>
<t-row :gutter="16">
<t-col :span="6">
<div class="item-card">
<div class="item-title" style="margin-bottom: 15px;">
<img src="/src/assets/icon/theme-logo.png" alt="" />
关键叙事分析
</div>
<div v-if="enemyData['关键叙事分析']" class="item-border-card tab-blue">
<div class="item-blue-card">
{{ enemyData['关键叙事分析']['叙事总结'] }}
</div>
<div class="item-title color-blue">
叙事内容
</div>
<div class="narrate-item">
<CodeData :markdown="enemyData['关键叙事分析']['叙事内容']"/>
</div>
<!-- <t-row :gutter="16">
<t-col :span="6">
<div class="narrate-item">
<ul>
<li>海马斯可覆盖大陆沿海</li>
<li>打了就跑的移动迷宫</li>
</ul>
</div>
</t-col>
<t-col :span="6">
<div class="narrate-item">
<ul>
<li>打了就跑的移动迷宫</li>
<li>让解放军吃火力墙</li>
</ul>
</div>
</t-col>
</t-row> -->
<div class="item-title color-blue margin-top-15">
观点分布
</div>
<t-row :gutter="16">
<t-col :span="6">
<div id="chart-pie" ref="chartRef">
</div>
</t-col>
<t-col :span="6">
<div class="viewpoint-item" v-for="(item, index) in opinionPieList" :key="index">
<div>{{ index + 1 }}.{{ item.name }}</div>
<div class="item-footer">观点占比:{{ item['data']['占比'] }}</div>
</div>
</t-col>
</t-row>
</div>
<t-empty v-if="!enemyData['关键叙事分析']"/>
</div>
</t-col>
<t-col :span="6">
<div v-if="enemyData['对手强弱点分析']" class="item-card">
<div class="item-title" style="margin-bottom: 15px;">
<img src="/src/assets/icon/theme-logo.png" alt="" />
对手强弱点分析
</div>
<div class="item-border-card tab-orange">
<div class="item-blue-card">
{{ enemyData['对手强弱点分析']['强弱点总结'] }}
</div>
<div class="item-title color-blue margin-top-15">
对手弱点
</div>
<div class="task-list-content">
<!-- <ul>
<li class="" v-for="(item, index) in weakPoints" :key="index">{{ item.title }}</li>
</ul> -->
<CodeData :markdown="enemyData['对手强弱点分析']['对手强点']"/>
</div>
<div class="item-title color-blue margin-top-15">
对手强点
</div>
<div class="task-list-content">
<!-- <ul>
<li class="" v-for="(item, index) in strongPoints" :key="index">{{ item.title }}</li>
</ul> -->
<CodeData :markdown="enemyData['对手强弱点分析']['对手弱点']"/>
</div>
</div>
</div>
</t-col>
</t-row>
</t-loading>
</div>
</template>
<script setup>
import { ref,reactive, onMounted, computed } from 'vue';
import { useStore } from 'vuex';
import * as echarts from 'echarts';
import { requestAxiosService } from '@/service/request-axios-service';
import CodeData from '../markdown/CodeData.vue';
const props = defineProps({
msg: String,
taskData: Object
})
const opinionPieList = ref([
{
value: 1500,
name: '支持我方观点',
itemStyle: {
color: '#7acaa4'
}
},
{
value: 735,
name: '中立观点',
itemStyle: {
color: '#c8cdd5'
}
},
{
value: 1500,
name: '反对我方观点',
itemStyle: {
color: '#f5a444'
}
}
]);
let colors = ['#7acaa4','#c8cdd5','#f5a444'];
const chartRef = ref(null);
const weakPoints = ref([
{ title: '俄乌战场经验可鉴,海马斯弱点已验证' },
{ title: '岛内对美售武器疑虑重重,存在认知裂痕' },
{ title: '台军虽可获得111套“海马斯”,但缺乏独立的侦察、指挥、数据链和电子战支撑体系,战时效能将大打折扣。' },
])
const strongPoints = ref([
{ title: '美方持续炒作“海马斯”威胁论' },
{ title: '“台独”势力将其视为“护身符”,加剧冒险' },
])
const enemyData = ref({});
// 获取 Vuex store
const store = useStore();
const taskData = store.state.taskData;
const service = requestAxiosService;
const loading = ref(false);
onMounted(() => {
enemySituationSearch();
})
// 查询敌情判定
const enemySituationSearch = async () => {
const parmy = {
query: taskData.overview || ''
}
loading.value = true;
const res = await service.get(`${environment['b1ConsumerUrl']}/cop/copEnemySituation`, parmy);
loading.value = false;
console.log('查询敌情判定', res);
let result = res.data;
enemyData.value = result;
opinionPieList.value = [];
if (result['关键叙事分析']) {
let pieList = result['关键叙事分析']['观点分布'] || [];
pieList.forEach((item, index) => {
opinionPieList.value.push({
value: Number(item['占比'].replace(/%/g, '')),
name: item['观点倾向'],
data: item,
itemStyle: {
color: colors[index]
}
})
})
}
setTimeout(() => {
initPieChart();
}, 100)
}
const initPieChart = () => {
let chartPie = echarts.init(chartRef.value);
const option = {
title: {
text: '',
left: 'center',
top: 'center'
},
legend: {
show: false // 隐藏图例
},
tooltip: {
show: true,
appendTo: 'body',
formatter: function (params) {
// console.log('params数据',params);
let text = ``;
text = `
<div class="pint-pie__tooltip">
<div>${params.data.name}</div>
<div>
<span class="">${params.data.value}</span>
</div>
</div>
`;
return text;
}
},
series: [
{
name: '访问来源',
type: 'pie',
radius: ['50%', '85%'], // 设置圆环的内径和外径
padAngle: 2,
// avoidLabelOverlap: false,
itemStyle: {
borderColor: '#fff',
// borderRadius: 4,
borderWidth: 0
},
label: {
show: false
},
labelLine: {
show: false // 隐藏标签线
},
emphasis: {
disabled: true,
label: {
show: false,
fontSize: '20',
fontWeight: 'bold'
}
},
data: opinionPieList.value
},
{
name: '外边框',
type: 'pie',
radius: ['90%', '90%'],
center: ['50%', '50%'],
emphasis: {
disabled: true
},
label: {
show: false
},
labelLine: {
show: false // 隐藏标签线
},
tooltip: {
show: false
},
data: [
{
value: 0,
name: '',
itemStyle: {
borderWidth: 1,
borderColor: '#e4e9f4'
}
}
]
}
]
}
chartPie.setOption(option)
}
</script>
<style scoped lang="less">
.judgment-conclusion {
z-index: 500;
color: #fff;
// 态势概览样式
.overview-content {
padding: 15px 0;
}
// 敌情判定样式
.enemy-assessmen {
padding: 15px 0;
}
}
.item-card {
padding: 15px;
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
.item-title {
font-size: var(--fontSize);
font-family: 'Noto Sans S Chinese';
font-weight: 700;
margin-bottom: 5px;
display: flex;
align-items: center;
img {
width: var(--fontSize);
margin-right: 5px;
}
}
.item-content {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
}
.item-border-card {
min-height: 145px;
border-left: 5px solid;
border-radius: 5px;
padding: 15px;
margin-bottom: 15px;
.item-title {
font-size: var(--fontSize);
font-family: 'Noto Sans S Chinese';
font-weight: 700;
margin-bottom: 5px;
display: flex;
align-items: center;
img {
width: var(--fontSize);
margin-right: 5px;
}
}
.item-content {
padding: 10px;
}
.ul li {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
}
.item-blue-card {
border: 1px solid;
border-radius: 5px;
border-color: rgba(85, 166, 254, 0.1);
padding: 15px;
margin-bottom: 15px;
background: rgba(0, 98, 217, 0.3);
}
.narrate-item {
padding: 10px 25px;
background: rgba(0, 238, 255, 0.2);
border-radius: 4px;
.ul {
li {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
}
}
.task-list-content {
padding: 10px 25px;
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
#chart-pie {
width: 150px;
height: 150px;
margin: 0 auto;
}
.viewpoint-item {
padding: 10px;
border-radius: 4px;
background: rgba(0, 140, 119, 0.1);
margin-bottom: 10px;
.item-footer {
color: #7acaa4;
}
}
.color-blue {
color: #0062d9;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.color-green {
color: #1eb07f;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.color-orange {
color: #d97b00;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.tab-orange {
border-color: #d97b00 !important;
background: #a6895f80;
.item-blue-card {
background: rgb(8 67 137);
}
}
</style>
@@ -0,0 +1,488 @@
<template>
<div class="handle-content">
<t-loading :loading="loading" show-overlay>
<t-row :gutter="16">
<t-col :span="7">
<div class="title-content-item margin-bottom-10">关键事态</div>
<CommonInfoDialog
:modelData="GJSTModelData"
:modelStatus="GJSTModelStatus"
@updateStatus="(v) => (GJSTModelStatus = v)"
@config="() => (GJSTModelStatus = false)"
/>
<!-- @click="openGJSTModel(value)" -->
<div class="item-card" v-for="value in handleData['关键事态']">
<div class="item-title">
<!-- {{ value }} -->
<span class="item-tag tab-green">{{ value["类型"] }}</span>
{{ value["标题"] }}
</div>
<div class="item-content flex-between-center">
{{ value["内容"] }}
<!-- <span class="item-value">海马斯失灵 俄乌战场</span>
<span class="item-label">
关联方:<span class="item-tag tag-lightblue">俄军</span><span class="item-tag tag-purple">美国政府</span><span
class="item-tag tag-green">美军</span>
</span> -->
<!-- <span class="item-label">
来源:<span class="item-value">{{ value.siteName }}</span>
</span> -->
</div>
<span class="item-label">
依据:<span class="item-value">{{ value["依据"] }}</span>
</span>
</div>
<!-- <div class="addEvent" @click="openAddModel">
+
</div> -->
<t-dialog
v-model:visible="addModelStatus"
attach="body"
header="添加关键事态"
width="600"
:confirm-on-enter="true"
:on-confirm="addModelConfig"
>
<div class="row" v-for="row in addRule">
<div class="label">{{ row.label }}:</div>
<div class="content">
<t-input v-model="row.value" v-if="row.key !== 'direction'" />
<t-select v-else>
<t-option key="U方向" label="U方向" value="U方向" />
<t-option key="W方向" label="W方向" value="W方向" />
</t-select>
</div>
</div>
</t-dialog>
</t-col>
<t-col :span="5">
<t-dialog
v-model:visible="modelStatus"
attach="body"
header="过程"
width="1000"
:confirm-on-enter="true"
:on-confirm="addModelConfig"
>
<CodeData :markdown="handleData['md']" />
</t-dialog>
<div v-if="handleData['处置建议']" class="suggestion-content">
<div
class="title-content-item margin-bottom-10"
@click="modelStatus = true"
>
处置建议总结
</div>
<div class="item-card">
<!-- <div class="item-title">
处置建议总结
</div> -->
<div class="item-content">
{{ handleData["处置建议总结"] }}
</div>
</div>
<div class="title-content-item margin-bottom-10">目标</div>
<div class="item-card">
<div class="item-content">
{{ handleData["目标"] }}
</div>
</div>
<!-- <div class="item-card">
<div class="item-title">
建议执行要点
</div>
<div class="item-content">
<ul>
<li v-for="(item, key, index) in handleData['建议执行要点']" :key="index">
{{ key }}:
<span class="font-weight-bold" v-if="!Array.isArray(item)">{{ item }}</span>
<ul v-else>
<li v-for="(v, i) in item">{{ i + 1 }}.
<span class="font-weight-bold">{{ v }}</span>
</li>
</ul>
</li>
</ul>
</div>
</div> -->
<div>
<div class="title-content-item margin-bottom-10">建议</div>
<t-swiper
class="tdesign-demo-block--swiper"
direction="vertical"
style="width: 480px"
:navigation="{ showSlideBtn: 'never', placement: 'outside' }"
:height="500"
:autoplay="false"
trigger="click"
>
<t-swiper-item
style="height: 500px; overflow-y: auto"
v-for="(item, index) in handleData['处置建议']"
:key="index"
>
<div class="item-card">
<div class="item-title">口径基调</div>
<div class="item-content">
{{ item["口径基调"].toString() }}
</div>
</div>
<t-row :gutter="16">
<t-col :span="6">
<div class="item-card">
<div class="item-title">处置主体</div>
<div class="item-content">
<div class="margin-bottom-10">
主责单位:
<span class="item-tag tag-lightblue">{{
item["处置主体"]["主责单位"]
}}</span>
</div>
<div class="margin-bottom-10">
配合单位:
<span
class="item-tag tag-lightblue"
v-for="(aItem, aIndex) in item['处置主体'][
'配合单位'
]"
:key="aIndex"
>{{ aItem }}</span
>
</div>
</div>
</div>
</t-col>
<t-col :span="6">
<div class="item-card">
<div class="item-title">处置对象</div>
<div class="item-content">
<div>
<div>
关联对象:
<span class="item-tag tag-yellow">{{
item["处置对象"]["关联对象"]
}}</span>
</div>
<div>
核心对象:
<span class="item-tag tag-yellow">{{
item["处置对象"]["核心对象"]
}}</span>
</div>
</div>
</div>
</div>
</t-col>
</t-row>
<div class="item-card" v-if="item['处置方式与步骤']">
<div class="item-title">处置方式与步骤</div>
<div class="item-content">
<CodeData :markdown="item['处置方式与步骤']" />
<!-- <div>{{ item['处置方式与步骤'] }}</div> -->
</div>
</div>
<div class="item-card">
<div class="item-title">建议内容</div>
<div class="item-content">
{{ item["建议内容"] }}
</div>
</div>
<div class="item-card">
<div class="item-title">立场与原则</div>
<div class="item-content">
{{ item["立场与原则"] }}
</div>
</div>
<!-- <div class="item-card">
<div class="item-title">
预期效果
</div>
<div class="item-content">
{{ item['预期效果'] }}
</div>
</div> -->
</t-swiper-item>
</t-swiper>
<!-- <div class="item-card">
<div class="item-title">
风险提示
</div>
<div class="item-content">
{{ item['风险提示'] }}
</div>
</div> -->
</div>
</div>
<div v-else class="padding-10">
<t-empty />
</div>
</t-col>
</t-row>
</t-loading>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from "vue";
import CodeData from "../markdown/CodeData.vue";
import { requestAxiosService } from "@/service/request-axios-service";
import CommonInfoDialog from "@/components/dialog/commonInfoDialog.vue";
import store from "@/store";
import dayjs from "dayjs";
import { MessagePlugin } from "tdesign-vue-next";
const props = defineProps({
msg: String,
taskId: Number,
updateKey: Number,
});
watch(
() => props.updateKey,
(v) => {
console.log(v);
getCZJY(true);
getGJSTData(true);
}
);
const modelStatus = ref(false);
const GJSTModelData = ref({});
const GJSTModelStatus = ref(false);
const openGJSTModel = (d) => {
console.log(d);
GJSTModelStatus.value = true;
GJSTModelData.value = d;
console.log(GJSTModelStatus.value);
};
const addModelStatus = ref(false);
const openAddModel = () => {
addModelStatus.value = true;
};
const addModelConfig = async () => {
console.log("搜索");
let params = {
taskId: props.taskId,
eventId: "",
};
addRule.value.forEach((i) => {
params[i.key] = i.value;
});
console.log(params);
const res = await service.post(
`${environment["b1ConsumerUrl"]}/cop/saveCopKeyEvents`,
params
);
console.log(res);
MessagePlugin.info(res.msg);
if (res.state === "201") {
addModelStatus.value = false;
getGJSTData();
}
};
const addRule = ref([
{ label: "标题", key: "title", value: "" },
{ label: "内容", key: "content", value: "" },
{ label: "方向", key: "direction", value: "" },
// { label: '表菩提', key: "eventId", value: '' },
{ label: "热度", key: "importNum", value: "" },
{ label: "纬度", key: "latitude", value: "" },
{ label: "经度", key: "longitude", value: "" },
{ label: "网站", key: "siteName", value: "" },
{ label: "来源", key: "sourceType", value: "" },
// { label: '', key: "taskId", value: 3059 },
]);
const loading = ref(false);
const taskData = store.state.taskData;
const service = requestAxiosService;
const handleData = ref({});
const GJSTData = ref([]);
onMounted(() => {
getGJSTData(); //获取关键事态
getCZJY(); //获取处置建议
});
//处置建议
const getCZJY = async (status = false) => {
const parmy = {
taskId: props.taskId,
refresh: status,
};
loading.value = true;
const res = await service.get(
`${environment["b1ConsumerUrl"]}/cop/queryHandlingSuggestions`,
parmy
);
loading.value = false;
console.log(res);
handleData.value = res.data.data || res.data;
console.log(handleData.value);
};
// 关键事态
const getGJSTData = async (status = false) => {
const parmy = {
taskId: props.taskId,
refresh: status,
};
loading.value = true;
const res = await service.get(
`${environment["b1ConsumerUrl"]}/cop/copSuggestionKeyEvents`,
parmy
);
loading.value = false;
console.log("关键事态", res);
let result = res.data;
GJSTData.value = result;
getCZJY();
};
</script>
<style scoped lang="less">
.handle-content {
z-index: 500;
color: #fff;
padding: 10px;
.item-card {
width: 100%;
background: rgba(0, 238, 255, 0.2);
border-radius: 4px;
padding: 10px 15px;
margin-bottom: 15px;
box-sizing: border-box;
.item-title {
font-size: var(--fontSize);
font-family: "Noto Sans S Chinese";
font-weight: 500;
margin-bottom: 10px;
}
.item-content {
font-size: var(--fontSizes);
font-family: "Noto Sans S Chinese";
.item-value {
text-decoration: underline;
}
ul {
margin: 0 25px;
li {
margin-bottom: 10px;
}
}
}
}
.addEvent {
font-size: 30px;
font-weight: 700;
text-align: center;
line-height: 80px;
border: 2px solid #575a61;
border-radius: 5px;
cursor: pointer;
}
.suggestion-content {
width: 100%;
height: 710px;
overflow-y: auto;
}
}
.item-tag {
font-size: var(--fontSizes);
display: inline-block;
// white-space: nowrap;
padding: 2px 10px;
border-radius: 4px;
margin: 5px;
}
// 标签样式
// 蓝色标签
.tag-blue {
border-color: #aad2ff !important;
color: #0062d9 !important;
background-color: #eaf4ff !important;
}
// 黄色标签
.tag-yellow {
border-color: #d95e00 !important;
color: #fff !important;
background-color: #dd8717;
}
// 红色标签
.tag-red {
border-color: #fcb5b9 !important;
color: #fff !important;
background-color: #cf1322;
}
// 绿色标签
.tag-green {
border-color: #baf1dd !important;
color: #ffffff !important;
background-color: #1eb07f;
}
// 紫色标签
.tag-purple {
border-color: #cec0fc !important;
color: #fff !important;
background-color: #6353cc;
}
// 浅蓝色标签
.tag-lightblue {
border-color: #c1ebfb !important;
color: #ffffff !important;
background-color: #2f9acc;
}
// 灰色标签
.tag-gray {
border-color: #d6d7db !important;
background-color: #ffffff;
color: #575a61;
}
.row {
display: flex;
.label {
width: 80px;
}
.content {
flex: 1;
flex-shrink: 0;
}
}
.btn {
padding: 0 5px;
background-color: #0e597f;
width: 100px;
text-align: center;
cursor: pointer;
line-height: 26px;
border-radius: 5px;
float: right;
}
</style>
@@ -0,0 +1,223 @@
<template>
<div class="judgment-conclusion">
<t-tabs v-model="tabIndex">
<t-tab-panel :value="1" label="总体战略态势" :destroy-on-hide="false">
<StrategyOverview/>
</t-tab-panel>
<t-tab-panel :value="2" label="敌情判定" :destroy-on-hide="false">
<EnemySituation/>
</t-tab-panel>
<t-tab-panel :value="3" label="我情判定" :destroy-on-hide="false">
<AssessmentContent/>
</t-tab-panel>
<t-tab-panel :value="4" label="战场环境" :destroy-on-hide="false">
<BattlefieldEnvironment/>
</t-tab-panel>
</t-tabs>
</div>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue';
import AssessmentContent from './AssessmentContent.vue';
import BattlefieldEnvironment from './BattlefieldEnvironment.vue';
import StrategyOverview from './StrategyOverview.vue';
import EnemySituation from './EnemySituation.vue';
import { useStore } from 'vuex';
import * as echarts from 'echarts';
import { requestAxiosService } from '@/service/request-axios-service';
const props = defineProps({
msg: String,
taskData: Object
})
const tabIndex = ref(1);
const opinionPieList = ref([
{
value: 1500,
name: '支持我方观点',
itemStyle: {
color: '#7acaa4'
}
},
{
value: 735,
name: '中立观点',
itemStyle: {
color: '#c8cdd5'
}
},
{
value: 1500,
name: '反对我方观点',
itemStyle: {
color: '#f5a444'
}
}
]);
const chartRef = ref(null);
const weakPoints = ref([
{ title: '俄乌战场经验可鉴,海马斯弱点已验证' },
{ title: '岛内对美售武器疑虑重重,存在认知裂痕' },
{ title: '台军虽可获得111套“海马斯”,但缺乏独立的侦察、指挥、数据链和电子战支撑体系,战时效能将大打折扣。' },
])
const strongPoints = ref([
{ title: '美方持续炒作“海马斯”威胁论' },
{ title: '“台独”势力将其视为“护身符”,加剧冒险' },
])
// 获取 Vuex store
const store = useStore();
const taskData = computed(() => store.state.taskData);
const service = requestAxiosService;
onMounted(() => {
})
</script>
<style scoped lang="less">
.judgment-conclusion {
z-index: 500;
color: #fff;
// 态势概览样式
.overview-content {
padding: 15px 0;
}
// 敌情判定样式
.enemy-assessmen {
padding: 15px 0;
}
}
.item-card {
padding: 15px;
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
.item-title {
font-size: var(--fontSize);
font-family: 'Noto Sans S Chinese';
font-weight: 700;
margin-bottom: 5px;
display: flex;
align-items: center;
img {
width: var(--fontSize);
margin-right: 5px;
}
}
.item-content {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
}
.item-border-card {
min-height: 145px;
border-left: 5px solid;
border-radius: 5px;
padding: 15px;
margin-bottom: 15px;
.item-title {
font-size: var(--fontSize);
font-family: 'Noto Sans S Chinese';
font-weight: 700;
margin-bottom: 5px;
display: flex;
align-items: center;
img {
width: var(--fontSize);
margin-right: 5px;
}
}
.item-content {
padding: 10px;
}
.ul li {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
}
.item-blue-card {
border: 1px solid;
border-radius: 5px;
border-color: rgba(85, 166, 254, 0.1);
padding: 15px;
margin-bottom: 15px;
background: rgba(0, 98, 217, 0.3);
}
.narrate-item {
padding: 10px 25px;
background: rgba(0, 238, 255, 0.2);
border-radius: 4px;
.ul {
li {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
}
}
.task-list-content {
padding: 10px 25px;
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
#chart-pie {
width: 150px;
height: 150px;
margin: 0 auto;
}
.viewpoint-item {
padding: 10px;
border-radius: 4px;
background: rgba(0, 140, 119, 0.1);
margin-bottom: 10px;
.item-footer {
color: #7acaa4;
}
}
.color-blue {
color: #0062d9;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.color-green {
color: #1eb07f;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.color-orange {
color: #d97b00;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.tab-orange {
border-color: #d97b00 !important;
background: #a6895f80;
.item-blue-card {
background: rgb(8 67 137);
}
}
</style>
@@ -0,0 +1,270 @@
<template>
<div class="overview-content">
<div class="margin-bottom-15">
<t-row :gutter="16">
<t-col :span="6">
<div class="item-card">
<div class="item-title">
<img src="/src/assets/icon/完成.svg" alt="" />
当前态势定性
</div>
<div class="item-cotnent">
{{ strategyData['当前态势定性'] || '暂无数据'}}
</div>
</div>
</t-col>
<t-col :span="6">
<div class="item-card">
<div class="item-title">
<img src="/src/assets/icon/zf-logo.png" alt="" />
核心矛盾
</div>
<div class="item-cotnent">
{{ strategyData['核心矛盾'] || '暂无数据' }}
</div>
</div>
</t-col>
</t-row>
</div>
<div class="item-card">
<div class="item-title" style="margin-bottom: 15px;">
<img src="/src/assets/icon/theme-logo.png" alt="" />
战略机遇与威胁(SWOT)
</div>
<t-row :gutter="16">
<t-col :span="6" v-for="(item, index) in overviewList" :key="index">
<div class="item-border-card" :class="item.color">
<div class="item-title">
{{ item.title }}
</div>
<div class="item-content">
<ul>
<t-empty v-if="item.list.length===0"/>
<li v-for="(aItem, aIndex) in item.list" :key="aIndex">
{{ aItem.title }}
</li>
</ul>
</div>
</div>
</t-col>
</t-row>
</div>
</div>
</template>
<script setup>
import { ref,reactive, onMounted, computed } from 'vue';
import { useStore } from 'vuex';
import * as echarts from 'echarts';
import { requestAxiosService } from '@/service/request-axios-service';
const props = defineProps({
msg: String,
taskData: Object
})
const overviewList = reactive([
{ title: '机遇', color: 'tab-blue', list: [] },
{ title: '威胁', color: 'tab-yellow', list: [] },
{ title: '优势', color: 'tab-green', list: [] },
{ title: '劣势', color: 'tab-red', list: [] },
]);
const opinionPieList = ref([
{
value: 1500,
name: '支持我方观点',
itemStyle: {
color: '#7acaa4'
}
},
{
value: 735,
name: '中立观点',
itemStyle: {
color: '#c8cdd5'
}
},
{
value: 1500,
name: '反对我方观点',
itemStyle: {
color: '#f5a444'
}
}
]);
const chartRef = ref(null);
// 获取 Vuex store
const store = useStore();
const taskData = store.state.taskData;
const service = requestAxiosService;
const strategyData = ref({})
onMounted(() => {
strategicSituationSearch();
})
// 总体战略态势
const strategicSituationSearch = async () => {
console.log(store.state.taskData,'任务信息')
const parmy = {
query: taskData.overview || ''
}
const res = await service.get(`${environment['b1ConsumerUrl']}/cop/copStrategicSituation`, parmy);
console.log('查询结果', res);
let result = res.data['总体战略态势分析'];
strategyData.value = result
if (result['战略机遇与威胁']) {
overviewList[0].list = [{title: result['战略机遇与威胁']['机遇']}];
overviewList[1].list = [{title: result['战略机遇与威胁']['威胁']}];
overviewList[2].list = [{title: result['战略机遇与威胁']['优势']}];
overviewList[3].list = [{title: result['战略机遇与威胁']['劣势']}];
}
}
</script>
<style scoped lang="less">
.judgment-conclusion {
z-index: 500;
color: #fff;
// 态势概览样式
.overview-content {
padding: 15px 0;
}
// 敌情判定样式
.enemy-assessmen {
padding: 15px 0;
}
}
.item-card {
padding: 15px;
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
.item-title {
font-size: var(--fontSize);
font-family: 'Noto Sans S Chinese';
font-weight: 700;
margin-bottom: 5px;
display: flex;
align-items: center;
img {
width: var(--fontSize);
margin-right: 5px;
}
}
.item-content {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
}
.item-border-card {
min-height: 145px;
border-left: 5px solid;
border-radius: 5px;
padding: 15px;
margin-bottom: 15px;
.item-title {
font-size: var(--fontSize);
font-family: 'Noto Sans S Chinese';
font-weight: 700;
margin-bottom: 5px;
display: flex;
align-items: center;
img {
width: var(--fontSize);
margin-right: 5px;
}
}
.item-content {
padding: 10px;
}
.ul li {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
}
.item-blue-card {
border: 1px solid;
border-radius: 5px;
border-color: rgba(85, 166, 254, 0.1);
padding: 15px;
margin-bottom: 15px;
background: rgba(0, 98, 217, 0.3);
}
.narrate-item {
padding: 10px 25px;
background: rgba(0, 238, 255, 0.2);
border-radius: 4px;
.ul {
li {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
}
}
.task-list-content {
padding: 10px 25px;
font-family: 'Noto Sans S Chinese';
font-size: 15px;
}
#chart-pie {
width: 150px;
height: 150px;
margin: 0 auto;
}
.viewpoint-item {
padding: 10px;
border-radius: 4px;
background: rgba(0, 140, 119, 0.1);
margin-bottom: 10px;
.item-footer {
color: #7acaa4;
}
}
.color-blue {
color: #0062d9;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.color-green {
color: #1eb07f;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.color-orange {
color: #d97b00;
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.tab-orange {
border-color: #d97b00 !important;
background: #a6895f80;
.item-blue-card {
background: rgb(8 67 137);
}
}
</style>
@@ -0,0 +1,67 @@
<template>
<div class="suggestion-content">
<div
class="btn"
style="position: absolute; right: 50px"
@click="updateData"
>
刷新
</div>
<t-tabs v-model="tabIndex">
<t-tab-panel :value="1" label="处置建议" :destroy-on-hide="false">
<HandleContent :taskId="taskData.id" :updateKey="handleUpdateKey" />
</t-tab-panel>
<t-tab-panel :value="2" label="决心建议" :destroy-on-hide="false">
<DeterminationContent :updateKey="determinationUpdateKey" />
</t-tab-panel>
</t-tabs>
</div>
</template>
<script setup>
import { ref } from "vue";
import HandleContent from "./HandleContent.vue";
import DeterminationContent from "./DeterminationContent.vue";
const props = defineProps({
msg: String,
taskData: Object,
});
const handleUpdateKey = ref(0);
const determinationUpdateKey = ref(0);
const updateData = () => {
tabIndex.value == 1
? handleUpdateKey.value++
: determinationUpdateKey.value++;
// updateKey.value++;
console.log(
tabIndex.value,
handleUpdateKey.value,
determinationUpdateKey.value
);
};
const tabIndex = ref(1);
</script>
<style scoped lang="less">
.suggestion-content {
z-index: 500;
color: #fff;
padding: 10px;
position: relative;
.btn {
padding: 0 5px;
background-color: #0e597f;
width: 100px;
text-align: center;
cursor: pointer;
line-height: 26px;
border-radius: 5px;
float: right;
cursor: pointer;
z-index: 9999;
}
}
</style>
@@ -0,0 +1,548 @@
<template>
<div class="situation-assessment">
<!-- 顶部tab页 -->
<div class="tabs-list">
<div class="tabs-item" :class="{ 'item-active': tabIndex === 1 }" @click="tabChange(1)">
优劣势分析
</div>
<div class="tabs-item" :class="{ 'item-active': tabIndex === 2 }" @click="tabChange(2)">
条件与限制
</div>
<div class="tabs-item" :class="{ 'item-active': tabIndex === 3 }" @click="tabChange(3)">
风险及应对
</div>
</div>
<!-- 内容区域 -->
<t-loading :loading="loading" show-overlay>
<!-- 优劣势分析 -->
<div v-if="tabIndex === 1" class="advantage-analysis">
<div class="title-content-item margin-bottom-10">民意RZ优劣势</div>
<!-- Echarts-图 -->
<!-- <t-row :gutter="16">
<t-col :span="6">
<div ref="chartRef" class="pie-charts"></div>
</t-col>
<t-col :span="6">
<div class="viewpoint-item" v-for="(item, index) in opinionPieList" :key="index">
<div>{{ index + 1 }}.{{ item.name }}</div>
<div class="item-footer">观点占比:{{ item.value }}%</div>
</div>
</t-col>
</t-row> -->
<t-dialog v-model:visible="YLModel" attach="body" header="详情" width="800" :confirm-on-enter="true"
:on-confirm="addModelConfig">
<div>
<div style="font-size: 26px;font-weight: 800px;color: #fff;margin-bottom: 20px;text-align: center;">
{{ YLData.title }}
</div>
<div style="font-size: 18px;font-weight: 600px;color: #fff;margin-bottom: 10px;">
{{ YLData.content }}
</div>
</div>
</t-dialog>
<!-- 优势,劣势 -->
<div class="advantage-content" v-if="advantageList.length > 0">
<div class="item-left advantage-bg">优势</div>
<div class="item-right">
<div class="list-content">
<div class="list-item" v-for="(item, index) in advantageList" :key="index"
@click="YLData = item; YLModel = true">
<div class="item-title" style="font-weight: 700;">{{ item.title }}</div>
<!-- <div class="item-title" style="font-weight: 300;margin-top: 10px;">{{ item.content }}</div> -->
</div>
</div>
</div>
</div>
<t-empty v-if="advantageList.length === 0" />
<div class="advantage-content" v-if="disadvantageList.length > 0">
<div class="item-left disadvantage-bg">劣势</div>
<div class="item-right">
<div class="list-content">
<div class="list-item" v-for="(item, index) in disadvantageList" :key="index"
@click="YLData = item; YLModel = true">
<div class="item-title" style="font-weight: 700;">{{ item.title }}</div>
<!-- <div class="item-title" style="font-weight: 300;margin-top: 10px;">{{ item.content }}</div> -->
</div>
</div>
</div>
</div>
<t-empty v-if="disadvantageList.length === 0" />
<!-- ZZ力量优劣势 -->
<div class="title-content-item margin-bottom-10">ZZ力量优劣势</div>
<div class="zz-content">
<div class="zz-list-content">
<div class="item-content" v-for="(value, key) in zzList" :key="key">
<div class="item-title">
{{ key }}
</div>
<div class="item-footer">
<template v-if="Array.isArray(value)">
<div class="row" style="margin: 5px 0;" v-for="item in value">
<div class="title" style="color: #fff;">
{{ item['维度'] }}:{{ item['判定'] }}
</div>
<div class="content" style="border-bottom: 1px solid #777;">描述:{{ item['描述'] }}</div>
</div>
</template>
<template v-else-if="isObject(value)">
<div class="row" style="margin: 5px 0;" v-for="(v, k) in value">
{{ k }}:{{ v }}
</div>
</template>
<template v-else>
{{ value }}
</template>
</div>
</div>
</div>
</div>
</div>
<!-- 条件与限制 -->
<div v-if="tabIndex === 2" class="conditions-constraints">
<t-space style="width: 100%" v-if="legalData" direction="vertical">
<t-collapse :expand-icon-placement="'right'" :defaultExpandAll="true" @change="handlePanelChange">
<t-collapse-panel :value="key" v-for="(value, key) in legalData" :key="key">
<template #header>
<div class="title-content-item">{{ key }}</div>
</template>
<template #default>
<div class="padding-10" v-for="(item, index) in value" :key="index">
{{ index + 1 }}.{{ item }}
</div>
</template>
</t-collapse-panel>
</t-collapse>
</t-space>
<div v-if="!legalData" class="padding-10">
<t-empty />
</div>
</div>
<!-- 风险及应对 -->
<div v-if="tabIndex === 3" class="risks-responses">
<t-space style="width: 100%" direction="vertical">
<t-collapse :expand-icon-placement="'right'" :defaultExpandAll="true" @change="handlePanelChange">
<t-collapse-panel :value="key" v-for="(value, key) in riskData" :key="key">
<template #header>
<div class="title-content-item">{{ key }}</div>
</template>
<template #default>
<div class="padding-10" v-for="(item, index) in value" :key="index">
{{ index + 1 }}.{{ item }}
</div>
</template>
</t-collapse-panel>
<!-- <t-collapse-panel value="0">
<template #header>
<div class="title-content-item">风险分析</div>
</template>
<template #default>
这部分是每个折叠面板折叠或展开的内容,可根据不同业务或用户的使用诉求,进行自定义填充。可以是纯文本、图文、子列表等内容形式。
</template>
</t-collapse-panel>
<t-collapse-panel value="1">
<template #header>
<div class="title-content-item">应对方案</div>
</template>
<template #default>
这部分是每个折叠面板折叠或展开的内容,可根据不同业务或用户的使用诉求,进行自定义填充。可以是纯文本、图文、子列表等内容形式。
</template>
</t-collapse-panel> -->
</t-collapse>
</t-space>
</div>
</t-loading>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from "vue";
import * as echarts from 'echarts';
import { requestAxiosService } from "@/service/request-axios-service";
import { index } from "d3";
const isObject = (value) => {
return value !== null && Object.prototype.toString.call(value) === '[object Object]';
}
const addModelConfig = () => {
}
const YLModel = ref(false)
const YLData = ref({})
const props = defineProps({
msg: String,
taskId: Number
});
const tabIndex = ref(1); // 1 优劣势分析 2 条件与劣势 3 风险及应对
const advantageList = ref([
// 优势
// { title: "内容内容内容内容内容内容内容内容内容内容" },
// { title: "内容内容内容内容内容内容内容内容内容内容" },
// { title: "内容内容内容内容内容内容内容内容内容内容" },
]);
const disadvantageList = ref([
//劣势
// { title: "内容内容内容内容内容内容内容内容内容内容" },
// { title: "内容内容内容内容内容内容内容内容内容内容" },
// { title: "内容内容内容内容内容内容内容内容内容内容" },
]);
const zzList = ref({});
const opinionPieList = ref([
{
value: 1500,
name: '支持我方观点',
itemStyle: {
color: '#7acaa4'
}
},
{
value: 735,
name: '中立观点',
itemStyle: {
color: '#c8cdd5'
}
},
{
value: 1500,
name: '反对我方观点',
itemStyle: {
color: '#f5a444'
}
}
]);
let colors = ['#7acaa4', '#c8cdd5', '#f5a444'];
const opinionPieLists = ref([
{
value: 1500,
name: '支持我方观点',
itemStyle: {
color: '#7acaa4'
}
},
{
value: 735,
name: '中立观点',
itemStyle: {
color: '#c8cdd5'
}
},
]);
const strengthsData = ref(null) // 优劣势分析
const legalData = ref(null); // 条件与劣势
const riskData = ref(null); // 风险及建议
const chartRef = ref(null);
const service = requestAxiosService;
const loading = ref(false);
onMounted(() => {
})
const initPieChart = () => {
let chartPie = echarts.init(chartRef.value);
const option = {
title: {
text: '',
left: 'center',
top: 'center'
},
legend: {
show: false // 隐藏图例
},
tooltip: {
show: true,
appendTo: 'body',
formatter: function (params) {
// console.log('params数据',params);
let text = ``;
text = `
<div class="pint-pie__tooltip">
<div>${params.data.name}</div>
<div>
<span class="">${params.data.value}</span>
</div>
</div>
`;
return text;
}
},
series: [
{
name: '访问来源',
type: 'pie',
radius: ['50%', '85%'], // 设置圆环的内径和外径
// padAngle: 2,
// avoidLabelOverlap: false,
itemStyle: {
borderColor: '#fff',
// borderRadius: 4,
borderWidth: 0
},
label: {
show: false
},
labelLine: {
show: false // 隐藏标签线
},
emphasis: {
disabled: true,
label: {
show: false,
fontSize: '20',
fontWeight: 'bold'
}
},
data: opinionPieList.value
},
{
name: '外边框',
type: 'pie',
radius: ['90%', '90%'],
center: ['50%', '50%'],
emphasis: {
disabled: true
},
label: {
show: false
},
labelLine: {
show: false // 隐藏标签线
},
tooltip: {
show: false
},
data: [
{
value: 0,
name: '',
itemStyle: {
borderWidth: 1,
borderColor: '#e4e9f4'
}
}
]
}
]
}
chartPie.setOption(option)
}
const tabChange = async (value) => {
// tabs标签页点击
tabIndex.value = value;
await querySituationEvaluation(props.taskId);
};
const handlePanelChange = (value) => {
console.log(value);
};
const querySituationEvaluation = async (taskId) => {
const parmy = {
taskId,
type: tabIndex.value
}
loading.value = true;
const res = await service.get(`${environment['b1ConsumerUrl']}/cop/querySituationEvaluation`, parmy);
console.log('情况判断', res);
loading.value = false;
let result = res.data;
if (tabIndex.value === 1) {
strengthsData.value = result;
advantageList.value = result['民意认知优劣势']['优势'];
disadvantageList.value = result['民意认知优劣势']['劣势'];
zzList.value = result['作战力量优劣势'];
opinionPieList.value = [];
for (let key in result['民意认知优劣势']['观点占比']) {
opinionPieList.value.push({
value: Number(result['民意认知优劣势']['观点占比'][key].replace(/%/g, '')),
name: key,
itemStyle: {
color: '#7acaa4'
}
})
}
opinionPieList.value.forEach((item, index) => {
item.itemStyle.color = colors[index];
});
console.log('观点占比', opinionPieList.value)
setTimeout(() => {
initPieChart();
}, 100)
} else if (tabIndex.value === 2) {
console.log(result);
legalData.value = result;
} else if (tabIndex.value === 3) {
riskData.value = result;
}
}
watch(() => props.taskId, (newVal, oldVal) => {
// console.log('count changed from', oldVal, 'to', newVal);
if (newVal) {
// getTaskActorDetailSearch(newVal);
querySituationEvaluation(newVal);
}
}, { immediate: true });
</script>
<style scoped lang="less">
.situation-assessment {
z-index: 500;
height: calc(100vh - 180px);
overflow-y: auto;
color: #fff;
padding: 10px;
.advantage-analysis {
padding: 0 12px;
.pie-charts {
width: 100%;
height: 150px;
background: rgba(1, 12, 28, 0.15);
}
.advantage-content {
padding: 10px;
display: flex;
align-items: stretch;
/* 使子元素在垂直方向上伸展 */
justify-content: space-between;
.advantage-bg {
background: rgba(0, 238, 255, 0.2);
}
.disadvantage-bg {
background: rgba(245, 34, 45, 0.3);
}
.item-left {
padding: 2px;
border-radius: 4px;
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #ffffff;
font-size: var(--fontSize);
text-align: center;
display: flex;
align-items: center;
}
.item-right {
flex-grow: 1;
.list-content {
.list-item {
font-family: Noto Sans S Chinese;
color: #ffffff;
font-size: var(--fontSize);
margin-bottom: 10px;
margin-left: 10px;
line-height: var(--fontSize);
background: rgba(0, 98, 217, 0.1);
padding: 10px 15px;
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 2px;
&:hover {
background: rgba(0, 98, 217, 0.3);
border-color: rgba(85, 166, 254, 0.1);
}
}
}
}
}
.zz-content {
padding: 10px;
.zz-list-content {
.item-content {
width: 100%;
background: rgba(1, 12, 28, 0.15);
border-radius: 4px;
padding: 10px 20px;
margin-bottom: 10px;
&:hover {
background: rgba(0, 98, 217, 0.3);
border-color: rgba(85, 166, 254, 0.1);
}
.item-title {
line-height: 36px;
font-family: "Noto Sans S Chinese";
color: #ffffff;
font-size: var(--titleSize);
}
.item-footer {
line-height: 28px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: rgba(255, 255, 255, 0.8);
}
}
}
}
}
.conditions-constraints {
padding: 0 12px;
}
.viewpoint-item {
padding: 10px;
border-radius: 4px;
background: rgba(0, 140, 119, 0.1);
margin-bottom: 10px;
.item-footer {
color: #7acaa4;
}
}
}
// 折叠面板整体样式
:deep(.t-collapse) {
font: var(--td-font-body-medium);
color: var(--td-text-color-primary);
box-sizing: border-box;
margin: 0;
padding: 0;
list-style: none;
border: none !important;
border-bottom: 0;
background: #24242400 !important;
}
// 折叠面板标题样式
:deep(.t-collapse-panel__wrapper .t-collapse-panel__header) {
padding: var(--td-comp-paddingTB-m) var(--td-comp-paddingLR-l);
border-bottom: none !important;
font: var(--td-font-title-small);
display: flex;
align-items: center;
}
// 折叠面板背景样式
:deep(.t-collapse-panel__wrapper .t-collapse-panel__body) {
border-bottom: none !important;
background: #24242400 !important;
overflow: inherit;
}
//折叠面板内容样式
:deep(.t-collapse-panel__wrapper .t-collapse-panel__content) {
padding: var(--td-comp-paddingTB-m) var(--td-comp-paddingLR-l) var(--td-comp-paddingTB-m) calc(var(--td-comp-paddingLR-l) + var(--td-comp-margin-xxl));
color: var(--td-text-color-primary) !important;
font-family: "Arial Negreta", "Arial Normal", "Arial", sans-serif;
// font-weight: 700;
font-style: normal;
// font-size: var(--titleSize);
}
</style>
@@ -0,0 +1,35 @@
<template>
<div class="task-analysis">
<TaskDataSearch v-if="!taskDetailShow" @taskDetailsC="taskDataChange"/>
<AnalysisData v-if="taskDetailShow"/>
</div>
</template>
<script setup>
import { ref, defineEmits } from 'vue';
import TaskDataSearch from './TaskAnalysis/TaskDataSearch.vue';
import AnalysisData from './TaskAnalysis/AnalysisData.vue';
import dayjs from 'dayjs';
defineProps({
msg: String,
taskDetailShow: Boolean
})
const taskData = ref({})
const emit = defineEmits(['taskDetailsC']) // 定义子组件发送给父组件的函数
const taskDataChange = (value) => { // 任务点击
taskData.value = value;
emit('taskDetailsC', value); // 给父组件传参
}
</script>
<style scoped lang="less">
.task-analysis {
width: 100%;
height: 100%;
z-index: 500;
color: #fff;
padding: 10px;
}
</style>
@@ -0,0 +1,719 @@
<template>
<div class="task-analysis">
<!-- 任务详情 -->
<div>
<div class="task-list-item task-detail cursor-pointer">
<div class="task-status-logo" :class="handleBg(taskData.taskStatus)">{{ taskData.taskStatus < 30 ?
taskStatus[taskData.taskStatus] : '已完成' }}</div>
<div class="item-title">{{ taskData.taskName }}</div>
<div class="tab-list">
<span class="item-tab tab-green">{{ taskData.taskDirection }}</span>
<span class="item-tab tab-lightblue">{{ taskLevel[taskData.taskLevel] }}</span>
</div>
<div class="item-content text-ellipsis ellipsis3">
{{ taskData.overview }}
</div>
<div class="item-footer flex-content">
<span class="item-label">
{{ sourceTypeDict[taskData.sourceType] }}
</span>
<span class="item-date">
{{ dayjs(taskData.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</span>
</div>
</div>
<!-- 分析结果 -->
<div class="title-content-item margin-bottom-10 flex-content">
<span>分析结果</span>
<span class="task-back" v-if="aimData" @click="treeMapChange">
<img src="../../assets/icon/tree-map-logo.svg" style="margin-right: 5px;" alt="" />
逻辑图
</span>
</div>
<t-loading :loading="taskLoading" show-overlay>
<div class="analysis-content">
<!-- 顶部tab页 -->
<!-- <div class="tabs-list">
<div class="tabs-item" :class="{ 'item-active': tabIndex === 0 }" @click="tabChange(0)">
支撑性目的1
</div>
<div class="tabs-item" :class="{ 'item-active': tabIndex === 1 }" @click="tabChange(1)">
支撑性目的2
</div>
</div> -->
<t-tabs v-model="tabIndex" @change="tabChange" theme="card">
<t-tab-panel v-for="(item, index) of taskDataList" :value="index" :label="'支持性目的' + (index + 1)"
:destroy-on-hide="false" :key="index">
</t-tab-panel>
</t-tabs>
<t-loading :loading="actorLoading" show-overlay>
<!-- 目的详情 -->
<div class="aim-item-card" @click="chatShowChange">
<div v-if="aimData" class="item-content">
<span class="aim-logo">目的</span><span style="margin-right: 50px;"></span>{{ aimData.zzPurpose }}
</div>
<t-empty v-if="!aimData" />
</div>
<!-- 行为体列表 -->
<div class="action-content">
<t-empty v-if="actorDataList?.length === 0" />
<div class="task-list-item" v-for="(item, index) in actorDataList" :key="index"
@click="actionShowChange(item)">
<div class="item-content text-ellipsis ellipsis3">
<span class="item-tab tab-blue">行为体</span> {{ item.actorMap[0].actorName }}
</div>
<div class="item-footer flex-content">
<!-- <span>
{{ item.deptName }}
</span> -->
<!-- <span>
<span class="item-value">2025-05-10 ~ 2025-05-25</span>
</span> -->
</div>
</div>
</div>
</t-loading>
</div>
</t-loading>
</div>
</div>
<t-dialog v-model:visible="visibles" header="详情" width="700" :confirm-on-enter="true" :on-cancel="handleCancels"
:on-close="handleCancels" :on-confirm="handleOks">
<t-space direction="vertical" style="width: 100%;">
<div class="action-details">
<!-- <div class="item-head">
桃色与军纪舆论裂变攻台军形象
</div>
<div class="item-card">
支撑性目的:利用桃色新闻与军纪涣散议题,瓦解台军社会形象与民众支持基础,引发线上网红、大V等对台军……
</div> -->
<!-- 顶部标签页 -->
<!-- <TabsContent :tabIndex="tabIndexs" :tabsList="tabsList"
:tabStyle="{ 'textAlign': 'left', 'borderBottom': '1px solid rgba(0, 98, 217, 0.4)' }"
@tabsDataC="tabDataChange" /> -->
<div class="tab-content">
<template v-for="(item, index) in tabsList" :key="index">
<div class="item-tab" :class="{ 'item-active': tabIndexs === item.value }"
@click="tabDataChange(item.value)">
{{ item.label }}
</div>
</template>
</div>
<div class="narrate-list" v-if="tabIndexs === 'narrate'">
<div class="item-card" v-for="(item, index) in narrateList" :key="index">
<div class="item-title">
<span class="item-index">{{ index + 1 }}</span>. {{ item.narration }}
</div>
</div>
</div>
<div class="narrate-list" v-if="tabIndexs !== 'narrate'">
<div class="item-card" v-for="(item, index) in behaviorList" :key="index">
<div class="item-content">
预期行为:{{ item.behavior }}
</div>
<div class="item-line"></div>
<div class="item-content" v-for="(aItem, aIndex) in item.factorList" :key="aIndex">
驱动因素:{{ aItem.drivingFactor }}
</div>
</div>
</div>
</div>
</t-space>
</t-dialog>
<t-dialog v-model:visible="treeMapShow" header="详情" width="1400" attach="body" :confirm-on-enter="true"
:on-cancel="handleTreeMapCancel" :on-close="handleCancels" :on-confirm="handleTreeMapOk">
<t-space direction="vertical" style="width: 100%;">
<div>
<TreeDataMap v-if="treeMapShow" :taskId="taskData.id" :taskData="taskData" />
</div>
</t-space>
</t-dialog>
<t-drawer v-model:visible="visible" attach="body" size="75%" :footer="false" :closeBtn="false"
:on-confirm="handleCancel" :close-btn="true">
<template #header>
<div class="drawer-head" @click="handleCancel">
<arrow-left-icon :stroke-width="2.5" fillColor="#fff" size="25px" />
<span>返回</span>
<span style="margin-top: -2px;">|</span>
<span style="margin-left: 10px;">智能参谋</span>
</div>
</template>
<div>
<IntelligentHelperDrawer />
</div>
</t-drawer>
</template>
<script setup>
import { ref, reactive, defineEmits, watch } from 'vue';
import TaskList from './TaskDataList.vue';
import TabsContent from '../views/TabsContent.vue';
import { ArrowLeftIcon } from 'tdesign-icons-vue-next';
import IntelligentHelperDrawer from '../intelligent-helper-drawer/IntelligentHelperDrawer.vue';
import taskStatus from '@/common/taskStatus';
import taskLevel from '@/common/taskLevel';
import sourceTypeDict from '@/common/sourceType';
import TreeDataMap from '@/components/TreeDataMap.vue';
import { requestAxiosService } from '@/service/request-axios-service';
import dayjs from 'dayjs';
const props = defineProps({
msg: String,
taskData: Object,
})
const inputValue = ref(''); // 输入款内容
const taskRadioValue = ref('all') // 任务类型选择
const presets = ref({
最近7天: [dayjs().subtract(6, 'day').toDate(), dayjs().toDate()],
最近3天: [dayjs().subtract(2, 'day').toDate(), dayjs().toDate()],
今天: [dayjs().toDate(), dayjs().toDate()],
});
const taskList = ref([
{ title: '任务01', taskStatus: '已完成', taskLogo: 'task-completed' },
{ title: '任务01', taskStatus: '分析中', taskLogo: 'task-uncompleted' },
{ title: '任务01', taskStatus: '待分析', taskLogo: 'task-pendinganalysis' },
{ title: '任务01', taskStatus: '未通过', taskLogo: 'task-failed' },
{ title: '任务01', taskStatus: '已完成', taskLogo: 'task-completed' },
]);
const actionList = ref([
{ title: '行动01', taskStatus: '已完成', taskLogo: 'task-completed' },
{ title: '行动01', taskStatus: '分析中', taskLogo: 'task-uncompleted' },
{ title: '行动01', taskStatus: '待分析', taskLogo: 'task-pendinganalysis' },
{ title: '行动01', taskStatus: '未通过', taskLogo: 'task-failed' },
{ title: '行动01', taskStatus: '已完成', taskLogo: 'task-completed' },
]);
const taskDataList = ref([]); // 任务信息列表
const taskLoading = ref(false);
const aimData = ref(null) // 目的信息
const actorDataList = ref([]); // 行为体信息
const actorLoading = ref(false);
const range = ref([]); // 日期时间筛选框
const taskDetailShow = ref(false);
const tabIndex = ref(0) // tab页切换
const emit = defineEmits(['taskDetailsC']) // 定义子组件发送给父组件的函数
const visible = ref(false);
const visibles = ref(false); // 对话框
const treeMapShow = ref(false) // 逻辑图
const tabIndexs = ref('narrate'); // narrate 叙事主题 behavior 预期行为
const tabsList = ref([
{ label: '叙事主题', value: 'narrate' },
{ label: '预期行为', value: 'behavior' },
])
const narrateList = ref([
{ title: '台军桃色丑闻频发暴露军纪涣散' },
{ title: '飞行事故频发揭穿台军装备老旧与训练造假' },
])
const behaviorList = ref([
{ actor: '台军各军种单位', behavior: '通过社交媒体或媒体渠道揭露上级贪腐、性丑闻等(如陆军109旅贩毒案后内部爆料)' },
]);
const service = requestAxiosService;
const handleBg = d => {
const colorList = {
20: 'uncompleted',
10: 'pendinganalysis',
50: 'failed',
}
return colorList[d] || 'completed'
}
// 查询zz目的
const getTaskActorDetailSearch = async (taskId) => {
const parmy = {
taskId,
}
taskLoading.value = true;
const res = await service.get(`${environment['b1ConsumerUrl']}/cop/findZzPurposeByTaskId`, parmy);
taskLoading.value = false;
console.log(res);
taskDataList.value = res.data;
if (taskDataList.value?.length > 0) {
await tabChange(0);
}
}
// 查询zz目的下的行为体等信息
const findActionDataByZzIdSearch = async (purposeId) => {
const parmy = {
purposeId,
}
actorLoading.value = true;
const res = await service.get(`${environment['b1ConsumerUrl']}/cop/findActionDataByZzId`, parmy);
actorLoading.value = false;
console.log(res);
actorDataList.value = res.data;
}
watch(props.taskData, (newVal, oldVal) => {
// console.log('count changed from', oldVal, 'to', newVal);
if (newVal) {
getTaskActorDetailSearch(newVal.id);
}
}, { immediate: true });
const tabDataChange = (value) => {
tabIndexs.value = value;
}
const actionShowChange = (item) => {
console.log('这是什么', item);
narrateList.value = item.narrationMap;
behaviorList.value = [];
item.expectedBehaviorMap.forEach((aItem, index) => {
behaviorList.value.push({
behavior: aItem.behavior,
factorList: [item.drivingFactorMap[index]],
})
})
visibles.value = true;
}
const handleOks = () => {
visibles.value = false;
}
const handleCancels = () => {
visibles.value = false;
}
const chatShowChange = () => {
visible.value = true;
}
const handleOk = () => {
visible.value = false;
};
const handleCancel = () => {
visible.value = false;
}
// 逻辑图
const treeMapChange = () => {
treeMapShow.value = true;
}
const handleTreeMapOk = () => {
treeMapShow.value = false;
};
const handleTreeMapCancel = () => {
treeMapShow.value = false;
}
// 回车搜索
const onEnter = () => {
}
// tab页切换
const tabChange = async (value) => {
console.log('点击了', value);
aimData.value = taskDataList.value[value];
console.log(aimData);
await findActionDataByZzIdSearch(aimData.value.id);
tabIndex.value = value;
}
// 任务类型选择
const taskChange = (value) => {
taskRadioValue.value = value
}
</script>
<style scoped lang="less">
.task-analysis {
width: 100%;
height: 100%;
z-index: 500;
color: #fff;
padding: 15px;
display: flex;
flex-direction: column;
overflow-y: auto;
.task-detail {
padding: 15px 20px !important;
margin: 0 !important;
margin-bottom: 10px !important;
}
// 任务信息
.task-information {
width: 100%;
height: 267px;
background: url('../assets/icon/task-data-bg.png') no-repeat;
background-size: cover;
margin-bottom: 25px;
display: flex;
justify-content: space-around;
.list-item {
width: 115px;
height: 100%;
.item-head {
width: 95px;
height: 95px;
border: 3px solid #ec9004;
border-radius: 50%;
margin: 0 auto;
margin-top: 30px;
position: relative;
.item-logo {
width: 81px;
height: 81px;
background: url('../assets/icon/map-icon-logo.png');
background-position: -500px -79px;
position: absolute;
left: 50%;
top: 5px;
transform: translate(-50%);
font-size: var(--titleSize);
color: #7fcdff;
line-height: 81px;
text-align: center;
}
}
.item-body {
padding: 10px 0;
.item-content {
margin-bottom: 10px;
font-size: var(--fontSize);
display: flex;
align-items: center;
.item-point {
height: 10px;
width: 10px;
margin-right: 10px;
border-radius: 5px;
display: inline-block;
}
.item-title {
color: #73c7ec;
margin-right: 20px;
font-family: Noto Sans S Chinese;
}
.item-value {
font-family: 'DDIN';
}
}
}
}
}
.aim-item-card {
background: rgba(0, 98, 217, 0.4);
border: 1px solid;
border-color: #0062d9;
border-radius: 4px;
margin: 15px;
padding: 10px;
position: relative;
.item-content {
line-height: 26px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: 18px;
.aim-logo {
background: rgba(160, 224, 249, 0.28);
border-radius: 4px 0px 12px 0px;
padding: 5px 10px;
line-height: 16px;
font-size: 16px;
position: absolute;
top: 0;
left: 0;
}
}
}
.task-back {
// background: linear-gradient(102.76deg, #2b8ffe 0%, #0062d9 100%);
background: #00368c;
border: 1px solid;
border-color: #0056c6;
border-radius: 4px;
padding: 5px 10px;
line-height: var(--fontSize);
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSize);
display: flex;
align-items: center;
cursor: pointer;
}
/* 垂直排列子元素 */
.task-body {
padding: 10px;
// flex-grow: 1; /* 让 div 填充剩余空间 */
height: calc(100vh - 225px);
box-sizing: border-box;
overflow-y: auto;
}
.task-list-item {
padding: 10px;
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
margin: 15px;
position: relative;
cursor: pointer;
overflow: hidden;
&:hover {
background: rgba(0, 98, 217, 0.4);
border: 1px solid;
border-color: #0062d9;
}
.task-status-logo {
width: 132px;
height: 30px;
transform: rotate(45deg);
position: absolute;
top: 12px;
text-align: center;
line-height: 30px;
right: -36px;
}
.completed {
background: linear-gradient(134.57deg, #05b89f 14.74%, #007f73 84.95%);
}
.uncompleted {
background: linear-gradient(134.57deg, #d09a14 14.74%, #a76e12 84.95%);
}
.pendinganalysis {
background: linear-gradient(134.57deg, #117dff 14.74%, #0057b8 84.95%);
}
.failed {
background: linear-gradient(134.57deg, #838383 14.74%, #5e5e5e 84.95%);
}
.item-title {
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #ffffff;
font-size: var(--titleSize);
line-height: 24px;
margin-bottom: 10px;
}
.tab-list {
margin-bottom: 10px;
.item-tab {
display: inline-block;
line-height: var(--fontSizes);
padding: 5px 10px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSizes);
border: 1px solid;
border-radius: 4px;
margin-right: 5px;
}
}
.item-content {
line-height: 29px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSize);
margin-bottom: 10px;
}
.item-footer {
font-size: var(--fontSizes);
color: rgba(255, 255, 255, 0.8);
.item-label {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: rgba(255, 255, 255, 0.8);
font-size: var(--fontSize);
}
.item-date {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: rgba(255, 255, 255, 0.8);
font-size: var(--fontSize);
}
}
}
}
// 详情弹窗页面
.action-details {
.item-head {
font-size: var(--fontSize);
font-family: 'Noto Sans S Chinese';
padding: 10px;
}
.item-card {
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
padding: 10px;
margin-top: 10px;
margin-bottom: 15px;
.item-index {
font-family: 'Noto Sans S Chinese';
font-weight: 500;
}
.item-title {
// font-size: var(--fontSize);
font-family: 'Noto Sans S Chinese';
// font-weight: 500;
margin-bottom: 5px;
}
}
}
.narrate-list {
.item-card {
background: rgba(1, 12, 28, 0.15);
border-radius: 4px;
padding: 15px;
margin: 10px 0;
.item-index {
font-family: Noto Sans S Chinese;
font-weight: 700;
color: #ffffff;
font-size: var(--fontSize);
}
.item-title {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #ffffff;
font-size: var(--fontSize);
}
.item-content {
line-height: 23px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: rgba(255, 255, 255, 0.8);
font-size: var(--fontSizes);
}
.item-line {
width: 100%;
height: 1px;
background: rgba(85, 159, 254, 0.25);
border-radius: 4px;
margin: 10px 0;
}
}
}
.tab-content {
width: 100%;
border-bottom: 1px solid rgba(85, 159, 254, 0.4);
.item-tab {
padding: 10px 25px;
background: rgba(3, 38, 80, 0.48);
border: 1px solid;
border-color: #0e3668;
border-radius: 4px 4px 0px 0px;
font-family: Noto Sans S Chinese;
color: rgba(255, 255, 255, 0.8);
font-size: var(--fontSize);
display: inline-block;
cursor: pointer;
}
.item-active {
border: 0;
background: linear-gradient(99.41deg, #2b8ffe 0%, #0062d9 100%);
border-radius: 4px 4px 0px 0px;
color: #FFFFFF;
}
}
.item-label {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
margin-right: 5px;
}
.item-value {
font-family: 'DDIN';
}
.item-tab {
font-size: var(--fontSizes);
line-height: var(--fontSize);
padding: 5px 10px;
margin-right: 5px;
border: 1px solid;
border-radius: 4px;
}
.sortBtn {
font-size: var(--fontSizes);
padding: 8px 10px;
}
:deep(.t-tabs__nav--card) {
font-size: var(--fontSizes);
background: transparent;
padding: 10px 15px;
}
:deep(.t-tabs__nav--card.t-tabs__nav-item:not(:first-of-type)) {
border: 0;
}
:deep(.t-tabs__nav--card.t-tabs__nav-item.t-is-active) {
background: linear-gradient(103.13deg, #2b8ffe 0%, #0062d9 100%);
border-radius: 24px;
color: #FFFFFF;
position: relative;
&::after {
width: 77px;
height: 2px;
background: url('../../assets/map-icon/tab-line-logo.svg') no-repeat;
background-size: cover;
content: '';
display: block;
position: absolute;
bottom: 0;
}
}
.action-content {
height: calc(100vh - 680px);
overflow-y: auto;
}
</style>
@@ -0,0 +1,142 @@
<template>
<div class="task-list">
<div v-for="(item, index) in taskList" :key="index">
<div class="task-list-item cursor-pointer" @click="taskDataChange(item)">
<div class="task-status-logo" :class="item.taskLogo">{{ item.taskStatus }}</div>
<div class="item-title">{{ item.title }}</div>
<div class="tab-list">
<span class="item-tab tab-green">W方向</span>
<span class="item-tab tab-lightblue">一般</span>
</div>
<div class="item-content">
利用退役飞官言论构建“T军离心力”叙事加强对T方向相关舆论热度。利用退役飞官言论构
</div>
<div class="item-footer flex-content">
<span class="item-label">
来源信息
</span>
<span class="item-date">
2025-05-15 10:16
</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, defineEmits } from 'vue'
defineProps({
taskList: Array,
})
const emit = defineEmits(['taskDetailsC']) // 定义子组件发送给父组件的函数
const count = ref(0)
const taskDataChange = (item) => {
emit('taskDetailsC', item)
}
</script>
<style scoped lang="less">
// 任务列表样式
.task-list {
width: 100%;
.task-list-item {
padding: 10px;
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
margin-bottom: 15px;
position: relative;
overflow: hidden;
&:hover {
background: rgba(0, 98, 217, 0.4);
border: 1px solid;
border-color: #0062d9;
}
.task-status-logo {
width: 132px;
height: 30px;
transform: rotate(45deg);
position: absolute;
top: 12px;
text-align: center;
line-height: 30px;
right: -36px;
}
.task-completed {
background: linear-gradient(134.57deg, #05b89f 14.74%, #007f73 84.95%);
}
.task-uncompleted {
background: linear-gradient(134.57deg, #d09a14 14.74%, #a76e12 84.95%);
}
.task-pendinganalysis {
background: linear-gradient(134.57deg, #117dff 14.74%, #0057b8 84.95%);
}
.task-failed {
background: linear-gradient(134.57deg, #838383 14.74%, #5e5e5e 84.95%);
}
.item-title {
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #ffffff;
font-size: var(--titleSize);
line-height: 24px;
margin-bottom: 10px;
}
.tab-list {
margin-bottom: 10px;
.item-tab {
display: inline-block;
line-height: var(--fontSizes);
padding: 5px 10px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSizes);
border: 1px solid;
border-radius: 4px;
margin-right: 5px;
}
}
.item-content {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSize);
margin-bottom: 10px;
}
.item-footer {
.item-label {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: rgba(255, 255, 255, 0.8);
font-size: var(--fontSize);
}
.item-date {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: rgba(255, 255, 255, 0.8);
font-size: var(--fontSize);
}
}
}
}
</style>
@@ -0,0 +1,367 @@
<template>
<div class="task-analysis">
<!-- 任务信息 -->
<div class="task-information">
<div class="list-item">
<div class="item-head">
<div class="item-logo">
W方向
</div>
</div>
<div class="item-body">
<div class="item-content">
<span class="item-point" style="background-color: rgb(236, 144, 4);"></span>
<span class="item-title">筹划中:</span>
<span class="item-value" style="color: rgb(236, 144, 4);">615</span>
</div>
<div class="item-content">
<span class="item-point" style="background-color: rgb(82, 220, 171);"></span>
<span class="item-title">投送中:</span>
<span class="item-value" style="color: rgb(82, 220, 171);">20</span>
</div>
<div class="item-content">
<span class="item-point" style="background-color: rgb(43, 143, 254);"></span>
<span class="item-title">已完成:</span>
<span class="item-value" style="color: rgb(43, 143, 254);">5</span>
</div>
</div>
</div>
<div class="list-item">
<div class="item-head">
<div class="item-logo">
u方向
</div>
</div>
<div class="item-body">
<div class="item-content">
<span class="item-point" style="background-color: rgb(236, 144, 4);"></span>
<span class="item-title">筹划中:</span>
<span class="item-value" style="color: rgb(236, 144, 4);">615</span>
</div>
<div class="item-content">
<span class="item-point" style="background-color: rgb(82, 220, 171);"></span>
<span class="item-title">投送中:</span>
<span class="item-value" style="color: rgb(82, 220, 171);">20</span>
</div>
<div class="item-content">
<span class="item-point" style="background-color: rgb(43, 143, 254);"></span>
<span class="item-title">已完成:</span>
<span class="item-value" style="color: rgb(43, 143, 254);">5</span>
</div>
</div>
</div>
</div>
<!-- 任务列表 -->
<div>
<div class="task-head">
<!-- 任务筛选 -->
<div class="margin-bottom-10">
<t-row :gutter="16">
<t-col :span="7">
<div>
<t-input v-model="inputValue" placeholder="请输入内容搜索" @enter="onEnter" />
</div>
</t-col>
<t-col :span="5">
<t-select>
<t-option key="待分析" label="待分析" value="待分析" />
<t-option key="分析中" label="分析中" value="分析中" />
<t-option key="已完成" label="已完成" value="已完成" />
</t-select>
</t-col>
</t-row>
</div>
<div>
<t-row :gutter="16">
<t-col :span="8">
<div>
<t-date-range-picker v-model="range" :presets="presets" enable-time-picker />
</div>
</t-col>
<t-col :span="4">
<div class="tabs-box">
<span class="sortBtn" :class="{ 'sort-active': taskRadioValue === 'all' }"
@click="taskChange('all')">全部</span>
<span class="sortBtn" :class="{ 'sort-active': taskRadioValue === 'me' }"
@click="taskChange('me')">我的</span>
</div>
</t-col>
</t-row>
</div>
</div>
<!-- 任务列表 -->
<div class="task-body">
<TaskList :taskList="taskList" @taskDetailsC="taskDataChange" />
</div>
</div>
</div>
</template>
<script setup>
import { ref, defineEmits } from 'vue';
import TaskList from './TaskDataList.vue';
import dayjs from 'dayjs';
defineProps({
msg: String,
})
const inputValue = ref(''); // 输入款内容
const taskStatus = ref('a'); // 任务状态
const taskRadioValue = ref('all') // 任务类型选择
const presets = ref({
最近7天: [dayjs().subtract(6, 'day').toDate(), dayjs().toDate()],
最近3天: [dayjs().subtract(2, 'day').toDate(), dayjs().toDate()],
今天: [dayjs().toDate(), dayjs().toDate()],
});
const taskList = ref([
{ title: '任务01', taskStatus: '已完成', taskLogo: 'task-completed' },
{ title: '任务01', taskStatus: '分析中', taskLogo: 'task-uncompleted' },
{ title: '任务01', taskStatus: '待分析', taskLogo: 'task-pendinganalysis' },
{ title: '任务01', taskStatus: '未通过', taskLogo: 'task-failed' },
{ title: '任务01', taskStatus: '已完成', taskLogo: 'task-completed' },
]);
const actionList = ref([
{ title: '行动01', taskStatus: '已完成', taskLogo: 'task-completed' },
{ title: '行动01', taskStatus: '分析中', taskLogo: 'task-uncompleted' },
{ title: '行动01', taskStatus: '待分析', taskLogo: 'task-pendinganalysis' },
{ title: '行动01', taskStatus: '未通过', taskLogo: 'task-failed' },
{ title: '行动01', taskStatus: '已完成', taskLogo: 'task-completed' },
])
const range = ref([]); // 日期时间筛选框
const taskDetailShow = ref(false);
const taskData = ref({})
const tabIndex = ref(0) // tab页切换
const emit = defineEmits(['taskDetailsC']) // 定义子组件发送给父组件的函数
// 回车搜索
const onEnter = () => {
}
// tab页切换
const tabChange = (value) => {
tabIndex.value = value;
}
// 任务类型选择
const taskChange = (value) => {
taskRadioValue.value = value
}
const taskDataChange = (value) => { // 任务点击
taskDetailShow.value = true;
taskData.value = value;
emit('taskDetailsC', value); // 给父组件传参
}
</script>
<style scoped lang="less">
.task-analysis {
width: 100%;
height: 100%;
z-index: 500;
color: #fff;
padding: 15px;
display: flex;
flex-direction: column;
// 任务信息
.task-information {
width: 100%;
height: 260px;
background: url('../../assets/icon/task-data-bg.png') no-repeat;
background-size: cover;
margin-bottom: 25px;
display: flex;
justify-content: space-around;
.list-item {
width: 115px;
height: 100%;
.item-head {
width: 95px;
height: 95px;
border: 3px solid #ec9004;
border-radius: 50%;
margin: 0 auto;
margin-top: 30px;
position: relative;
.item-logo {
width: 81px;
height: 81px;
background: url('../../assets/icon/map-icon-logo.png');
background-position: -500px -79px;
position: absolute;
left: 50%;
top: 5px;
transform: translate(-50%);
font-size: var(--titleSize);
color: #7fcdff;
line-height: 81px;
text-align: center;
}
}
.item-body {
padding: 10px 0;
.item-content {
margin-bottom: 10px;
font-size: var(--fontSize);
display: flex;
align-items: center;
.item-point {
height: 10px;
width: 10px;
margin-right: 10px;
border-radius: 5px;
display: inline-block;
}
.item-title {
color: #73c7ec;
margin-right: 20px;
font-family: Noto Sans S Chinese;
}
.item-value {
font-family: 'DDIN';
}
}
}
}
}
/* 垂直排列子元素 */
.task-body {
padding: 10px;
// flex-grow: 1; /* 让 div 填充剩余空间 */
height: calc(100vh - 225px);
box-sizing: border-box;
overflow-y: auto;
}
.task-list-item {
padding: 10px;
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
margin: 15px;
position: relative;
overflow: hidden;
&:hover {
background: rgba(0, 98, 217, 0.4);
border: 1px solid;
border-color: #0062d9;
}
.task-status-logo {
width: 132px;
height: 30px;
transform: rotate(45deg);
position: absolute;
top: 12px;
text-align: center;
line-height: 30px;
right: -36px;
}
.task-completed {
background: linear-gradient(134.57deg, #05b89f 14.74%, #007f73 84.95%);
}
.task-uncompleted {
background: linear-gradient(134.57deg, #d09a14 14.74%, #a76e12 84.95%);
}
.task-pendinganalysis {
background: linear-gradient(134.57deg, #117dff 14.74%, #0057b8 84.95%);
}
.task-failed {
background: linear-gradient(134.57deg, #838383 14.74%, #5e5e5e 84.95%);
}
.item-title {
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #ffffff;
font-size: var(--titleSize);
line-height: 24px;
margin-bottom: 10px;
}
.tab-list {
margin-bottom: 10px;
.item-tab {
display: inline-block;
line-height: var(--fontSizes);
padding: 5px 10px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSizes);
border: 1px solid;
border-radius: 4px;
margin-right: 5px;
}
}
.item-content {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSize);
margin-bottom: 10px;
}
.item-footer {
font-size: var(--fontSizes);
color: rgba(255, 255, 255, 0.8);
.item-label {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: rgba(255, 255, 255, 0.8);
font-size: var(--fontSize);
}
.item-date {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: rgba(255, 255, 255, 0.8);
font-size: var(--fontSize);
}
}
}
}
.item-label {
font-family: 'Noto Sans S Chinese';
font-size: 15px;
margin-right: 5px;
}
.item-value {
font-family: 'DDIN';
}
.item-tab {
font-size: var(--fontSizes);
line-height: var(--fontSize);
padding: 2px 10px;
margin-right: 5px;
border: 1px solid;
border-radius: 4px;
}
.sortBtn {
font-size: var(--fontSizes);
padding: 8px 10px;
}
</style>
@@ -0,0 +1,335 @@
<template>
<div class="task-details">
<!-- 顶部tab页 -->
<div class="tabs-list">
<div class="tabs-item" :class="{ 'item-active': tabIndex === 'enemy' }" @click="tabChange('enemy')">
敌情
</div>
<div class="tabs-item" :class="{ 'item-active': tabIndex === 'friendly' }" @click="tabChange('friendly')">
我情
</div>
<div class="tabs-item" :class="{ 'item-active': tabIndex === 'zz' }" @click="tabChange('zz')">
Z场环境
</div>
</div>
<!-- 敌情 -->
<div class="enemy-content" v-if="tabIndex === 'enemy'">
<EnemySituation :taskId="taskId" :taskDirection="taskDirection" />
</div>
<!-- 我情 -->
<div class="friendly-content" v-if="tabIndex === 'friendly'">
<OurSituation :taskId="taskId" />
</div>
<div class="enemy-content" v-if="tabIndex === 'zz'">
<BattlefieldEnvironment :taskId="taskId" />
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
import BattlefieldEnvironment from "./TaskDetails/BattlefieldEnvironment.vue";
import OurSituation from "./TaskDetails/OurSituation.vue";
import EnemySituation from "./TaskDetails/EnemySituation.vue";
import { requestAxiosService } from "@/service/request-axios-service"; // 引入发送异步请求方法
const props = defineProps({
msg: String,
taskId: Number, taskDirection: String
});
const tabIndex = ref("enemy"); // enemy 敌情 friendly 我情 zz战场环境
const pieChartData = [
{ value: 335, name: "直接访问" },
{ value: 310, name: "邮件营销" },
{ value: 234, name: "联盟广告" },
{ value: 135, name: "视频广告" },
{ value: 1548, name: "搜索引擎" },
];
const chartTitle = "访问来源";
const state = reactive({
thinkIndex: 0,
thinkList: [],
chatTask: '',
})
const tabChange = (value) => {
tabIndex.value = value;
};
onMounted(async () => {
// await taskGenerateChat();
})
const taskGenerateChat = async () => {
state.thinkIndex = 0;
state.thinkList = [];
state.chatTask = '';
let scoure = new AbortController();
const response = await fetch(`http://ch1.b.uat.4.cn/qq_b1_chat/generate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
prompt: '赖清德',
}),
signal: scoure.signal,
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({ detail: 'Unknown error' }));
throw new Error(errorData.detail || `HTTP error ${response.status}`);
}
if (!response.body) {
throw new Error('Response body is null');
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
const lastLine = lines.pop();
buffer = lastLine || '';
for (let line of lines) {
if (!line.startsWith('data: ')) continue;
try {
// 解析SSE数据
// line = line.replace(/'/g, '"').trim();
const parsedData = JSON.parse(line.slice(6));
const { event, data } = parsedData;
// 处理不同类型的事件
switch (event) {
case 'task_created': {
// taskIdRef.current = data.task_id;
break;
}
case 'tool_call': {
handleToolCall(data);
console.log('任务分析', state.thinkList, state.chatTask);
break;
}
case 'message': {
// 处理消息事件
break;
}
case 'done': {
break;
}
case 'references': {
break;
}
default:
console.log(`未知事件类型: ${event}`, data);
}
} catch (error) {
console.error('JSON解析错误:', error);
console.log('原始数据:', line.slice(6));
}
}
}
}
// 处理工具调用事件
const handleToolCall = (toolData) => {
// 生产环境中可以移除或使用条件日志
// console.log('工具调用:', toolData?.tool_name);
if (state.thinkList.length > 0) {
state.thinkList[state.thinkIndex].thinkLoading = false;
state.thinkIndex = state.thinkList.length - 1;
}
switch (toolData.tool_name) {
case 'show_text': {
const chatText = toolData.tool_input.text || '';
if (chatText.includes('<think>')) {
// 添加新的思考过程
const thinkContent = chatText.replace('<think>', '').replace('</think>', '');
state.thinkList.push({
thinkTitle: thinkContent,
thinkLoading: false,
thinkSearch: null,
searchData: null,
searchResult: null,
list: [],
});
} else {
// 更新总结回答
state.chatTask += chatText;
}
break;
}
case 'google_search': {
if (toolData.tool_input.result) {
state.thinkList[state.thinkIndex].thinkLoading = false;
try {
let result = JSON.parse(toolData.tool_input.result);
let urlMap = new Map();
result.organic = result.organic.filter((item) => {
let url = item.title;
// 如果urlMap中还没有这个url,则添加到Map中并返回true
if (!urlMap.has(item.title)) {
urlMap.set(item.title, true);
return true;
}
return false;
});
console.log('---google_search---', result);
// 更新思考过程的搜索标题和参考列表
if (state.thinkList[state.thinkIndex]) {
state.thinkList[state.thinkIndex].searchTitle = result.query || '';
state.thinkList[state.thinkIndex].list = (result.organic || []).map((item) => ({
title: item.title || '',
content: item.content || item.summary,
url: item.recUuid || ''
}));
}
} catch (error) {
console.error('本地搜索结果JSON解析错误:', error);
// 生产环境中可以移除原始数据日志
// console.error('原始数据:', toolData.tool_input.result);
}
} else if (toolData.tool_input.q) {
state.thinkList[state.thinkIndex].thinkLoading = true;
state.thinkList[state.thinkIndex].thinkSearch = toolData.tool_input.q;
}
break;
}
case 'getTaskLikeTop': {
if (toolData.tool_input.result) {
state.thinkList[state.thinkIndex].thinkLoading = false;
try {
let result = JSON.parse(toolData.tool_input.result);
console.log('---getTaskLikeTop---', result);
// 更新思考过程的搜索标题和参考列表
if (state.thinkList[state.thinkIndex]) {
state.thinkList[state.thinkIndex].searchTitle = result.query || '';
state.thinkList[state.thinkIndex].list = result.data;
}
} catch (error) {
console.error('本地搜索结果JSON解析错误:', error);
// 生产环境中可以移除原始数据日志
// console.error('原始数据:', toolData.tool_input.result);
}
} else if (toolData.tool_input.keyword) {
state.thinkList[state.thinkIndex].thinkLoading = true;
state.thinkList[state.thinkIndex].thinkSearch = toolData.tool_input.keyword;
}
break;
}
case 'scrape_and_extract_info': {
console.log('toolData.tool_input.info_to_extract', toolData.tool_input);
if (toolData.tool_input.info_to_extract) {
state.thinkList[state.thinkIndex].searchData = toolData.tool_input;
} else if (toolData.tool_input.result) {
state.thinkList[state.thinkIndex].searchResult = JSON.parse(toolData.tool_input.result);
}
break;
}
case 'getTaskinfo': {
console.log('toolData.tool_input.info_to_extract', toolData.tool_input)
if (toolData.tool_input.info_to_extract) {
state.thinkList[state.thinkIndex].searchData = toolData.tool_input;
} else if (toolData.tool_input.result) {
state.thinkList[state.thinkIndex].searchResult = toolData.tool_input.result;
}
break;
}
default:
// console.log(`未知工具类型: ${toolData.tool_name}`);
break;
}
};
</script>
<style scoped lang="less">
.task-details {
z-index: 500;
color: #fff;
padding: 10px;
width: 100%;
.t-collapse {
background-color: transparent;
border: 0;
.t-collapse-panel__content {
padding: 0;
}
}
}
// 敌情样式
.enemy-content {
padding: 10px;
box-sizing: border-box;
}
.tab-content {
.item-tab {
display: inline-block;
line-height: var(--fontSize);
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSize);
background: rgba(0, 98, 217, 0.3);
border-radius: 4px;
padding: 5px 10px;
margin: 5px;
cursor: pointer;
.item-count {
font-family: "DDIN";
}
&:hover {
background: #2b86fe;
}
}
.item-active {
background: #2b86fe;
}
}
//我情样式
.friendly-content {
padding: 10px;
box-sizing: border-box;
}
:deep(.t-swiper__arrow-right) {
width: 20px;
height: 28px;
background: rgba(255, 255, 255, 0.15);
border-radius: 4px;
right: -28px;
}
:deep(.t-swiper__arrow-left) {
width: 20px;
height: 28px;
background: rgba(255, 255, 255, 0.15);
border-radius: 4px;
left: -28px;
}
:deep(.t-tabs__nav-item) {
.t-size-m {
height: 100% !important;
line-height: 18px !important;
}
}
.tabs-item {
width: 33%;
}
</style>
@@ -0,0 +1,356 @@
<template>
<div class="battlefield-environment">
<div class="title-content-item margin-bottom-10">信息环境</div>
<div ref="platformPieRef" class="pie-content"></div>
<div class="legendList">
<div class="item" v-for="(item, index) in infoData">
<div class="kuai" :style="{ backgroundColor: colorList[index % colorList.length] }"></div>
<span class="name">{{ item.name }}</span>
<span>{{ item.value }}</span>
<span>条</span>
</div>
</div>
<t-tabs v-model="informationTabIndex" @change="informationTabChange">
<t-tab-panel v-for="(item, index) in informationList" :key="index" :value="index" :label="item.title"
:destroy-on-hide="false">
<div class="environment-content">
<ul>
<li v-for="(items, indexs) in item.content" :key="indexs" v-html="processedText(items)"
@click="renwenHandel($event)">
</li>
</ul>
</div>
</t-tab-panel>
</t-tabs>
<div class="title-content-item margin-bottom-10">人文环境</div>
<t-tabs v-model="humanisticTabIndex">
<t-tab-panel v-for="(item, index) in humanisticList" :key="index" :value="index" :label="item.title"
:destroy-on-hide="false">
<div class="environment-content">
<ul>
<li v-for="(items, indexs) in item.content" :key="indexs" v-html="processedText(items)"
@click="renwenHandel($event)">
</li>
</ul>
</div>
</t-tab-panel>
</t-tabs>
<t-dialog v-model:visible="docDetailsStatus" attach="body" header="详情" width="1200" :confirm-on-enter="true"
:on-confirm="() => docDetailsStatus = false">
<DocDetails :docData="docData" />
</t-dialog>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import * as echarts from "echarts";
import { requestAxiosService } from "@/service/request-axios-service"; // 引入发送异步请求方法
import DocDetails from "../details-dialog/DocDetails.vue";
const service = requestAxiosService;
const props = defineProps({
msg: String,
taskId: Number,
});
const docDetailsStatus = ref(false)
const docData = ref({})
const platformPieRef = ref(null);
const informationTabIndex = ref(0);
const informationList = ref([
]);
const humanisticTabIndex = ref(1);
const humanisticList = ref([]);
const infoData = ref(null)
const colorList = ['#587bf3', '#b6d634', '#575a7b', '#ffa753', '#0cb3ee', '#ffd10a', '#7acaa4', '#c8cdd5', '#f40']
// tab页切换
const informationTabChange = async (value) => {
console.log('点击了', value);
}
onMounted(() => {
platformPieChange();
getRenWen(1) //信息环境
getRenWen(2) //人文环境
});
const informationListDocs = ref([])
const humanisticListDocs = ref([])
//处理[[数字]]
const processedText = (text) => {
return text.replace(/\[\[(\d+)\]\]/g,
`<span class="num-dot">$1</span>`
);
};
// 获取点击的数字
const renwenHandel = (e) => {
if (e.target.classList.contains('num-dot')) {
let num = e.target.innerText
console.log(num);
docDetailsStatus.value = true
docData.value = humanisticListDocs.value[num]
console.log(humanisticListDocs.value);
console.log(docData.value);
}
};
const getRenWen = (type) => {
service
.get(`${environment["b1ConsumerUrl"]}/cop/queryCombatEnvironment`, {
taskId: props.taskId,
// taskId: 3064,
type: type
}).then(res => {
if (type == 1) {
console.log("信息环境", res.data);
informationListDocs.value = res.data.docs
var list = formattedData(res.data.data)
//删除type项
const deleteIndex = list.findIndex(item => item.title == 'type');
if (deleteIndex > -1) {
const [deletedItem] = list.splice(deleteIndex, 1);
list = [...list];
}
//把概况移到首位
const index = list.findIndex(item => item.title === '概览');
if (index > -1) {
const [item] = list.splice(index, 1);
list.unshift(item);
}
informationList.value = list
} else {
console.log("人文环境", res.data);
humanisticListDocs.value = res.data.docs
var list = formattedData(res.data.data)
//删除type项
const deleteIndex = list.findIndex(item => item.title == 'type');
if (deleteIndex > -1) {
const [deletedItem] = list.splice(deleteIndex, 1);
list = [...list];
}
//把概况移到首位
const index = list.findIndex(item => item.title === '概览');
if (index > -1) {
const [item] = list.splice(index, 1);
list.unshift(item);
}
humanisticList.value = list
}
// xushiText.value = res.data
console.log('informationListDocs', informationListDocs.value)
})
}
const processString = (input) => {
// 使用正则表达式提取数字
const match = input.match(/\d+/);
const number = match ? parseInt(match[0], 10) : 0;
// 处理字符串,去除数字及其周围的括号
const processedString = input.replace(/\平台((\d+)个帖子\)/, '').trim();
return {
name: processedString,
value: Number(number) || 0
};
}
const platformPieChange = async () => {
let data = []
await service
.get(
`${environment['b1ConsumerUrl']}/eventAnalysis/informationEnvironment?taskId=${props.taskId}`
).then(res => {
console.log(res);
const result = res.data.split('\n');
let arr = result[1].replaceAll(' ', '').split(',')
arr.forEach(i => {
data.push(processString(i))
});
console.log(data);
})
let chartPie = echarts.init(platformPieRef.value);
infoData.value = data
let count = 0
data.forEach(i => {
count += i.value
})
const option = {
color: colorList,
// 标题
title: {
left: 'center'
},
// 提示框
tooltip: {
trigger: 'item',
formatter: '{a}<br/>{b}: {c} ({d}%)' // 显示系列名、数据名、值和百分比
},
graphic: [{
type: 'text',
left: '80px',
top: 'center',
style: {
text: '账号总数 \n' + count,
fontSize: 16,
textAlign: 'center',
fill: '#fff',
width: '50%',
height: '50%'
}
}],
// 系列配置
series: [
{
name: '数据类型', // 系列名称
type: 'pie', // 类型为饼图
radius: ['50%', '60%'], // 环形内外半径(控制环形宽度)
center: ['30%', '50%'], // 图表中心位置
data: data,
// 设置扇形之间的间隔(通过边框模拟)
itemStyle: {
borderRadius: 0, // 扇形圆角(可选)
borderColor: 'rgba(10, 36, 64, 0.8)', // 分隔线颜色(白色)
borderWidth: 5 // 分隔线宽度(控制间隔大小)
},
// 分隔线配置
splitLine: {
length: 15, // 分隔线长度(从外圆到标签的长度)
lineStyle: { // 分隔线样式
color: 'rgba(255, 255, 255, 0.5)', // 透明度
width: 2
}
},
// 标签配置
label: {
show: false,
formatter: '{b}: {c} ({d}%)', // 标签格式(名称、值、百分比)
position: 'outside', // 标签位置(外部)
color: '#fff' // 标签颜色
},
}
]
};
chartPie.setOption(option);
};
const formattedData = (list) => {
return Object.entries(list).map(([title, content]) => ({
title,
content
}));
}
</script>
<style>
.num-dot {
border-radius: 50%;
display: inline-block;
height: 20px;
width: 20px;
font-size: 12px;
background-color: rgba(0, 12, 28, 0.2);
text-align: center;
line-height: 20px;
cursor: pointer;
}
</style>
<style scoped lang="less">
.battlefield-environment {
position: relative;
z-index: 500;
color: #fff;
padding: 10px;
height: calc(100vh - 200px);
overflow-y: auto;
.pie-content {
width: 100%;
height: 300px;
background: url("@/assets/icon/账号环形图.png");
background-repeat: no-repeat;
background-size: 134px;
background-position: 43px 83px;
}
.environment-content {
line-height: 26px;
font-family: Noto Sans S Chinese;
color: #ffffff;
font-size: var(--fontSize);
padding: 10px;
.item-title {
font-size: var(--fontSize);
font-family: Noto Sans S Chinese;
color: #ffffff;
font-weight: 700;
}
ul {
margin: 10px 25px;
li {
margin-bottom: 5px;
.item-label {
font-size: var(--fontSize);
font-family: Noto Sans S Chinese;
color: #ffffff;
font-weight: 500;
.item-value {
font-size: var(--fontSize);
font-family: Noto Sans S Chinese;
color: #ffffff;
font-weight: 300;
}
}
}
}
}
}
.legendList {
position: absolute;
right: 10px;
top: 100px;
display: flex;
gap: 14px;
height: 200px;
overflow-y: auto;
flex-direction: column;
.kuai {
width: 6px;
height: 6px;
}
.item {
// width: 114px;
height: 22px;
// background: linear-gradient(90deg, rgba(47, 100, 173, 0.4) 0%, rgba(0, 82, 119, 0.04) 100%);
display: flex;
gap: 10px;
align-items: center;
justify-content: space-between;
color: rgba(255, 255, 255, 0.8);
font-size: 14px;
padding: 0 5px;
img {
width: 8px;
height: 8px;
}
.name {
flex: 1;
flex-shrink: 0;
}
}
}
</style>
@@ -0,0 +1,773 @@
<template>
<t-space class="body" direction="vertical">
<t-dialog v-model:visible="targetModelStatus" attach="body" header="任务重要目标" width="1200" :confirm-on-enter="true"
:on-confirm="() => targetModelStatus = false">
<!-- <div class="targetModel">
<div class="title">
<div class="item">
<span>人物</span>
</div>
<div class="item">
<span>组织</span>
</div>
</div>
<div class="contentBox">
<div class="human">
<div v-for="(item, index) in targetList" :key="index">
<div class="targetItem">
<div class="img">
<img :src="item.src" alt="" />
</div>
<div class="info">
<div class="name ">
{{ item.name }}
</div>
<div class="reason ">
{{ item.reason }}
</div>
</div>
</div>
</div>
</div>
<div class="organization">
<div v-for="(item, index) in organization" :key="index">
<div class="targetItem">
<div class="img">
<img :src="item.src" alt="" />
</div>
<div class="info">
<div class="name ">
{{ item.name }}
</div>
<div class="reason ">
{{ item.reason }}
</div>
</div>
</div>
</div>
</div>
</div>
</div> -->
<div class="zl">
<div class="fliter">
<div class="item">
<div class="label">
类型:
</div>
<div class="content">
<t-select v-model="fliterType">
<t-option key="human" label="人物" value="human" />
<t-option key="organization" label="组织" value="organization"></t-option>
</t-select>
</div>
</div>
<div class="item">
<div class="label">
排序:
</div>
<div class="content">
<t-select v-model="fliterSort" @change="sortChange">
<t-option key="2" label="任务相关性" value="2" />
<t-option key="3" label="目标重要性" value="3"></t-option>
<t-option key="7" label="传播可控度" value="7" />
</t-select>
</div>
</div>
</div>
<div class="contentBox">
<div v-for="(item, index) in fliterType === 'human' ? targetList : organization" :key="index">
<div class="targetItem">
<div class="img">
<img :src="item.src" alt="" />
</div>
<div class="info">
<div class="name ">
{{ item.name }}
</div>
<div class="reason ">
{{ item.reason }}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- organization -->
</t-dialog>
<t-collapse v-model="enemyCurrentItem" :expand-icon-placement="'right'" @change="enemyCurrentItemChange">
<t-collapse-panel value="0" :expandIcon="false">
<template #header>
<div class="title-content-item margin-bottom-10" @click.stop="noChange">
<span>
任务重要目标
</span>
<div class="more" @click.stop="openTargetMmdeol">
更多>>
</div>
</div>
</template>
<template #default>
<div class="task-target margin-bottom-10">
<t-loading :loading="targetLoading" show-overlay>
<div class="target-list">
<t-swiper class="tdesign-demo-block--swiper" :duration="300" :interval="2000"
:navigation="{ placement: 'outside' }">
<t-swiper-item v-for="(item, index) in targetList" :key="index">
<div class="item-content flex-between-center" @click="targetListChange(item)">
<div class="item-left">
<img :src="item.src" alt=""
onerror="this.src = 'https://present.a.uat.4.cn/gene/image/img/schema_entity/human@basic_human'" />
</div>
<div class="item-right">
<div class="item-title text-ellipsis ellipsis1">
{{ item.name }}
</div>
<div class="item-footer text-ellipsis ellipsis3">
{{ item.reason }}
</div>
</div>
</div>
</t-swiper-item>
</t-swiper>
</div>
</t-loading>
</div>
</template>
</t-collapse-panel>
<CommonInfoDialog :modelData="modelData" :modelStatus="modelStatus" @updateStatus="v => modelStatus = v"
@config="() => modelStatus = false" />
<t-collapse-panel value="1">
<template #header>
<div class="title-content-item margin-bottom-10">任务关键事件</div>
</template>
<template #default>
<div class="task-event">
<!-- 任务类型 -->
<div class="tab-content">
<template v-for="(item, index) in tabList">
<span class="item-tab" :class="{ 'item-active': tabListIndex == index }" v-if="item.count > 0"
:key="index" @click="tabListIndex = index">
{{ item.topic
}}<span class="item-count">({{ item.count }})</span>
</span></template>
</div>
<!-- 任务事件 -->
<div class="event-list">
<t-loading :loading="eventLoading" show-overlay>
<template v-if="tabList.length > 0">
<div class="event-item" v-for="(item, index) in tabList[tabListIndex].events" :key="index"
@click="openModel(item)">
<div class="item-time">
{{ item.date }}
</div>
<div class="item-content">
<span class="item-tab" v-if="item.type" :class="{
'tab-green': item.type === '机会',
'tab-red': item.type === '风险',
}">{{ item.type }}</span>
{{ item.title }}
</div>
</div>
<t-empty v-if="!tabList[tabListIndex] || tabList[tabListIndex].events.length === 0" />
</template>
</t-loading>
</div>
</div>
</template>
</t-collapse-panel>
<t-collapse-panel value="2">
<template #header>
<div class="title-content-item margin-bottom-10">相关对手叙事</div>
</template>
<template #default>
<div class="narrate-content">
<div class="narrate-list">
<t-loading :loading="narrateLoading" show-overlay>
<div class="item-content" v-for="(item, index) in narrateList" :key="index"
@click="openXushiModel(item)">
<div class="item-title">
{{ item.topic }}
</div>
<div class="item-footer">
<!-- <span class="item-tab tab-blue" v-for="(aItem, aIndex) in item.tabList" :key="aIndex">{{ aItem
}}</span> -->
<span class="item-tab tab-blue">{{ item.tabList[0]
}}</span>
</div>
</div>
<t-empty v-if="narrateList.length === 0" />
</t-loading>
</div>
</div>
</template>
</t-collapse-panel>
</t-collapse>
<t-dialog v-model:visible="xushiModelStatus" attach="body" header="叙事" width="1000" :confirm-on-enter="true"
:on-confirm="() => xushiModelStatus = false">
<div class="xushiContent">
<template>
</template>
<div class="title-content-item margin-bottom-10">
意图
</div>
<div class="title">
{{ xushiItem['intention'] || '暂无' }}
</div>
<div class="title-content-item margin-bottom-10">
摘要
</div>
<div class="yitu"> {{ xushiItem['summary'] || '暂无' }}</div>
<div class="title-content-item margin-bottom-10">
话题
</div>
<div class="content">
{{ xushiItem['topic'] || '暂无' }}
</div>
<div class="title-content-item margin-bottom-10">
叙事主体
</div>
<div class="content">
{{ xushiItem['entity'] || '暂无' }}
</div>
<div class="title-content-item margin-bottom-10">
话题类型
</div>
<div class="tag" v-if="xushiItem['topicType']">
<div class="item" v-for="i in xushiItem['topicType'].split('、')">
{{ i }}
</div>
</div>
</div>
</t-dialog>
</t-space>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { requestAxiosService } from "@/service/request-axios-service"; // 引入发送异步请求方法
import { useStore } from 'vuex';
import CommonInfoDialog from "@/components/dialog/CommonInfoDialog.vue"
const service = requestAxiosService;
const props = defineProps({
msg: String,
taskId: Number,
taskDirection: String
});
const xushiModelStatus = ref(false)
const xushiItem = ref({})
const xushiText = ref('');
const openXushiModel = d => {
xushiItem.value = d
console.log(d);
xushiModelStatus.value = true
}
const targetModelStatus = ref(false)
const openTargetMmdeol = () => {
targetModelStatus.value = true
}
const modelData = ref({})
const modelStatus = ref(false)
const openModel = d => {
console.log(d);
modelStatus.value = true
modelData.value = d
}
const targetLoading = ref(false);
const eventLoading = ref(false);
const narrateLoading = ref(false);
const store = useStore();
onMounted(() => {
getTargetData();
getEventData();
getNarrateData();
});
const organization = ref([])
const fliterType = ref('human')
const fliterSort = ref('2')
const getTargetData = () => {
if (props.taskId) {
const parmy = {
taskId: props.taskId,
sortType: fliterSort.value
};
targetLoading.value = true;
service
.get(
`${environment["b1ConsumerUrl"]}/eventAnalysis/targetSummaryList`,
parmy
)
.then((res) => {
console.log("任务检索", res);
targetLoading.value = false
let result = res.data;
result.human.forEach((item) => {
item.src =
environment["aImagePath"] +
(item.image_path
? item.image_path?.replace(".", "")
: item.image_path?.replace(".", ""));
});
result.organization.forEach((item) => {
item.src =
environment["aImagePath"] +
(item.image_path
? item.image_path?.replace(".", "")
: item.image_path?.replace(".", ""));
});
targetList.value = result.human;
organization.value = result.organization
store.commit('setTargetList', [...result.human, ...result.organization]);
});
}
};
const sortChange = d => {
console.log(d);
console.log(fliterSort.value);
getTargetData()
}
const tabList = ref([]);
const tabListIndex = ref(0)
// 获取关键事件
const getEventData = () => {
if (props.taskId) {
const parmy = {
taskId: props.taskId,
direction: props.taskDirection,
// discriminant: "热点",
};
eventLoading.value = true;
service
.get(
`${environment["b1ConsumerUrl"]}/cop/copKeyEvents`,
parmy
)
.then((res) => {
eventLoading.value = false;
console.log("热点事件", res);
if (res.data.length > 0) {
let result = res.data;
tabList.value = result;
}
});
}
};
const getNarrateData = () => {
if (props.taskId) {
const parmy = {
taskId: props.taskId,
};
narrateLoading.value = true;
service
.get(
`${environment["b1ConsumerUrl"]}/eventAnalysis/opponentNarrative`,
parmy
)
.then((res) => {
console.log("叙事", res);
narrateLoading.value = false;
let result = res.data;
narrateList.value = result;
narrateList.value.forEach((item) => {
item.tabList = item.topicType.split('、');
})
console.log(narrateList.value)
});
}
};
const count = ref(0);
const noChange = () => { };
const targetList = ref([]);
const enemyCurrentItem = ref(["0", "1", "2"]); //折叠面板展开索引
const enemyCurrentItemChange = (value) => {
console.log(value);
};
const narrateList = ref([]);
const targetListChange = (item) => {
console.log('点击了', item);
store.commit('setTargetData', item)
}
</script>
<style scoped lang="less">
.zl {
.fliter {
width: 100%;
display: flex;
padding: 10px 0;
.item {
width: 50%;
display: flex;
align-items: center;
}
}
.contentBox {
height: 60vh;
overflow-y: auto;
}
}
.targetModel {
.title {
font-size: 24px;
font-weight: 700;
display: flex;
color: #fff;
.item {
width: 50%;
}
}
.contentBox {
display: flex;
.human,
.organization {
width: 50%;
height: 65vh;
overflow-y: auto;
}
}
}
.targetItem {
border-bottom: 1px solid #777;
display: flex;
gap: 10px;
align-items: center;
.img {
width: 80px;
height: 80px;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.info {
flex: 1;
flex-shrink: 0;
.name {
line-height: 36px;
font-family: Noto Sans S Chinese;
color: #ffffff;
font-size: var(--titleSize);
}
.reason {
height: 81px;
line-height: 26px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSize);
}
}
}
.body {
width: 100%;
height: calc(100vh - 200px);
overflow-y: auto;
}
.t-collapse {
background-color: transparent;
border: 0;
.t-collapse-panel__content {
padding: 0;
}
}
:deep(.t-collapse-panel__wrapper .t-collapse-panel__content) {
padding: 0;
}
.title-content-item {
width: 100%;
display: flex;
justify-content: space-between;
.more {
font-size: 14px;
text-align: right;
width: 100px;
}
}
:deep(.t-collapse-panel__wrapper .t-collapse-panel__body) {
background-color: transparent;
border-bottom: 0px;
}
:deep(.t-collapse-panel__wrapper .t-collapse-panel__header) {
padding: 0;
border-bottom: 0px;
}
.task-target {
.target-list {
padding: 0 30px;
.item-content {
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
padding: 10px;
.item-left {
width: 70px;
height: 70px;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
vertical-align: middle;
object-fit: cover;
}
}
.item-right {
flex: 1;
margin-left: 10px;
.item-title {
line-height: 36px;
font-family: Noto Sans S Chinese;
color: #ffffff;
font-size: var(--titleSize);
}
.item-footer {
height: 81px;
line-height: 26px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSize);
}
}
}
}
}
// 任务事件
.task-event {
.tab-content {
.item-tab {
display: inline-block;
line-height: var(--fontSize);
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSize);
background: rgba(0, 98, 217, 0.3);
border-radius: 4px;
padding: 5px 10px;
margin: 5px;
cursor: pointer;
.item-count {
font-family: "DDIN";
}
&:hover {
background: #2b86fe;
}
}
.item-active {
background: #2b86fe;
}
}
// 事件样式
.event-list {
padding: 10px 15px;
box-sizing: border-box;
.event-item {
margin-bottom: 10px;
padding-left: 25px;
position: relative;
&::after {
content: "";
display: block;
width: 12px;
height: 12px;
background: #ffffff;
border: 2px solid;
border-color: #45c3f3;
border-radius: 50px;
position: absolute;
top: 0px;
left: 0px;
}
&::before {
content: "";
display: block;
width: 1px;
height: 100%;
background: #2c66a7;
position: absolute;
top: var(--fontSize);
left: 6px;
}
.item-time {
line-height: 20px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: rgba(255, 255, 255, 0.6);
margin-bottom: 10px;
}
.item-tab {
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSizes);
line-height: var(--fontSize);
padding: 5px 10px;
border: 1px solid;
border-radius: 4px;
margin-right: 5px;
}
.item-content {
line-height: 30px;
font-family: Noto Sans S Chinese;
color: #ffffff;
font-size: var(--fontSize);
}
}
}
}
// 对手叙事样式
.narrate-content {
padding: 10px;
.narrate-list {
.item-content {
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
padding: 10px;
margin-bottom: 15px;
&:hover {
background: rgba(0, 98, 217, 0.2);
border-color: rgba(85, 166, 254, 0.1);
}
.item-title {
line-height: 26px;
font-family: Noto Sans S Chinese;
color: #ffffff;
font-size: var(--fontSize);
margin-bottom: 10px;
}
.item-footer {
.item-tab {
line-height: var(--fontSize);
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSizes);
padding: 5px 10px;
border: 1px solid;
border-radius: 4px;
display: inline-block;
margin-right: 10px;
margin-bottom: 10px;
}
}
}
}
}
.xushiContent {
color: #fff;
font-size: 16px;
h2 {
color: #fff;
margin: 20px 0 10px;
}
.title {
font-size: 18px;
font-weight: 700;
}
.yitu {
margin: 0px 0;
}
.tag {
display: flex;
flex-wrap: wrap;
gap: 10px;
.item {
line-height: var(--fontSize);
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSizes);
padding: 5px 10px;
border: 1px solid;
border-radius: 4px;
display: inline-block;
background: rgba(0, 121, 254, 0.1);
border-color: #0079fe !important;
}
}
.content {
padding: 0px 0;
color: #fff;
}
}
</style>
@@ -0,0 +1,548 @@
<template>
<t-space class="body" direction="vertical">
<t-collapse
v-model="currentItem"
:defaultExpandAll="true"
:expand-icon-placement="'right'"
@change="handlePanelChange"
>
<t-collapse-panel value="0">
<template #header>
<div class="title-content-item">
<div>我方发声口径与叙事</div>
</div>
</template>
<template #default>
<div style="text-align: right; margin-top: 10px">
<t-radio-group
variant="primary-filled"
size="small"
default-value="selfSpeech"
@change="friendlyTopTagChange"
>
<t-radio-button value="selfSpeech">总书记</t-radio-button>
<t-radio-button value="selfConsistents">口径</t-radio-button>
<t-radio-button value="xushi">叙事</t-radio-button>
</t-radio-group>
</div>
<div class="target-list">
<CommonInfoDialog
:modelData="infoModelData"
:modelStatus="infoModelStatus"
:remarkRule="{
trendSpeechTime: '时间',
trendConsistentTime: '时间',
}"
@updateStatus="(v) => (infoModelStatus = v)"
@config="() => (infoModelStatus = false)"
/>
<template v-if="friendlyTopTagFlag !== 'xushi'">
<t-loading :loading="kjLoading" show-overlay>
<t-empty v-if="xuAndKJ[friendlyTopTagFlag]?.length === 0" />
<div
v-for="(value, vIndex) in xuAndKJ[friendlyTopTagFlag]"
:key="vIndex"
@click="openInfoModel(value)"
class="target-list-story-item"
>
<!-- flex-between-center -->
<div
class="target-list-story-item-top text-ellipsis ellipsis1"
>
<div>
{{
value.trendConsistentTitleMini ||
value.trendConsistentTitle ||
value.trendSpeechTitleMini ||
value.trendSpeechTitle
}}
</div>
</div>
<div class="item-line"></div>
<div
class="target-list-story-item-content text-ellipsis ellipsis3"
>
<div>
{{
value.trendConsistentContent ||
value.trendConsistentLike ||
value.trendSpeechContent ||
value.trendSpeechLike
}}
</div>
</div>
<div
class="target-list-story-item-bottom flex-between-baseline"
>
<div v-if="value.xwt">发生主体:{{ value.xwt }}</div>
<div>
发生时间:{{
value.trendConsistentTime || value.trendSpeechTime
}}
</div>
</div>
</div>
</t-loading>
</template>
<!-- </t-swiper-item>
</t-swiper> -->
</div>
<div class="target-list" v-if="friendlyTopTagFlag == 'xushi'">
<!-- <Empty /> -->
<!-- {{ xushiText }} -->
<t-loading :loading="narrateLoading" show-overlay>
<t-empty v-if="!xushiText" />
<div
class="target-list-story-item"
v-for="value in xushiText"
@click="openXushiModel(value)"
>
<!-- <CodeData :markdown="xushiText" /> -->
{{ value["标题"] }}
</div>
</t-loading>
<t-dialog
v-model:visible="xushiModelStatus"
attach="body"
header="叙事"
width="600"
:confirm-on-enter="true"
:on-confirm="() => (xushiModelStatus = false)"
>
<div class="xushiContent">
<div class="title-content-item margin-bottom-10">标题</div>
<div class="title" v-if="xushiItem['标题']">
{{ xushiItem["标题"] }}
</div>
<div class="title-content-item margin-bottom-10">意图</div>
<div class="yitu" v-if="xushiItem['意图']">
{{ xushiItem["意图"] }}
</div>
<div class="title-content-item margin-bottom-10">标签</div>
<div class="tag" v-if="xushiItem['标签']">
<div class="item" v-for="i in xushiItem['标签']">
{{ i }}
</div>
</div>
<div class="title-content-item margin-bottom-10">内容</div>
<div class="content" v-if="xushiItem['内容']">
{{ xushiItem["内容"] }}
</div>
</div>
</t-dialog>
</div>
</template>
</t-collapse-panel>
<t-collapse-panel value="1">
<template #header>
<div class="title-content-item">我方zz资源与力量</div>
</template>
<template #default>
<div style="text-align: right; margin-top: 10px">
<t-radio-group
variant="primary-filled"
size="small"
default-value="ziyuan"
@change="resourcesAndPowerChange"
>
<t-radio-button value="ziyuan">资源</t-radio-button>
<t-radio-button value="liliang">力量</t-radio-button>
</t-radio-group>
</div>
<div class="resourcesAndPower flex-between-center">
<!-- <div class="resourcesAndPower-left">
<div class="resourcesAndPower-left-tag" @click="resourcesAndPowerChange('ziyuan')" :class="{
'resourcesAndPower-left-tag-on':
resourcesAndPowerFlag == 'ziyuan',
}">
资源
</div>
<div class="resourcesAndPower-left-tag" @click="resourcesAndPowerChange('liliang')" :class="{
'resourcesAndPower-left-tag-on':
resourcesAndPowerFlag == 'liliang',
}">
力量
</div>
</div> -->
<div class="resourcesAndPower-right">
<div v-if="resourcesAndPowerFlag == 'ziyuan'">
<!-- <PieChart :taskId="taskId" /> -->
<Resources :taskId="taskId" />
</div>
<div v-if="resourcesAndPowerFlag == 'liliang'">
<Power />
</div>
</div>
</div>
</template>
</t-collapse-panel>
<t-collapse-panel value="2">
<template #header>
<div class="title-content-item">上级要求</div>
</template>
<template #default>
<!-- <CodeData :markdown="upYaopqiuText" /> -->
<div style="cursor: pointer" @click="openReqModel()">
{{ upYaopqiuText.slice(0, 100) }}
</div>
</template>
</t-collapse-panel>
<t-collapse-panel value="3">
<template #header>
<div class="title-content-item">相关方案预案</div>
</template>
<template #default>
<div
class="planItem"
v-for="i in planList"
:key="i"
@click="openPlanModel(i)"
>
{{ i.trendPlanName }}
</div>
</template>
</t-collapse-panel>
</t-collapse>
<t-dialog
v-model:visible="planModelStatus"
attach="body"
header="相关方案预案"
width="1000"
:confirm-on-enter="true"
:on-confirm="() => (planModelStatus = false)"
>
<div class="planModel">
<CodeData :markdown="planModelData.trendPlanGoal" />
</div>
</t-dialog>
<t-dialog
v-model:visible="reqModelStatus"
attach="body"
header="上级要求"
width="1000"
:confirm-on-enter="true"
:on-confirm="() => (reqModelStatus = false)"
>
<div class="planModel">
<CodeData :markdown="upYaopqiuText" />
</div>
</t-dialog>
</t-space>
</template>
<script setup>
import { ref, onMounted, reactive } from "vue";
import PieChart from "../views/PieChart.vue";
import Power from "./Power.vue";
import CodeData from "../markdown/CodeData.vue";
import CommonInfoDialog from "@/components/dialog/CommonInfoDialog.vue";
import { requestAxiosService } from "@/service/request-axios-service"; // 引入发送异步请求方法
import Resources from "./component/Resources.vue";
const service = requestAxiosService;
import Empty from "../shared/Empty.vue";
import axios from "@/utils/request";
const props = defineProps({
msg: String,
taskId: Number,
});
onMounted(() => {
getKouJing();
getPlan();
upYaopqiu();
getXushi();
});
const infoModelStatus = ref(false);
const infoModelData = ref({});
const openInfoModel = (d) => {
console.log(d);
infoModelData.value = {
title: d.trendSpeechTitle || d.trendConsistentTitle,
content: d.trendSpeechContent || d.trendConsistentContent,
...d,
};
infoModelStatus.value = true;
};
const xushiModelStatus = ref(false);
const xushiItem = ref({});
const xushiText = ref("");
const narrateLoading = ref(false);
const reqModelStatus = ref(false);
const reqModelData = ref({});
const openReqModel = (d) => {
reqModelStatus.value = true;
reqModelData.value = d;
};
const planModelStatus = ref(false);
const planModelData = ref({});
const openPlanModel = (d) => {
planModelStatus.value = true;
planModelData.value = d;
};
//我情内容
const friendlyTopTagFlag = ref("selfSpeech");
const friendlyTopTagChange = (flag) => {
friendlyTopTagFlag.value = flag;
};
const upYaopqiuText = ref("");
const openXushiModel = (d) => {
xushiItem.value = d;
xushiModelStatus.value = true;
};
//获取叙事
const getXushi = () => {
narrateLoading.value = true;
service
.get(`${environment["b1ConsumerUrl"]}/cop/querySelfNarrative`, {
taskId: props.taskId,
// taskId: 3038
})
.then((res) => {
console.log(res);
narrateLoading.value = false;
xushiText.value = res.data;
});
};
//获取上级要求
const upYaopqiu = () => {
service
.get(`${environment["b1ConsumerUrl"]}/cop/querySuperiorRequirements`, {
taskId: props.taskId,
})
.then((res) => {
console.log(res);
upYaopqiuText.value = res.data.replaceAll("\\n", "\n");
});
};
const xuAndKJ = ref({ selfSpeech: [], selfConsistents: [] }); // 口径接口
const kjLoading = ref(false);
const getKouJing = () => {
console.log({ taskId: props.taskId });
kjLoading.value = true;
service
.get(`${environment["b1ConsumerUrl"]}/cop/querySelfSpeechConsistents`, {
taskId: props.taskId,
})
.then((res) => {
kjLoading.value = false;
console.log("口径接口", res);
xuAndKJ.value = res.data;
});
};
const planList = ref([]);
const getPlan = () => {
service
.get(`${environment["b1ConsumerUrl"]}/trend/getTrendPlan`, {
taskId: props.taskId,
})
.then((res) => {
console.log(res.data);
planList.value = res.data;
});
};
const resourcesAndPowerFlag = ref("ziyuan");
const resourcesAndPowerChange = (flag) => {
resourcesAndPowerFlag.value = flag;
};
const currentItem = ref(["0"]); //折叠面板展开索引
const handlePanelChange = (value) => {
console.log(value);
};
</script>
<style scoped lang="less">
.planItem {
padding: 10px;
}
.body {
width: 100%;
height: calc(100vh - 200px);
overflow-y: auto;
}
.t-collapse {
background-color: transparent;
border: 0;
.t-collapse-panel__content {
padding: 0;
}
}
:deep(.t-collapse-panel__wrapper .t-collapse-panel__body) {
background-color: transparent;
border-bottom: 0px;
}
:deep(.t-collapse-panel__wrapper .t-collapse-panel__header) {
border-bottom: 0px;
padding: 0;
}
:deep(.t-collapse-panel__wrapper .t-collapse-panel__content) {
padding: 0;
}
.title-content-item {
width: 100%;
display: flex;
justify-content: space-between;
.title-content-item-tab {
font-size: 13px;
color: #f2f2f2;
display: flex;
width: 120px;
height: 20px;
font-weight: 400;
.title-content-item-tab-item {
width: 33%;
line-height: 20px;
text-align: center;
background-color: rgba(28, 51, 60, 1);
cursor: pointer;
}
.title-content-item-tab-item-on {
background-color: rgb(11, 110, 227);
}
}
}
.target-list {
// padding: 0 10px;
:deep(.t-swiper--outside .t-swiper__navigation) {
display: none;
}
.target-list-story-item {
width: 100%;
background-color: rgba(0, 0, 0, 0.196078431372549);
border: none;
border-radius: 7px;
padding: 10px 15px;
margin-top: 10px;
cursor: pointer;
.target-list-story-item-top {
font-weight: 500;
font-size: var(--fontSize);
color: #ffffff;
// margin-bottom: 10px;
}
.target-list-story-item-content {
font-size: var(--fontSizes);
color: #ffffff;
margin-bottom: 10px;
}
.target-list-story-item-bottom {
color: #7f7f7f;
font-size: var(--fontSizes);
}
}
}
.resourcesAndPower {
width: 100%;
margin-top: 5px;
.resourcesAndPower-left {
display: flex;
flex-wrap: wrap;
align-items: center;
width: 80px;
.resourcesAndPower-left-tag {
width: 100%;
background-color: rgba(2, 23, 33, 1);
border-radius: 11px;
font-weight: 700;
font-style: normal;
font-size: var(--fontSize);
color: #f2f2f2;
line-height: 57px;
text-align: center;
margin-bottom: 10px;
cursor: pointer;
}
.resourcesAndPower-left-tag-on {
background-color: #2b86fe;
}
}
.resourcesAndPower-right {
flex-grow: 1;
background-color: rgba(11, 34, 55, 0.670588235294118);
padding: 10px;
}
}
.xushiContent {
color: #fff;
font-size: 16px;
h2 {
color: #fff;
margin: 20px 0 10px;
}
.title {
font-size: 18px;
font-weight: 700;
}
.yitu {
margin: 0px 0;
}
.tag {
display: flex;
gap: 10px;
.item {
line-height: var(--fontSize);
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSizes);
padding: 5px 10px;
border: 1px solid;
border-radius: 4px;
display: inline-block;
background: rgba(0, 121, 254, 0.1);
border-color: #0079fe !important;
}
}
.content {
padding: 0px 0;
color: #fff;
}
}
.switch {
display: flex;
.item {
width: 50px;
}
}
</style>
@@ -0,0 +1,94 @@
<template>
<div class="power">
<div class="title">
正在执行中{{ tabData.taskProgressCount }}项任务,当前空闲{{ tabData.freeGroupCount }}组力量。
</div>
<t-empty v-if="tabData.groups.length === 0"></t-empty>
<t-tabs v-else :default-value="1">
<t-tab-panel v-for="(item, index) in tabData.groups" :key="index" :value="index + 1" :label="item.name">
<div class="content">
<div v-if="item.progressTask">
<div class="padding-10">
{{ item.progressTask?.length || 0 }}项活跃任务
</div>
<div class="list-item">
<div class="item-title" v-for="(aItem, aIndex) in item.progressTask" :key="aIndex">
{{ aIndex + 1 }}. {{ aItem.name }}
</div>
</div>
</div>
<div v-else>
<t-empty />
</div>
</div>
</t-tab-panel>
</t-tabs>
</div>
</template>
<script>
import { requestAxiosService } from "@/service/request-axios-service"; // 引入发送异步请求方法
export default {
data() {
return {
tabData: {
freeGroupCount: 0,
taskProgressCount: 0,
groups: [],
loading: false
},
}
},
methods: {
getPower() {
let url = environment['b1ConsumerUrl'] + '/cop/copOwnPower';
this.loading = true;
requestAxiosService.get(url, {
// accessToken: localStorage.getItem('accessToken')
accessToken: '123'
}).then(res => {
this.loading = false;
console.log('我方力量', res);
let result = res.data;
if (result) {
this.tabData = result;
}
})
}
},
mounted() {
this.getPower()
}
}
</script>
<style scoped lang='less'>
/* Your styles here */
.power {
width: 370px;
.title {
font-size: 16px;
font-weight: 600;
color: #fff;
}
.content {
.list-item {
width: 100%;
height: 145px;
padding: 10px;
overflow-y: auto;
.item-title {
margin-bottom: 10px;
background: rgba(0, 98, 217, 0.1);
padding: 10px 15px;
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
}
}
}
}
</style>
@@ -0,0 +1,514 @@
<template>
<div class="Resources">
<div class="tab">
<div :class="['item', tabId == k ? 'active' : '']" v-for="(v, k) in tabList" @click="tabChange(k)">
<div class="text">
{{ v }}
</div>
<div class="info">
<img src="@/assets/icon/资源-优.png" alt="">
资源
{{ '优' }}
</div>
</div>
</div>
<div class="content">
<template v-if="tabId == '1'">
<div class="label">
任务{{ tabList[tabId] }}总数{{ 134 }}条,相似任务中平均使用{{ tabList[tabId] }}{{ 134 }}条。
</div>
<div class="MTChart chart" ref="MTChart"></div>
<div class="legendList">
<div class="item" v-for="(item, index) in MTData">
<img :src="`src/assets/icon/媒资图例${index + 1}.png`" alt="">
<span>{{ item.name }}</span>
<span>{{ item.value }}</span>
<span>条</span>
</div>
</div>
</template>
<template v-if="tabId == '2'">
<div class="label">
任务{{ tabList[tabId] }}总数{{ accountAndCWB.totalCount }}条。
</div>
<div class="AccountChart chart" ref="AccountChart"></div>
<div class="legendList">
<div class="item" v-for="(item, index) in accountData">
<div class="kuai" :style="{ backgroundColor: accountColorList[index] }"></div>
<span>{{ item.name }}</span>
<span>{{ item.value }}</span>
<span>条</span>
</div>
</div>
</template>
<template v-if="tabId == '3'">
<div class="label">
任务相关目标总计{{ accountAndCWB.targetCount }}个,其中{{ accountAndCWB.cbwTargetCount }}个可通过CBW触达,涉及CBW{{
accountAndCWB.cbwCount
}}张。
</div>
<div class="cbw">
<div class="item" v-for="(v, k, index) in accountAndCWB.cwb">
<div class="title">
{{ k }}
</div>
<div class="cbwContent">
<div class="row" v-for="i in v">
{{ i.username }}
</div>
</div>
</div>
</div>
</template>
<template v-if="tabId == '4'">
<div class="cbw">
<div class="item" v-for="(v, k, index) in b3DataRule">
<div class="title">
{{ v }}
</div>
<div class="cbwContent">
{{ b3Data[k] }}
</div>
</div>
</div>
</template>
</div>
</div>
</template>
<script>
import * as echarts from "echarts";
import { requestAxiosService } from "@/service/request-axios-service"; // 引入发送异步请求方法
export default {
props: ['taskId'],
data() {
return {
tabId: '1',
tabList: {
1: '相关媒资',
2: '相关账号',
3: 'CBW情况',
4: '资源通道'
},
axios: requestAxiosService,
MTColorList: ['#27c7ff', '#00ffff', '#f18d1e', '#bbf9ff'],
MTData: [ // 数据
{ value: 335, name: '文本' },
{ value: 310, name: '图片' },
{ value: 274, name: '音频' },
{ value: 235, name: '视频' },
],
accountAndCWB: null,
accountColorList: ['#00c7ff', '#e6a12d', '#49f5d2', '#f5e74f'],
accountData: [
],
b3Data: {},
b3DataRule: {
total: '实时通道总量',
using: '使用中',
backup: '备用中',
error: '异常中',
creating: '创建中',
retired: '临期通道',
}
};
},
methods: {
tabChange(d) {
this.tabId = d
if (d == '1') {
this.$nextTick(() => {
this.setMTChart()
})
}
if (d == '2') {
this.$nextTick(() => {
this.setAccountChart()
})
}
if (d == '4') {
this.$nextTick(() => {
this.getB3Data()
})
}
},
getB3Data() {
this.axios
.get(`${environment["b1ConsumerUrl"]}/cop/copChannelOverview`).then(res => {
console.log(res.data);
if (res.data) {
this.b3Data = res.data
}
})
},
getAccountAndCBWData() {
// requestAxiosService
// .get(`${environment["b1ConsumerUrl"]}/cop/copOwnAccount`, {
// taskId: this.taskId,
// }).then(res => {
// console.log(res.data);
// if (res.data) {
// this.accountData = res.data.personas.map(i => {
// return {
// value: i.personaAccountCount,
// name: i.persona.split(',')[0]
// }
// })
// this.setAccountChart()
// }
// })
let res = {
"state": "200",
"msg": "操作成功!",
"data": {
"cbwTargetCount": 0,
"cbw": {},
"cbwCount": 0,
"totalCount": 740,
"personas": [
{
"persona": "中东地缘经济分析师,精通能源供应链与区域冲突联动机制",
"personaAccountCount": 161
},
{
"persona": "中国海权战略研究员,关注海峡航运安全与能源进口路径风险",
"personaAccountCount": 162
},
{
"persona": "跨领域危机应对专家,结合军事、能源与外交案例分析台海局势",
"personaAccountCount": 417
}
],
"targetCount": 84
}
}
this.accountAndCWB = res.data
this.accountData = res.data.personas.map(i => {
return {
value: i.personaAccountCount,
name: i.persona.split(',')[0]
}
})
},
setAccountChart() {
const dom = this.$refs.AccountChart
let chart = echarts.init(dom);
let count = 0
this.accountData.forEach(i => {
count += i.value
})
chart.setOption({
color: this.accountColorList,
// 标题
title: {
left: 'center'
},
// 提示框
tooltip: {
trigger: 'item',
formatter: '{a}<br/>{b}: {c} ({d}%)' // 显示系列名、数据名、值和百分比
},
// 图例
legend: {
show: false,
orient: 'vertical', // 垂直排列
right: 20, // 图例位置
top: 20,
height: 300,
data: ['资源A', '资源B', '资源C', '资源D', '资源E'], // 图例名称
textStyle: {
color: '#fff'
},
itemGap: 30,
backgroundColor: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [
{ offset: 0, color: 'rgba(47, 100, 173, 0.4)' },
{ offset: 1, color: 'rgba(0, 82, 119, 0.04)' }
]
},
},
graphic: [{
type: 'text',
left: '40px',
top: 'center',
style: {
text: '账号总数 \n' + count,
fontSize: 16,
textAlign: 'center',
fill: '#fff',
width: '50%',
height: '50%'
}
}],
// 系列配置
series: [
{
name: this.tabList[this.tabId], // 系列名称
type: 'pie', // 类型为饼图
radius: ['50%', '60%'], // 环形内外半径(控制环形宽度)
center: ['20%', '50%'], // 图表中心位置
data: this.accountData,
// 设置扇形之间的间隔(通过边框模拟)
itemStyle: {
borderRadius: 0, // 扇形圆角(可选)
borderColor: 'rgba(10, 36, 64, 0.8)', // 分隔线颜色(白色)
borderWidth: 5 // 分隔线宽度(控制间隔大小)
},
// 分隔线配置
splitLine: {
length: 15, // 分隔线长度(从外圆到标签的长度)
lineStyle: { // 分隔线样式
color: 'rgba(255, 255, 255, 0.5)', // 透明度
width: 2
}
},
// 标签配置
label: {
show: false,
formatter: '{b}: {c} ({d}%)', // 标签格式(名称、值、百分比)
position: 'outside', // 标签位置(外部)
color: '#fff' // 标签颜色
},
}
]
})
},
//设置媒体
setMTChart() {
const dom = this.$refs.MTChart
let chart = echarts.init(dom);
chart.setOption({
color: this.MTColorList,
// 标题
title: {
left: 'center'
},
// 提示框
tooltip: {
trigger: 'item',
formatter: '{a}<br/>{b}: {c} ({d}%)' // 显示系列名、数据名、值和百分比
},
// 图例
legend: {
show: false,
orient: 'vertical', // 垂直排列
right: 20, // 图例位置
top: 20,
height: 300,
data: ['资源A', '资源B', '资源C', '资源D', '资源E'], // 图例名称
textStyle: {
color: '#fff'
},
itemGap: 30,
backgroundColor: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [
{ offset: 0, color: 'rgba(47, 100, 173, 0.4)' },
{ offset: 1, color: 'rgba(0, 82, 119, 0.04)' }
]
},
},
// 系列配置
series: [
{
name: this.tabList[this.tabId], // 系列名称
type: 'pie', // 类型为饼图
radius: ['50%', '60%'], // 环形内外半径(控制环形宽度)
center: ['32%', '50%'], // 图表中心位置
data: this.MTData,
// 设置扇形之间的间隔(通过边框模拟)
itemStyle: {
borderRadius: 0, // 扇形圆角(可选)
borderColor: 'rgba(10, 36, 64, 0.8)', // 分隔线颜色(白色)
borderWidth: 5 // 分隔线宽度(控制间隔大小)
},
// 分隔线配置
splitLine: {
length: 15, // 分隔线长度(从外圆到标签的长度)
lineStyle: { // 分隔线样式
color: 'rgba(255, 255, 255, 0.5)', // 透明度
width: 2
}
},
// 标签配置
label: {
show: false,
formatter: '{b}: {c} ({d}%)', // 标签格式(名称、值、百分比)
position: 'outside', // 标签位置(外部)
color: '#fff' // 标签颜色
},
}
]
})
},
},
watch: {
},
mounted() {
this.setMTChart()
this.getAccountAndCBWData()
}
};
</script>
<style lang="less">
.Resources {
.tab {
display: flex;
justify-content: center;
gap: 10px;
.item {
display: flex;
flex-direction: column;
padding: 10px 0 0;
cursor: pointer;
width: 80px;
height: 59px;
background: rgba(3, 38, 80, 0.6);
border: 1px solid;
border-color: rgba(43, 143, 254, 0.6);
border-radius: 4px;
.text {
text-align: center;
color: #ffffff;
font-size: 16px;
}
.info {
display: flex;
align-items: center;
justify-content: center;
color: rgba(255, 255, 255, 0.8);
font-size: 16px;
text-align: center;
img {
width: 16px;
height: 16px;
}
}
}
.active {
background: url('@/assets/icon/资源tab选中.png');
background-size: 114px 63px;
background-repeat: no-repeat;
border: none;
height: 63px;
}
}
.content {
position: relative;
width: 368px;
height: 300px;
.label {}
.chart {
width: 368px;
height: 250px;
}
.MTChart {
background: url("@/assets/icon/媒资环形图.png");
background-repeat: no-repeat;
background-size: 200px;
background-position: 20px 50px;
}
.AccountChart {
background: url("@/assets/icon/账号环形图.png");
background-repeat: no-repeat;
background-size: 118px;
background-position: 15px 65px;
}
.legendList {
position: absolute;
right: 10px;
top: 100px;
display: flex;
gap: 14px;
flex-direction: column;
.kuai {
width: 6px;
height: 6px;
}
.item {
// width: 114px;
height: 22px;
background: linear-gradient(90deg, rgba(47, 100, 173, 0.4) 0%, rgba(0, 82, 119, 0.04) 100%);
display: flex;
gap: 10px;
align-items: center;
justify-content: space-between;
color: rgba(255, 255, 255, 0.8);
font-size: 14px;
padding: 0 5px;
img {
width: 8px;
height: 8px;
}
}
}
.cbw {
height: 250px;
overflow-y: auto;
.item {
width: 368px;
background: rgba(0, 12, 28, 0.15);
border: 1px solid;
border-color: rgba(0, 98, 217, 0.3);
border-radius: 4px;
.title {
background: url("@/assets/icon/CBWBG.png");
width: 368px;
height: 26px;
font-weight: 500;
color: #ffffff;
font-size: 16px;
padding: 0 0 0 16px;
line-height: 26px;
background-position-x: -5px;
}
.cbwContent {
padding: 14px 16px;
font-weight: 300;
color: #ffffff;
font-size: 16px;
}
}
}
}
}
</style>
@@ -0,0 +1,20 @@
<template>
<div class="task-analysis">task-analysis</div>
</template>
<script setup>
import { ref } from 'vue'
defineProps({
msg: String,
})
const count = ref(0)
</script>
<style scoped>
.task-analysis{
z-index: 500;
color: #fff;
}
</style>
@@ -0,0 +1,337 @@
<template>
<div class="step-task-fullmap">
<div ref="graphRef" class="graph-container"></div>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import {
Graph,
treeToGraphData,
ExtensionCategory,
register,
Rect,
} from "@antv/g6";
import { requestAxiosService } from "@/service/request-axios-service";
import treemapCardBg from "@/assets/icon/treemap-card-bg.png";
const props = defineProps({
msg: String,
taskData: Object,
taskId: {
default: "",
},
});
let graph = null;
const graphRef = ref(null);
const count = ref(0);
let treemapData = {};
const mouseUpShow = ref(false);
const service = requestAxiosService;
const grupMapSeach = () => {
class taskImageRectNode extends Rect {
render(attributes = this.parsedAttributes, container) {
super.render(attributes, container); // 渲染圆形节点
const [width, height] = this.getSize(attributes);
const { contentTitle } = attributes;
this.upsert(
"node-image",
"image",
{
x: -width / 2, // 图片的x坐标,使其居中
y: -height / 2, // 图片的y坐标,使其居中
width: width, // 图片宽度略小于圆形节点
text: contentTitle,
height: height, // 图片高度略小于圆形节点
src: treemapCardBg,
},
container
);
}
}
register(ExtensionCategory.NODE, "custom-image-rect", taskImageRectNode);
const graphData = treeToGraphData(treemapData);
graphData.nodes.forEach((item) => {
item.src = treemapCardBg;
item.data.src = treemapCardBg;
// if (item.data.isExpanded === 1) {
// item.style = {
// collapsed: true
// };
// }
});
console.log("---------graphData", graphData);
console.log("这是什么", graphData);
graph = new Graph({
container: graphRef.value,
autoFit: "view",
data: graphData,
node: {
type: "custom-image-rect",
style: {
size: [400, 170],
labelText: (d) => d.data.contentText,
labelPlacement: "middle",
labelOffsetY: 10,
labelFill: "#FFF",
labelStorke: "#fcc",
labelWordWrap: true,
labelMaxLines: 3,
labelFontSize: 20,
labelLineHeight: 30,
labelZIndex: 100,
labelMaxWidth: "90%",
contentTitle: (d) => d.data.contentText,
// subtitle: (d) => d.data.contentText,
src: treemapCardBg,
badges: (d) => {
return [
{
text: d.data.headerBarText,
color: "#fff",
fontSize: 20,
padding: [10, 15],
backgroundFill: "",
backgroundRadius: 0,
offsetY: 15,
placement: "top",
// backgroundWidth: 400,
wordWrap: true,
maxLines: 1,
minWidth: 300,
},
];
},
halo: (d) => (d.id === "node0" ? true : false),
ports: [{ placement: "right" }, { placement: "left" }],
},
},
edge: {
type: "polyline",
style: {
lineWidth: 3,
radius: 20,
stroke: "#8b9baf",
endArrow: true,
labelFill: "#8b9baf",
labelFontWeight: 600,
labelBackground: true,
labelBackgroundFill: "#f8f8f8",
labelBackgroundOpacity: 1,
labelBackgroundLineWidth: 3,
labelBackgroundStroke: "#8b9baf",
labelPadding: [1, 10],
labelBackgroundRadius: 4,
lineDashOffset: 100,
router: {
type: "orth",
// padding:100
},
},
animation: {
enter: "fade", // 使用渐变动画
exit: "fade", // 使用渐变动画
},
},
layout: {
type: "compact-box",
direction: "LR",
// getHeight: function getHeight() { //:增大 getWidth() / getHeight() 匹配节点大小
// return 100;
// }
getWidth: function getWidth() {
return 400;
},
getVGap: function getVGap(d) {
// 增大垂直间距
// console.log('这是什么',d)
const { data } = d;
const height =
50 +
11 * (data.contentText.length / 20 + data.bottomText.length / 20);
return height;
// return 100;
},
getHGap: function getHGap() {
// 增大水平间距
return 50;
},
},
behaviors: [
"zoom-canvas",
"drag-element",
"drag-canvas",
{
type: "collapse-expand",
key: "collapse-expand-1",
trigger: "click", // 修改触发方式为单击
animation: true, // 启用动画效果
onCollapse: (id) => {
// 收起
console.log("这是什么", id);
},
onExpand: (id) => {
// 展开
console.log(id);
},
},
],
});
// // 节点点击事件
// graph.value.on('node:click', (e) => {
// // const nodeData = this.graph.getNodeData('actor4979');
// // console.log('这是什么', e, nodeData);
// // this.graph.collapseElement('actor4979', { animation: false });
// // graph.layout();
// });
graph.render();
// console.log('这是什么',this.treemapData.length)
// if (treemapData.length > 30) {
// setTimeout(() => {
// makeGraphZoom(0.6);
// }, 500);
// }
};
const makeGraphZoom = (index) => {
graph.zoomTo(index);
};
const taskDataSearch = async (taskId) => {
const parmy = {
taskId,
};
const res = await service.get(
`${environment["b1ConsumerUrl"]}/taskAnalyseSearch/getTaskPurposeDetail`,
parmy
);
console.log("逻辑图", res);
let result = res.data;
result.forEach((item) => {
item.childrenList = item.childrenList.filter(
(aItem) => aItem.childrenList.length > 0
);
});
taskDataChange(result);
treemapData = {
id: props.taskData.id,
data: {
id: props.taskData.id,
nodeName: "node-task",
contentText: props.taskData.overview,
bottomText: "",
headerBarText: props.taskData.taskName || "",
collapseText: "展开",
type: "",
isExpanded: 1,
},
children: result,
};
console.log("treemapData", treemapData);
grupMapSeach();
console.log(result);
};
const setLevelsAndFilter = (result, level = 1) => {
result.forEach((item) => {
item.level = level;
if (item.childrenList) {
// 递归设置子节点的 level 并过滤
item.childrenList = setLevelsAndFilter(
item.childrenList,
level + 1
).filter((child) => child.level === 5);
}
});
return result;
};
const taskDataChange = (list) => {
const DTO_TYPES = [
{
key: "purposeDto",
nodeName: "node-aim",
headerBarText: "ZZ目的",
contentKey: "zzPurpose",
nodeId: "aim",
},
{
key: "actorDto",
nodeName: "node-actor",
headerBarText: "行为体",
contentKey: "actorName",
bottomTextKey: "recReason",
nodeId: "actor",
},
{
key: "expectedBehaviorDto",
nodeName: "node-behavior",
headerBarText: "预期行为",
contentKey: "behavior",
nodeId: "behavior",
},
{
key: "drivingFactorDto",
nodeName: "node-factor",
headerBarText: "驱动因素",
contentKey: "drivingFactor",
nodeId: "factor",
},
{
key: "narrationDto",
nodeName: "node-narrate",
headerBarText: "叙事",
contentKey: "narration",
bottomTextKey: "recReason",
nodeId: "narrate",
},
];
const transformItem = (item, dtoType) => {
const dto = item[dtoType.key];
if (dto) {
item.id = dtoType.nodeId + dto.id;
item.data = {
id: dto.id,
nodeName: dtoType.nodeName,
contentText: dto[dtoType.contentKey],
bottomText: dtoType.bottomTextKey ? dto[dtoType.bottomTextKey] : "",
headerBarText: dtoType.headerBarText || "",
collapseText: "展开",
type: "",
isExpanded: dto.isExpanded,
};
}
};
list.forEach((item) => {
DTO_TYPES.forEach((dtoType) => {
transformItem(item, dtoType);
});
if (item.childrenList) {
item.children = item.childrenList;
taskDataChange(item.children);
}
});
};
onMounted(() => {
taskDataSearch(props.taskId);
});
</script>
<style scoped lang="less">
.step-task-fullmap {
width: 100%;
height: 700px;
color: #fff;
.graph-container {
width: 100%;
height: 100%;
}
}
</style>
@@ -0,0 +1,78 @@
<template>
<div class="DocDetails">
<div class="title">
{{ docData.m_title }}
</div>
<div class="info">
<div class="source">
{{ docData.source1 }}
</div>
<div class="date">
{{ docData.m_publish }}
</div>
</div>
<div class="content">
{{ docData.m_content }}
</div>
</div>
</template>
<script>
import { Handler } from 'leaflet';
export default {
props: {
docData: {
default: {}
}
},
data() {
return {
};
},
methods: {
},
watch: {
docData: {
handler(newV, oldV) {
console.log(newV);
},
deep: true
}
},
};
</script>
<style lang="less">
.DocDetails {
color: #fff;
.title {
font-weight: 700;
font-size: 18px;
}
.info {
display: flex;
gap: 10px;
margin: 10px 0;
.source {
border: 1px solid;
border-color: #d95e00 !important;
color: #dd8717 !important;
background-color: #fff6ea !important;
padding: 0 5px;
}
}
.content {
padding: 10px;
background-color: rgba(0, 140, 119, 0.1);
border-radius: 5px;
}
}
</style>
@@ -0,0 +1,310 @@
<template>
<div class="addTask">
<div @click="addModelStatus = true" v-if="taskSuperiorFlag !== null">
<slot>
<div class="addBtn">
+ 创建任务
</div>
</slot>
</div>
<t-dialog v-model:visible="addModelStatus" attach="body" header="创建任务" width="600" :confirm-on-enter="true"
:on-confirm="confirm">
<div class="frame">
<div class="row">
<div class="label">
<div class="text">
任务名称
</div>
<div class="required">
*
</div>
</div>
<div class="content"><t-input v-model="modelData.taskName" /></div>
</div>
<div class="row">
<div class="label">
<div class="text">
任务简介
</div>
<div class="required">
*
</div>
</div>
<div class="content">
<div>
<span class="JS">
!
</span> 任务描述对描述COH(CH)质量影响重大,请认真、完整填写
</div>
<t-textarea :autosize="{ minRows: 4, maxRows: 7 }" v-model="modelData.overview"
placeholder="这一步需要完整准确填写任务描述,您填写的内容对任务分析至关重要,填写的要素完整度和任务要求会贯穿整个COH(CH)过程,直接影响智能COH(CH)的质量" />
</div>
</div>
<div class="row">
<div class="label">
<div class="text">
任务等级
</div>
<div class="required">
*
</div>
</div>
<div class="content">
<t-select v-model="modelData.taskLevel">
<t-option v-for="(v, k) in taskLevel" :key="k" :label="v" :value="k" />
</t-select>
</div>
</div>
<div class="row">
<div class="label">
<div class="text">
下发单位
</div>
</div>
<div class="content"><t-input v-model="modelData.issuingDept" /></div>
</div>
<div class="row">
<div class="label">
<div class="text">
任务方向
</div>
<div class="required">
*
</div>
</div>
<div class="content"> <t-select v-model="modelData.taskDirection">
<t-option v-for="i in taskDirectionList" :key="i.value" :label="i.label" :value="i.value" />
</t-select></div>
</div>
<div class="row">
<div class="label">
<div class="text">
任务代号
</div>
</div>
<div class="content"><t-input v-model="modelData.taskNo" /></div>
</div>
<div class="row">
<div class="label">
<div class="text">
任务类型
</div>
<div class="required">
*
</div>
</div>
<div class="content"> <t-select v-model="modelData.taskType">
<t-option v-for="i in taskTypeList" :key="i.value" :label="i.label" :value="i.value" />
</t-select></div>
</div>
<div class="row">
<div class="label">
<div class="text">
任务时间
</div>
<div class="required">
*
</div>
</div>
<div class="content">
<t-date-range-picker v-model="date" :presets="presets" enable-time-picker allow-input clearable
@change="onChange" style="width: 100%;" />
</div>
</div>
</div>
</t-dialog>
</div>
</template>
<script>
import taskLevel from '@/common/taskLevel';
import dayjs from 'dayjs'
import { MessagePlugin } from 'tdesign-vue-next';
import { requestAxiosService } from '@/service/request-axios-service';
export default {
data() {
return {
addModelStatus: false,
taskLevel,
taskDirectionList: [
{ label: 'W方向', value: 'W方向' },
{ label: 'U方向', value: 'U方向' },
],
presets: {
最近7天: [dayjs().subtract(6, 'day').toDate(), dayjs().toDate()],
最近3天: [dayjs().subtract(2, 'day').toDate(), dayjs().toDate()],
今天: [dayjs().toDate(), dayjs().toDate()],
},
taskTypeList: [
{ label: '塑势', value: 0 },
{ label: 'DJ', value: 1 },
],
modelData: {
"issuingDept": "",
"overview": "",
"taskDirection": "W方向",
"taskEndDate": "",
"taskLevel": '1',
"taskName": "",
"taskNo": "",
"taskStartDate": "",
"taskStatus": 0,
"taskSuperiorFlag": 0,
"taskType": 1,
},
date: []
};
},
props: {
url: {
Type: String,
default: ''
},
taskSuperiorFlag: {
default: null
},
taskId: {
default: null
},
overview: {
default: ''
},
taskName: {
default: ''
}
},
watch: {
addModelStatus: {
handler(v) {
console.log(v);
//重置
if (v) {
this.modelData = {
"issuingDept": "",
"overview": this.overview,
"taskDirection": "W方向",
"taskEndDate": "",
"taskLevel": '1',
"taskName": this.taskName,
"taskNo": "",
"taskStartDate": "",
"taskStatus": 0,
"taskSuperiorFlag": 0,
"taskType": 1,
}
}
}
}
},
methods: {
onChange(d) {
console.log(d);
},
async confirm() {
console.log(this.modelData);
if (!this.modelData.taskName) {
MessagePlugin.warning('请填写任务名称后重试!')
return false
}
if (!this.modelData.overview) {
MessagePlugin.warning('请填写任务简介后重试!')
return false
}
if (this.date.length == 0) {
MessagePlugin.warning('请选择任务时间后重试!')
return false
}
let params = { ...this.modelData }
params.taskStartDate = dayjs(this.date[0]).toISOString()
params.taskEndDate = dayjs(this.date[1]).toISOString()
console.log(params);
params.taskSuperiorFlag = this.taskSuperiorFlag
params.pTaskId = this.taskId
const res = await requestAxiosService.post(`${environment['b1ConsumerUrl']}/cop/saveSuperiorTask`, params);
console.log(res);
MessagePlugin.warning(res.msg)
if (res.state == 201) {
this.addModelStatus = false
this.$emit('success')
}
}
},
};
</script>
<style lang="less">
.addTask {
.addBtn {
text-align: center;
color: #fff;
line-height: 40px;
border-radius: 5px;
border: 1px solid #2b8ffe99;
margin: 10px 20px;
cursor: pointer;
&:hover {
background: linear-gradient(123.69deg, #2b8ffe, #0062d9) !important;
}
}
}
.frame {
display: flex;
flex-direction: column;
.row {
display: flex;
align-items: center;
min-height: 50px;
.label {
width: 100px;
display: flex;
line-height: 20px;
font-size: 16px;
.text {
color: #fff;
}
.required {
color: red;
font-size: 20px;
}
}
.content {
flex: 1;
flex-shrink: 0;
color: #fff;
.t-textarea__inner {
border-color: var(--td-brand-color);
;
}
.JS {
color: red;
display: inline-block;
border: 1px solid red;
width: 20px;
height: 20px;
border-radius: 50px;
text-align: center;
line-height: 20px;
}
}
}
}
</style>
@@ -0,0 +1,137 @@
<template>
<t-dialog
v-model:visible="modelVisible"
attach="body"
:header="modelTitle"
width="1000"
:cancelBtn="null"
:confirm-on-enter="true"
:on-confirm="modelConfig"
>
<div class="GJSTModel">
<div class="title">
{{ modelData.title }}
</div>
<div class="remark">
<template v-for="(label, key) in remarkRule">
<div class="item" v-if="modelData[key]">
{{ label }}:{{ modelData[key] }}
</div>
</template>
</div>
<div
class="abstract"
style="color: #aaa"
v-if="modelData.trendSpeechLike || modelData.trendConsistentLike"
>
摘要:{{ modelData.trendSpeechLike || modelData.trendConsistentLike }}
</div>
<div class="content">
{{ modelData.content }}
</div>
<div class="liyou" style="color: #aaa" v-if="modelData.recommendReason">
推荐理由:{{ modelData.recommendReason }}
</div>
<div
class="liyou"
style="color: #aaa"
v-if="modelData.narrativeDirection"
>
叙事方向:{{ modelData.narrativeDirection }}
</div>
<div
class="liyou"
style="color: #aaa"
v-if="modelData.narrativeConstraints"
>
叙事限制:{{ modelData.narrativeConstraints }}
</div>
</div>
</t-dialog>
</template>
<script>
export default {
data() {
return {
modelVisible: false,
};
},
props: {
modelTitle: {
default: "详情",
},
remarkRule: {
default: {
direction: "方向",
importNum: "热度",
latitude: "纬度",
longitude: "经度",
siteName: "网站",
sourceType: "来源",
type: "类型",
date: "时间",
},
},
modelData: {
default: {},
},
modelStatus: {
default: false,
},
},
methods: {
modelConfig() {
this.$emit("config");
},
},
watch: {
modelStatus(v) {
console.log(v);
this.modelVisible = v;
},
modelVisible(v) {
this.$emit("updateStatus", v);
},
},
mounted() {
console.log(this.modelStatus);
},
};
</script>
<style lang="less">
.CommonInfoDialog {
}
.GJSTModel {
color: #fff;
.title {
text-align: center;
font-size: 24px;
}
.remark {
color: #aaa;
margin: 10px;
display: flex;
justify-content: center;
gap: 10px;
.item {
}
}
.content {
font-size: 16px;
padding-bottom: 20px;
}
}
.abstract {
color: rgb(170, 170, 170);
font-size: 18px;
margin-bottom: 10px;
}
</style>
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,176 @@
<template>
<div class="Audience" @click.stop>
<!-- {{ data.designName }} -->
<div class="head">
<img src="@/assets/icon/群组..svg" alt="">
<div class="JJ">
<div class="title">
<div class="tag">
<img src="@/assets/icon/群体.svg" alt="">
<span>
群体
</span>
</div>
<div class="name"> {{ data.designName }}</div>
</div>
<div class="info">
共涉及10个账号
</div>
</div>
</div>
<div class="content">
<t-tabs v-model="tabValue">
<t-tab-panel :value="1" label="群体概述" :destroy-on-hide="false">
<p style="padding: 25px">选项卡1的内容,使用 t-tab-panel 渲染</p>
</t-tab-panel>
<t-tab-panel :value="2" label="成员账号" :destroy-on-hide="false">
<!-- <template #panel>
<p style="padding: 25px">选项卡2的内容,使用 t-tab-panel 渲染</p>
</template> -->
<div class="userList">
<div class="item">
<div class="head">
<img src="@/assets/icon/群组..svg" alt="">
<div class="JJ">
<div class="title">
<div class="name"> {{ data.designName }}</div>
</div>
<div class="info">
<div class="tag">
<img src="@/assets/icon/粉丝量.svg" alt="">
<span>
粉丝量 805
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</t-tab-panel>
</t-tabs>
</div>
</div>
</template>
<script>
export default {
props: ['data'],
data() {
return {
tabValue: 1
};
},
methods: {
},
watch: {
},
};
</script>
<style lang="less">
.Audience {
width: 391px;
height: 476px;
background: rgba(3, 38, 80, 0.8);
border: 1px solid;
border-color: rgba(43, 143, 254, 0.6);
border-radius: 4px;
backdrop-filter: blur(15px);
padding: 16px 28px;
.head {
display: flex;
gap: 17px;
height: 60px;
img {
width: 60px;
height: 60px;
}
.JJ {
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
display: flex;
align-items: center;
gap: 10px;
.tag {
width: 56px;
height: 22px;
background: rgba(82, 221, 171, 0.5);
border: 1px solid;
border-color: #52ddab;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
img {
width: 14px;
height: 14px;
}
}
.name {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #ffffff;
font-size: 18px;
}
}
.info {
opacity: 80%;
line-height: 28px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: 16px;
}
}
}
.content {
margin-top: 24px;
.t-tabs__nav-scroll {
justify-content: center;
}
.userList {
display: flex;
flex-direction: column;
gap: 10px;
padding: 10px 0;
.tag {
width: 126px;
height: 24px;
background: rgba(255, 153, 0, 0.3);
border: 1px solid;
border-color: rgba(255, 153, 0, 0.85);
border-radius: 2px;
display: flex;
align-items: center;
padding: 0 6px;
img {
width: 16px;
height: 16px;
}
}
}
}
}
</style>
@@ -0,0 +1,195 @@
<template>
<div class="strategy-container" @click.stop>
<div class="strategy-main">
<div class="strategy-main-title">
{{ "ZF策略" }}
</div>
<div>
<div v-for="(strategy, index) in strategyInfoDict" class="strate-list">
<div class="strate-item" v-if="strategy.isVisible">
<img :src="`src/assets/strategy-logo/${strategy.key}.svg`" alt="" class="strate-item-logo" />
<span class="strate-item-key">{{ strategy.key }}:</span>
<span class="strate-item-value text-ellipsis" :class="{
' ellipsis2':
strategy.name == '信息主题' || strategy.name == '人设',
}">
{{ strategy?.value }}
</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
const strategyInfoDict = ref([
{
key: "信息主题",
value: "",
isVisible: true,
},
{
key: "信息数量",
value: "",
isVisible: true,
},
{
key: "人设",
value: "",
isVisible: true,
},
{
key: "人设数量",
value: "",
isVisible: true,
},
{
key: "平台",
value: "",
isVisible: true,
},
{
key: "模态",
value: "",
isVisible: true,
},
{
key: "语种",
value: "",
isVisible: true,
},
{
key: "账号类型",
value: "",
isVisible: true,
},
{
key: "信息发布时间段",
value: "",
isVisible: false,
},
]);
const props = defineProps({
msg: String,
data: Object,
});
onMounted(() => {
console.log({ data: props });
if (props.data) {
const data = props.data;
strategyInfoDict.value.forEach((it) => {
switch (it.key) {
case "信息主题": {
it["value"] = data?.extendInfo?.informationTopic;
break;
}
case "信息数量": {
it["value"] = "";
break;
}
case "人设": {
it["value"] = data?.personaJson ? data?.personaJson[0]?.persona : "";
break;
}
case "人设数量": {
it["value"] = data?.personaJson ? data?.personaJson[0]?.size : "";
break;
}
case "平台": {
it["value"] = data?.extendInfo?.platformData;
break;
}
case "模态": {
it["value"] = "";
break;
}
case "语种": {
it["value"] = "";
break;
}
case "账号类型": {
it["value"] = "";
break;
}
}
});
}
});
</script>
<style scoped>
.strategy-container {
z-index: 600;
color: #fff;
position: absolute;
left: 55%;
backdrop-filter: blur(15px);
.strategy-main {
width: 316px;
height: 460px;
background: rgba(3, 38, 80, 0.8);
border: 1px solid;
border-color: rgba(43, 143, 254, 0.6);
border-radius: 4px;
padding: 0 10px;
.strategy-main-title {
width: 141px;
height: 32px;
background: rgba(3, 38, 80, 1);
border: 1px solid;
border-color: rgba(43, 143, 254, 0.6);
border-radius: 100px;
backdrop-filter: blur(15px);
position: relative;
top: -16px;
left: 25%;
text-align: center;
line-height: 32px;
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #ffffff;
font-size: 16px;
}
}
}
.strate-item {
display: flex;
align-items: top;
justify-content: left;
margin: 20px 5px;
.strate-item-logo {
width: 16px;
height: 25px;
margin-right: 10px;
}
.strate-item-key {
width: 80px;
height: 16px;
line-height: 26px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #aaceff;
font-size: 16px;
margin-right: 10px;
text-align: left;
}
.strate-item-value {
width: 148px;
max-height: 50px;
line-height: 26px;
font-family: Noto Sans S Chinese;
color: #ffffff;
font-size: 16px;
}
}
</style>
@@ -0,0 +1,365 @@
<template>
<div class="yqxg-container" @click.stop>
<div class="yqxg-title">预期效果</div>
<div class="yqxg-content-top-one">
<div class="yqxg-left-top">
<div class="yqxg-left-top-count">
{{ data["撬动关键节点"] }}
<span class="yqxg-left-top-count-a">个</span>
</div>
<div class="yqxg-left-top-title">撬动关键节点</div>
</div>
<div class="yqxg-center">
<div class="yqxg-center-count">
{{ numberToChinese(data["六度量等级"]) }} 级
</div>
<div class="yqxg-center-title">六度量等级</div>
</div>
<div class="yqxg-right-top">
<div class="yqxg-right-top-count">
{{ data["引发主流媒体报道"] }}
<span class="yqxg-right-top-count-a">个</span>
</div>
<div class="yqxg-right-top-title">引发主流媒体报道</div>
</div>
</div>
<div class="yqxg-content-top-two">
<div class="yqxg-left-bottom">
<div class="yqxg-left-bottom-flag">{{ data["引发官方回应"] }}</div>
<div class="yqxg-left-bottom-title">引发官方回应</div>
</div>
<div class="yqxg-right-bottom">
<div class="yqxg-right-bottom-flag">{{ data["引发线下活动"] }}</div>
<div class="yqxg-right-bottom-title">引发线下活动</div>
</div>
</div>
<div class="yqxg-content-top-three">
<div class="yqxg-content-top-three-content">
<span class="yqxg-conetnt-top-three-tag" :style="tagColor('未推演')">
{{ "未推演" }}
</span>
{{ data["预期效果"] }}
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, watch } from "vue";
const props = defineProps({
msg: String,
data: Object,
});
onMounted(() => { });
const tagColor = (status = "未推演") => {
const colorList = [
{
name: "已推演",
backgroundColor: "rgba(0, 140, 119, 0.5)",
borderColor: "#008c77",
},
{
name: "推演中",
backgroundColor: "rgba(255, 153, 0, 0.5)",
borderColor: "#ff9900",
},
{
name: "未推演",
backgroundColor: "rgba(0, 121, 254, 0.5)",
borderColor: "#0079fe",
},
];
const item = colorList.find((it) => it.name === status);
// 添加默认样式处理
if (!item) {
console.warn(`找不到对应状态的样式: ${status}`);
return {
background: "rgba(200, 200, 200, 0.5)",
"border-color": "#cccccc",
};
}
return {
background: item.backgroundColor,
"border-color": item.borderColor,
};
};
const numberToChinese = (num) => {
const map = {
1: "一",
2: "二",
3: "三",
4: "四",
5: "五",
6: "六",
};
return map[num] || num;
};
</script>
<style scoped>
.yqxg-container {
position: absolute;
right: 80px;
width: 536px;
height: 346px;
background: rgba(3, 38, 80, 1);
border: 1px solid;
border-color: rgba(43, 143, 254, 0.6);
border-radius: 4px;
z-index: 600;
.yqxg-title {
position: relative;
top: -16px;
left: 155px;
width: 227px;
height: 32px;
background: rgba(3, 38, 80, 0.8);
border: 1px solid;
border-color: rgba(43, 143, 254, 0.6);
border-radius: 100px;
backdrop-filter: blur(15px);
text-align: center;
line-height: 30px;
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #ffffff;
font-size: 16px;
}
}
.yqxg-content-top-one {
display: flex;
justify-content: center;
position: absolute;
width: 100%;
top: 30px;
}
.yqxg-left-top {
width: 125px;
height: 52px;
background: url("../../assets/6duliang/六度量四周bg.svg") no-repeat;
background-size: cover;
margin: 0 5px;
position: relative;
top: 30px;
.yqxg-left-top-count {
height: 37px;
line-height: 62px;
text-shadow: 0px 2px 4px rgba(67, 233, 233, 0.4);
font-family: DS-Digital;
font-weight: 700;
color: #ffffff;
font-size: 38px;
text-align: center;
position: relative;
top: -30px;
left: 5px;
}
.yqxg-left-top-count-a {
width: 16px;
height: 16px;
line-height: 28px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: 16px;
}
.yqxg-left-top-title {
height: 14px;
line-height: 28px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: 14px;
text-align: center;
position: relative;
top: -11px;
}
}
.yqxg-center {
width: 213px;
height: 111px;
background: url("../../assets/6duliang/六度量中心bg.svg") no-repeat;
background-size: cover;
.yqxg-center-count {
height: 38px;
line-height: normal;
text-shadow: 0px 0px 12px rgba(232, 233, 67, 0.62);
font-family: Noto Sans S Chinese;
font-weight: 700;
color: #ffffff;
font-size: 38px;
letter-spacing: 0px;
text-align: center;
position: relative;
top: 17px;
}
.yqxg-center-title {
height: 16px;
line-height: normal;
font-family: Noto Sans S Chinese;
color: #ffffff;
font-size: 16px;
text-align: center;
position: relative;
top: 70px;
}
}
.yqxg-right-top {
width: 125px;
height: 52px;
background: url("../../assets/6duliang/六度量四周bg.svg") no-repeat;
background-size: cover;
margin: 0 5px;
position: relative;
top: 44px;
.yqxg-right-top-count {
line-height: 62px;
text-shadow: 0px 2px 4px rgba(67, 233, 233, 0.4);
font-family: DS-Digital;
font-weight: 700;
color: #ffffff;
font-size: 38px;
text-align: center;
position: relative;
top: -30px;
}
.yqxg-right-top-count-a {
width: 16px;
height: 16px;
line-height: 28px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: 16px;
}
.yqxg-right-top-title {
height: 14px;
line-height: 28px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: 14px;
text-align: center;
top: -36px;
position: relative;
}
}
.yqxg-content-top-two {
padding: 0 55px;
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
top: 120px;
.yqxg-left-bottom {
width: 125px;
height: 52px;
background: url("../../assets/6duliang/六度量四周bg.svg") no-repeat;
background-size: cover;
.yqxg-left-bottom-flag {
height: 20px;
line-height: 28px;
text-shadow: 0px 2px 4px rgba(67, 233, 233, 0.4);
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #ffffff;
font-size: 20px;
text-align: center;
position: relative;
top: -10px;
}
.yqxg-left-bottom-title {
height: 14px;
line-height: 28px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: 14px;
text-align: center;
position: relative;
top: 5px;
}
}
.yqxg-right-bottom {
width: 125px;
height: 52px;
background: url("../../assets/6duliang/六度量四周bg.svg") no-repeat;
background-size: cover;
.yqxg-right-bottom-flag {
height: 20px;
line-height: 28px;
text-shadow: 0px 2px 4px rgba(67, 233, 233, 0.4);
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #ffffff;
font-size: 20px;
text-align: center;
position: relative;
top: -10px;
}
.yqxg-right-bottom-title {
height: 14px;
line-height: 28px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: 14px;
text-align: center;
position: relative;
top: 5px;
}
}
}
.yqxg-content-top-three {
width: 488px;
height: 79px;
background: rgba(1, 12, 28, 0.15);
border-radius: 4px;
margin: 19px 23px;
padding: 5px;
position: relative;
top: 120px;
.yqxg-conetnt-top-three-tag {
padding: 3px;
height: 22px;
border: 1px solid;
border-radius: 2px;
}
.yqxg-content-top-three-content {
width: 456px;
height: 44px;
line-height: 28px;
font-family: Noto Sans S Chinese;
color: #ffffff;
font-size: 16px;
}
}
</style>
@@ -0,0 +1,65 @@
<template>
<Teleport to="body">
<div class="G6Modal" v-if="modalType" ref="G6Modal" @click="closeModal()">
<component :is="componentRule[modalType]" :data="data" />
</div>
</Teleport>
</template>
<script>
import Yqxg from "./components/Yqxg.vue"
import Strategy from "./components/Strategy.vue"
import Audience from './components/Audience.vue'
export default {
props: ['modalType', 'data'],
data() {
return {
componentRule: {
'xgfx': 'Yqxg',
'CL': 'Strategy',
'audience': 'Audience'
}
};
},
emits: ['updateModalType',],
components: { Yqxg, Strategy, Audience },
watch: {
modalType: {
handler(v) {
console.log(v);
if (v) {
this.openModal(v)
}
}
}
},
methods: {
openModal(t) {
},
closeModal() {
this.$emit('updateModalType', '')
}
},
mounted() {
console.log(this.$refs.G6Modal);
}
};
</script>
<style lang="less" scoped>
.G6Modal {
z-index: 99999;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, .4);
display: flex;
align-items: center;
justify-content: center;
}
</style>
@@ -0,0 +1,114 @@
<template>
<div class="analysis-tool">
<div class="title-content-item margin-bottom-10">
分析工具
</div>
<div class="tool-content">
<div class="list-item" v-for="(item, index) in toolList" :key="index">
{{ item.title }}
</div>
</div>
<div class="title-content-item margin-bottom-10">
分析结果
</div>
<div class="analysis-content">
<div class="list-item" v-for="(item, index) in list" :key="index">
<div class="item-title">
<span class="item-tag tab-lightblue">战机</span>
{{ item.title }}
</div>
<div class="item-footer">
<span class="item-value">参考依据</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
defineProps({
msg: String,
})
const count = ref(0);
const toolList = ref([
{ title: '战机抽取', checked: false },
{ title: '威胁分析抽取', checked: false },
{ title: '整体态势分析', checked: false },
{ title: '对手叙事抽取', checked: false },
{ title: '口径分析', checked: false },
{ title: '目标分析', checked: false },
]);
const list = ref([
{ title: '舆论揭露民进党政客鼓吹战争却将家人送往海外的双标行为,认为其是战争贩子,削弱了台湾当局的执政合法性。', type: '战机' },
{ title: '舆论揭露民进党政客鼓吹战争却将家人送往海外的双标行为,认为其是战争贩子,削弱了台湾当局的执政合法性。', type: '战机' },
{ title: '舆论揭露民进党政客鼓吹战争却将家人送往海外的双标行为,认为其是战争贩子,削弱了台湾当局的执政合法性。', type: '战机' },
{ title: '舆论揭露民进党政客鼓吹战争却将家人送往海外的双标行为,认为其是战争贩子,削弱了台湾当局的执政合法性。', type: '战机' },
{ title: '舆论揭露民进党政客鼓吹战争却将家人送往海外的双标行为,认为其是战争贩子,削弱了台湾当局的执政合法性。', type: '战机' },
])
</script>
<style scoped lang="less">
.analysis-tool {
z-index: 500;
color: #fff;
padding: 10px;
height: calc(100vh - 200px);
overflow-y: auto;
.tool-content {
padding: 10px;
.list-item {
width: 29%;
display: inline-block;
padding: 15px 15px;
font-size: 20px;
font-family: 'Noto Sans S Chinese';
font-weight: 700;
background: #02416a;
border-radius: 5px;
margin: 10px;
text-align: center;
}
}
.analysis-content {
.list-item {
padding: 10px;
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
margin: 15px;
.item-title {
font-size: var(--fontSize);
font-family: 'Noto Sans S Chinese';
}
.item-footer {
font-size: var(--fontSizes);
text-align: right;
.item-value {
color: #45c3f3;
text-decoration: underline;
cursor: pointer;
}
}
}
}
.item-tag {
display: inline-block;
padding: 2px 5px;
margin: 5px;
font-size: var(--fontSizes);
border-radius: 4px;
border: 1px solid;
}
}
</style>
@@ -0,0 +1,67 @@
<template>
<div class="chat-content">
<div class="chat-list-content">
<ChatList :chatList="chatList"/>
</div>
<div class="chat-input-content">
<t-textarea v-model="chatInputValue" placeholder="请输入内容"
name="description" :autosize="{ minRows: 2, maxRows: 5 }" />
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import ChatList from './ChatList.vue';
import chatData from '../../assets/json/chatData.json'
defineProps({
msg: String,
})
const chatList = ref([]);
const chatInputValue = ref('');
onMounted(() => {
chatList.value = chatData;
console.log('chatList',chatList.value)
})
</script>
<style scoped lang="less">
.chat-content {
z-index: 500;
color: #fff;
padding: 10px;
background: rgba(0, 98, 217, 0.1);
border-radius: 4px;
box-shadow: 0 1px var(--fontSize) #8b8b8b0f inset;
position: relative;
box-sizing: border-box;
.chat-list-content {
height: calc(100vh - 335px);
overflow-y: auto;
margin-bottom: 60px;
}
.chat-input-content {
width: 100%;
background-color: rgba(0, 98, 217, 0.2);
padding: 10px;
border: 1px solid;
border-color: #0062d9;
border-radius: 10px;
box-shadow: 0 3px 6px #8b8b8b29;
overflow: hidden;
}
}
:deep(.t-textarea__inner) {
border: 0;
&:focus {
box-shadow: none;
}
}
</style>
@@ -0,0 +1,373 @@
<template>
<div class="chat-list">
<t-loading size="small" :loading="loading" show-overlay>
<div class="chat-list-content">
<div class="chat-list-items" v-for="(item,index) in chatList" :key="index">
<div class="chat-list-item">
<div class="user-item-container">
<div class="user-item">
<div class="user-item-content">
<div class="user-content-title">{{ item.userTitle }} </div>
</div>
<div class="chat-user-logo" style="margin-left: 10px">
<img src="../../assets/icon/user-logo.svg" alt="" />
</div>
</div>
</div>
<div class="chat-item-container">
<div class="chat-item">
<div class="chat-logo-red" style="margin-right: 10px">
<img src="../../assets/icon/chat-logo.svg" alt="" />
</div>
<div class="chat-item-contents">
<div class="chat-item-content">
<span v-if="item.loading">正在思考<span class="chat-blink">...</span></span>
<div v-if="item.thinkTitle" class="chat-think-title">
<div class="chat-think-head flex-between-center" @click="chatThinkChange(index)">
<span>
<check-circle-icon :stroke-width="2.5" strokeColor="#45c3f3" size="20px"/>
<span nz-icon nzType="check-circle" nzTheme="outline"
style="color: var(--color-main); margin-right: 10px"></span>
<span>已深度思考</span>
</span>
<span nz-icon nzType="down" nzTheme="outline"></span>
<chevron-down-icon :stroke-width="2.5" strokeColor="#fff" size="20px"/>
</div>
<div class="chat-think-body" :class="{ 'chat-think-hidden': item.thinkShow }">
<CodeData :markdown="item.thinkTitle"/>
</div>
</div>
<div class="chat-content-title" v-if="chatIndex !== index || !editShow">
<CodeData :markdown="item.chatTitle"/>
</div>
<div class="answer-title" v-if="item.chatStop" @click="taskStop"> 停止生成 </div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</t-loading>
</div>
</template>
<script setup>
import { ref } from 'vue'
import CodeData from '../markdown/CodeData.vue'
import { CheckCircleIcon, ChevronDownIcon } from 'tdesign-icons-vue-next';
defineProps({
chatList: Array,
})
const loading = ref(false);
const chatIndex = ref(0);
const editShow = ref(false);
const chatThinkChange = (index) => {
}
const taskStop = () => {
}
const materialsListChange = () => {
}
</script>
<style scoped lang="less">
.chat-list {
width: 100%;
padding: 10px;
.chat-list-item {
width: 100%;
&::after {
content: '';
display: block;
clear: both;
}
.user-item-container,
.chat-item-container {
width: 100%;
}
.user-item {
display: flex;
justify-content: flex-end;
margin-bottom: 30px;
position: relative;
font-size: var(--fontSize);
line-height: 26px;
font-family: 'Noto Sans S Chinese';
.user-item-logo {
width: 45px;
height: 43px;
background-position: -706px -23px;
}
.user-item-content {
max-width: 80%;
// background: #d7e9f0;
background: var(--user-item-bg);
padding: 10px 15px;
border-radius: 8px 0px 8px 8px;
}
}
.chat-item {
min-height: 60px;
display: flex;
margin-bottom: 30px;
font-size: var(--fontSize);
line-height: 26px;
font-family: 'Noto Sans S Chinese';
// justify-content: flex-end;
// margin: 10px 0px;
.chat-item-contents {
width: 80%;
}
.chat-item-content {
// border: 1px solid #ddd;
// padding: 6px;
// border-radius: 5px;
background: var(--chat-item-bg);
border-radius: 0px 8px 8px 8px;
box-shadow: 0px 3px 12px rgba(0, 0, 0, 0.07);
padding: 10px 20px;
}
.chat-item-logo {
width: 45px;
height: 43px;
background-position: -758px -23px;
}
.chat-option-content {
padding: 5px 15px;
background: #ffffff;
border-radius: 8px;
box-shadow: 0px 3px 12px rgba(0, 0, 0, 0.07);
margin-top: 10px;
float: right;
}
}
}
}
// 引用样式调整
.chat-content {
max-height: 500px;
overflow-y: auto;
padding-right: 10px;
.chat-header {
margin-bottom: 5px;
.chat-head-title {
font-size: 20px;
font-weight: bold;
font-family: 'Noto Sans S Chinese';
margin-bottom: 5px;
}
.chat-head-subtitle {
font-size: var(--fontSize);
color: #222222;
}
}
.chat-link {
color: #ffffff;
background: var(--color-main);
display: inline-block;
padding: 2px 10px;
border-radius: 5px;
cursor: pointer;
}
}
.chat-think-title {
padding: 10px;
box-sizing: border-box;
font-family: 'Noto Sans S Chinese';
background-color: var(--theme-area-bg);
border-radius: 5px;
border: 1px solid var(--think-border-color);
margin-bottom: 10px;
.chat-think-head {
margin-bottom: 5px;
cursor: pointer;
}
.chat-think-body {
max-height: 10000px;
/* 设置一个足够大的值 */
padding: 0 10px;
overflow-y: auto;
font-size: var(--fontSize);
color: var(--think-font-color);
transition: max-height 0.5s ease;
/* 过渡效果 */
}
.chat-think-hidden {
max-height: 0;
overflow: hidden;
}
}
.chat-content-clear {
text-align: center;
margin-top: 50px;
span {
font-size: var(--fontSizes);
}
&:hover {
color: #575a61;
}
}
.cloud-content {
cursor: pointer;
text-align: center;
}
.chat-save {
color: green !important;
}
.user-content {
border: 1px solid #dddddd;
border-radius: 5px;
padding: 10px;
box-sizing: border-box;
.user-head {
width: 100%;
}
.user-body {
max-height: 400px;
overflow-y: auto;
}
}
.knowledge-title {
font-size: var(--fontSizes);
margin-top: 10px;
color: #98a2b3;
}
.blue-pxnew {
background-image: url('src/assets/icon/pxnew-blue.png');
}
.red-pxnew {
background-image: url('src/assets/icon/pxnew-red.png');
}
@keyframes blink {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.chat-blink {
/* -webkit-animation: blink 1s steps(5, start) infinite; */
animation: blink 1s infinite;
/* content: "▋"; */
margin-left: 0.25rem;
vertical-align: baseline;
}
.chat-link-title {
width: 100%;
color: #537ac0;
font-size: var(--fontSize);
cursor: pointer;
}
.edit-history {
width: 100%;
padding: 0px 5px;
border: 2px solid var(--bg-color);
border-radius: 5px;
}
.answer-title {
color: var(--color-main) !important;
font-size: var(--fontSizes) !important;
cursor: pointer;
}
[contenteditable='true']:focus {
outline: none;
/* 取消默认的焦点样式 */
/* 设置边框颜色 */
}
.flex-content {
display: flex;
justify-content: space-between;
}
.font-color {
color: var(--color-main);
}
.item-tag {
padding: 2px;
border: 1px solid;
}
.tag-yellow {
border-color: #fda !important;
color: #d97b00 !important;
background-color: #fff6ea !important;
}
.extraction-content {
padding: 5px 10px;
color: var(--color-main) !important;
background: #ffffff;
border: 1px solid var(--color-main);
border-radius: 5px;
margin-top: 15px;
display: inline-block;
cursor: pointer;
}
.edit-user {
cursor: pointer;
color: var(--color-main);
position: absolute;
bottom: -20px;
right: 56px;
}
.edit-user-concal {
cursor: pointer;
color: var(--color-main);
position: absolute;
bottom: -20px;
right: 86px;
}
</style>
@@ -0,0 +1,30 @@
<template>
<div class="inteligent-helper">
<t-tabs v-model="tabIndex">
<t-tab-panel :value="1" label="交互式分析" :destroy-on-hide="false">
<InteractiveAnalysis/>
</t-tab-panel>
<t-tab-panel :value="2" label="分析素材" :destroy-on-hide="false">
</t-tab-panel>
</t-tabs>
</div>
</template>
<script setup>
import { ref } from 'vue';
import InteractiveAnalysis from './InteractiveAnalysis.vue';
defineProps({
msg: String,
})
const tabIndex = ref(1)
</script>
<style scoped>
.inteligent-helper {
z-index: 500;
color: #fff;
padding: 10px;
}
</style>
@@ -0,0 +1,37 @@
<template>
<div class="interactive-analysis">
<t-row :gutter="16">
<t-col :span="8">
<div>
<ChatContent/>
</div>
</t-col>
<t-col :span="4">
<div>
<AnalysisTool/>
</div>
</t-col>
</t-row>
</div>
</template>
<script setup>
import { ref } from 'vue';
import ChatContent from './ChatContent.vue';
import AnalysisTool from './AnalysisTool.vue';
defineProps({
msg: String,
})
const count = ref(0)
</script>
<style scoped>
.interactive-analysis{
z-index: 500;
color: #fff;
padding: 10px;
}
</style>
@@ -0,0 +1,194 @@
<template>
<div class="markdown-renderer markdown-body" v-html="renderedMarkdown"></div>
</template>
<script setup>
import { ref, computed, onMounted } from "vue";
import MarkdownIt from 'markdown-it'
import hljs from "highlight.js";
import "highlight.js/styles/github-dark.css";
const props = defineProps({
markdown: {
type: String,
default: "",
},
});
const md = new MarkdownIt({
html: true, // 启用 HTML 解析
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return (
'<pre class="hljs"><code>' +
hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +
"</code></pre>"
);
} catch (__) {}
}
return (
'<pre class="hljs"><code>' + md.utils.escapeHtml(str) + "</code></pre>"
);
},
breaks: true,
linkify: true,
});
const renderedMarkdown = computed(() => {
return md.render(props.markdown);
});
</script>
<style scoped lang="less">
/* 覆盖 github-markdown-css 的一些样式,使其更美观 */
:deep(.markdown-body) {
font-size: var(--fontSize);
line-height: 1.6;
}
:deep(.markdown-body h1),
:deep(.markdown-body h2),
:deep(.markdown-body h3),
:deep(.markdown-body h4),
:deep(.markdown-body h5),
:deep(.markdown-body h6) {
margin-top: 24px;
margin-bottom: var(--fontSize);
font-weight: 600;
line-height: 1.25;
}
:deep(.markdown-body h1) {
font-size: 2em;
border-bottom: 1px solid #eaecef;
padding-bottom: 0.3em;
}
:deep(.markdown-body h2) {
font-size: 1.5em;
border-bottom: 1px solid #eaecef;
padding-bottom: 0.3em;
}
:deep(.markdown-body h3) {
font-size: 1.25em;
}
:deep(.markdown-body p) {
margin-top: 0;
margin-bottom: var(--fontSize);
}
:deep(.markdown-body ul),
:deep(.markdown-body ol) {
margin-top: 0;
margin-bottom: var(--fontSize);
padding-left: 2em;
}
:deep(.markdown-body li) {
margin-top: 0.25em;
}
:deep(.markdown-body pre) {
margin-top: 0;
margin-bottom: var(--fontSize);
padding: var(--fontSize);
overflow: auto;
font-size: 85%;
line-height: 1.45;
background-color: #f6f8fa;
border-radius: 6px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
:deep(.markdown-body code) {
padding: 0.2em 0.4em;
margin: 0;
font-size: 85%;
background-color: rgba(27, 31, 35, 0.05);
border-radius: 3px;
}
:deep(.markdown-body pre code) {
padding: 0;
background-color: transparent;
border: 0;
}
:deep(.markdown-body a) {
color: #0366d6;
text-decoration: none;
transition: color 0.2s;
}
:deep(.markdown-body a:hover) {
text-decoration: underline;
color: #0353a4;
}
:deep(.markdown-body blockquote) {
padding: 0 1em;
color: #6a737d;
border-left: 0.25em solid #dfe2e5;
margin: 0 0 var(--fontSize) 0;
background-color: #f6f8fa;
border-radius: 0 6px 6px 0;
}
:deep(.markdown-body img) {
max-width: 100%;
box-sizing: content-box;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
:deep(.markdown-body table) {
display: block;
width: 100%;
overflow: auto;
margin-bottom: var(--fontSize);
border-spacing: 0;
border-collapse: collapse;
}
:deep(.markdown-body table th) {
font-weight: 600;
background-color: #f6f8fa;
}
:deep(.markdown-body table th),
:deep(.markdown-body table td) {
padding: 6px 13px;
border: 1px solid #dfe2e5;
}
:deep(.markdown-body table tr) {
background-color: #fff;
border-top: 1px solid #c6cbd1;
}
:deep(.markdown-body table tr:nth-child(2n)) {
background-color: #f6f8fa;
}
:deep(.markdown-body .task-list-item) {
list-style-type: none;
}
:deep(.markdown-body .task-list-item input[type="checkbox"]) {
margin: 0 0.2em 0.25em -1.6em;
vertical-align: middle;
}
:deep(.markdown-body) {
hr {
height: 2px;
background: #559ffe;
border-color: #559ffe;
}
}
</style>
@@ -0,0 +1,71 @@
<template>
<div class="scrollingloading" ref="targetElement">
</div>
</template>
<script>
export default {
data() {
return {
isIntersecting: false,
targetElement: null,
observer: null
}
},
props: {
onState: {
type: Boolean,
default: false
},
},
methods: {
initObserver() {
this.targetElement = this.$refs.targetElement
this.observer = new IntersectionObserver(this.handleIntersection, {
threshold: 1 // 当元素尺寸进入视口时触发,0-1代表0%-100%
});
if (this.targetElement) {
this.observer.observe(this.targetElement);
}
},
stopObserver() {
if (this.targetElement && this.observer) {
this.observer.unobserve(this.targetElement);
}
},
handleIntersection(entries, observer) {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.isIntersecting = true;
console.log(this.onState);
if (this.onState) {
this.$emit('onChange')
}
console.log('元素出现在了视图中,开始触发事件');
} else {
this.isIntersecting = false;
console.log('元素在视图中不可见');
}
});
}
},
mounted() {
this.initObserver();
console.log('初始化');
},
beforeDestroy() {
this.stopObserver();
},
}
</script>
<style lang="less">
.scrollingloading {
width: 100%;
height: 10px;
}
</style>
@@ -0,0 +1,391 @@
<template>
<div class="searchTaskList" :style="{ 'height': height }">
<div class="filter">
<t-input style="flex: 1;" v-model="keyword" placeholder="请输入内容搜索" @enter="resetSearch" />
<t-select style="width: 200px" v-if="searchType === 'task'" v-model="selectTaskStatus"
@change="resetSearch">
<t-option v-for="(item, index) in statusList" :label="item.label" :value="item.value" :key="index" />
</t-select>
<t-date-range-picker :presets="presets" style="width: 240px;" @change="resetSearch" v-model="time"
enable-time-picker />
<div class="tabs-box" v-if="searchType === 'task'">
<span class="sortBtn" :class="{ 'sort-active': range === 'all' }" @click="switchRane('all')">全部</span>
<span class="sortBtn" :class="{ 'sort-active': range === 'me' }" @click="switchRane('me')">我的</span>
</div>
</div>
<AddTaskDialog :taskSuperiorFlag="taskSuperiorFlag" @success="addTaskSuccess" />
<div class="list">
<template v-for="(item, index) in taskList" :key="index">
<div class="item cursor-pointer" @click="selectTask(item)">
<div class="task-status-logo" :class="handleBg(item.taskStatus)">{{ handleStatus(item.taskStatus) }}
</div>
<div class="item-title">{{ item.taskName }}</div>
<div class="tab-list">
<span class="item-tab tab-green">{{ item.taskDirection }}</span>
<span class="item-tab tab-lightblue">{{ taskLevel[item.taskLevel] }}</span>
<span v-if="searchType === 'task'" class="item-tab"
style="background-color:skyblue;border-color: goldenrod;">{{ item.ifCreateTask === 0 ?
'已创建任务分析' : '未创建任务分析'
}}</span>
</div>
<div class="item-content text-ellipsis ellipsis3">
{{ item.taskContent }}
</div>
<div class="item-footer flex-content">
</div>
<div class="item-footer flex-content">
<span class="item-label">
{{ sourceType[item.sourceType] }}
</span>
<span v-if="item['sumAll']" class="item-label">完成度 {{ item['endCount'] }}/{{
item['sumAll'] }}</span>
<span class="item-date">
{{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</span>
</div>
</div>
</template>
<scrollingloading :onState="isScrolling" @onChange="scrollingloadingChange()" />
</div>
<t-back-top container=".list" size="small" theme="light" :visible-height="100" :offset="[20, 20]"
style="position: absolute; right: 20px; bottom: 0"></t-back-top>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, watch } from 'vue';
import axios from "@/utils/request"
import taskStatus from '@/common/taskStatus';
import taskLevel from '@/common/taskLevel';
import sourceType from "@/common/sourceType"
import dayjs from 'dayjs'
import scrollingloading from "@/components/scrollingloading/index.vue"
import AddTaskDialog from "@/components/dialog/addTaskDialog.vue"
import { useRoute } from 'vue-router';
const route = useRoute()
const time = ref([])
const keyword = ref('')
const taskList = ref([])
const emit = defineEmits(['selectTask', 'updateRange'])
const isScrolling = ref(false) //是否开起滚动加载
const presets = ref({
最近7天: [dayjs().subtract(6, 'day').toDate(), dayjs().toDate()],
最近3天: [dayjs().subtract(2, 'day').toDate(), dayjs().toDate()],
今天: [dayjs().toDate(), dayjs().toDate()],
});
const statusList = ref([
{ label: "分析中", value: "20", bgClass: 'pendinganalysis' },
{ label: "已完成", value: "25,30,40,60,70,80,90,100,110", bgClass: 'completed' },
{ label: "未通过", value: "50,120", bgClass: 'failed' },
])
const props = defineProps({
range: String,
height: {
default: '100%'
},
searchType: {
default: 'task'
},
taskDirection: {
default: 'all'
},
taskSuperiorFlag: {
default: null
}
})
const addTaskSuccess = () => {
resetSearch()
}
//滚动加载事件
const scrollingloadingChange = () => {
console.log('开始加载数据');
pageNum.value++
if (props.searchType === 'task') {
getListData();
} else if (props.searchType === 'action') {
taskActionSearch();
}
}
const resetSearch = () => {
pageNum.value = 1
taskList.value = []
if (props.searchType !== 'task') {
taskActionSearch();
} else {
getListData();
}
}
// 行动任务搜索
const taskActionSearch = async () => {
console.log(props.taskDirection);
isScrolling.value = false
const params = {
pageNo: pageNum.value,
pageSize: pageSize.value,
orderBy: 'createTime',
orderByType: 'desc',
type: 'task',
keyword: keyword.value,
taskDirection: props.taskDirection == 'all' ? null : props.taskDirection
}
console.log(params);
let urlCount = environment['b1ConsumerUrl'] + '/taskActionSearch/getActionSearchCount';
await axios.get(urlCount, { params }).then(res => {
console.log('res', res);
total.value = res.data;
})
let url = environment['b1ConsumerUrl'] + '/taskActionSearch/getActionSearch';
axios.get(url, { params }).then(res => {
console.log('res', res);
let result = res.data;
taskList.value = [...taskList.value, ...result];
if (total.value > taskList.value.length) {
isScrolling.value = true
}
})
}
const switchRane = (d) => {
emit('updateRange', d)
};
watch(() => props.range, (newRange) => {
resetSearch()
});
watch(() => props.taskDirection, (newRange) => {
console.log(newRange);
resetSearch()
});
const handleStatus = d => {
return searchStatus(d).label
}
const handleBg = d => {
return searchStatus(d).bgClass
}
const searchStatus = d => {
let obj
statusList.value.forEach(i => {
let arr = i.value.split(',').map(Number)
if (arr.includes(d)) {
obj = i
}
})
return obj
}
const selectTaskStatus = ref('20,25,30,40,60,70,80,90,100,110,50,120')
const pageNum = ref(1)
const pageSize = ref(10)
const total = ref(0)
const url = ref('')
const getListData = () => {
isScrolling.value = false
let params = {
content: keyword.value,
endTime: time.value[1],
pageNum: pageNum.value,
pageSize: pageSize.value,
startTime: time.value[0],
taskStatus: selectTaskStatus.value,
taskDirection: props.taskDirection == 'all' ? null : props.taskDirection
}
let allUrl = props.range === 'all' ? url.value : '/taskAnalyseSearch/cop-my-tasks';
allUrl = environment['b1ConsumerUrl'] + allUrl
axios.get(allUrl, { params }).then(res => {
total.value = res.data.total
taskList.value = [...taskList.value, ...res.data.records]
if (total.value > taskList.value.length) {
isScrolling.value = true
}
})
}
const selectTask = d => {
console.log(d);
emit('selectTask', d)
}
onMounted(() => {
console.log(route.path);
if (route.path.indexOf('/action/task') == -1) {
selectTaskStatus.value = '0,10,20,25,30,40,60,70,80,90,100,110,50,120'
url.value = '/taskAnalyseSearch/cop-task-three-list'
statusList.value = [
{
label: '全部',
value: '0,10,20,25,30,40,60,70,80,90,100,110,50,120'
},
{ label: "待分析", value: "0,10", bgClass: 'uncompleted' },
...statusList.value
]
} else {
selectTaskStatus.value = '20,25,30,40,60,70,80,90,100,110,50,120'
url.value = '/taskAnalyseSearch/cop-task-list'
statusList.value = [
{
label: '全部',
value: '20,25,30,40,60,70,80,90,100,110,50,120'
},
...statusList.value
]
}
resetSearch()
})
</script>
<style scoped lang='less'>
/* Your styles here */
.searchTaskList {
width: 100%;
padding: 20px 0;
display: flex;
flex-direction: column;
position: relative;
width: 450px;
.filter {
display: flex;
flex-wrap: wrap;
gap: 10px;
padding: 0 20px;
.tabs-box {
display: flex;
gap: 10px;
.sortBtn {
padding: 0 10px;
border: 1px solid #2b8ffe99;
color: #fff;
line-height: 32px;
cursor: pointer;
border-radius: 3px;
margin: 0;
}
.action {
background-color: linear-gradient(123.69deg, #2b8ffe, #0062d9) !important;
}
}
}
.list {
height: calc(100% - 76px);
padding: 20px;
overflow-y: auto;
.item {
padding: 10px;
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
border-radius: 4px;
margin-bottom: 15px;
position: relative;
overflow: hidden;
&:hover {
background: rgba(0, 98, 217, 0.4);
border: 1px solid;
border-color: #0062d9;
}
.task-status-logo {
width: 132px;
height: 30px;
transform: rotate(45deg);
position: absolute;
top: 12px;
color: #fff;
text-align: center;
line-height: 30px;
right: -36px;
}
.completed {
background: linear-gradient(134.57deg, #05b89f 14.74%, #007f73 84.95%);
}
.uncompleted {
background: linear-gradient(134.57deg, #d09a14 14.74%, #a76e12 84.95%);
}
.pendinganalysis {
background: linear-gradient(134.57deg, #117dff 14.74%, #0057b8 84.95%);
}
.failed {
background: linear-gradient(134.57deg, #838383 14.74%, #5e5e5e 84.95%);
}
.item-title {
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #ffffff;
font-size: var(--titleSize);
line-height: 24px;
margin-bottom: 10px;
}
.tab-list {
margin-bottom: 10px;
.item-tab {
display: inline-block;
line-height: var(--fontSizes);
padding: 5px 10px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSizes);
border: 1px solid;
border-radius: 4px;
margin-right: 5px;
}
}
.item-content {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSize);
margin-bottom: 10px;
}
.item-footer {
.item-label {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: rgba(255, 255, 255, 0.8);
font-size: var(--fontSize);
}
.item-date {
line-height: 24px;
font-family: Noto Sans S Chinese;
font-weight: 300;
color: rgba(255, 255, 255, 0.8);
font-size: var(--fontSize);
}
}
}
}
}
</style>
@@ -0,0 +1,22 @@
<template>
<t-space direction="vertical" class="flex-center">
<t-empty />
</t-space>
</template>
<script setup>
import { ref } from "vue";
defineProps({
msg: String,
});
const count = ref(0);
</script>
<style scoped>
.task-analysis {
z-index: 500;
color: #fff;
}
</style>
@@ -0,0 +1,279 @@
<template>
<t-tabs :default-value="1" @change="tabChange">
<t-tab-panel :value="1">
<template #label>
<div class="tabLabel">
<!-- <div style="width: 40px;height: 40px;"><img style="width: 100%;" src="/src/assets/icon/u8647.png" alt=""
srcset=""></div> -->
<div>
<div>相关资源</div>
</div>
</div>
<div class="biao" style="color: red;background-image: url('/src/assets/icon/u8649.svg');">差</div>
</template>
<div>
任务相关媒资总数134条,相似任务中平均使用媒资80条。</div>
<div ref="resourcePieRef" class="item-pie"></div>
</t-tab-panel>
<t-tab-panel :value="2">
<template #label>
<div class="tabLabel">
<!-- <div style="width: 40px;height: 40px;"><img style="width: 100%;" src="/src/assets/icon/u8653.png" alt=""
srcset=""></div> -->
<div>
<div>相关账号</div>
</div>
</div>
<div class="biao" style="color: #4B7902;background-image: url('/src/assets/icon/u8654.svg');">良</div>
</template>
<div>任务相关账号总共{{ accountAndCWB.totalCount }}个。</div>
<div ref="accountPieRef" class="item-pie"></div>
</t-tab-panel>
<t-tab-panel :value="3">
<template #label>
<div class="tabLabel">
<!-- <div style="width: 40px;height: 40px;"><img style="width: 100%;" src="/src/assets/icon/u8658.png" alt=""
srcset=""></div> -->
<div>
<div>CWB情况</div>
</div>
</div>
<div class="biao" style="color: #7B4D12;background-image: url('/src/assets/icon/u8659.svg');">优</div>
</template>
<div>
任务相关目标总计{{ accountAndCWB.targetCount }}个,其中{{ accountAndCWB.cbwTargetCount }}个可通过CBW触达,涉及CBW{{
accountAndCWB.cbwCount
}}张。
</div>
<div class="cbw-item" v-for="(v, k, index) in accountAndCWB.cwb">
<div class="cbw-item-title" :style="{ 'background': colorList[index] }">{{ k }}</div>
<div class="cbw-item-content">
<div class="item" v-for="i in v">
{{ i.username }}
</div>
</div>
</div>
</t-tab-panel>
</t-tabs>
</template>
<script setup>
import { ref, onMounted, nextTick } from "vue";
import * as echarts from "echarts";
import { requestAxiosService } from "@/service/request-axios-service"; // 引入发送异步请求方法
import { Background } from "@antv/g6";
const service = requestAxiosService;
const props = defineProps({
msg: String,
taskId: Number
});
onMounted(() => {
resourcePieChart();
getAccountAndCWBData()
});
const colorList = [
'#169bd5',
'#008080',
'#7b4d12', '#169bd5',
'#008080',
'#7b4d12', '#169bd5',
'#008080',
'#7b4d12', '#169bd5',
'#008080',
'#7b4d12',
]
const cbwList = {
传播网id1: [{ username: '名字' }, { username: '名字' }],
传播网id2: [{ username: '名字' }, { username: '名字' }],
传播网id3: [{ username: '名字' }, { username: '名字' }],
传播网id4: [{ username: '名字' }, { username: '名字' }]
}
;
const description = ref("任务相关媒资总数134条,相似任务中平均使用媒资80条。");
const resourcePieRef = ref(null);
const accountPieRef = ref(null);
const tabChange = (value) => {
console.log(value);
nextTick(() => {
if (value === 1) {
resourcePieChart();
} else if (value === 2) {
description.value =
"";
accountPieChart();
} else {
description.value =
"任务相关目标总计85个,其中32个可通过CBW触达,涉及CBW3张。";
}
});
};
// 信息分析饼状图
const resourcePieChart = () => {
if (resourcePieRef.value) {
let chartPie = echarts.init(resourcePieRef.value);
const option = {
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b}: {c} ({d}%)",
},
legend: {
orient: "vertical",
left: "right",
top: "center",
data: ['文本', '图片', '音频', '视频'],
textStyle: {
color: "#fff",
},
},
series: [
{
name: "数据类型",
type: "pie",
radius: "75%",
center: ["25%", "40%"],
label: {
show: false,
},
labelLine: {
show: false, // 隐藏标签线
},
data: [{
name: '文本',
value: 134
}, {
name: '图片',
value: 42
}, {
name: '音频',
value: 33
}, {
name: '视频',
value: 14
}],
},
],
};
chartPie.setOption(option);
}
};
const accountAndCWB = ref({})
const getAccountAndCWBData = () => {
service
.get(`${environment["b1ConsumerUrl"]}/cop/copOwnAccount`, {
taskId: props.taskId,
}).then(res => {
accountAndCWB.value = res.data;
accountPieChart()
})
}
const accountPieChart = () => {
if (accountPieRef.value) {
let data = accountAndCWB.value.personas.map(i => {
return {
value: i.personaAccountCount,
name: i.persona.split(',')[0]
}
})
console.log(data);
let chartPie = echarts.init(accountPieRef.value);
const option = {
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b}: {c} ({d}%)",
},
legend: {
orient: "vertical",
left: "right",
top: "center",
data: data.map(i => i.name),
textStyle: {
color: "#fff",
},
},
series: [
{
name: "数据类型",
type: "pie",
radius: "75%",
center: ["25%", "40%"],
label: {
show: false,
},
labelLine: {
show: false, // 隐藏标签线
},
data: data,
},
],
};
chartPie.setOption(option);
}
};
const count = ref(0);
</script>
<style scoped>
.task-analysis {
z-index: 500;
color: #fff;
}
.tabLabel {
display: flex;
justify-content: space-between;
position: relative;
}
.biao {
position: absolute;
top: 0;
left: -20px;
width: 30px;
line-height: var(--fontSize);
font-size: 12px;
font-weight: 400;
-webkit-transform: rotate(324deg);
-moz-transform: rotate(324deg);
-ms-transform: rotate(324deg);
transform: rotate(324deg);
}
.item-pie {
width: 335px;
height: 200px;
}
.cbw-item {
display: flex;
width: 335px;
line-height: 27px;
}
.cbw-item-title {
line-height: 27px;
padding: 0 10px;
border-radius: 5px;
margin: 2px 0;
}
:deep(.t-tabs__nav-item.t-size-m) {
line-height: 1;
}
:deep(.t-tabs__nav-item-wrapper) {
color: #fff;
text-align: center;
}
:deep(.t-tabs__nav-item.t-is-active) {
background-color: rgba(22, 155, 213, 1);
border-radius: 8px;
}
.cbw-item-content {
display: flex;
gap: 5px;
}
</style>
@@ -0,0 +1,32 @@
<template>
<div class="tabs-list" :style="tabStyle">
<template v-for="(item, index) in tabsList" :key="index">
<div class="tabs-item" :class="{ 'item-active': tabIndex === item.value }" @click="tabsDataChange(item.value)">
{{ item.label }}
</div>
</template>
</div>
</template>
<script setup>
import { ref, defineEmits } from 'vue'
defineProps({
tabsList: Array,
tabIndex: [String, Number, Object, Boolean, Array],
tabStyle: {}
})
const emit = defineEmits(['tabsDataC']) // 定义子组件发送给父组件的函数
const count = ref(0)
const tabsDataChange = (value) => {
console.log('点击了', value)
emit('tabsDataC', value)
}
</script>
<style scoped>
.task-analysis {
z-index: 500;
color: #fff;
}
</style>
+17
View File
@@ -0,0 +1,17 @@
import { createApp } from "vue";
import TDesign from "tdesign-vue-next";
import "tdesign-vue-next/es/style/index.css";
import "leaflet/dist/leaflet.css";
import "./style.css";
import "./style/theme.less";
import "./style/tdesign-style.less";
import "./assets/markdown-css/github-markdown.css";
import App from "./App.vue";
import store from "./store";
import router from "./router";
const app = createApp(App);
app.use(store);
app.use(router);
app.use(TDesign);
app.mount("#app");
@@ -0,0 +1,91 @@
import { path } from "d3";
import { createRouter, createWebHashHistory } from "vue-router";
const routes = [
{
path: "/",
redirect: "/situation-overview",
},
// {
// path: "/test",
// component: () => import("@/views/situation-overview.vue"),
// },
{
path: "/situation-overview",
component: () => import("@/views/situation-overview/index.vue"),
redirect: "/situation-overview/action",
children: [
{
path: "/situation-overview/monitoring",
name: "监测模式",
},
{
path: "action",
name: "行动模式",
redirect: "/situation-overview/action/sentiment",
children: [
{
path: "sentiment",
component: () => import("@/views/sentiment/index.vue"),
},
{
path: "task",
component: () => import("@/views/task/index.vue"),
},
{
path: "action",
component: () => import("@/views/action/index.vue"),
},
{
path: "reply",
component: () => import("@/views/reply/index.vue"),
},
{
path: "control",
component: () => import("@/views/control/index.vue"),
},
{
path: "homeoverview",
component: () => import("@/views/homeOverview/index.vue"),
},
],
},
{
path: "query",
name: "查询模式",
},
],
},
{
path: "/dashboard",
name: "Dashboard",
component: () => import("@/views/Dashboard.vue"),
},
{
path: "/chart",
name: "Chart",
component: () => import("../views/Chart.vue"),
},
{
path: "/map",
name: "Map",
component: () => import("../views/Map.vue"),
},
{
path: "/graph",
name: "Graph",
component: () => import("../views/Graph.vue"),
},
{
path: "/GroupContent",
name: "GroupContent",
component: () => import("../views/GroupContent.vue"),
},
];
const router = createRouter({
history: createWebHashHistory(),
routes,
});
export default router;
@@ -0,0 +1,47 @@
import service from "../utils/request";
export const requestAxiosService = {
get: async (endpoint, params = {}) => {
try {
const response = await service.get(endpoint, { params });
return response;
} catch (error) {
throw new Error(`GET request failed: ${error.message}`);
}
},
post: async (endpoint, data = {}) => {
try {
const response = await service.post(endpoint, data);
return response;
} catch (error) {
throw new Error(`POST request failed: ${error.message}`);
}
},
put: async (endpoint, data = {}) => {
try {
const response = await service.put(endpoint, data);
return response;
} catch (error) {
throw new Error(`PUT request failed: ${error.message}`);
}
},
update: async (endpoint, data = {}) => {
try {
const response = await service.patch(endpoint, data);
return response;
} catch (error) {
throw new Error(`patch request failed: ${error.message}`);
}
},
delete: async (endpoint) => {
try {
const response = await service.delete(endpoint);
return response;
} catch (error) {
throw new Error(`DELETE request failed: ${error.message}`);
}
}
}
@@ -0,0 +1,141 @@
import { environment } from '@/environments/environment';
import { requestCrudService } from '@/service/request-axios-service';
export interface GetOneParam {
fields?: string[]; // 指定返回的字段 id,name
join?: string[]; // 指定关联表,如 ['user||id,name', 'relation||id']
cache?: 0 | 1; // 0直接DB,1缓存,默认1缓存
}
export interface GetAllParam {
fields?: string[] | string; // 指定返回的字段: 多个字段如 'id', 'name'
filter?: string[]; // 指定过滤条件,如 ['name||$eq||batman', 'id||$in||1,2,3', 'field||$isnull', 'relation.id||$eq||1']
or?: string[]; // 同filter
join?: string[]; // 指定关联表,如 ['user||id,name', 'relation||id']
cache?: 0 | 1; // 0直接DB,1缓存,默认1缓存
page?: number; // 页码(会被转换成offset)
offset?: number; // 偏移量
limit?: number; // 每页数量
sort?: string[]; // 排序,如 '['name,ASC', 'id,DESC]'
s?: string;
joinTaskAction?: boolean; //是否连行动表查询
joinTaskActionBoci?: boolean; //策略分析列表使用
}
export interface GetAllResponse {
data: any[];
page: number;
pageCount: number;
count: number;
total: number;
errMsg?: string;
}
let deepCopy = (str: any) => {
return JSON.parse(JSON.stringify(str));
}
export class RequestCrudService {
/**
* 获取单个对象
* @param url 地址
* @param id ID
* @param params 参数
* @returns 单个对象
*/
async getOne(url: string, id: number, params?: GetOneParam): Promise<any> {
const getUrl = `${url}/${id}`;
const res = await requestCrudService.get(getUrl, params);
if (res) return res;
// this.notification.create('error', getUrl, `${res.data}`);
return {};
}
/**
* 获取多个对象
* @param url 地址
* @param params 参数
* @returns 多个对象数组
*/
async getAll(url: string, params: GetAllParam | null = null): Promise<GetAllResponse> {
const formattedParams = deepCopy(params || {});
// 分页默认值
if (!params || !params.limit) formattedParams.limit = 999;
if (!params || !params.page) formattedParams.page = 1;
// 计算offset
if (params && formattedParams.page) {
formattedParams.offset = (formattedParams.page - 1) * formattedParams.limit!;
delete formattedParams.page;
}
const res = await requestCrudService.get(url, formattedParams);
if (res.status === 200) return res.data;
// this.notification.create('error', url, `${res.data}`);
return {
count: 0,
data: [],
page: 1,
pageCount: 1,
total: 0
};
}
/**
* 创建单个对象
* @param url 地址
* @param data 单个对象
* @returns 被创建的单个对象
*/
async createOne(url: string, data: any) {
const res = await requestCrudService.post(url, data);
if (res.status === 201) return res.data;
// this.notification.create('error', url, `${res.data}`);
return {};
}
/**
* 创建多个对象
* @param url 地址
* @param data 多个对象
* @returns 被创建的多个对象
*/
async createMulti(url: string, data: any[]) {
const res = await requestCrudService.post(url, {
bulk: data
});
if (res.status === 201) return res.data;
// this.notification.create('error', url, `${res.data}`);
return [];
}
/**
* 更新单个对象
* @param url 地址
* @param id ID
* @param data 单个对象部分键值对
* @returns 被修改的单个对象
*/
async updateOne(url: string, id: number, data: any) {
const res = await requestCrudService.update(`${url}/${id}`, data);
if (res.status === 200) return res.data;
// this.notification.create('error', url, `${res.data}`);
return {};
}
/**
* 删除单个对象
* @param url 地址
* @param id ID
* @returns 操作结果
*/
async deleteOne(url: string, id: number) {
const res = await requestCrudService.delete(`${url}/${id}`);
if (res.status === 200) return res.data;
// this.notification.create('error', url, `${res.data}`);
return 'error';
}
// get 请求
async simpleGet(url: string, params?: any): Promise<any> {
const res = await requestCrudService.get(url, params);
if (res.status === 200) return res.data;
return res.data;
}
// post 请求
async simplePost(url: string, data: any) {
const res = await requestCrudService.post(url, data);
if (res.status === 200) return res.data;
return res.data;
}
}
+43
View File
@@ -0,0 +1,43 @@
import { createStore } from 'vuex'
export default createStore({
state: {
count: 0,
user: null,
taskData: null,
targetList: [],
targetData: null,
actionOverview: null,
},
getters: {
doubleCount: (state) => state.count * 2
},
mutations: {
increment(state) {
state.count++
},
setUser(state, user) {
state.user = user
},
setTaskData(state, value) {
state.taskData = value;
},
setTargetList(state,value) {
state.targetList = value
},
setTargetData(state,value) {
state.targetData = value
},
setActionOverview(state,value) {
state.actionOverview = value;
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
},
modules: {}
})
Whitespace-only changes.
@@ -0,0 +1,134 @@
:root {
--td-brand-color-8: '#0062d9';
}
.t-input {
border-color: var(--td-brand-color);
}
.t-range-input {
border-color: var(--td-brand-color);
}
.t-layout, .t-layout__direction-vertical {
background: none;
}
.t-layout__sider {
background: none;
}
// 对话框样式
.t-dialog {
background: #0f2844 !important;
border: 1px solid;
border-color: #2b8ffe99;
padding: 20px 25px;
border-radius: 4px;
}
.t-dialog__header {
border-radius: 4px 4px 0 0;
padding: 20px 25px;
padding-top: 0;
box-shadow: none !important;
position: relative;
font-weight: 500;
color: #fff;
font-size: 25px;
background: url('../assets/icon/title-header-logo.svg') no-repeat bottom center !important;
}
.t-dialog__header .t-dialog__header-content {
justify-content: center;
}
.t-button--variant-base {
color: #FFFFFF;
background: rgba(3, 38, 80, 0.8);
border-color: rgba(43, 143, 254, 0.6);
}
.t-button--variant-base.t-button--theme-primary {
background: linear-gradient(102.76deg, #2b8ffe 0%, #0062d9 100%);
}
.t-drawer__close-btn {
display: none;
}
// 抽屉样式
.t-drawer__content-wrapper {
background: #021e3e;
}
.t-drawer__header {
background: linear-gradient(90deg, #0062d9 0%, rgba(0, 98, 217, 0) 100%);
border-bottom: 2px solid;
border-color: rgba(255, 255, 255, 0.2);
}
.t-drawer__body {
background: #021e3e;
}
// 标签页
.t-tabs {
background-color: transparent;
}
.t-tabs__nav-item.t-is-active {
font-size: var(--fontSize);
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #0062d9;
}
.t-tabs__nav-item {
font-size: var(--fontSize);
}
.t-tabs__bar {
background-color: #0062d9;
}
.t-tabs__nav-container.t-is-top::after {
background: rgba(85, 159, 254, 0.2);
}
.t-tabs__nav-item:not(.t-is-disabled):not(.t-is-active):hover .t-tabs__nav-item-wrapper{
background: rgba(255, 255, 255, 0.1);
}
.t-tabs__btn {
background: rgba(3, 38, 80, 0.8);
border-color: #053e59 !important;
}
.t-tabs__btn:hover {
background: rgba(3, 38, 80, 0.8);
}
.t-tabs__nav-item.t-size-m {
line-height: 18px;
height:auto;
}
.t-tabs__nav--card.t-tabs__nav-item:not(.t-is-disabled):not(.t-is-active):hover {
background:linear-gradient(103.13deg,#2b8ffe 0%,#0062d9 100%);
border-radius:24px;
}
// 单选框样式
.t-radio-group.t-radio-group--filled{
background-color: #08527b;
border-color: #08527b;
}
.t-radio-group.t-radio-group--filled .t-radio-button.t-is-checked {
background-color: #07324c;
}
.markdown-body{
background: transparent !important;
color: #FFFFFF !important;
}
+676
View File
@@ -0,0 +1,676 @@
:root {
--color-main: #0062d9;
--bg-color: #012044;
--fontSize: 18px;
--titleSize: 20px;
--fontSizes: 16px;
--chatSize: calc(18 * var(--px-to-vw));
--router-bg-color: #f8ccce;
--three-color: #fbd8da;
--task-button-bgcolor: #feeded;
--tag-border-color: #006efe;
--antd-wave-shadow-color: #ce2d39;
--border-color: linear-gradient(180deg, #f86c73, #ce1322);
--theme-img: url("/assets/icon/layout-bg-theme-red.png");
--them-icon: url("/assets/icon/pxcook-red.png");
--ant-modal-header: url("/assets/overiew-logo/ant-modal-header-bg.svg");
--theme-area-bg: rgba(3, 38, 80, 0.6);
--theme-area-border-color: rgba(43, 143, 254, 0.6);
--theme-box-shadow: 0px 8px var(--fontSize) rgba(139, 139, 139, 0.06);
--theme-font-color: #ffffff;
--theme-font-text: rgba(255, 255, 255, 0.6);
--theme-font-details: rgba(255, 255, 255, 0.8);
--theme-card-bg: rgba(0, 98, 217, 0.2);
--theme-card-border: rgba(85, 166, 254, 0.1);
--theme-card-active: rgba(0, 98, 217, 0.4);
--theme-active-border: #0062d9;
--theme-border-color: #559ffe;
--index-color: #ffffff;
--extract-content-bg: rgba(3, 38, 80, 0.6);
--logo-color: #45c3f3;
--user-item-bg: rgba(0, 98, 217, 0.3);
--chat-item-bg: rgba(0, 98, 217, 0.2);
--chat-content-bg: rgba(0, 98, 217, 0.1);
--think-content-bg: rgba(0, 98, 217, 0.2);
--think-border-color: #0062d9;
--think-logo-color: #45c3f3;
--think-font-color: rgba(255, 255, 255, 0.6);
--chat-source-color: #0079fe;
--chat-source-bg: rgba(0, 98, 217, 0.2);
--extraction-content-bg: #00368c;
--extraction-content-border: #0056c6;
--extraction-content-color: rgba(255, 255, 255, 0.8);
--chat-input-border: #0062d9;
--list-item-bg: var(--chat-item-bg);
--list-item-border: var(--theme-card-border);
--list-item-active: var(--theme-card-active);
--list-item-active-border: var(--theme-active-border);
--drawer-bg-color: #021e3e;
--table-border-color: #1592e6;
--table-bg-color: #01316d;
--time-range-th-bg-color: #012b6e;
--time-range-th-font-color: #ffffff;
--time-range-border-color: #006efe;
--time-range-font-color: #2b86fe;
--time-range-icon-color: #022043;
--time-range-tag-bg-color: #02387a;
--grap-container-bg: var(--chat-item-bg);
--full-screen: var(--bg-color);
--xwt-linear-gradient: linear-gradient(165.07deg, #0066cc 0%, #003366 100%);
--card-border: rgba(43, 143, 254, 0.6);
--item-borer-line: rgba(85, 159, 254, 0.2);
--gray-color: rgba(255, 255, 255, 0.6);
--item-index: var(--color-main);
--item-active-color: #0062d9;
--item-expand-color: #002c57;
--item-expand-active: #002d61;
--tag-bg-color: rgba(69, 195, 243, 0.5);
--theme-option-color: #023064;
--tag-border-bg: rgba(43, 143, 254, 0.6);
--file-tag-color: rgba(43, 143, 254, 0.6);
--ant-title-color: rgba(255, 255, 255, 0.8);
/* --heightVh: 920px; */
}
@font-face {
font-family: DDIN;
font-weight: normal;
src: url("../assets/font/D-Din/D-DIN.ttf");
unicode-range: U+0030-0039;
}
@font-face {
font-family: DDINBold;
font-weight: bold;
src: url("../assets/font/D-Din/D-DIN-Bold.ttf");
unicode-range: U+0030-0039;
}
@font-face {
font-family: Douyu;
src: url("../assets/font/DouyuFont/douyuFont-2.otf") format("opentype");
}
@font-face {
font-family: Noto Sans S Chinese;
font-weight: 100;
src: url("../assets/font/NotoSansHans/NotoSansHans-Thin-Windows.otf")
format("opentype");
}
@font-face {
font-family: Noto Sans S Chinese;
font-weight: 300;
src: url("../assets/font/NotoSansHans/NotoSansHans-Light.otf")
format("opentype");
}
@font-face {
font-family: Noto Sans S Chinese;
font-weight: 400;
src: url("../assets/font/NotoSansHans/NotoSansHans-Regular.otf")
format("opentype");
}
@font-face {
font-family: Noto Sans S Chinese;
font-weight: 500;
src: url("../assets/font/NotoSansHans/NotoSansHans-Medium.otf")
format("opentype");
}
@font-face {
font-family: Noto Sans S Chinese;
font-weight: 700;
src: url("../assets/font/NotoSansHans/NotoSansHans-Bold.otf")
format("opentype");
}
@font-face {
font-family: Noto Sans S Chinese;
font-weight: 900;
src: url("../assets/font/NotoSansHans/NotoSansHans-Black.otf")
format("opentype");
}
@font-face {
font-family: DS-Digital;
font-weight: 300;
src: url("../assets/font/DS-Digital/DS-DIGI-1.ttf") format("opentype");
}
@font-face {
font-family: DS-Digital;
font-weight: 400;
src: url("../assets/font/DS-Digital/DS-DIGIB-2.ttf") format("opentype");
}
@font-face {
font-family: DS-Digital;
font-weight: 500;
src: url("../assets/font/DS-Digital/DS-DIGII-3.ttf") format("opentype");
}
@font-face {
font-family: DS-Digital;
font-weight: 700;
src: url("../assets/font/DS-Digital/DS-DIGIT-4.ttf") format("opentype");
}
// flex 布局
.flex-center-center {
display: flex;
justify-content: center;
align-items: center;
}
.flex-start-center {
display: flex;
justify-content: flex-start;
align-items: center;
}
.flex-start-baseline {
display: flex;
justify-content: flex-start;
align-items: baseline;
}
.flex-start-start {
display: flex;
justify-content: flex-start;
align-items: start;
}
.flex-end-center {
display: flex;
justify-content: flex-end;
align-items: center;
}
.flex-end-start {
display: flex;
justify-content: flex-end;
align-items: start;
}
.flex-between-center {
display: flex;
justify-content: space-between;
align-items: center;
}
.flex-between-baseline {
display: flex;
justify-content: space-between;
align-items: baseline;
}
.flex-between-start {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.flex-content {
display: flex;
justify-content: space-between;
}
.font-weight-bold {
font-family: "Noto Sans S Chinese";
font-weight: 700;
}
.margin-bottom-5 {
margin-bottom: 5px;
}
.margin-bottom-10 {
margin-bottom: 10px;
}
.margin-bottom-15 {
margin-bottom: 15px;
}
.margin-top-5 {
margin-top: 5px;
}
.margin-top-10 {
margin-top: 10px;
}
.margin-top-15 {
margin-top: 15px;
}
.padding-10 {
padding: 10px;
}
.cursor-pointer {
cursor: pointer;
}
// 字体设置
span,
p,
div,
li {
font-family: "Noto Sans S Chinese";
}
.markdown-body table tr {
background: transparent !important;
}
// 单选框样式
.tabs-box {
.sortBtn {
font-size: var(--fontSize);
line-height: var(--fontSize);
color: #fff;
display: inline-block;
padding: 5px 10px;
border-radius: 4px;
border: 1px solid #2b8ffe99 !important;
margin: 0 5px;
cursor: pointer;
}
.sort-active {
background: linear-gradient(123.69deg, #2b8ffe, #0062d9) !important;
}
}
// tab颜色
.tab-green {
background: rgba(0, 140, 119, 0.5);
border-color: #008c77 !important;
}
.tab-blue {
background: rgba(0, 121, 254, 0.1);
border-color: #0079fe !important;
}
.tab-lightblue {
background: rgba(69, 195, 243, 0.5);
border-color: #45c3f3 !important;
}
.tab-yellow {
background: #ff990080;
border-color: #f90 !important;
}
.tab-red {
background: rgba(207, 19, 34, 0.5);
border-color: #cf1322 !important;
}
// tab标签页
.tabs-list {
text-align: center;
.tabs-item {
background: rgba(0, 12, 28, 0.2);
color: rgba(255, 255, 255, 0.6);
display: inline-block;
font-size: var(--fontSize);
font-family: "Noto Sans S Chinese";
padding: 5px 15px;
cursor: pointer;
&:hover {
color: #ffffff;
background: rgba(255, 255, 255, 0.1);
border-bottom: 1.5px solid #ffffff;
}
}
.item-active {
color: #ffffff;
background: rgba(255, 255, 255, 0.1);
border-bottom: 1.5px solid #ffffff;
}
}
// 标题
.title-content-item {
line-height: 22px;
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #ffffff;
font-size: var(--titleSize);
border-bottom: 1px solid rgba(0, 98, 217, 0.4);
padding: 10px 15px;
position: relative;
&::after {
content: "";
display: block;
width: 4px;
height: var(--titleSize);
background: linear-gradient(167.47deg, #a2e1f9 0%, #45c3f3 100%);
border-radius: 2px 0px 2px 0px;
position: absolute;
top: 13px;
left: 0px;
}
}
.drawer-head {
font-size: 20px;
font-family: Noto Sans S Chinese;
font-weight: 300;
display: flex;
align-items: center;
cursor: pointer;
span {
margin-right: 5px;
}
}
.chat-source {
color: #80b7ff;
background-color: rgba(85, 159, 254, 0.3);
border-radius: 5px;
padding: 1px 5px;
text-align: center;
width: auto;
height: auto;
font-size: var(--fontSizes);
display: inline-block;
margin: 5px;
cursor: pointer;
}
.markdown-body hr {
height: 1.5px !important;
background: #559ffe !important;
border-color: #559ffe !important;
}
// 文字省略号
.text-ellipsis {
display: -webkit-box;
-webkit-box-orient: vertical;
/* 限制显示的行数 */
overflow: hidden;
text-overflow: ellipsis;
}
.ellipsis1 {
-webkit-line-clamp: 1;
}
.ellipsis2 {
-webkit-line-clamp: 2;
}
.ellipsis3 {
-webkit-line-clamp: 3;
}
.ellipsis4 {
-webkit-line-clamp: 4;
}
.ellipsis5 {
-webkit-line-clamp: 5;
}
// 逻辑图样式
.treemap-darkblue {
width: 100%;
// border: 2px solid;
// height: 100%;
color: lightblue;
padding: 0px;
user-select: none;
// padding: 10px;
border: 1px solid;
border-radius: 4px;
background-color: var(--chat-item-bg);
box-sizing: border-box;
box-shadow: 0px 0px 9px rgba(252, 131, 131, 0.27);
.treemap-title {
border-radius: 0;
}
.treemap-body {
color: #ffffff;
}
.node-red {
background: linear-gradient(
90deg,
rgba(245, 34, 45, 0.5) 0%,
rgba(138, 0, 8, 0.3) 100%
);
box-shadow: 0px 1px var(--fontSize) rgba(0, 0, 0, 0.08);
}
.node-orange {
background: rgba(255, 153, 0, 0.5);
border-bottom: 1px solid;
border-color: #ff9900;
}
.node-yellow {
background: rgba(255, 196, 0, 0.5);
border-bottom: 1px solid;
border-color: #ffc400;
}
.node-lightblue {
background: rgba(69, 195, 243, 0.5);
border-bottom: 1px solid;
border-color: #45c3f3;
}
.node-blue {
background: rgba(0, 121, 254, 0.5);
border-bottom: 1px solid;
border-color: #0079fe;
}
.node-purple {
background: rgba(125, 80, 255, 0.5);
border-bottom: 1px solid;
border-color: #7d50ff;
}
}
.pulse-content {
width: 34px;
height: 40px;
background: url("../assets/map-icon/map-point.svg") no-repeat;
background-size: cover;
display: flex;
align-items: center;
justify-content: center;
.user-logo {
width: 26px;
height: 26px;
margin-top: -5px;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
}
.overiew-content {
width: 400px;
padding: 10px;
box-sizing: border-box;
color: #ffffff;
border: 1px solid #2b8ffe99;
border-radius: 5px;
background-color: rgba(3, 38, 80, 0.8);
position: absolute;
top: -117px;
left: 310px;
z-index: 500;
.font-weight-bold {
font-size: 17px;
font-family: "Noto Sans S Chinese";
font-weight: 700;
}
.overiew-head {
padding: 10px 0;
display: flex;
align-items: center;
justify-content: space-between;
.user-logo {
width: 60px;
height: 60px;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
vertical-align: middle;
object-fit: cover;
}
}
.user-right {
flex: 1;
margin-left: 10px;
.user-title {
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #fff;
font-size: 18px;
line-height: 24px;
}
.user-text {
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #fff;
font-size: 16px;
line-height: 26px;
margin-top: 4px;
}
}
}
.overiew-body {
padding: 10px 0;
.typeLabel {
margin: 5px;
line-height: 28px;
font-family: Noto Sans S Chinese;
font-weight: 500;
color: #55a6fe;
font-size: 16px;
display: flex;
align-items: center;
.details-logo {
width: 20px;
height: 14px;
background: url("../assets/icon/make-logo.svg") no-repeat;
background-size: cover;
margin-right: 5px;
}
}
.text-content {
font-family: Noto Sans S Chinese;
font-size: 16px;
padding: 0 10px;
}
}
.item-line {
border-bottom: 1px solid #2b8ffe99;
}
&::after {
content: "";
width: 200px;
height: 80px;
display: block;
background: url("../assets/map-icon/line-logo.png") no-repeat;
z-index: 1000;
position: absolute;
top: 75px;
left: -112px;
}
.text-content {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
word-break: break-all; /* 自动换行 */
white-space: normal; /* 允许正常换行 */
}
}
.item-line {
height: 1px;
background: rgba(85, 159, 254, 0.25);
margin: 10px 0;
}
.leaflet-container a.leaflet-popup-close-button {
position: absolute;
top: -115px;
right: -305px;
z-index: 600;
}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
background: transparent;
box-shadow: none;
}
.leaflet-popup-tip {
background: transparent !important;
}
.leaflet-left {
z-index: 100;
}
// 滚动条样式
// 滚动条整体样式
::-webkit-scrollbar {
/*滚动条整体样式*/
width: 6px !important;
height: 6px;
}
::-webkit-scrollbar-thumbk {
/*滚动条里面小方块*/
background: #ddd;
background: transparent;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
/*滚动条里面小方块*/
background: #555;
border-radius: 3px;
}
::-webkit-scrollbar-track {
/*滚动条里面轨道*/
background: transparent;
border-radius: 3px;
}
.t-dialog__body {
height: 70vh;
overflow-y: auto;
}
.t-dialog__ctx .t-dialog__position.t-dialog--top {
padding-top: 10vh;
}
@@ -0,0 +1,34 @@
import axios from "axios";
const request = axios.create({
baseURL: "/",
timeout: 10000000,
});
request.interceptors.request.use(
(config) => {
const token = localStorage.getItem("token");
// if (token) {
// config.headers.authorization = `Bearer admin`
// }
config.headers.Authorization = `Bearer admin`;
console.log(config.headers.authorization);
return config;
},
(error) => {
return Promise.reject(error);
}
);
request.interceptors.response.use(
(response) => {
return response.data;
},
(error) => {
console.error("Request error:", error);
return Promise.reject(error);
}
);
export default request;
+128
View File
@@ -0,0 +1,128 @@
<template>
<div class="chart">
<t-layout>
<t-header>
<h1>图表演示</h1>
<nav>
<t-menu :value="activeMenu" @click="handleMenuClick" theme="light" mode="horizontal">
<t-menu-item value="/">首页</t-menu-item>
<t-menu-item value="/dashboard">仪表盘</t-menu-item>
<t-menu-item value="/chart">图表</t-menu-item>
<t-menu-item value="/map">地图</t-menu-item>
<t-menu-item value="/graph">关系图</t-menu-item>
</t-menu>
</nav>
</t-header>
<t-content>
<t-grid :columns="2" :gutter="20">
<t-grid-item>
<t-card title="柱状图">
<div ref="barChartRef" class="chart-item"></div>
</t-card>
</t-grid-item>
<t-grid-item>
<t-card title="折线图">
<div ref="lineChartRef" class="chart-item"></div>
</t-card>
</t-grid-item>
<t-grid-item>
<t-card title="饼图">
<div ref="pieChartRef" class="chart-item"></div>
</t-card>
</t-grid-item>
<t-grid-item>
<t-card title="散点图">
<div ref="scatterChartRef" class="chart-item"></div>
</t-card>
</t-grid-item>
</t-grid>
</t-content>
</t-layout>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import * as echarts from 'echarts'
const router = useRouter()
const activeMenu = ref('/chart')
const barChartRef = ref(null)
const lineChartRef = ref(null)
const pieChartRef = ref(null)
const scatterChartRef = ref(null)
const handleMenuClick = (value) => {
activeMenu.value = value
router.push(value)
}
onMounted(() => {
initBarChart()
initLineChart()
initPieChart()
initScatterChart()
})
const initBarChart = () => {
const chart = echarts.init(barChartRef.value)
chart.setOption({
xAxis: { data: ['A', 'B', 'C', 'D', 'E'] },
yAxis: {},
series: [{
data: [10, 20, 30, 40, 50],
type: 'bar'
}]
})
}
const initLineChart = () => {
const chart = echarts.init(lineChartRef.value)
chart.setOption({
xAxis: { type: 'category', data: ['1月', '2月', '3月', '4月', '5月'] },
yAxis: {},
series: [{
data: [120, 200, 150, 300, 250],
type: 'line'
}]
})
}
const initPieChart = () => {
const chart = echarts.init(pieChartRef.value)
chart.setOption({
series: [{
type: 'pie',
data: [
{ value: 30, name: 'A' },
{ value: 20, name: 'B' },
{ value: 50, name: 'C' }
]
}]
})
}
const initScatterChart = () => {
const chart = echarts.init(scatterChartRef.value)
chart.setOption({
xAxis: {},
yAxis: {},
series: [{
type: 'scatter',
data: [[10, 20], [20, 30], [30, 40], [40, 50], [50, 60]]
}]
})
}
</script>
<style scoped>
.chart {
padding: 20px;
}
.chart-item {
width: 100%;
height: 300px;
}
</style>
@@ -0,0 +1,130 @@
<template>
<div class="dashboard">
<t-layout>
<t-header>
<h1>仪表盘</h1>
<nav>
<t-menu :value="activeMenu" @click="handleMenuClick" theme="light" mode="horizontal">
<t-menu-item value="/">首页</t-menu-item>
<t-menu-item value="/dashboard">仪表盘</t-menu-item>
<t-menu-item value="/chart">图表</t-menu-item>
<t-menu-item value="/map">地图</t-menu-item>
<t-menu-item value="/graph">关系图</t-menu-item>
</t-menu>
</nav>
</t-header>
<t-content>
<t-grid :columns="3" :gutter="20">
<t-grid-item>
<t-card title="用户统计">
<div class="stat-item">
<t-statistic :value="1234" :precision="0" />
<p>总用户数</p>
</div>
</t-card>
</t-grid-item>
<t-grid-item>
<t-card title="数据统计">
<div class="stat-item">
<t-statistic :value="5678" :precision="0" />
<p>数据总量</p>
</div>
</t-card>
</t-grid-item>
<t-grid-item>
<t-card title="访问统计">
<div class="stat-item">
<t-statistic :value="9876" :precision="0" />
<p>总访问量</p>
</div>
</t-card>
</t-grid-item>
</t-grid>
<t-card title="近期趋势" class="chart-card">
<div ref="chartRef" class="chart"></div>
</t-card>
<t-card title="用户列表" class="table-card">
<t-table :data="userList">
<t-table-column prop="name" label="姓名" />
<t-table-column prop="age" label="年龄" />
<t-table-column prop="email" label="邮箱" />
<t-table-column prop="status" label="状态">
<template #default="{ row }">
<t-tag :theme="row.status === 'active' ? 'success' : 'default'">{{ row.status }}</t-tag>
</template>
</t-table-column>
</t-table>
</t-card>
</t-content>
</t-layout>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import * as echarts from 'echarts'
const router = useRouter()
const activeMenu = ref('/dashboard')
const chartRef = ref(null)
const userList = ref([
{ name: '张三', age: 25, email: 'zhangsan@example.com', status: 'active' },
{ name: '李四', age: 30, email: 'lisi@example.com', status: 'active' },
{ name: '王五', age: 28, email: 'wangwu@example.com', status: 'inactive' }
])
const handleMenuClick = (value) => {
activeMenu.value = value
router.push(value)
}
onMounted(() => {
initChart()
})
const initChart = () => {
const chart = echarts.init(chartRef.value)
const option = {
title: { text: '访问趋势' },
tooltip: { trigger: 'axis' },
xAxis: {
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月', '6月']
},
yAxis: { type: 'value' },
series: [{
data: [120, 200, 300, 400, 500, 600],
type: 'line',
smooth: true
}]
}
chart.setOption(option)
}
</script>
<style scoped>
.dashboard {
padding: 20px;
}
.stat-item {
text-align: center;
}
.chart-card {
margin-top: 20px;
}
.table-card {
margin-top: 20px;
}
.chart {
width: 100%;
height: 400px;
}
</style>
@@ -0,0 +1,91 @@
<template>
<div class="graph">
<t-layout>
<t-header>
<h1>关系图演示</h1>
<nav>
<t-menu :value="activeMenu" @click="handleMenuClick" theme="light" mode="horizontal">
<t-menu-item value="/">首页</t-menu-item>
<t-menu-item value="/dashboard">仪表盘</t-menu-item>
<t-menu-item value="/chart">图表</t-menu-item>
<t-menu-item value="/map">地图</t-menu-item>
<t-menu-item value="/graph">关系图</t-menu-item>
</t-menu>
</nav>
</t-header>
<t-content>
<t-card title="@antv/g6 关系图">
<div ref="graphRef" class="graph-container"></div>
</t-card>
</t-content>
</t-layout>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { Graph } from '@antv/g6'
const router = useRouter()
const activeMenu = ref('/graph')
const graphRef = ref(null)
const handleMenuClick = (value) => {
activeMenu.value = value
router.push(value)
}
onMounted(() => {
initGraph()
})
const initGraph = () => {
const data = {
nodes: [
{ id: 'node1', label: 'Vue 3', size: 30 },
{ id: 'node2', label: 'TDesign', size: 25 },
{ id: 'node3', label: 'ECharts', size: 25 },
{ id: 'node4', label: 'D3.js', size: 25 },
{ id: 'node5', label: 'Leaflet', size: 25 },
{ id: 'node6', label: 'Vuex', size: 20 },
{ id: 'node7', label: 'Axios', size: 20 }
],
edges: [
{ source: 'node1', target: 'node2' },
{ source: 'node1', target: 'node3' },
{ source: 'node1', target: 'node4' },
{ source: 'node1', target: 'node5' },
{ source: 'node1', target: 'node6' },
{ source: 'node1', target: 'node7' }
]
}
const graph = new Graph({
container: graphRef.value,
width: 800,
height: 600,
data,
modes: {
default: ['drag-canvas', 'zoom-canvas', 'drag-node']
},
layout: {
type: 'force',
preventOverlap: true
}
})
graph.render()
}
</script>
<style scoped>
.graph {
padding: 20px;
}
.graph-container {
width: 800px;
height: 600px;
}
</style>
@@ -0,0 +1,32 @@
<template>
<div class="home">
打开群聊
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const activeMenu = ref('/')
const handleMenuClick = (value) => {
activeMenu.value = value
router.push(value)
}
onMounted(async () => {
window.location.href = 'workbench://#XDKZ#open#/dialog/b3Dialog?dialog=chatDialog';
// setTimeout(() => {
// window.opener = null;
// const myWindow = window.open('', '_self'); // 这句是关键,假装是自己打开的自己
// myWindow.close();
// console.log('关闭页面')
// },2000);
})
</script>
<style scoped>
</style>
+97
View File
@@ -0,0 +1,97 @@
<template>
<div class="home">
<t-layout>
<t-header>
<h1>Vue3 技术栈演示</h1>
<nav>
<t-menu :value="activeMenu" @click="handleMenuClick" theme="light" mode="horizontal">
<t-menu-item value="/">首页</t-menu-item>
<t-menu-item value="/dashboard">仪表盘</t-menu-item>
<t-menu-item value="/chart">图表</t-menu-item>
<t-menu-item value="/map">地图</t-menu-item>
<t-menu-item value="/graph">关系图</t-menu-item>
</t-menu>
</nav>
</t-header>
<t-content>
<div class="hero">
<h2>欢迎使用 Vue3 技术栈</h2>
<p>本项目集成了以下技术:</p>
<t-grid :columns="3" :gutter="20">
<t-grid-item>
<t-card title="UI 组件">
<p>TDesign</p>
</t-card>
</t-grid-item>
<t-grid-item>
<t-card title="数据可视化">
<p>ECharts</p>
<p>D3.js</p>
<p>@antv/g6</p>
</t-card>
</t-grid-item>
<t-grid-item>
<t-card title="地图">
<p>Leaflet</p>
</t-card>
</t-grid-item>
<t-grid-item>
<t-card title="网络请求">
<p>Axios</p>
</t-card>
</t-grid-item>
<t-grid-item>
<t-card title="状态管理">
<p>Vuex</p>
</t-card>
</t-grid-item>
<t-grid-item>
<t-card title="构建工具">
<p>Vite</p>
<p>Less</p>
</t-card>
</t-grid-item>
</t-grid>
</div>
</t-content>
</t-layout>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const activeMenu = ref('/')
const handleMenuClick = (value) => {
activeMenu.value = value
router.push(value)
}
onMounted(() => {
activeMenu.value = router.currentRoute.value.path
})
</script>
<style scoped>
.home {
padding: 20px;
}
.hero {
margin-top: 40px;
text-align: center;
}
.hero h2 {
font-size: 28px;
margin-bottom: 20px;
}
.hero p {
font-size: var(--titleSize);
margin-bottom: 40px;
}
</style>
+71
View File
@@ -0,0 +1,71 @@
<template>
<div class="map">
<t-layout>
<t-header>
<h1>地图演示</h1>
<nav>
<t-menu :value="activeMenu" @click="handleMenuClick" theme="light" mode="horizontal">
<t-menu-item value="/">首页</t-menu-item>
<t-menu-item value="/dashboard">仪表盘</t-menu-item>
<t-menu-item value="/chart">图表</t-menu-item>
<t-menu-item value="/map">地图</t-menu-item>
<t-menu-item value="/graph">关系图</t-menu-item>
</t-menu>
</nav>
</t-header>
<t-content>
<t-card title="Leaflet 地图">
<div ref="mapRef" class="map-container"></div>
</t-card>
</t-content>
</t-layout>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import L from 'leaflet'
const router = useRouter()
const activeMenu = ref('/map')
const mapRef = ref(null);
const markerGroup = ref(null);
const handleMenuClick = (value) => {
activeMenu.value = value
router.push(value)
}
onMounted(() => {
initMap()
})
const initMap = () => {
const map = L.map(mapRef.value).setView([39.9042, 116.4074], 13)
L.tileLayer('http://ch1.b.uat.4.cn/jiansuo/mapnew/root/images0_11/{z}/{x}/{y}.png', { // http://ch1.b.uat.4.cn/jiansuo/mapnew/root/images0_11/{z}/{x}/{y}.png https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png
attribution: '&copy; OpenStreetMap contributors'
}).addTo(map)
L.marker([39.9042, 116.4074]).addTo(map)
.bindPopup('北京市中心')
.openPopup()
L.circle([39.9042, 116.4074], { radius: 500 }).addTo(map)
.bindPopup('北京市中心区域')
markerGroup.value = L.layerGroup().addTo(map);
console.log('地图markerGroup', markerGroup.value)
}
</script>
<style scoped>
.map {
padding: 20px;
}
.map-container {
width: 100%;
height: 600px;
}
</style>
@@ -0,0 +1,206 @@
<template>
<div class="actionDeatil">
<div class="header">
<div class="title">
行动详情
</div>
<div class="close" @click="close()">
X
</div>
</div>
<div class="content">
<div class="title">
行动名称
</div>
<div class="tabHead">
<div class="item" :class="{ 'active': tabId == 1 }" @click="tabId = 1">
叙事主题
</div>
<div class="item" :class="{ 'active': tabId == 2 }" @click="tabId = 2">
预期行为
</div>
</div>
<div class="tabContent">
<template v-if="tabId == 1">
<div class="xushi" v-for="(item, index) in xushiList">
{{ index + 1 }}.
{{ item.text }}
</div>
</template>
<template v-if="tabId == 2">
<div class="item">
<div class="label">
行为体
</div>
<div class="text">
行为体内容内容内容内容内容内容内容内容内容内容内容内容
</div>
</div>
<div class="item">
<div class="label">
预期行为
</div>
<div class="text">
预期行为内容内容内容内容内容内容内容内容内容内容内容内容
</div>
</div>
</template>
<div class="Analysis">
原因分析
</div>
</div>
<div class="tagget">
<span>
支撑性目的:
</span>
利用桃色新闻与军纪涣散议题利用桃色新闻与军纪涣散议题利用桃色新闻与军纪涣散议题,瓦解台军社会形象与民众支持基础,引发线上网红、大V等对台军……利用桃色新闻与军纪涣散议题利用桃色新闻与军纪涣散议题利用桃色新闻与军纪涣散议题,瓦解台军社会形象与民众支持基础,引发线上网红、大V等对台军……
</div>
</div>
</div>
</template>
<script>
export default {
props: ['activeData'],
data() {
return {
tabId: 1,
xushiList: [
{
text: '叙事内容'
}, {
text: '叙事内容'
},
]
};
},
methods: {
close() {
console.log('1');
this.$emit('close')
}
},
watch: {
},
};
</script>
<style lang="less">
.actionDeatil {
width: 400px;
height: 400px;
background-color: #032650;
position: fixed;
top: 80px;
z-index: 1000;
right: 10px;
border: 1px solid;
border-color: #2b8ffe99;
border-radius: 4px 4px 4px 4px;
.header {
display: flex;
justify-content: space-between;
padding: 0 10px;
height: 50px;
align-items: center;
.title {
color: #fff;
}
.close {
color: #fff;
cursor: pointer;
}
}
.content {
padding: 0 10px;
.title {
font-weight: 700;
font-size: 24px;
color: #fff;
padding: 0 0 10px 20px;
}
.tabHead {
display: flex;
gap: 10px;
padding: 0 10px;
.item {
padding: 0 20px;
color: #aaaaaa;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
background-color: rgba(0, 98, 217, 0.1);
cursor: pointer;
}
.active {
color: #fff;
background-color: #0668de;
}
}
.tabContent {
background-color: rgba(0, 98, 217, 0.1);
height: 180px;
overflow-y: auto;
padding: 10px;
.xushi {
color: #fff;
}
.item {
color: #fff;
display: flex;
gap: 10px;
.label {
border: 1px solid #0668de;
width: 80px;
height: 26px;
border-radius: 5px;
text-align: center;
}
.text {
flex: 1;
}
}
.Analysis {
text-align: right;
color: blue;
text-decoration: underline;
cursor: pointer;
}
}
.tagget {
margin-top: 10px;
padding: 5px;
height: 70px;
overflow: hidden;
color: #fff;
background-color: #092845;
span {
font-weight: 700;
}
}
}
}
</style>
@@ -0,0 +1,260 @@
<template>
<div class="bociDetail">
<div class="header">
<div class="title">
波次详情
</div>
<div class="close">
X
</div>
</div>
<div class="boci">
<div class="name">
<div>
波次1
</div>
<div>
波次名称1
</div>
</div>
<div class="bociLayout">
<div class="timeLine">
<div class="item" v-for="item in timeLine">
{{ item }}
</div>
</div>
<div class="row" v-for="item in timeArr"
:style="{ left: getPercentageInRange(item[0]) + '%', width: getPercentageInRange(item[1]) - getPercentageInRange(item[0]) + '%' }">
</div>
</div>
</div>
<div class="bociConent">
<div class="head">
<span>
波次信息主题
</span>
<span>
修改
</span>
</div>
<div class="info">
<div class="row">
<div class="item">
<div class="label">
信息主题:
</div>
<div class="content">
渴望被官方和主流舆论认可为两岸议题的权威声音理
</div>
</div>
</div>
<div class="row">
<div class="item">
<div class="label">
信息数量:
</div>
<div class="content">
8878
</div>
</div>
<div class="item">
<div class="label">
人设数量:
</div>
<div class="content">
123
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
timeArr: [['2026-04-18', '2026-04-29'], ['2026-03-18', '2026-04-16'], ['2026-03-20', '2026-04-21']],
timeLine: []
};
},
methods: {
getPercentageInRange(targetDate) {
// 1. 数据预处理:展平数组并转为时间戳
const timestamps = this.timeLine.flat(Infinity).map(dateStr => new Date(dateStr).getTime());
// 2. 确定范围的边界
const minTimestamp = Math.min(...timestamps); // 最早时间 (0%)
const maxTimestamp = Math.max(...timestamps); // 最晚时间 (100%)
// 3. 计算总时长差值
const totalDuration = maxTimestamp - minTimestamp;
// 边界情况处理:如果最大最小时间相同,避免除以0
if (totalDuration === 0) {
return 0;
}
// 4. 计算目标时间
const targetTimestamp = new Date(targetDate).getTime();
// 5. 计算百分比公式:(目标 - 最小) / (最大 - 最小)
const percentage = ((targetTimestamp - minTimestamp) / totalDuration) * 100;
// 6. 返回保留两位小数的结果
console.log(parseFloat(percentage.toFixed(2)));
return parseFloat(percentage.toFixed(2));
},
getDateRangeResult(dateRanges) {
// 1. 将二维数组展平并时间戳
// 使用 flat(Infinity) 展平多维数组,map 将日期字符串转为时间戳数值
const timestamps = dateRanges.flat(Infinity).map(dateStr => new Date(dateStr).getTime());
// 2. 获取最小时间戳和最大时间戳
const minTimestamp = Math.min(...timestamps);
const maxTimestamp = Math.max(...timestamps);
// 3. 计算中间时间戳 (取平均值)
const midTimestamp = (minTimestamp + maxTimestamp) / 2;
// 4. 格式化函数:将时间戳转为 'YYYY-MM-DD' 格式
const formatDate = (timestamp) => {
const date = new Date(timestamp);
// toISOString() 返回 UTC 时间格式 (YYYY-MM-DDTHH:mm:ss.sssZ),我们只需要日期部分
return date.toISOString().split('T')[0];
};
// 5. 返回结果数组
return [
formatDate(minTimestamp),
formatDate(midTimestamp),
formatDate(maxTimestamp)
];
}
},
watch: {
},
mounted() {
this.timeLine = this.getDateRangeResult(this.timeArr)
console.log(this.timeLine);
}
};
</script>
<style lang="less">
.bociDetail {
width: 400px;
height: 400px;
background-color: #032650;
position: fixed;
bottom: 20px;
z-index: 1000;
right: 10px;
border: 1px solid;
border-color: #2b8ffe99;
border-radius: 4px 4px 4px 4px;
.header {
display: flex;
justify-content: space-between;
padding: 0 10px;
height: 50px;
align-items: center;
.title {
color: #fff;
}
.close {
color: #fff;
cursor: pointer;
}
}
.boci {
display: flex;
padding: 0 10px;
.name {
display: flex;
flex-direction: column;
justify-content: center;
color: #fff;
width: 100px;
height: 80px;
div {
text-align: center;
}
}
.bociLayout {
flex: 1;
flex-shrink: 0;
background-color: rgba(0, 98, 217, 0.1);
position: relative;
.timeLine {
color: #fff;
display: flex;
justify-content: space-between;
.item {
font-size: 12px;
}
}
.row {
height: 5px;
background-color: red;
position: relative;
margin-top: 10px;
cursor: pointer;
border-radius: 5px;
}
}
}
.bociConent {
background-color: rgba(0, 98, 217, 0.1);
height: 100px;
margin: 10px;
border-radius: 5px;
color: #fff;
.head {}
.info {
.row {
display: flex;
justify-content: space-between;
.item {
display: flex;
.label {
font-size: 12px;
}
.content {
flex: 1;
flex-shrink: 0;
}
}
}
}
}
}
</style>
@@ -0,0 +1,280 @@
<template>
<div class="sentiment">
<div class="ts-type-block type-block-left">
<div class="collapse-content collapse-content-left flex-center-center cursor-pointer" v-if="expandShow"
@click="expandChange">
<img src="@/assets/map-icon/expand-logo.svg" alt="" />
</div>
<div class="expand-content" :class="{ 'expand-hidden': expandShow }">
<div class="cHotTopic">
<!-- 标题 -->
<div class="title-handle flex-between-center">
<div class="flex-content cursor-pointer" @click="expandChange">
<div class="collapse-icon">
<img src="@/assets/map-icon/expand-logo.svg" alt="" />
</div>
<div class="title">当前任务</div>
</div>
<div v-if="taskId" class="task-back" @click="taskBackChange">
<img src="@/assets/map-icon/back-logo.svg" alt="" />
返回任务
</div>
</div>
<!-- 输入框 -->
<div class="title-content">
<!-- 行动策划 -->
<template v-if="!taskId">
<!-- <taskStatistics :range="range" /> -->
<searchTaskList height="calc(100vh - 150px)" searchType="action" :range="range" :taskDirection="tabValue"
@updateRange="updateRange" @selectTask="selectTask" />
</template>
<template v-else>
<ActionPlanning :taskData="taskData" @actionDataC="actionDataChange" />
</template>
</div>
</div>
</div>
</div>
<!-- 关系图 -->
<div class="box-overview">
<G6NetworkGraph v-if="taskData && actionId" :actionData="actionData" :actionId="actionId" :taskData="taskData"
:taskId="taskData.id" :showActionCount="showActionCount" />
</div>
<!-- <actionDetail v-if="actionDetailStatus" :activeData="actionDetailData" @close="actionDetailClose" /> -->
<!-- <bociDetail v-if="bociDetailStatus" /> -->
</div>
</template>
<script setup>
import { ref, reactive } from "vue";
import ActionPlanning from "@/components/ActionPlanning.vue";
import ActionOverview from "@/components/ActionOverview.vue";
import taskStatistics from "../task/components/taskStatistics.vue";
import searchTaskList from "@/components/searchTaskList/index.vue";
import G6NetworkGraph from "@/components/graph/G6NetworkGraph.vue";
import actionDetail from "./components/actionDetail.vue";
import bociDetail from "./components/bociDetail.vue";
const tabValue = ref("all");
const taskId = ref("");
const taskDetailShow = ref(false); // 是否显示任务详情
const taskData = ref({});
const range = ref("all");
const actionData = ref({});
const actionId = ref(null);
const expandShow = ref(false);
const actionDetailStatus = ref(false);
const actionDetailData = ref({});
const bociDetailStatus = ref(false);
const showActionCount = ref(true);
const updateRange = (d) => {
range.value = d;
};
// 任务类型切换
const tabChange = (value) => {
tabValue.value = value;
};
const selectTask = (d) => {
console.log(d, d.id);
taskDetailShow.value = true;
taskId.value = d.id;
taskData.value = d;
actionId.value = null
};
const taskBackChange = () => {
taskId.value = null;
taskData.value = null;
};
const actionDetailClose = () => {
console.log("关闭");
actionDetailStatus.value = false;
};
const actionDataChange = (info) => {
console.log(info);
actionDetailStatus.value = true;
actionDetailData.value = info;
showActionCount.value = false;
actionData.value = info;
actionId.value = info.id;
};
const expandChange = () => {
expandShow.value = !expandShow.value;
};
</script>
<style scoped lang="less">
/* Your styles here */
// 详情样式
.sentiment {
height: 100%;
display: flex;
justify-content: space-between;
.ts-type-block {
// inset: var(--fontSize) auto 8px 124px;
width: 436px;
height: 90.3%;
overflow: hidden;
z-index: 1000;
// display: flex;
// flex-direction: column;
box-sizing: border-box;
transition: all 0.5s ease;
.cHotTopic {
width: 436px;
height: 100%;
background: #032650cc;
border: 1px solid;
border-color: #2b8ffe99;
border-radius: 4px 4px 4px 4px;
overflow: hidden;
box-sizing: border-box;
// display: flex;
// flex-direction: column;
transition: transform 0.5s ease;
.title-handle {
width: 102%;
height: 40px;
padding-right: var(--fontSize);
line-height: 22px;
font-family: Noto Sans S Chinese;
font-weight: 550;
color: #fff;
font-size: var(--titleSize);
padding-left: var(--fontSize);
box-sizing: border-box;
border-bottom: 1px solid rgba(43, 143, 254, 0.6);
letter-spacing: 1px;
background: linear-gradient(89.65deg,
#0062d9 0.03%,
#0062d900 99.97%) !important;
// .collapse-icon {
// margin-left: auto;
// margin-right: 5px;
// cursor: pointer;
// position: absolute;
// top: 12px;
// left: 8px;
// z-index: 1000;
// }
.title {
margin-left: 12px;
font-family: Noto Sans S Chinese;
font-weight: 550;
}
.tab-list {
.tab-list-item {
font-size: var(--fontSizes);
line-height: var(--fontSizes);
display: inline-block;
padding: 5px 10px;
border-radius: 5px;
cursor: pointer;
}
.item-active {
background: linear-gradient(104.44deg, #2b8ffe, #0062d9);
}
}
}
}
.title-content {
flex: 1;
height: calc(100vh - 130px);
display: flex;
flex-direction: column;
align-items: center;
padding: 20px 0;
overflow-y: auto;
}
.title-content::-webkit-scrollbar {
display: none;
}
.task-back {
background: linear-gradient(102.76deg, #2b8ffe 0%, #0062d9 100%);
border-radius: 4px;
padding: 5px 10px;
line-height: var(--fontSize);
font-family: Noto Sans S Chinese;
font-weight: 300;
color: #ffffff;
font-size: var(--fontSize);
display: flex;
align-items: center;
cursor: pointer;
img {
width: var(--fontSize);
margin-right: 5px;
}
}
}
// 关系图样式
.box-overview {
width: 100%;
height: calc(100% - 62px);
background: rgba(2, 22, 47, 0.8);
// background: url('../../assets/map-icon/relation-bg.png') no-repeat;
background-size: cover;
z-index: 500;
position: fixed;
top: 62px;
left: 0;
}
.collapse-content {
width: 30px;
height: 40px;
background: #032650cc;
border: 1px solid;
border-color: #2b8ffe99;
border-radius: 4px 0 0 4px;
z-index: 500;
position: absolute;
top: 0;
img {
width: 16px;
}
}
.collapse-content-right {
right: 0;
}
.collapse-content-left {
left: 0;
}
.expand-hidden {
width: 0px !important;
border: 0px !important;
}
.expand-content {
width: 100%;
transition: all 0.5s ease;
overflow: hidden;
}
.expand-content-right {
float: right;
}
}
</style>
@@ -0,0 +1,228 @@
<template>
<div class="zxtp_wrap">
<div :id="conId" style="height: 100%; width: 100%"></div>
</div>
</template>
<script setup>
import { Rect, Circle, Diamond, Ellipse, Hexagon, register, Graph, ExtensionCategory } from '@antv/g6';
import {onMounted} from "vue";
import BottomIconImg from "@/assets/xdzxtp_bottom_icon.png"
const shapes = {
rect: Rect,
circle: Circle,
diamond: Diamond,
ellipse: Ellipse,
hexagon: Hexagon
}
Object.keys(shapes).forEach(key=>{
class IconNode extends shapes[key] {
get data() {
return this.context.graph.getNodeData(this.id).data;
}
get nodeData(){
return this.context.graph.getNodeData(this.id);
}
getCustomIconStyle(attributes) {
const [width, height] = this.getSize(attributes);
const { imgSrc } = this.data;
return {
x: -10,
y: -10,
width: 20,
height: 20,
src: imgSrc,
z: 100
};
}
drawCustomIconShape(attributes, container) {
const iconStyle = this.getCustomIconStyle(attributes);
this.upsert('custom-icon', 'image', iconStyle, container);
}
getSubtitleStyle(attributes) {
const [width, height] = this.getSize(attributes);
const { subTitle, fillColor } = this.nodeData;
return {
x: 0,
y: 0, // 放在主标题下方
text: subTitle || '',
fontSize: 14,
fontWeight: 'bold', // 加粗字体
fill: fillColor || '#fff',
textAlign: 'center',
textBaseline: 'middle',
};
}
// 绘制副标题
drawSubtitleShape(attributes, container) {
const subtitleStyle = this.getSubtitleStyle(attributes);
this.upsert('subtitle', 'text', subtitleStyle, container);
}
// 绘制额外的图标
drawBottomIconShape(attributes, container) {
const { isShowBottom } = this.nodeData;
const [width, height] = this.getSize(attributes);
const style = {
x: 0,
y: 0,
width: 20,
height: 20,
src: BottomIconImg,
z: 101,
opacity: isShowBottom ? 1 : 0 // 控制是否显示底部图标
}
this.upsert('bottom_icon', 'image', style, container);
}
render(attributes, container) {
// 渲染基础矩形
super.render(attributes, container);
// 添加图标
const { shape } = this.nodeData;
if(['rect', 'diamond'].includes(shape)){
this.drawSubtitleShape(attributes, container);
}else{
this.drawCustomIconShape(attributes, container);
}
this.drawBottomIconShape(attributes, container)
}
}
register(ExtensionCategory.NODE, `custom_xdzxtp_${key}`, IconNode);
})
const conId = 'rwxq_xdzxtp_con';
let graph;
const draw = async (params={})=>{
if(!graph){
graph = new Graph({
container: conId, // 通过 DOM ID 指定容器
padding: 30,
autoResize: true,
// 视口配置
zoom: 1,
autoFit: 'center',
// 节点配置
node: {
type: (e)=>{
if(e.shape){
return `custom_xdzxtp_${e.shape}`
}
return 'custom_xdzxtp_rect'
},
style: {
badge: (e)=>{
return !!e.isShowBadge
}, // 是否显示徽标
badges: [
{ text: '!', placement: 'left-top', offsetX: 6, offsetY: 0, fill: "#fff", backgroundFill: "#f59a23", backgroundRadius: 0 },
],
size: (e)=>{
if(e.shape === 'ellipse'){
return [60, 40]
}else if(e.shape === 'diamond'){
return [50, 50]
}else if(e.shape === 'circle'){
return [40, 40]
}else if(e.shape === 'rect'){
return [50, 45]
}else if(e.shape === 'hexagon'){
return [50, 50]
}
},
label: (e)=>{
return !!e.showLabel
}, // 是否显示节点标签
labelText: (e)=>{
return e.label
}, // 标签文字内容
labelFill: '#fff',
fill: (e)=>{
return e.fillColor || '#535353'
},
fillOpacity: 0.5,
stroke: (e)=>{
return e.fillColor || '#535353'
},
lineWidth: 1,
},
},
// 边配置
edge: {
type: "quadratic",
style: {
stroke: (e)=>{
if(e.lineColor) return e.lineColor;
return '#959899'
},
lineDash: (e)=>{
if(e.isDash) return 5;
return 0
}, // 虚线样式
lineDashOffset: 5, // 虚线偏移量
lineWidth: 1.5,
endArrow: true,
enableTooltip: false,
// 线条标签
//label: false, // 开启边标签展示
// labelText: 'labelText', // 边标签文字
// labelPlacement: 'center', // 边标签相对于边的位置
// labelFill: '#fff', // 边标签文字颜色
// labelOffsetY: 20, // 边标签在y轴方向上的偏移量
},
},
// 布局配置
layout: {
type: 'force',
preventOverlap: true,
linkDistance: 100,
},
// 交互行为
behaviors: ['drag-canvas', 'zoom-canvas', 'drag-element'],
plugins: [
{
type: 'tooltip',
getContent: (e, items) => {
let target = items[0]
let type = e.targetType
if (type==='node'){
let result = `<h4>${type==='node'?'节点详情':''}</h4>`;
result += `<p>${target.label}</p>`;
return result;
}
},
},
],
});
}
return graph;
}
defineExpose({
draw,
graph,
/*findNodeById(id){
const nodes = graph.getNodeData();
return nodes ? nodes.find(i => i.id === id) : null;
},*/
async updateNode(nodeDataArr){
graph.updateNodeData(nodeDataArr)
await graph.draw()
}
})
</script>
<style lang="less">
.zxtp_wrap{
height: 100%;
width: 100%;
}
</style>
@@ -0,0 +1,144 @@
<template>
<div class="xdzx_vis_timeline_wrap">
<div ref="conRef" style="width:100%;height:100%"></div>
</div>
</template>
<script setup>
import { onMounted, ref } from "vue";
import dayjs from "dayjs";
// vistimeline中文化
moment.locale('zh-cn')
const conRef = ref()
let timeline;
const draw = (params)=>{
const currentDate = params.current;
// Create a DataSet (allows two way data-binding)
let items = new vis.DataSet(params.list||[]);
// Configuration for the Timeline
let options = {
start: currentDate,
// 设置时间轴的范围 前后扩展7天
min: dayjs().subtract(365, 'day').format('YYYY-MM-DD HH:mm:ss'),
max: dayjs().add(365, 'day').format('YYYY-MM-DD HH:mm:ss'),
showCurrentTime: false,
showMajorLabels: false,
verticalScroll: true,
maxHeight: '92px',
height: '92px',
format: {
minorLabels(date, scale, step){
if(scale === 'hour'){
return dayjs(date).format("YYYY-MM-DD HH")
}else if(scale === 'minute'){
return dayjs(date).format("HH:mm")
}else if(scale === 'second'){
return dayjs(date).format("HH:mm:ss")
}
return dayjs(date).format("YYYY-MM-DD HH:mm")
}
}
};
// Create a Timeline
timeline = new vis.Timeline(conRef.value, items, options);
updateCustomTime(currentDate, true)
}
const updateCustomTime = (date, init=false)=>{
if(init){
timeline.addCustomTime(date, "playTimeline")
}else{
timeline.setCustomTime(date, "playTimeline")
}
timeline.setCustomTimeTitle(dayjs(date).format("YYYY-MM-DD HH:mm:ss"),'playTimeline')
timeline.setCustomTimeMarker(dayjs(date).format("YYYY-MM-DD HH:mm:ss"),'playTimeline', false)
}
// onMounted(()=>{
// init()
// })
defineExpose({
draw,
updateCustomTime
})
</script>
<style lang="less">
.xdzx_vis_timeline_wrap{
height: 92px;
position: absolute;
left: 20px;
right: 20px;
bottom: 8px;
overflow: auto;
background-color: rgba(2, 125, 180, 0.4);
.vis-time-axis .vis-text{
color: #fff;
}
.vis-item{
&.bcks{
.vis-dot{
background: red;
border: none;
width: 15px;
height: 25px;
transform: translate(-50%, 50%) !important;
background: url('@/assets/xdzx_timelin_bcks_icon.svg') no-repeat top left/100% 100%;
}
}
&.bcjs{
.vis-dot{
background: red;
border: none;
width: 15px;
height: 25px;
transform: translate(-50%, 50%) !important;
background: url('@/assets/xdzx_timelin_bcjs_icon.svg') no-repeat top left/100% 100%;
}
}
&.xxts{
.vis-dot{
background: red;
border: 1px solid #fff !important;
width: 15px;
height: 15px;
transform: translate(-50%, 100%) !important;
border-radius: 50%;
}
&.tscg{
.vis-dot{
background: blue;
}
}
&.tssb{
.vis-dot{
background: red;
}
}
&.wts{
.vis-dot{
background: yellow;
}
}
}
}
.vis-tooltip{
//&>div{
// background: red;
// div:first-child{
// background: #fff;
// }
// div:nth-child(2){
// background: #00f;
// }
//}
}
.vis-custom-time{
pointer-events: none;
}
}
</style>
@@ -0,0 +1,761 @@
<template>
<div class="rw_detail_zxtp_wrap">
<div class="header_bar">
<span style="font-weight: 700;font-style: normal;font-size: 20px;color: #D7D7D7;">{{currentRw.assName}}</span>
<span style="font-weight: 700;font-style: normal;font-size: 20px;color: #D7D7D7;">行动执行拓扑</span>
<t-button theme="primary" @click="emit('close')">返回</t-button>
</div>
<div class="content">
<div class="left_wrap">
<div class="wrap_top">
<t-tooltip
class="placement bottom center"
:content="`${tpInfo.xdData.actionNum}:${tpInfo.xdData.actionName}`"
:overlay-style="{ width: '200px', zIndex: 9999 }"
placement="bottom"
show-arrow
>
<div class="middle-title cursor-pointer">{{ tpInfo.xdData?.actionNum}}:{{ tpInfo.xdData?.actionName }}</div>
</t-tooltip>
<div class="wrap_top_content">
<div>开始时间:{{ tpInfo.xdData?.actionStartTime || '---'}}</div>
<div>预计结束:{{ tpInfo.xdData?.actionStartTime || '---'}}</div>
<div class="wrap_top_footer">
<div>
持续时长:{{ tpInfo.xdData?.duration || '---'}}
</div>
<div v-if="props.currentRw.actionList.length > 1" class="btns">
<t-button size="small" @click="tpInfo.last(tpInfo.rwData.assId,tpInfo.xdData.actionId,'last')"><</t-button>
<t-button size="small" @click="tpInfo.next(tpInfo.rwData.assId,tpInfo.xdData.actionId,'next')">></t-button>
</div>
</div>
</div>
</div>
<div class="wrap_center">
<span class="middle-title">行动伴随评估等级</span>
<div class="level">
<!--任务伴随评估级别图块-->
<div class="bs-content">
<div class="bs-left">
三级
</div>
触发关键节点
</div>
<!--任务伴随评估各级别分类-->
<div class="bs-detail">
评估时间:05-06 14:00:00
<div class="bs-detail-icon">
<div class="bs-detail-item1"></div>
<div class="bs-detail-item2"></div>
<div class="bs-detail-item3">
<span class="detail-text">三级</span>
</div>
<div class="bs-detail-item4"></div>
<div class="bs-detail-item5"></div>
</div>
</div>
</div>
</div>
<div class="wrap_bottom">
<span class="middle-title">行动执行日志</span>
<t-timeline v-if="props.taskInfo.trackList.length !== 0" class="jd-timeline">
<t-timeline-item
style="margin-left: -80px"
:key="index"
v-for="(item, index) in props.taskInfo.trackList"
>
<t-space>
<div
class="jd-logType"
:class="
item.logType === '任务指令' ? 'jd-logType-rwzl' :
item.logType === '任务执行' ? 'jd-logType-rwzx' :
item.logType === '资源告警' ? 'jd-logType-zygj' :
item.logType === '任务偏差' ? 'jd-logType-rwpc' :
''
"
>
{{ item.logType }}
</div>
<div class="jd-text">{{ item.logTime }} </div>
<div class="jd-text">{{ item.logSource }}</div>
</t-space>
<div
class="jd-logContent"
:class="
item.logType === '资源告警' || item.logType === '任务偏差' ? 'jd-logContent-alert' : 'jd-logContent'
"
>
{{ item.logContent }}
</div>
</t-timeline-item>
</t-timeline>
<t-empty class="empty-style" v-else title="任务暂无关联进度"/>
</div>
</div>
<div class="right_wrap">
<G6Tp :ref="el=>tpInfo.ref=el"/>
<Timeline :key="playInfo.key" :ref="el=>playInfo.timelineRef=el" :currentDate="playInfo.current"/>
</div>
</div>
</div>
</template>
<script setup>
import G6Tp from "./g6Tp.vue"
import Timeline from "./timeline.vue"
import {onMounted, shallowReactive, reactive, nextTick, onUnmounted, watch} from "vue";
import DemoPng1 from "@/assets/xdkztp_icon_01.svg"
import DemoPng2 from "@/assets/xdkztp_icon_02.svg"
import DemoPng3 from "@/assets/xdkztp_icon_03.svg"
import DemoPng4 from "@/assets/xdkztp_icon_04.svg"
import dayjs from "dayjs";
import axios from "@/utils/request.js";
const props = defineProps({
currentRw: {},
currentXd: {},
taskInfo: {},
})
const emit = defineEmits(["close"])
const tpInfo = shallowReactive({
graph: null,
isfirst: false,
islast: false,
rwData: [],
xdData: [],
//拓扑图数据
data: [],
ref: null,
async getTpData(assId, actionId){
let res = await axios.get(`/b3api/bigScreen/actionControl/getActionWaveTPInfo?assId=${assId}&actionId=${actionId}`)
tpInfo.data = res.data;
tpInfo.getData();
},
async last(assId, actionId, act){
let param = {
assId: assId,
actionId: actionId,
act: act
}
//获取下一个行动的拓扑图数据和行动信息
//更新拓扑图
//更新进度
//更新任务伴随评估等级
//更新行动信息
let res = await axios.post('/b3api/bigScreen/actionControl/getOtherAction',param)
tpInfo.xdData = res.data;
tpInfo.getTpData(tpInfo.rwData.assId, tpInfo.xdData.actionId);
console.log(tpInfo.xdData,"上一个")
playInfo.getData();
},
async next(assId, actionId, act){
let param = {
assId: assId,
actionId: actionId,
act: act
}
let res = await axios.post('/b3api/bigScreen/actionControl/getOtherAction',param)
tpInfo.xdData = res.data;
tpInfo.getTpData(tpInfo.rwData.assId, tpInfo.xdData.actionId);
console.log(tpInfo.xdData,"下一个")
playInfo.getData();
},
//判断是否为第一个
async isFirst(){
if (tpInfo.rwData.actionList[0].actionNum === tpInfo.xdData.actionNum){
tpInfo.isfirst = true;
}
// return tpInfo.currentIndex === 0;
},
async isLast(){
if (tpInfo.rwData.actionList[tpInfo.rwData.actionList.length-1].actionNum === tpInfo.xdData.actionNum){
tpInfo.islast = true;
}
// return tpInfo.currentIndex === props.currentRw.actionList.length - 1;
},
//获取拓扑图
async getData(){
tpInfo.graph = await tpInfo.ref.draw();
console.log(tpInfo.data,"获取拓扑图")
/* let data = {
nodes: [
{ id: 'node0', showLabel: true, label: "台军装备关注者人设" },
{ id: 'node1', showLabel: true, label: "前军方技术人员人设" },
{ id: 'node2', showLabel: true, label: "台军装备关注者人设" },
{ id: 'node3', showLabel: true, label: "波次1:集中造势\n02.12-02.13"},
{ id: 'node4', showLabel: true, isShowBadge: true },
{ id: 'node5', showLabel: true, isShowBadge: true },
{ id: 'node6', shape: "circle", isShowBadge: true, fillColor: "#f00" },
{ id: 'node7', shape: "rect", isShowBadge: true, isShowBottom: true, fillColor: "#f00", subTitle: "XD" },
{ id: 'node8', shape: "diamond", fillColor: "#f00", subTitle: "BC2" },
{ id: 'node9', shape: "hexagon", showLabel: true },
{ id: 'node10', shape: "ellipse", fillColor: "#0f0" },
{ id: 'node11', shape: "circle", fillColor: "#00f", isShowBottom: true },
{ id: 'node12', },
{ id: 'node13', },
{ id: 'node14', },
{ id: 'node15', },
{ id: 'node16', },
],
edges: [
{ source: 'node0', target: 'node1', lineColor: '#ce7481' },
{ source: 'node0', target: 'node2', lineColor: '#e1e306' },
{ source: 'node0', target: 'node3', lineColor: '#ac75e4', isDash: true },
{ source: 'node0', target: 'node5', isDash: true },
{ source: 'node1', target: 'node6' },
{ source: 'node1', target: 'node7' },
{ source: 'node2', target: 'node8' },
{ source: 'node2', target: 'node9' },
{ source: 'node2', target: 'node10' },
{ source: 'node2', target: 'node11' },
{ source: 'node2', target: 'node12' },
{ source: 'node2', target: 'node13' },
{ source: 'node3', target: 'node14' },
{ source: 'node3', target: 'node15' },
{ source: 'node3', target: 'node16' },
],
}*/
// 定义图片映射规则
const imageRules = [
{ idPattern: /rs/i, img: DemoPng1 }, // 包含"rs"的ID使用DemoPng1
{ idPattern: /zh/i, img: DemoPng2 }, // 包含"zh"的ID使用DemoPng2
{ idPattern: /cbNode/i, img: DemoPng3 }, // 包含"cbNode"的ID使用DemoPng3
{ idPattern: /cbw/i, img: DemoPng4 }, // 包含"cbw"的ID使用DemoPng4
];
tpInfo.data.nodes.forEach(node => {
const nodeId = node.id || '';
let matchedImg = DemoPng1; // 默认图片
// 查找匹配的规则
for (let rule of imageRules) {
if (rule.idPattern.test(nodeId)) {
matchedImg = rule.img;
break;
}
}
node.data = {
imgSrc: matchedImg,
};
node.shape = node.shape || "circle";
});
//随机生成图片
/*tpInfo.data.nodes.forEach(node => {
node.data = {
imgSrc: [DemoPng1,DemoPng2,DemoPng3,DemoPng4][Math.floor(Math.random()*4)],
}
node.shape = node.shape || "circle"
})*/
tpInfo.graph.setData(tpInfo.data);
tpInfo.graph.render();
window._TP = tpInfo.graph
}
})
const playInfo = reactive({
timelineRef: null,
current: new Date(),
range: [],
isPlay: false,
key: Math.random(),
async getData(){
playInfo.key = Math.random();
await nextTick();
playInfo.current = new Date()
const currentDate = playInfo.current;
playInfo.range = [playInfo.current, new Date(+currentDate + 1000*60*60*5)]
// 检查数据是否存在再访问
const newBcArray = tpInfo.xdData?.waveList?.flatMap(item => {
// 确保 item 存在
if (!item) return [];
const actionPoints = item.waveActions?.flatMap(childItem => {
if (!childItem) return [];
const getClassNames = () => {
switch(childItem.tsResult) {
case 1: return "xxts tscg";
case 2: return "xxts tssb";
case 3: return "xxts wts";
default: return "xxts tssb";
}
};
return [{
id: `${childItem.actCode}_start`,
className: getClassNames(),
type: 'point',
start: new Date(childItem.tsTime),
title: `<div>
<div>${childItem.userName}</div>
<div v-if="getClassNames() === 'xxts wts'">未投送</div>
<div v-if="getClassNames() !== 'xxts wts'">${dayjs(childItem.tsTime).format("YYYY-MM-DD HH:mm:ss")}</div>
</div>`,
}];
}) || [];
// 确保 item.startTime 和 item.endTime 存在
const wavePoints = [{
id: `${item.waveId}_start`,
className: "bcks",
type: 'point',
start: item.startTime,
title: `<div>
<div>${item.waveName} - 开始</div>
<div>${dayjs(item.startTime).format("YYYY-MM-DD HH:mm:ss")}</div>
</div>`,
}, {
id: `${item.waveId}_end`,
className: "bcjs",
type: 'point',
start: item.endTime,
title: `<div>
<div>${item.waveName} - 结束</div>
<div>${dayjs(item.endTime).format("YYYY-MM-DD HH:mm:ss")}</div>
</div>`,
}];
return [...actionPoints, ...wavePoints];
}) || [];
console.log(newBcArray,"时间轴数据");
playInfo.timelineRef.draw({
current: playInfo.current,
list: newBcArray
/* [
{id: 1, className: "bcks", tips: "波次开始",
title: `
<div>
<div>波次开始</div>
<div>${dayjs().format("YYYY-MM-DD HH:mm:ss")}</div>
</div>
`,
start: new Date(+currentDate + 1000*60*60), type: 'point'},
{id: 2, className: "xxts tscg", tips: "信息投送成功",start: new Date(+currentDate + 1000*60*60*2), type: 'point'},
{id: 3, className: "xxts tssb", tips: "信息投送失败", start: new Date(+currentDate + 1000*60*60*3), type: 'point'},
{id: 4, className: "xxts wts", tips: "信息未投送", start: new Date(+currentDate + 1000*60*60*4), type: 'point'},
{id: 5, className: "bcjs", tips: "波次结束", start: new Date(+currentDate + 1000*60*60*5), type: 'point'},
]*/
})
},
//播放
play(){
playInfo.timer && clearInterval(playInfo.timer);
playInfo.timer = setInterval(()=>{
playInfo.current = new Date(+playInfo.current + 1000)
if(playInfo.current >= playInfo.range[1]){
clearInterval(playInfo.timer)
playInfo.timer = null
}
}, 1000)
}
})
watch(()=>playInfo.current, ()=>{
// console.log("current:", playInfo.current)
// 更新拓扑和时间轴
playInfo.timelineRef.updateCustomTime(playInfo.current);
//当有节点更新时闪烁
/*let node = tpInfo.ref.findNodeById('xd')
tpInfo.ref.updateNode([
{
...node,
isShowBadge: !node.isShowBadge,
isShowBottom: !node.isShowBottom,
}
])*/
})
onMounted(()=>{
tpInfo.rwData = props.currentRw;
tpInfo.xdData = props.currentXd;
tpInfo.isFirst()
tpInfo.isLast()
tpInfo.getTpData(tpInfo.rwData.assId,tpInfo.xdData.actionId)
playInfo.getData()
playInfo.play()
console.log(props.currentXd,"currentXd")
})
onUnmounted(()=>{
playInfo.timer && clearInterval(playInfo.timer)
})
defineExpose({})
</script>
<style lang="less">
.rw_detail_zxtp_wrap{
position: fixed;
inset: 0;
background: rgba(0, 27, 38, 0.75);
z-index: 9999;
.header_bar{
height: 53px;
display: flex;
padding: 0 10px;
align-items: center;
justify-content: space-between;
background: url('@/assets/zxtp_header_bar.svg') no-repeat top left/100% 100%;
}
.content{
height: calc(100% - 53px);
display: flex;
.left_wrap{
display: flex;
flex-direction: column;
padding: 20px 0 0 20px;
width: 440px;
height: 100%;
gap: 10px;
.middle-title{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 95%;
height: 45px;
padding: 8px 12px;
display: flex;
color: #ffffff;
font-size: 20px;
font-weight: bold;
}
.wrap_top {
color: #fff;
height: 15%;
width: 100%;
background: inherit;
background-color: rgba(2, 125, 180, 0.4);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(2, 125, 180, 1);
border-radius: 5px;
.wrap_top_content {
height: calc(100% - 45px);
display: flex;
flex-direction: column;
gap: 6px;
color: #AAAAAA;
padding: 0 12px;
.wrap_top_footer {
display: flex;
justify-content: space-between;
.btns {
display: flex;
gap: 8px;
}
}
}
}
.wrap_center {
width: 100%;
background: inherit;
background-color: rgba(2, 125, 180, 0.4);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(2, 125, 180, 1);
border-radius: 5px;
height: 10%;
//width: 100%;
.level {
display: flex;
.bs-content {
display: flex;
align-items: center;
justify-content: space-around;
width: 217px;
height: 46px;
margin-left: 12px;
background: inherit;
background-color: rgba(255, 255, 0, 0.15);
border-radius: 7px;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
font-size: 18px;
color: #FFFFFF;
.bs-left {
display: flex;
align-items: center;
justify-content: center;
width: 69px;
height: 31px;
background: inherit;
background-color: rgba(255, 255, 0, 0.65);
border: none;
border-radius: 7px;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
font-size: 18px;
}
}
.bs-detail {
font-size: 14px;
padding-left: 10px;
color: #ffffff;
.bs-detail-icon{
display: flex;
color: #0d1117;
.detail-text {
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
width: 100%;
}
.bs-detail-item1 {
margin-top: 5px;
width: 34px;
height: 13px;
background: inherit;
background-color: rgba(202, 249, 130, 0.5);
border: none;
border-radius: 0px;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
font-size: 9px;
}
.bs-detail-item2 {
margin-top: 5px;
width: 34px;
height: 13px;
background: inherit;
background-color: rgba(0, 255, 255, 0.5);
border: none;
border-radius: 0px;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
font-size: 9px;
}
.bs-detail-item3 {
margin-top: 5px;
width: 34px;
height: 13px;
background: inherit;
background-color: rgba(255, 255, 0, 1);
border: none;
border-radius: 0px;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
font-size: 9px;
}
.bs-detail-item4 {
display: flex;
align-items: center;
justify-content: center;
margin-top: 5px;
width: 34px;
height: 13px;
background: inherit;
background-color: rgba(245, 154, 35, 0.498039215686275);
font-size: 9px;
color: red;
}
.bs-detail-item5 {
margin-top: 5px;
width: 34px;
height: 13px;
background: inherit;
background-color: rgba(217, 0, 27, 0.498039215686275);
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
font-size: 9px;
}
}
}
}
.zy-content {
width: 100%;
display: flex;
flex-wrap: wrap;
height: 100%;
gap: 0.5rem;
padding-left: 18px;
.zy-item {
display: flex;
padding: 3px;
width: 195px;
height: 76px;
background: inherit;
background-color: rgba(2, 125, 180, 0.2);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(2, 125, 180, 1);
border-radius: 9px;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
.zy-icon {
padding: 10px;
width: 71px;
height: 68px;
background: inherit;
background-color: rgba(2, 125, 180, 0.88);
border-radius: 9px;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
.icon-zy{
width: 100%;
color: #ffffff;
font-size: 30px;
display: flex;
justify-content: center;
}
.title-zy {
color: #ffffff;
font-weight: bold;
font-size: 12px;
}
}
.zy-text{
color: #ffffff;
font-size: 14px;
padding: 2px 10px;
width: 120px;
}
}
}
}
.wrap_bottom {
width: 100%;
height: calc(75% - 20px);
background: inherit;
background-color: rgba(2, 125, 180, 0.4);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(2, 125, 180, 1);
border-radius: 5px;
}
.jd-timeline {
width: 100%;
height: 100%;
color: #fff;
overflow: hidden;
overflow-y: scroll;
display: flex;
flex-direction: column;
align-items: center;
padding: 0 10px;
.jd-logType {
width: 74px;
height: 22px;
background: inherit;
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-radius: 19px;
display: flex;
align-items: center;
justify-content: center;
}
.jd-logType-rwzl {
background-color: rgba(149, 242, 4, 0.2);
border-color: rgba(112, 182, 3, 1);
color: #95F204;
}
.jd-logType-rwzx {
background-color: rgba(128, 255, 255, 0.2);
border-color: rgba(128, 255, 255, 1);
color: #80FFFF;
}
.jd-logType-zygj {
background-color: rgba(255, 255, 128, 0.2);
border-color: rgba(255, 255, 0, 1);
color: #FFFF00;
}
.jd-logType-rwpc {
background-color: rgba(250, 205, 145, 0.2);
border-color: rgba(250, 205, 145, 1);
color: #F59A23;
}
.jd-text {
font-size: 14px;
}
.jd-logContent {
margin-top: 5px;
width: 367px;
background: inherit;
background-color: rgba(2, 125, 180, 0.3);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(2, 125, 180, 1);
border-radius: 7px;
display: flex;
align-items: center;
padding: 5px 10px;
}
.jd-logContent-alert {
color: #F59A23;
}
}
}
.right_wrap{
width: calc(100% - 440px);
height: 100%;
position: relative;
}
}
}
.empty-style {
border-radius: 4px;
width: 100%;
height: 100%;
align-items: center;
display: flex;
justify-content: center;
}
</style>
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,65 @@
<template>
<div>
<div class="tabs-list" style="text-align: left;">
<div
class="tabs-item"
:class="{ 'item-active': tabIndex === item.id }"
@click="tabChange(item.id)"
v-for="(item, index) in tabList"
:key="index"
>
{{ item.name }}
</div>
</div>
<TableTwo title="平台传播占比" v-if="tabIndex == 1" style="width: 100%;">
<template #contentTable>
<AspEcharts :actionId="actionId" :token="token" />
</template>
</TableTwo>
<TableTwo title="平台触达" v-if="tabIndex == 2" style="width: 100%;">
<template #contentTable>
<XdTrend :actionId="actionId" :token="token" />
</template>
</TableTwo>
</div>
</template>
<script setup>
import {
ref,
reactive,
nextTick,
inject,
computed,
onMounted,
defineExpose,
watch,
} from "vue";
import AspEcharts from "./asp-echarts.vue"; //预定ts通道评估
import XdTrend from "./xd-trend.vue"; //预定ts通道评估 平台触达
import TableTwo from "./table-two.vue";
const props = defineProps({
actionId: {
type: Number,
defalt: 0,
},
token: {
type: String,
defalt: "",
},
});
const actionId = computed(() => props.actionId);
const token = computed(() => props.token);
const tabList = ref([
{ name: "平台传播占比", id: 1 },
{ name: "平台触达", id: 2 },
]);
const tabIndex = ref(1);
const tabChange = (id) => {
tabIndex.value = id;
};
</script>
<style lang="less" scoped>
* {
box-sizing: border-box;
}
</style>
@@ -0,0 +1,221 @@
<template>
<div class="asp-page">
<div ref="platformPieRef" class="pie-content"></div>
<div class="legendList">
<div class="item" v-for="(item, index) in data" :key="index">
<div
class="kuai"
:style="{ backgroundColor: colorList[index % colorList.length] }"
></div>
<span class="name">{{ item.name }}</span>
<span>{{ item.value }}</span>
<span>条</span>
</div>
</div>
</div>
</template>
<script setup>
import {
ref,
reactive,
nextTick,
inject,
computed,
onMounted,
defineExpose,
watch,
} from "vue";
import * as echarts from "echarts";
import axios from "@/utils/request";
import { color } from "d3";
const colorList = [
"#587bf3",
"#b6d634",
"#575a7b",
"#ffa753",
"#0cb3ee",
"#ffd10a",
"#7acaa4",
"#c8cdd5",
"#f40",
];
const platformPieRef = ref(null);
const props = defineProps({
actionId: {
type: Number,
defalt: 0,
},
token: {
type: String,
defalt: "",
},
});
const actionId = computed(() => props.actionId);
const token = computed(() => props.token);
const data = ref([]);
const getData = () => {
let url =
environment["b5ReplyUrl"] +
"/assessment/bs/getActionDetails/platformPutNew?belongType=1&infoType=2" +
"&belongId=" +
actionId.value;
axios
.get(url, {
headers: {
"Access-token": `${token.value}`,
},
})
.then((res) => {
data.value = [];
res.data.forEach((item) => {
data.value.push({
name: item.name,
value: (item.list && item.list[0]?.value) || 0,
percent: (item.list && item.list[2]?.value + "%") || "0%",
});
});
setTimeout(() => {
initEchart()
},100)
});
};
const initEchart = () => {
let chartPie = echarts.init(platformPieRef.value);
let count = 0;
data.value.forEach((i) => {
count += i.value;
});
const option = {
color: colorList,
// 标题
title: {
left: "center",
},
// 提示框
tooltip: {
trigger: "item",
formatter: "{a}<br/>{b}: {c} ({d}%)", // 显示系列名、数据名、值和百分比
},
graphic: [
{
type: "text",
left: "80px",
top: "center",
style: {
text: "账号总数 \n" + count,
fontSize: 16,
textAlign: "center",
fill: "#fff",
width: "50%",
height: "50%",
color:'var(--textColor--)'
},
},
],
// 系列配置
series: [
{
name: "平台占比", // 系列名称
type: "pie", // 类型为饼图
radius: ["50%", "60%"], // 环形内外半径(控制环形宽度)
center: ["30%", "50%"], // 图表中心位置
data: data.value,
// 设置扇形之间的间隔(通过边框模拟)
itemStyle: {
borderRadius: 0, // 扇形圆角(可选)
borderColor: "rgba(10, 36, 64, 0.8)", // 分隔线颜色(白色)
borderWidth: 5, // 分隔线宽度(控制间隔大小)
},
// 分隔线配置
splitLine: {
length: 15, // 分隔线长度(从外圆到标签的长度)
lineStyle: {
// 分隔线样式
color: "rgba(255, 255, 255, 0.5)", // 透明度
width: 2,
},
},
// 标签配置
label: {
show: false,
formatter: "{b}: {c} ({d}%)", // 标签格式(名称、值、百分比)
position: "outside", // 标签位置(外部)
color: "#fff", // 标签颜色
},
},
],
};
chartPie.setOption(option);
};
watch(
() => actionId.value,
(val) => {
if (val) {
getData();
}
},
{
deep: true,
}
);
onMounted(() => {
if (actionId.value) {
getData();
}
})
</script>
<style lang="less" scoped>
* {
box-sizing: border-box;
}
.asp-page {
display: flex;
position: relative;
width: 368px;
}
.pie-content {
width: 100%;
height: 300px;
background: url("@/assets/icon/账号环形图.png");
background-repeat: no-repeat;
background-size: 134px;
background-position: 43px 83px;
}
.legendList {
position: absolute;
right: 10px;
top: 50px;
display: flex;
gap: 14px;
height: 200px;
overflow-y: auto;
flex-direction: column;
.kuai {
width: 6px;
height: 6px;
}
.item {
height: 22px;
display: flex;
gap: 10px;
align-items: center;
justify-content: space-between;
color: rgba(255, 255, 255, 0.8);
font-size: 14px;
padding: 0 5px;
img {
width: 8px;
height: 8px;
}
.name {
flex: 1;
flex-shrink: 0;
}
}
}
</style>
@@ -0,0 +1,104 @@
<!--
* @Author :
* @Date : 2024-07-12 10:18:57
* @LastEditors:
* @LastEditTime: 2025-07-11 10:04:39
* @Description : 全局组件- 操作(编辑、确定、取消)
-->
<template>
<div
class="edit-group"
:class="{ 'edit-group_ing': isEdit }"
v-if="groupVisible"
>
<span class="edit-svg" v-if="!isEditStatus" @click="onEdit()"></span>
<span class="cancel-icon" v-if="isEditStatus" @click="onCancel()"></span>
<span class="finish-icon" v-if="isEditStatus" @click="onFinish()"> </span>
</div>
</template>
<script setup>
import { computed } from 'vue'
const emits = defineEmits([
'update:isEdit',
'update:visible',
'edit',
'cancel',
'finish'
])
const props = defineProps({
isEdit: {
type: Boolean,
default: false
},
visible: {
type: Boolean,
default: true
}
})
const groupVisible = computed({
get() {
return props.visible || props.isEdit
},
set(val) {
emits('update:visible', val)
}
})
const isEditStatus = computed({
get() {
return props.isEdit
},
set(val) {
emits('update:isEdit', val)
}
})
const onEdit = () => {
isEditStatus.value = true
emits('edit')
}
const onCancel = () => {
isEditStatus.value = false
groupVisible.value = false
emits('cancel')
}
const onFinish = () => {
isEditStatus.value = false
groupVisible.value = false
emits('finish')
}
defineExpose({ onEdit, onCancel, onFinish })
</script>
<style lang="less" scoped>
.edit-group {
display: flex;
align-items: center;
gap: 10px;
margin-right: 10px;
z-index: 2;
&.edit-group_ing {
display: flex !important;
}
> span {
display: inline-block;
cursor: pointer;
}
.cancel-icon {
width: 15px;
height: 15px;
}
.finish-icon {
width: 21px;
height: 15px;
}
}
</style>
@@ -0,0 +1,668 @@
<!--
* @Author :
* @Date : 2024-06-25 11:03:54
* @LastEditors:
* @LastEditTime: 2025-05-03 22:44:17
* @Description : 伴随任务-信息ts-左侧列表
-->
<template>
<div
class="information-list"
v-loading.lock="loadingStatus"
element-loading-text="loading"
element-loading-custom-class="big-part-loading"
>
<div
class="information-list-wrapper"
v-for="(item, index) in list"
:key="index"
ref="setRef"
style="min-height: 280px"
v-show="item.bsLink?.status != 2"
>
<div class="first-line">
<div class="left">
<img
:src="`src/assets/reply-img/logo/${item.asp}.png`"
alt=""
style="width: 24px; height: auto; margin-right: 5px"
/>
<t-tooltip :content="item.account" placement="top" effect="dark">
<div
class="line-value line-value__account"
v-html="item.accountHL || item.account"
></div>
</t-tooltip>
<div class="line-value num-font">
{{ dayjs(item.publishTime).format("YYYY年MM月DD日") || "-" }}
</div>
</div>
</div>
<div class="second-line">
<div class="line-cont-contaier">
<div class="line-cont" :class="{ 'list-cont-all': item.isShowAll }">
<span
class="content"
v-html="item.contentHL || item.content"
style="display: inline"
:ref="(el) => setListRef(el, index)"
></span>
</div>
</div>
<div
class="line-img"
v-if="
item.picturePathsList !== null && item.picturePathsList?.length > 0
"
>
<!-- <div class="line-img" v-if="false"> -->
<div v-for="(itemJ, index) in item.picturePathsList" :key="itemJ">
<!-- <img :src="itemJ" alt="" /> -->
<t-image
:src="itemJ"
:zoom-rate="1.5"
:max-scale="7"
:min-scale="0.5"
:initial-index="initialIndex"
fit="cover"
:preview-src-list="item.picturePathsList"
></t-image>
</div>
</div>
<div
class="b-media-grid"
v-if="item.videoPathsList !== null && item.videoPathsList?.length > 0"
>
<!-- <BMedia
v-for="(itemL, index) in item.videoPathsList"
:key="itemL"
:src="itemL"
:gchkey="item.gchkey"
type="video"
:rawSrc="item.videoPaths[index]"
></BMedia> -->
</div>
</div>
<div
class="five-line"
>
<t-image
style="width: 100%; height: 100%"
v-if="
item.evidence &&
item.evidence.length > 0 &&
item.evidence[item.evidence.length - 1].image &&
item.evidence[item.evidence.length - 1].image.length > 0
"
:src="item.evidence[item.evidence.length - 1]?.image[0]"
fit="contain"
:preview-src-list="item.evidence[item.evidence.length - 1]?.image"
:initial-index="0"
></t-image>
</div>
<div class="six-line">
<div
style="width: 100%; height: 280px"
v-if="item.contList && item.contList.length > 0"
>
<Radar :data="item.contList" />
</div>
</div>
<div class="third-line">
<div class="left">
<div class="line-title" v-if="item.bsLevelName">信息评级</div>
<div
class="line-value line-value__level"
:class="{ 'is-click': item?.bsLevelid > 3 }"
v-if="item.bsLevelName"
>
{{ item.bsLevelName }}
</div>
<div
class="right-line"
v-for="(itemS, index) in item.interactives"
:key="index"
:style="{
cursor:
itemS.interactiveName == '转' && item.linkStatus
? 'pointer'
: itemS.interactiveName == '评' && item.linkStatus
? 'pointer'
: '',
}"
>
<span>{{ itemS.interactiveName }}</span>
<span class="num-font">{{
(itemS.interactiveValue &&
itemS.interactiveValue.toLocaleString()) ||
0
}}</span>
</div>
</div>
</div>
<!-- <div class="six-name">
<span class="header-title-logo"></span>DY制作评估
</div> -->
</div>
<div class="data-none" v-if="list?.length == 0" style="margin-top: 90px">
<div class="data-none-img"></div>
<div v-if="searchType == 'search'">C系统ts数据0条</div>
<div v-else style="text-align: center;">C系统ts数据0条,无法进行评级</div>
</div>
</div>
</template>
<script setup>
import axios from "@/utils/request";
// import informationDrawerKey from '@/components/modules/accompanying-task/information-drawer-key.vue'
// import informartionPartDialog from '@/components/modules/accompanying-task/informartionPartDialog.vue'
// import { tooltipEffect } from '@/components/modules/situation/tools'
// import xdlistDialog from '@/components/modules/accompanying-task/dataDetail/xdlist-dialog.vue'
// import { BMedia } from '@/components/ui'
import Radar from './radar-echart.vue'
import {
nextTick,
onMounted,
watch,
ref,
computed,
watchEffect,
inject,
} from "vue";
import { useRoute, useRouter } from "vue-router";
import dayjs from "dayjs";
const route = useRoute();
const props = defineProps({
list: {
type: Array,
default: () => [],
},
currentPage: {
type: Number,
default: 0,
},
pageSizes: {
type: Number,
default: 0,
},
searchType: {
type: String,
default: "",
},
loadingStatus: {
type: Boolean,
default: false,
},
// 是否可勾选
isCheck: {
type: Boolean,
default: false,
},
// 勾选内容
checkId: {
type: String,
default: "id",
},
taskId: {
default: null,
},
//从信息运营过来的必须用这个id
usetaskId: {
type: Boolean,
default: false,
},
userProject: {
type: String,
default: "",
},
});
let initialIndex = ref(0);
const keywordInputRef = ref(null);
console.log(props.checkId, "=======", props.list);
const listPage = ref(1);
const listSizes = ref(null);
const informationDrawerRef = ref();
let currPageComp = computed(() => {
return [props.currentPage, props.pageSizes];
});
watch(currPageComp, (newValue, oldValue) => {
listPage.value = newValue[0];
listSizes.value = newValue[1];
});
const edit_key_word = ref(-1);
const edit_key_word_value = ref("");
const showBtn = ref(-1);
const showBtnEditFlag = ref(-1);
const showBtnEdit = ref("");
// const lineContRef0 = ref(null);
const setRef = ref(null);
const listRefs = ref({});
const minHeight = ref({});
const emit = defineEmits([
"informationlistC",
"checkedDataChange",
"getBfiveDetail",
"translateContentF",
]);
const setListRef = (el, index) => {
// console.info(el, index)
listRefs.value[index] = el;
nextTick(() => {
minHeight.value[index] = el?.offsetHeight;
});
};
let keywordType = "";
const keywordDel = (id, bsactionId, keywords, index) => {
//删除
let param = {
bsactionId: bsactionId,
bsConfigKeywordId: id,
};
$http("post", "assessConfigKeywordDel", param).then((res) => {
keywords.splice(index, 1);
// emit("informationlistC");
});
};
const keywordPlay = (id, bsConfigKeywordIsUses, key) => {
//启动
let param = {
bsConfigKeywordId: id,
bsactionId: Number(route.query.bsactionId),
isUse: 1,
};
$http("post", "assessConfigKeywordIsuse", param).then((res) => {
bsConfigKeywordIsUses[key] = 1;
// keywords.push(showBtnEdit.value)
// emit("informationlistC");
});
};
const keywordPlaus = (id, bsConfigKeywordIsUses, key) => {
//停止
let param = {
bsConfigKeywordId: id,
bsactionId: Number(route.query.bsactionId),
isUse: 0,
};
$http("post", "assessConfigKeywordIsuse", param).then((res) => {
bsConfigKeywordIsUses[key] = 0;
// keywords.push(showBtnEdit.value)
// emit("informationlistC");
});
};
const keywordEdit = (keyItem, indexKey, index) => {
keywordType = "edit";
showBtnEditFlag.value = indexKey + "-" + index;
showBtnEdit.value = keyItem;
nextTick(() => {
setTimeout(() => {
keywordInputRef.value[0].focus();
}, 100);
});
};
const keywordAddFinish = (
indexKey,
keywords,
putInfoId,
wordid,
bstaskId,
bsactionId
) => {
showBtnEditFlag.value = -1;
if (keywordType == "add") {
if (showBtnEdit.value == "") {
//添加是空不管
keywords.splice(keywords.length - 1, 1);
return;
}
let param = {
bstaskId: bstaskId,
bsactionId: bsactionId,
type: 2, //固定
putInfoId: putInfoId,
keyword: showBtnEdit.value,
};
// console.log("param", param);
$http("post", "assessConfigKeywordAdd", param).then((res) => {
// keywords.push(showBtnEdit.value)
emit("informationlistC");
});
} else if (keywordType == "edit") {
let param = {
bsactionId: bsactionId,
bsConfigKeywordId: wordid,
keyword: showBtnEdit.value,
};
if (showBtnEdit.value == "") {
//编辑是空不管
return;
}
$http("post", "assessConfigKeywordUpdata", param).then((res) => {
// keywords.splice(indexKey,1,showBtnEdit.value)
keywords[indexKey] = showBtnEdit.value;
// emit("informationlistC");
});
}
};
// 选中数据
const checkData = ref({});
watch(
() => props.list,
() => {
console.info("列表变化", checkData.value);
checkData.value = {};
props.list.forEach((d) => {
checkData.value[d[props.checkId]] = false;
});
}
);
// 获取选中数据
const getCheckedData = () => {
let arr = [];
for (let i in checkData.value) {
if (checkData.value[i]) arr.push(i);
}
return arr;
};
// 清空选中数据
const clearCheckedData = () => {
for (let i in checkData.value) {
checkData.value[i] = false;
}
};
// 全选
const allCheckedData = () => {
for (let i in checkData.value) {
checkData.value[i] = true;
}
};
defineExpose({
getCheckedData,
clearCheckedData,
allCheckedData,
});
onMounted(() => {});
</script>
<style lang="less">
.information-list {
&-wrapper {
width: calc(100% - 40px);
margin-left: 20px;
margin-bottom: 20px;
padding-bottom: 10px;
background: rgba(0, 98, 217, 0.1);
border: 1px solid;
border-color: rgba(85, 166, 254, 0.1);
position: relative;
color: #fff;
.first-line {
height: 45px;
padding: 0px 20px;
.left {
display: flex;
align-items: center;
// width: calc(100% - 220px);
flex-grow: 1;
.lef-index {
font-size: 20px;
font-family: "boldNum";
color: var(--textColor--);
margin-right: 5px;
}
}
}
.second-line {
padding: 10px 20px;
margin-bottom: 15px;
width: 100%;
min-height: 35px;
.line-cont-contaier {
position: relative;
}
.line-cont {
display: -webkit-box;
position: relative;
font-size: 18px;
// max-height: 4.5em;
// line-height: 1.5em;
max-height: 78px;
// letter-spacing: 0.5px;
overflow: hidden;
text-overflow: ellipsis;
text-align: justify;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
.list-cont-all {
max-height: max-content;
-webkit-line-clamp: unset;
}
.line-cont-button {
color: var(--color1);
cursor: pointer;
}
.tran_span {
margin-right: 10px;
}
.line-cont-button__show {
position: absolute;
bottom: -23px;
right: 17px;
}
.line-img {
display: flex;
width: 100%;
overflow-x: auto;
overflow-y: hidden;
img {
margin-top: 10px;
border-radius: 10px;
margin-right: 20px;
}
}
.line-video {
width: 283px;
height: 161px;
display: flex;
video {
margin-top: 20px;
width: 100%;
height: 100%;
}
}
}
.third-line {
display: flex;
justify-content: space-between;
padding: 0 20px;
.left {
display: flex;
align-items: center;
width: calc(100% - 300px);
white-space: nowrap;
}
.right {
display: flex;
align-items: center;
width: 300px;
justify-content: end;
}
}
.five-line {
position: relative;
left: 20px;
width: calc(100% - 40px);
height: calc(100% - 113px);
border-radius: 4px;
overflow: hidden;
}
.six-name {
position: absolute;
top: 10px;
right: 190px;
display: flex;
align-items: center;
}
.six-line {
position: relative;
top: 0px;
width: calc(100% - 40px);
height: 100%;
display: flex;
align-items: center;
right: -20px;
overflow: hidden;
}
.line-title {
font-size: 16px;
font-family: "textLight";
color: var(--textColor6--);
}
.line-value {
font-size: 16px;
color: var(--textColor--);
margin: 0px 17px 0px 10px;
font-family: "textRegular";
}
.line-value__position {
height: 20px;
padding: 0 5px;
display: flex;
align-items: center;
border-radius: 2px;
font-size: 16px;
margin-right: 10px;
}
.line-value__action {
max-width: calc(100% - 130px);
@include single-text-hidden;
}
.line-value__account {
max-width: calc(100% - 80px);
@include single-text-hidden;
}
.line-split {
width: 2px;
height: 14px;
background-color: #9e9fa6;
opacity: 0.5;
margin-right: 17px;
}
// 级别特殊部分
.line-value__level {
width: 56px;
height: 24px;
border-radius: 2px;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-family: "textBold";
}
.is-click {
cursor: pointer;
}
}
}
.header-title-logo {
width: 4px;
height: 21px;
border-radius: 2px 0px 2px 0px;
margin-right: 10px;
background: var(--bgColor5);
}
.line-ellipsis {
white-space: nowrap; /* 防止文本换行 */
overflow: hidden; /* 隐藏超出容器的文本 */
text-overflow: ellipsis; /* 当文本溢出时显示省略号 */
width: 200px; /* 设置一个固定的宽度,根据需要调整 */
}
</style>
<style lang="less">
.hightValue {
/* display: contents; */
background-color: yellow;
color: black;
}
.text-not__allowed {
color: #ccd3e0;
cursor: not-allowed;
span {
background-image: none;
background-color: #ccd3e0 !important;
}
}
.button-picture {
width: 15px;
height: 13px;
background-color: var(--color1);
background-image: null;
mask-position: -478px -1194px;
mask-image: var(--icon1);
position: relative;
top: 1px;
}
.button-picture__not {
cursor: not-allowed;
background-color: rgba(161, 166, 182, 0.2);
}
.button-send {
width: 80px;
height: 16px;
cursor: pointer;
margin-left: 10px;
line-height: 16px;
font-size: 16px;
color: var(--color1);
}
.button-send-not {
cursor: not-allowed;
color: #ccd3e0;
}
.el-image-viewer__img {
width: fit-content !important;
height: fit-content !important;
}
.data-none-img {
width: 40px;
height: 49px;
background-image: url("@/assets/reply-img/empty-logo.svg");
background-repeat: no-repeat;
margin-bottom: 10px;
margin: auto;
}
.right-line {
margin-left: 10px;
color: #fff;
span:nth-child(1) {
margin-right: 5px;
}
span:nth-child(2) {
color: #fff;
}
}
</style>
Loaded 100 of 142 files, more files were not shown because too many files have changed in this diff. Show more