diff --git a/apps/web/src/lib/tableColumns.ts b/apps/web/src/lib/tableColumns.ts
index 9f9e548..3374ccb 100644
--- a/apps/web/src/lib/tableColumns.ts
+++ b/apps/web/src/lib/tableColumns.ts
@@ -159,6 +159,15 @@ declare module 'vue' {
}
}
+/** برای جدولهای غیر `
` (مثلاً گرید div) که ستونهایشان را خودشان پنهان میکنند. */
+export function registerTableColumns(key: string, labels: string[]) {
+ ensureInit();
+ const prev = labelsByTable[key];
+ if (!prev || prev.length !== labels.length || prev.some((v, i) => v !== labels[i])) {
+ labelsByTable[key] = labels;
+ }
+}
+
export function useTableColumns(table: () => string) {
ensureInit();
const columns = () =>
diff --git a/apps/web/src/views/ActivitiesView.vue b/apps/web/src/views/ActivitiesView.vue
index df32371..04a53bb 100644
--- a/apps/web/src/views/ActivitiesView.vue
+++ b/apps/web/src/views/ActivitiesView.vue
@@ -45,6 +45,34 @@ import { brand } from '@mento/shared';
import { useAuthStore } from '@/stores/auth';
import { canViewAllRecords } from '@/lib/roles';
import { PAGE_SIZE_OPTIONS, usePageSize } from '@/lib/pageSize';
+import { registerTableColumns, useTableColumns } from '@/lib/tableColumns';
+import TableColumnsMenu from '@/components/TableColumnsMenu.vue';
+
+const ACT_TABLE_KEY = 'activities';
+const ACT_COLUMNS = [
+ { key: 'title', label: 'مشتری / عنوان فعالیت', width: 'minmax(0, 2.2fr)' },
+ { key: 'type', label: 'نوع فعالیت', width: '7.6rem' },
+ { key: 'when', label: 'زمان شروع', width: '7.2rem' },
+ { key: 'who', label: 'کارشناس', width: '8.4rem' },
+ { key: 'status', label: 'وضعیت', width: '8.6rem' },
+] as const;
+type ActColKey = (typeof ACT_COLUMNS)[number]['key'];
+registerTableColumns(
+ ACT_TABLE_KEY,
+ ACT_COLUMNS.map((c) => c.label),
+);
+const actCols = useTableColumns(() => ACT_TABLE_KEY);
+function colOn(key: ActColKey) {
+ const col = ACT_COLUMNS.find((c) => c.key === key)!;
+ return actCols.isVisible(col.label);
+}
+const actGridStyle = computed(() => ({
+ gridTemplateColumns: [
+ '2.4rem',
+ ...ACT_COLUMNS.filter((c) => actCols.isVisible(c.label)).map((c) => c.width),
+ '2.4rem',
+ ].join(' '),
+}));
type TypeFilter = 'all' | ActivityType;
type StatusFilter = 'all' | ActivityStatus;
@@ -698,19 +726,20 @@ onUnmounted(() => {
{{ filterLabel }} — {{ toFaDigits(total.toLocaleString('en-US')) }} فعالیت
-
-
-
+
-
+
#
- مشتری / عنوان فعالیت
- نوع فعالیت
- زمان شروع
- کارشناس
- وضعیت
+
+ {{ col.label }}
+
{
:key="item.id"
class="trow"
role="row"
+ :style="actGridStyle"
>
{{ toFaDigits((page - 1) * pageSize + idx + 1) }}
-
+
@@ -729,17 +759,17 @@ onUnmounted(() => {
{{ subtitle(item) }}
-
+
{{ typeLabel[item.type] }}
-
+
{{ clockText(item) }}
{{ dayText(item) }}
-
+
{{
item.assignees?.length
? item.assignees.map((a) => a.fullName).join('، ')
@@ -750,7 +780,7 @@ onUnmounted(() => {
{{ item.company?.name || item.person?.fullName }}
-
+
{{ statusLabel[uiStatus(item)] }}
@@ -1225,6 +1255,12 @@ h1 {
color: #0f766e;
}
+.list-head-tools {
+ display: flex;
+ align-items: center;
+ gap: 0.6rem;
+}
+
.table {
background: #fff;
border-radius: var(--radius);
diff --git a/apps/web/src/views/ActivityFormView.vue b/apps/web/src/views/ActivityFormView.vue
index 5334eff..19fb16c 100644
--- a/apps/web/src/views/ActivityFormView.vue
+++ b/apps/web/src/views/ActivityFormView.vue
@@ -128,6 +128,11 @@ function pickPerson(p: PersonDto) {
personOpen.value = false;
}
+function clearPerson() {
+ personId.value = '';
+ personOpen.value = false;
+}
+
function openNewPerson() {
personOpen.value = false;
newPersonOpen.value = true;
@@ -389,7 +394,6 @@ function validate() {
if (title.value.trim().length < 2) return 'عنوان فعالیت را بنویسید.';
if (!dueDate.value || !dueTime.value) return 'تاریخ و ساعت را مشخص کنید.';
if (!assigneeIds.value.length) return 'حداقل یک مسئول فعالیت را انتخاب کنید.';
- if (isNew.value && !personId.value) return 'شخص یا مشتری مرتبط را انتخاب کنید.';
if (needsNote.value && !description.value.trim()) return 'توضیح این فعالیت را بنویسید.';
if (reminderAt.value && !reminderNotifyApp.value && !reminderNotifySms.value) {
return 'برای یادآوری، اعلان یا پیامک را انتخاب کنید.';
@@ -644,7 +648,7 @@ watch([id, isNew], () => void load(), { immediate: true });
-
+