mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-14 12:25:17 +00:00
Schedule year view (#2145)
Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
parent
4f8b4706e9
commit
a74ae0ee89
@ -33,6 +33,7 @@
|
||||
"@anticrm/platform": "~0.6.6",
|
||||
"svelte": "^3.47",
|
||||
"@anticrm/calendar": "~0.6.0",
|
||||
"@anticrm/calendar-resources": "~0.6.0",
|
||||
"@anticrm/hr": "~0.6.0",
|
||||
"@anticrm/ui": "~0.6.0",
|
||||
"@anticrm/presentation": "~0.6.2",
|
||||
|
@ -46,7 +46,7 @@
|
||||
}
|
||||
})
|
||||
|
||||
$: value = new Date(date).getTime()
|
||||
let value = new Date(date).getTime()
|
||||
$: dueDate = new Date(value).setDate(new Date(value).getDate() + 1)
|
||||
|
||||
export function canClose (): boolean {
|
||||
@ -72,6 +72,10 @@
|
||||
|
||||
function typeSelected (_id: Ref<RequestType>): void {
|
||||
type = types.find((p) => p._id === _id)
|
||||
dueDate =
|
||||
Math.abs(type?.value ?? 0 % 1) === 0.5
|
||||
? new Date(value).setHours(12)
|
||||
: new Date(value).setDate(new Date(value).getDate() + 1)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -18,16 +18,15 @@
|
||||
import { Table } from '@anticrm/view-resources'
|
||||
|
||||
export let date: Date
|
||||
export let endDate: number
|
||||
export let employee: Ref<Staff>
|
||||
|
||||
$: endDate = new Date(date).setDate(date.getDate() + 1)
|
||||
</script>
|
||||
|
||||
<Table
|
||||
_class={hr.class.Request}
|
||||
query={{
|
||||
attachedTo: employee,
|
||||
dueDate: { $gte: date.getTime() },
|
||||
dueDate: { $gt: date.getTime() },
|
||||
date: { $lt: endDate }
|
||||
}}
|
||||
config={['$lookup.type.label', 'date', 'dueDate']}
|
||||
|
@ -13,13 +13,14 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import calendar from '@anticrm/calendar'
|
||||
import calendar from '@anticrm/calendar-resources/src/plugin'
|
||||
import { CalendarMode } from '@anticrm/calendar-resources'
|
||||
import { Ref } from '@anticrm/core'
|
||||
import { Department } from '@anticrm/hr'
|
||||
import { createQuery, SpaceSelector } from '@anticrm/presentation'
|
||||
import { Button, Icon, IconBack, IconForward, Label } from '@anticrm/ui'
|
||||
import hr from '../plugin'
|
||||
import ScheduleView from './ScheduleView.svelte'
|
||||
import ScheduleMonthView from './ScheduleView.svelte'
|
||||
|
||||
let department = hr.ids.Head
|
||||
let currentDate: Date = new Date()
|
||||
@ -29,6 +30,8 @@
|
||||
let descendants: Map<Ref<Department>, Department[]> = new Map<Ref<Department>, Department[]>()
|
||||
let departments: Map<Ref<Department>, Department> = new Map<Ref<Department>, Department>()
|
||||
|
||||
let mode: CalendarMode = CalendarMode.Month
|
||||
|
||||
query.query(hr.class.Department, {}, (res) => {
|
||||
departments.clear()
|
||||
descendants.clear()
|
||||
@ -43,7 +46,16 @@
|
||||
})
|
||||
|
||||
function inc (val: number): void {
|
||||
currentDate.setMonth(currentDate.getMonth() + val)
|
||||
switch (mode) {
|
||||
case CalendarMode.Month: {
|
||||
currentDate.setMonth(currentDate.getMonth() + val)
|
||||
break
|
||||
}
|
||||
case CalendarMode.Year: {
|
||||
currentDate.setFullYear(currentDate.getFullYear() + val)
|
||||
break
|
||||
}
|
||||
}
|
||||
currentDate = currentDate
|
||||
}
|
||||
|
||||
@ -58,31 +70,49 @@
|
||||
<div class="ac-header__wrap-title">
|
||||
<div class="ac-header__icon"><Icon icon={calendar.icon.Calendar} size={'small'} /></div>
|
||||
<span class="ac-header__title"><Label label={hr.string.Schedule} /></span>
|
||||
<div class="flex ml-4 gap-2">
|
||||
<div class="flex gap-2 ml-6">
|
||||
<Button
|
||||
icon={IconBack}
|
||||
size={'small'}
|
||||
label={calendar.string.ModeMonth}
|
||||
on:click={() => {
|
||||
inc(-1)
|
||||
mode = CalendarMode.Month
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
size={'small'}
|
||||
label={hr.string.Today}
|
||||
label={calendar.string.ModeYear}
|
||||
on:click={() => {
|
||||
currentDate = new Date()
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
icon={IconForward}
|
||||
size={'small'}
|
||||
on:click={() => {
|
||||
inc(1)
|
||||
mode = CalendarMode.Year
|
||||
}}
|
||||
/>
|
||||
<div class="flex ml-4 gap-2">
|
||||
<Button
|
||||
icon={IconBack}
|
||||
size={'small'}
|
||||
on:click={() => {
|
||||
inc(-1)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
size={'small'}
|
||||
label={calendar.string.Today}
|
||||
on:click={() => {
|
||||
currentDate = new Date()
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
icon={IconForward}
|
||||
size={'small'}
|
||||
on:click={() => {
|
||||
inc(1)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fs-title ml-4 flex-row-center">
|
||||
{getMonthName(currentDate)}
|
||||
{#if mode === CalendarMode.Month}
|
||||
{getMonthName(currentDate)}
|
||||
{/if}
|
||||
{currentDate.getFullYear()}
|
||||
</div>
|
||||
</div>
|
||||
@ -90,5 +120,5 @@
|
||||
</div>
|
||||
|
||||
<div class="mr-6 h-full">
|
||||
<ScheduleView {department} {descendants} departmentById={departments} {currentDate} />
|
||||
<ScheduleMonthView {department} {descendants} departmentById={departments} {currentDate} {mode} />
|
||||
</div>
|
||||
|
@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { getCurrentAccount, Ref, Timestamp } from '@anticrm/core'
|
||||
import type { Department, Request, Staff } from '@anticrm/hr'
|
||||
import type { Department, Request, RequestType, Staff } from '@anticrm/hr'
|
||||
import { createQuery } from '@anticrm/presentation'
|
||||
import {
|
||||
Label,
|
||||
@ -30,6 +30,7 @@
|
||||
LabelAndProps
|
||||
} from '@anticrm/ui'
|
||||
import { EmployeePresenter } from '@anticrm/contact-resources'
|
||||
import { CalendarMode } from '@anticrm/calendar-resources'
|
||||
import contact from '@anticrm/contact-resources/src/plugin'
|
||||
import hr from '../plugin'
|
||||
import { Employee, EmployeeAccount } from '@anticrm/contact'
|
||||
@ -41,14 +42,30 @@
|
||||
export let descendants: Map<Ref<Department>, Department[]>
|
||||
export let departmentById: Map<Ref<Department>, Department>
|
||||
export let currentDate: Date = new Date()
|
||||
export let mode: CalendarMode
|
||||
|
||||
$: startDate = new Date(new Date(currentDate).setDate(1)).setHours(0, 0, 0, 0)
|
||||
$: endDate = new Date(startDate).setMonth(new Date(startDate).getMonth() + 1)
|
||||
$: startDate = new Date(
|
||||
new Date(mode === CalendarMode.Year ? new Date(currentDate).setMonth(1) : currentDate).setDate(1)
|
||||
).setHours(0, 0, 0, 0)
|
||||
$: endDate =
|
||||
mode === CalendarMode.Year
|
||||
? new Date(startDate).setFullYear(new Date(startDate).getFullYear() + 1)
|
||||
: new Date(startDate).setMonth(new Date(startDate).getMonth() + 1)
|
||||
$: departments = [department, ...getDescendants(department, descendants)]
|
||||
|
||||
const lq = createQuery()
|
||||
const typeQuery = createQuery()
|
||||
const staffQuery = createQuery()
|
||||
let staff: Staff[] = []
|
||||
let types: Map<Ref<RequestType>, RequestType> = new Map<Ref<RequestType>, RequestType>()
|
||||
|
||||
typeQuery.query(hr.class.RequestType, {}, (res) => {
|
||||
types = new Map(
|
||||
res.map((type) => {
|
||||
return [type._id, type]
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
staffQuery.query(hr.mixin.Staff, {}, (res) => {
|
||||
staff = res
|
||||
@ -96,7 +113,7 @@
|
||||
if (requests === undefined) return []
|
||||
const res: Request[] = []
|
||||
const time = date.getTime()
|
||||
const endTime = new Date(date).setDate(date.getDate() + 1)
|
||||
const endTime = getEndDate(date)
|
||||
for (const request of requests) {
|
||||
if (request.date < endTime && request.dueDate > time) {
|
||||
res.push(request)
|
||||
@ -134,16 +151,45 @@
|
||||
return lead === currentEmployee
|
||||
}
|
||||
|
||||
function getEndDate (date: Date): number {
|
||||
return mode === CalendarMode.Year
|
||||
? new Date(date).setMonth(date.getMonth() + 1)
|
||||
: new Date(date).setDate(date.getDate() + 1)
|
||||
}
|
||||
|
||||
function getTooltip (employee: Staff, date: Date): LabelAndProps | undefined {
|
||||
const requests = getRequests(employee._id, date)
|
||||
if (requests.length === 0) return
|
||||
const endDate = getEndDate(date)
|
||||
return {
|
||||
component: RequestsPopup,
|
||||
props: { date, employee: employee._id }
|
||||
props: { date, endDate, employee: employee._id }
|
||||
}
|
||||
}
|
||||
|
||||
$: departmentStaff = staff.filter((p) => departments.includes(p.department) || employeeRequests.has(p._id))
|
||||
|
||||
$: values = [...Array(mode === CalendarMode.Year ? 12 : daysInMonth(currentDate)).keys()]
|
||||
|
||||
function getMonthName (date: Date): string {
|
||||
return new Intl.DateTimeFormat('default', { month: 'long' }).format(date)
|
||||
}
|
||||
function getMonth (date: Date, m: number): Date {
|
||||
date = new Date(date)
|
||||
date.setDate(1)
|
||||
date.setMonth(m)
|
||||
return date
|
||||
}
|
||||
|
||||
function getTotal (requests: Request[]): number {
|
||||
let total = 0
|
||||
for (const request of requests) {
|
||||
const type = types.get(request.type)
|
||||
const days = (request.dueDate - request.date) / 1000 / 60 / 60 / 24
|
||||
total += Math.ceil(days) * (type?.value ?? 0)
|
||||
}
|
||||
return total
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if departmentStaff.length}
|
||||
@ -154,14 +200,27 @@
|
||||
<th>
|
||||
<Label label={contact.string.Employee} />
|
||||
</th>
|
||||
{#each [...Array(daysInMonth(currentDate)).keys()] as dayOfMonth}
|
||||
{@const day = getDay(new Date(startDate), dayOfMonth)}
|
||||
<th class:today={areDatesEqual(todayDate, day)} class:weekend={isWeekend(day)}>
|
||||
<div class="cursor-pointer uppercase flex-col-center">
|
||||
<div class="flex-center">{getWeekDayName(day, 'short')}</div>
|
||||
<div class="flex-center">{day.getDate()}</div>
|
||||
</div>
|
||||
</th>
|
||||
{#each values as value}
|
||||
{#if mode === CalendarMode.Year}
|
||||
{@const month = getMonth(currentDate, value)}
|
||||
<th
|
||||
class="fixed"
|
||||
class:today={month.getFullYear() === todayDate.getFullYear() &&
|
||||
month.getMonth() === todayDate.getMonth()}
|
||||
>
|
||||
<div class="cursor-pointer uppercase flex-col-center">
|
||||
<div class="flex-center">{getMonthName(month)}</div>
|
||||
</div>
|
||||
</th>
|
||||
{:else}
|
||||
{@const day = getDay(new Date(startDate), value)}
|
||||
<th class:today={areDatesEqual(todayDate, day)} class:weekend={isWeekend(day)}>
|
||||
<div class="cursor-pointer uppercase flex-col-center">
|
||||
<div class="flex-center">{getWeekDayName(day, 'short')}</div>
|
||||
<div class="flex-center">{day.getDate()}</div>
|
||||
</div>
|
||||
</th>
|
||||
{/if}
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
@ -171,21 +230,36 @@
|
||||
<td>
|
||||
<EmployeePresenter value={employee} />
|
||||
</td>
|
||||
{#each [...Array(daysInMonth(currentDate)).keys()] as dayOfMonth}
|
||||
{@const date = getDay(new Date(startDate), dayOfMonth)}
|
||||
{@const requests = getRequests(employee._id, date)}
|
||||
{@const editable = isEditable(employee)}
|
||||
<td
|
||||
class:today={areDatesEqual(todayDate, date)}
|
||||
class:weekend={isWeekend(date)}
|
||||
class:cursor-pointer={editable}
|
||||
use:tooltip={getTooltip(employee, date)}
|
||||
on:click={(e) => createRequest(e, date, employee)}
|
||||
>
|
||||
{#if requests.length}
|
||||
<ScheduleRequests {requests} {date} {editable} />
|
||||
{/if}
|
||||
</td>
|
||||
{#each values as value}
|
||||
{#if mode === CalendarMode.Year}
|
||||
{@const month = getMonth(currentDate, value)}
|
||||
{@const requests = getRequests(employee._id, month)}
|
||||
<td
|
||||
class:today={month.getFullYear() === todayDate.getFullYear() &&
|
||||
month.getMonth() === todayDate.getMonth()}
|
||||
class="fixed"
|
||||
use:tooltip={getTooltip(employee, month)}
|
||||
>
|
||||
<div class="flex-center">
|
||||
{getTotal(requests)}
|
||||
</div>
|
||||
</td>
|
||||
{:else}
|
||||
{@const date = getDay(new Date(startDate), value)}
|
||||
{@const requests = getRequests(employee._id, date)}
|
||||
{@const editable = isEditable(employee)}
|
||||
<td
|
||||
class:today={areDatesEqual(todayDate, date)}
|
||||
class:weekend={isWeekend(date)}
|
||||
class:cursor-pointer={editable}
|
||||
use:tooltip={getTooltip(employee, date)}
|
||||
on:click={(e) => createRequest(e, date, employee)}
|
||||
>
|
||||
{#if requests.length}
|
||||
<ScheduleRequests {requests} {date} {editable} />
|
||||
{/if}
|
||||
</td>
|
||||
{/if}
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
@ -209,6 +283,9 @@
|
||||
th {
|
||||
width: auto;
|
||||
min-width: 1rem;
|
||||
&.fixed {
|
||||
width: 5rem;
|
||||
}
|
||||
&:first-child {
|
||||
width: 15rem;
|
||||
padding: 0.5rem;
|
||||
|
Loading…
Reference in New Issue
Block a user