fix(web): mobile automation canvas/inspector, compact activity row, timestamped comments
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user