[ELMA3] Создание собственных событий в календаре
В статье приведен пример создания собственных событий в календаре для объекта типа Справочник IDelivery. Данный справочник служит для фиксирования заказов на доставку. Справочник IDelivery содержит следующие поля:
- Базовые поля (Наименование, Дата создания, Дата изменения, Автор создания, Автор изменения);
- Дата отправки (Дата/время);
- Планируемая дата доставки (Дата/время);
- Адрес доставки (Текст);
- Посылка доставлена (Да/нет);
- Исполнитель (Пользователь, тип связи - Одиночная);
- Информировать (Пользователь, тип связи – Многие-ко-многим).
При использовании данных свойств будет доступно следующее:
- отображение всего срока события (от Даты начала до Даты окончания события);
- отображение места события (в примере за место отвечает поле Адрес доставки);
- отображение завершения события (в примере используется поле Посылка доставлена, если значение будет Да, то в календаре событие будет зачеркнутым);
- возможность информировать несколько участников (поле Информировать).
Пример отображения данных
Рис. 1. Событие в календаре для объекта
Рис. 2. Завершенное событие и место события
Методы расширения (интерфейса) ICalendarItemProvider
Точка расширения (интерфейс) ICalendarItemProvider имеет следующие методы:
/// <summary> /// Уникальный идентификатор провайдера /// </summary> Guid Uid { get; } /// <summary> /// Список событий в календаре /// </summary> /// <param name="user">Пользователь</param> /// <param name="startDate">Дата начала</param> /// <param name="endDate">Дата окончания</param> /// <param name="checkPermission">Проверять привилегии?</param> /// <param name="showExpired">Отображать ли истекшие события</param> /// <returns>Коллекцию событий в календаре</returns> ICollection<ICalendarItem> GetItems(IUser user, DateTime startDate, DateTime endDate, bool checkPermission = true, bool showExpired = false); /// <summary> /// Список событий в календаре /// </summary> /// <param name="schedule">Календарь</param> /// <param name="startDate">Дата начала</param> /// <param name="endDate">Дата окончания</param> /// <param name="checkPermission">Проверять привилегии?</param> /// <param name="showExpired">Отображать ли истекшие события</param> /// <returns>Коллекцию событий в календаре</returns> ICollection<ICalendarItem> GetItems(ISchedule schedule, DateTime startDate, DateTime endDate, bool checkPermission = true, bool showExpired = false); /// <summary> /// Список событий в календаре /// </summary> /// <param name="schedules">Коллекция календарей</param> /// <param name="startDate">Дата начала</param> /// <param name="endDate">Дата окончания</param> /// <param name="checkPermission">Проверять привилегии?</param> /// <param name="showExpired">Отображать ли истекшие события</param> /// <returns>Коллекцию событий в календаре</returns> ICollection<ICalendarItem> GetItems(ICollection<ISchedule> schedules, DateTime startDate, DateTime endDate, bool checkPermission = true, bool showExpired = false); /// <summary> /// События которые можно запланировать несколько раз /// </summary> /// <param name="user">Пользователь</param> /// <returns>Коллекцию событий в календаре</returns> ICollection<ICalendarPlannedItem> GetRePlannedItems(IUser user); /// <summary> /// Не запланированные события /// </summary> /// <param name="user">Пользователь</param> /// <returns>Коллекцию событий в календаре</returns> ICollection<ICalendarPlannedItem> GetUnPlannedItems(IUser user); /// <summary> /// Получить пересекающиеся события сгруппированые по календарям /// </summary> /// <param name="schedules">Коллекция календарей</param> /// <param name="startDate">Дата начала</param> /// <param name="endDate">Дата окончания</param> /// <returns>События, сгруппированные по календарям</returns> IDictionary<ISchedule, ICollection<ICalendarItem>> CrossingItems(ICollection<ISchedule> schedules, DateTime startDate, DateTime endDate); /// <summary> /// Добавить событие в календарь /// </summary> /// <param name="user">Пользователь</param> /// <param name="id">CalendarPlannedItem.Id</param> /// <param name="startDate">Дата начала</param> /// <param name="endDate">Дата окончания</param> /// <returns>Событие календаря</returns> ICalendarItem AddItem(IUser user, string id, DateTime startDate, DateTime endDate, bool removeOther); /// <summary> /// Изменить время события событие в календарь /// </summary> /// <param name="id">ICalendarItem.Id</param> /// <param name="dayDelta">дельта смещения в днях</param> /// <param name="minuteDelta">дельта смещения в минутах</param> /// <param name="moved">смещено все событие</param> /// <returns>Событие календаря</returns> ICalendarItem ModifyTime(string id, int dayDelta, int minuteDelta, bool moved); /// <summary> /// Удалить событие /// </summary> /// <param name="id">ICalendarItem.Id</param> void Remove(string id); /// <summary> /// Календарь является внешним (события загружаются с внешних ресурсов) /// </summary> bool External { get; }
Пример класса точки расширения ICalendarItemProvider
[Component] public class CalendarItemProvider : ICalendarItemProvider { private readonly Guid _uid = new Guid("{03B3D20A-0807-4b20-B1FC-819833399602}"); private IDeliveryFilter GetFilter(ICollection<ISchedule> schedules, DateTime startDate, DateTime endDate) { return new InstanceOf<IDeliveryFilter> { New = { EndDate = new DateTimeRange { From = startDate, To = endDate } } }.New; } private IUser CurrentUser { get { return AuthenticationService.GetCurrentUser<IUser>(); } } public DeliveryManager DeliveryManager { get; set; } public ScheduleManager ScheduleManager { get; set; } public ISecurityService SecurityService { get; set; } public IEntityManager<ITaskTimePlan, long> TaskTimePlanManager { get; set; } public Guid Uid { get { return _uid; } } public ICollection<ICalendarItem> GetItems(IUser user, DateTime startDate, DateTime endDate, bool checkPermission = true, bool showExpired = false) { return GetItems(ScheduleManager.GetUserSchedule(user), startDate, endDate, checkPermission, showExpired); } public ICollection<ICalendarItem> GetItems(ISchedule schedule, DateTime startDate, DateTime endDate, bool checkPermission = true, bool showExpired = false) { return schedule.Owner != null ? GetItems(new List<ISchedule> { schedule }, startDate, endDate, checkPermission, showExpired) : new List<ICalendarItem>(); } public ICollection<ICalendarItem> GetItems(ICollection<ISchedule> schedules, DateTime startDate, DateTime endDate, bool checkPermission = true, bool showExpired = false) { if (schedules.All(s => s.Owner == null)) return new List<ICalendarItem>(); var filter = GetFilter(schedules, startDate, endDate); IList<ICalendarItem> ret = new List<ICalendarItem>(); if (checkPermission) { ret = DeliveryManager.Find(filter, FetchOptions.All).Select(t => new DeliveryCalendarItem(t)).Cast<ICalendarItem>().ToList(); } else { SecurityService.RunWithElevatedPrivilegies(() => ret = DeliveryManager.Find(filter, FetchOptions.All).Select(t => new DeliveryCalendarItem(t)).Cast<ICalendarItem>().ToList()); } return ret; } public ICollection<ICalendarPlannedItem> GetRePlannedItems(IUser user) { return new List<ICalendarPlannedItem>(); } public ICollection<ICalendarPlannedItem> GetUnPlannedItems(IUser user) { return new List<ICalendarPlannedItem>(); } public IDictionary<ISchedule, ICollection<ICalendarItem>> CrossingItems(ICollection<ISchedule> schedules, DateTime startDate, DateTime endDate) { if (schedules.All(s => s.Owner == null)) return new Dictionary<ISchedule, ICollection<ICalendarItem>>(); startDate = new DateTime(startDate.Ticks + 1000000000); //необходимо для того, чтобы события не пересекались, если время начала одного события = времени завершения другого endDate = new DateTime(endDate.Ticks - 1000000000); //необходимо для того, чтобы события не пересекались, если время начала одного события = времени завершения другого var filter = GetFilter(schedules, startDate, endDate); var list = new List<IDelivery>(); SecurityService.RunWithElevatedPrivilegies(() => list = DeliveryManager.Find(filter, FetchOptions.All).ToList()); var ret = schedules.ToDictionary<ISchedule, ISchedule, ICollection<ICalendarItem>>(schedule => schedule, schedule => list.Where(e => e.Executor == schedule.Owner) .Select(e => new DeliveryCalendarItem(e) { OnlyInfo = !SecurityService.CanCheckPermission(PermissionProvider.ViewTaskPermission, e) || (SecurityService.CanCheckPermission(PermissionProvider.ViewTaskPermission, e) && !SecurityService.HasPermission(PermissionProvider.ViewTaskPermission, e)) }) .Cast<ICalendarItem>() .ToList() ); return ret.Where(s => s.Value.Any()).ToDictionary(s => s.Key, s => s.Value); } public ICalendarItem AddItem(IUser user, string id, DateTime startDate, DateTime endDate, bool removeOther) { return null; } public ICalendarItem ModifyTime(string id, int dayDelta, int minuteDelta, bool moved) { return null; } public void Remove(string id) { } public bool External { get { return false; } } }
Методы расширения (интерфейса) ICalendarItem
/// <summary> /// Идентификатор обьекта /// </summary> string Id { get; } /// <summary> /// Идентификатор исходного обьекта /// </summary> string SourceId { get; } /// <summary> /// Тип исходного объекта /// </summary> Guid SourceTypeUid { get; } /// <summary> /// Дата начала /// </summary> DateTime StartDate { get; set; } /// <summary> /// Дата окончания /// </summary> DateTime EndDate { get; set; } /// <summary> /// Завершено ли событие /// </summary> bool Completed { get; set; } /// <summary> /// Выделять просроченные события /// </summary> bool MarkExpired { get; } /// <summary> /// Определяет есть ли текущий пользователь в информируемых событиях /// </summary> bool ToInform { get; } /// <summary> /// Тема события /// </summary> string Theme { get; set; } /// <summary> /// Место события /// </summary> string Place { get; set; } /// <summary> /// Кому /// </summary> string To { get; set; } /// <summary> /// Участники события /// </summary> IDictionary<string, string> EventUsers { get; set; } /// <summary> /// Описание события /// </summary> string Description { get; set; } /// <summary> /// Флаг означает можно ли копировать событие, перетаскиванием в календаре /// </summary> bool HasCopy { get; set; } /// <summary> /// Клонировать событие /// </summary> /// <returns></returns> ICalendarItem Clone(); /// <summary> /// Флаг означает что пользователь не имеет доступа к обьекту события и данные только для информации /// </summary> bool OnlyInfo { get; set; } /// <summary> /// Ид автора /// </summary> long CreationAuthor { get; set; } /// <summary> /// Событие только для показа /// </summary> bool ReadOnly { get; set; } /// <summary> /// Возвращает список комментариев /// </summary> /// <returns></returns> ICollection<EleWise.ELMA.Common.Models.IComment> Comments { get; } /// <summary> /// Конфиденциален ли элемент календаря /// </summary> bool PrivateAccess { get; }
Пример класса точки расширения ICalendarItem
[Serializable] public class DeliveryCalendarItem : ICalendarItem { [ScriptIgnore] public readonly IDelivery Delivery; public DeliveryCalendarItem(IDelivery delivery, IUser currentUser = null) { if (delivery == null) throw new ArgumentNullException("delivery"); Delivery = delivery; StartDate = delivery.StartDate; EndDate = delivery.EndDate; Completed = delivery.IsComplete == true; Theme = delivery.Name; Place = delivery != null ? delivery.Adress : ""; Description = ""; HasCopy = true; OnlyInfo = false; CreationAuthor = delivery.CreationAuthor.Id; ReadOnly = false; var users = new List<IUser> { delivery.Executor }; if (delivery.InformTo.Any()) users.AddRange(delivery.InformTo); EventUsers = users.Distinct((a, b) => a.Id == b.Id, c => c.Id.GetHashCode()).ToDictionary(u => u.Id.ToString(), u => u.GetShortName()); } public string Id { get { return Delivery.Id.ToString(); } } public string SourceId { get { return Delivery.Id.ToString(); } } public Guid SourceTypeUid { get { return InterfaceActivator.UID<IDelivery>(); } } public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } public DateTime? LimitStartDate { get; set; } public DateTime? LimitEndDate { get; set; } public CalendarEventPeriod Period { get; set; } public bool Completed { get; set; } public bool MarkExpired { get { return false; } } public bool ToInform { get; private set; } public string Theme { get; set; } public string Place { get; set; } public string To { get; set; } public IDictionary<string, string> EventUsers { get; set; } public string Description { get; set; } public bool Periodical { get; private set; } public ICalendarItem Template { get; set; } public bool HasCopy { get; set; } public bool OnlyInfo { get; set; } public long CreationAuthor { get; set; } public bool ReadOnly { get; set; } public ICalendarItem Clone() { return new DeliveryCalendarItem(Delivery); } public ICollection<EleWise.ELMA.Common.Models.IComment> Comments { get { return null; } } public bool PrivateAccess { get { return false; } } }
При использовании данного примера для реализации Ваших собственных событий в календаре – события будут без иконок и без ссылок. Чтобы записи в календаре имели ссылки на объекты и иконки, необходимо реализовать следующие точки расширения: IObjectIcon и IObjectLink. Данные точки расширения необходимо реализовать для объекта DeliveryCalendarItem (реализованного в данном примере).