Team/user CRMFS export + scoped chat

This commit is contained in:
Ruslan Bakiev
2026-02-18 09:37:48 +07:00
parent 513a394b93
commit a8db021597
17 changed files with 1872 additions and 23 deletions

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
import { onMounted } from "vue";
type TabId = "communications" | "documents";
type CalendarView = "day" | "week" | "month" | "year" | "agenda";
type SortMode = "name" | "lastContact";
@@ -493,26 +494,42 @@ const documents = ref<WorkspaceDocument[]>([
},
]);
const pilotMessages = ref([
{ id: "p1", role: "assistant", text: "I monitor calendar, contacts, and communications in one flow." },
{ id: "p2", role: "user", text: "What is critical to do today?" },
{ id: "p3", role: "assistant", text: "First Anna after demo, then Murat on legal owner." },
]);
type PilotMessage = {
id: string;
role: "user" | "assistant" | "system";
text: string;
plan?: string[] | null;
tools?: string[] | null;
createdAt?: string;
};
const pilotMessages = ref<PilotMessage[]>([]);
const pilotInput = ref("");
const pilotSending = ref(false);
function sendPilotMessage() {
const text = pilotInput.value.trim();
if (!text) return;
pilotMessages.value.push({ id: `p-${Date.now()}`, role: "user", text });
pilotMessages.value.push({
id: `p-${Date.now() + 1}`,
role: "assistant",
text: "Got it. Added to context and will use it in the next recommendations.",
});
pilotInput.value = "";
async function loadPilotMessages() {
const res = await $fetch<{ items: PilotMessage[] }>("/api/chat");
pilotMessages.value = res.items ?? [];
}
async function sendPilotMessage() {
const text = pilotInput.value.trim();
if (!text || pilotSending.value) return;
pilotSending.value = true;
try {
await $fetch("/api/chat", { method: "POST", body: { text } });
pilotInput.value = "";
await loadPilotMessages();
} finally {
pilotSending.value = false;
}
}
onMounted(() => {
loadPilotMessages();
});
const calendarView = ref<CalendarView>("month");
const calendarCursor = ref(new Date(new Date().getFullYear(), new Date().getMonth(), 1));
const selectedDateKey = ref(dayKey(new Date()));
@@ -1117,7 +1134,10 @@ function makeId(prefix: string) {
}
function pushPilotNote(text: string) {
pilotMessages.value.push({ id: makeId("p"), role: "assistant", text });
// Fire-and-forget: log assistant note to the same conversation.
$fetch("/api/chat/log", { method: "POST", body: { text } })
.then(loadPilotMessages)
.catch(() => {});
}
function openCommunicationThread(contact: string) {
@@ -1269,8 +1289,31 @@ function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected") {
class="chat"
:class="message.role === 'assistant' ? 'chat-start' : 'chat-end'"
>
<div class="chat-bubble text-sm" :class="message.role === 'assistant' ? 'chat-bubble-neutral' : ''">
{{ message.text }}
<div class="space-y-2">
<div class="chat-bubble text-sm" :class="message.role === 'assistant' ? 'chat-bubble-neutral' : ''">
{{ message.text }}
</div>
<details
v-if="message.role === 'assistant' && ((message.plan && message.plan.length) || (message.tools && message.tools.length))"
class="rounded-lg border border-base-300 bg-base-100 p-2 text-xs"
>
<summary class="cursor-pointer select-none font-semibold text-base-content/70">Plan & tools</summary>
<div class="mt-2 space-y-2">
<div v-if="message.plan && message.plan.length">
<div class="font-semibold text-base-content/70">Plan</div>
<ul class="list-disc pl-4">
<li v-for="(step, idx) in message.plan" :key="`plan-${message.id}-${idx}`">{{ step }}</li>
</ul>
</div>
<div v-if="message.tools && message.tools.length">
<div class="font-semibold text-base-content/70">Tools</div>
<ul class="list-disc pl-4">
<li v-for="(tool, idx) in message.tools" :key="`tools-${message.id}-${idx}`">{{ tool }}</li>
</ul>
</div>
</div>
</details>
</div>
</div>
</div>