fix(web): mobile automation canvas/inspector, compact activity row, timestamped comments

This commit is contained in:
2026-10-11 16:48:37 +03:30
parent 17638786a8
commit f4398cdb3e
5 changed files with 116 additions and 5 deletions
@@ -55,6 +55,12 @@ const dueLabel = computed(() => {
return `${formatJalaliDay(d)} ${clock}`; return `${formatJalaliDay(d)} ${clock}`;
}); });
const now = ref(new Date());
let clockTimer: ReturnType<typeof setInterval> | undefined;
const nowLabel = computed(
() => `${formatJalaliDay(now.value)} ساعت ${formatClockFa(now.value)}`,
);
const canSubmit = computed( const canSubmit = computed(
() => comment.value.trim().length > 0 && !props.saving && !voiceBusy.value, () => comment.value.trim().length > 0 && !props.saving && !voiceBusy.value,
); );
@@ -115,6 +121,9 @@ function onKeydown(ev: KeyboardEvent) {
onMounted(async () => { onMounted(async () => {
document.body.style.overflow = 'hidden'; document.body.style.overflow = 'hidden';
window.addEventListener('keydown', onKeydown); window.addEventListener('keydown', onKeydown);
clockTimer = setInterval(() => {
now.value = new Date();
}, 30_000);
await nextTick(); await nextTick();
textareaRef.value?.focus(); textareaRef.value?.focus();
try { try {
@@ -143,6 +152,7 @@ onMounted(async () => {
onBeforeUnmount(() => { onBeforeUnmount(() => {
document.body.style.overflow = ''; document.body.style.overflow = '';
window.removeEventListener('keydown', onKeydown); window.removeEventListener('keydown', onKeydown);
clearInterval(clockTimer);
}); });
</script> </script>
@@ -182,11 +192,15 @@ onBeforeUnmount(() => {
{{ activity.assignee?.fullName || 'بدون مسئول' }} {{ activity.assignee?.fullName || 'بدون مسئول' }}
</span> </span>
<i /> <i />
<span> <span title="موعد فعالیت">
<UiIcon name="calendar" :size="14" /> <UiIcon name="calendar" :size="14" />
{{ dueLabel }} موعد: {{ dueLabel }}
</span> </span>
</div> </div>
<p class="stamp">
<UiIcon name="clock" :size="14" />
زمان ثبت نظر: {{ nowLabel }}
</p>
</div> </div>
<span class="type" :class="activity.type"> <span class="type" :class="activity.type">
<UiIcon :name="typeIcon[activity.type]" :size="22" /> <UiIcon :name="typeIcon[activity.type]" :size="22" />
@@ -396,6 +410,16 @@ onBeforeUnmount(() => {
border-top: 1px solid #f1f5f9; border-top: 1px solid #f1f5f9;
} }
.stamp {
display: flex;
align-items: center;
gap: 0.3rem;
margin: 0.55rem 0 0;
color: #0f766e;
font-size: 0.8rem;
font-weight: 600;
}
.meta i { .meta i {
width: 1px; width: 1px;
height: 14px; height: 14px;
@@ -674,9 +674,80 @@ strong {
font-size: 0.78rem; font-size: 0.78rem;
} }
/* موبایل: چیدمان عمودی؛ هر شاخه یک کارت زیر کارت قبلی */
@media (max-width: 700px) { @media (max-width: 700px) {
.canvas {
min-height: 0;
padding: 1rem 0.75rem;
}
.flow,
.flow:has(.branches) {
flex-direction: column;
align-items: center;
min-width: 0;
min-height: 0;
padding-bottom: 0;
}
.node.trigger { .node.trigger {
width: 13rem; width: min(100%, 15rem);
}
.wire,
.wire.stub {
width: 2px;
height: 2.1rem;
}
.wire::after {
inset-inline-end: auto;
top: auto;
bottom: -1px;
left: 50%;
transform: translateX(-50%);
border-block: 0;
border-inline: 5px solid transparent;
border-top: 7px solid #cbd5e1;
}
.wire.end {
width: 2px;
height: 2.4rem;
background: repeating-linear-gradient(180deg, #cbd5e1 0 6px, transparent 6px 10px);
}
.branches {
align-items: stretch;
width: 100%;
gap: 0.75rem;
}
.branch {
flex-direction: column;
align-items: center;
padding: 1.9rem 0.5rem 0.5rem;
border: 1px dashed #fed7aa;
border-radius: var(--radius);
background: rgba(255, 255, 255, 0.55);
}
.branch::before {
display: none;
}
.branch-tag {
top: 0.45rem;
inset-inline-start: 0.6rem;
}
.add-branch {
position: static;
align-self: center;
}
.picker {
max-width: none;
} }
} }
</style> </style>
@@ -506,6 +506,7 @@ watch(
<style scoped> <style scoped>
.inspector { .inspector {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr);
align-content: start; align-content: start;
gap: 0.75rem; gap: 0.75rem;
padding: 1rem; padding: 1rem;
@@ -534,6 +535,7 @@ label,
gap: 0.35rem; gap: 0.35rem;
font-size: 0.84rem; font-size: 0.84rem;
color: #64748b; color: #64748b;
min-width: 0;
} }
.field-label { .field-label {
@@ -550,6 +552,9 @@ textarea {
font: inherit; font: inherit;
color: #0f172a; color: #0f172a;
background: #fff; background: #fff;
min-width: 0;
max-width: 100%;
text-overflow: ellipsis;
} }
.channels { .channels {
+6 -1
View File
@@ -345,7 +345,9 @@ function dateText(item: ActivityDto) {
} }
function subtitle(item: ActivityDto) { function subtitle(item: ActivityDto) {
return item.deal?.title || item.description || ''; const linked = item.deal?.title || item.lead?.title || item.person?.fullName;
if (linked) return linked;
return (item.description ?? '').split('\n')[0].trim();
} }
async function loadStages() { async function loadStages() {
@@ -1665,6 +1667,9 @@ h1 {
.sub { .sub {
margin: 0.2rem 0 0; margin: 0.2rem 0 0;
font-size: 0.8rem; font-size: 0.8rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
.type-cell { .type-cell {
+7 -1
View File
@@ -6,6 +6,7 @@ import {
calendarDaysBetween, calendarDaysBetween,
formatClockFa, formatClockFa,
formatJalaliDay, formatJalaliDay,
formatJalaliNumeric,
} from '@/lib/jalali'; } from '@/lib/jalali';
import UiIcon from '@/components/UiIcon.vue'; import UiIcon from '@/components/UiIcon.vue';
import UserAvatar from '@/components/UserAvatar.vue'; import UserAvatar from '@/components/UserAvatar.vue';
@@ -222,7 +223,11 @@ async function submitComment(text: string) {
error.value = ''; error.value = '';
try { try {
const prev = activity.value.description?.trim(); const prev = activity.value.description?.trim();
const next = prev ? `${prev}\n${body}` : body; const now = new Date();
const author = auth.user?.fullName?.trim();
const stamp = `[${formatJalaliNumeric(now)} ساعت ${formatClockFa(now)}${author ? ` — ${author}` : ''}]`;
const entry = `${stamp}\n${body}`;
const next = prev ? `${prev}\n\n${entry}` : entry;
await api.patch(`/activities/${id.value}`, { description: next }); await api.patch(`/activities/${id.value}`, { description: next });
commentOpen.value = false; commentOpen.value = false;
await load(); await load();
@@ -787,6 +792,7 @@ dd {
color: #334155; color: #334155;
line-height: 1.9; line-height: 1.9;
font-size: 0.9rem; font-size: 0.9rem;
white-space: pre-line;
} }
.note p.empty { .note p.empty {