diff --git a/header_search_panel/static/src/search/header_search/components/fields_filter/date_filter/date_filter.js b/header_search_panel/static/src/search/header_search/components/fields_filter/date_filter/date_filter.js index d27ef8ff0..5d5eba74b 100644 --- a/header_search_panel/static/src/search/header_search/components/fields_filter/date_filter/date_filter.js +++ b/header_search_panel/static/src/search/header_search/components/fields_filter/date_filter/date_filter.js @@ -2,7 +2,7 @@ import { Component } from "@odoo/owl"; import { DateTimeInput } from "@web/core/datetime/datetime_input"; -import { deserializeDate } from "@web/core/l10n/dates"; +import { serializeDateTime, serializeDate, deserializeDate, deserializeDateTime } from "@web/core/l10n/dates"; import { standardFieldFilterProps } from "../standard_field_filter_props.js" export class DateFilter extends Component { @@ -14,17 +14,23 @@ export class DateFilter extends Component { this.endDate = this.env.searchModel.headerSearchInfo.FieldsFilter[this.props.id]?.endDate; } + get dateFieldType() { + return this.props.type; + } + get dateFrom() { - return this.startDate ? deserializeDate(this.startDate): undefined; + const dateValue = this.startDate; + return dateValue ? (this.dateFieldType === "datetime" ? deserializeDateTime(dateValue) : deserializeDate(dateValue)) : undefined; } get dateTo() { - return this.endDate ? deserializeDate(this.endDate): undefined; + const dateValue = this.endDate; + return dateValue ? (this.dateFieldType === "datetime" ? deserializeDateTime(dateValue) : deserializeDate(dateValue)) : undefined; } // 设置筛选字段的值 setActiveValues(dateValue, type) { - const value = dateValue ? (this.props.type === "datetime" ? dateValue.toFormat("yyyy-MM-dd HH:mm:ss") : dateValue.toFormat("yyyy-MM-dd")) : undefined; + const value = dateValue ? (this.dateFieldType === "datetime" ? serializeDateTime(dateValue) : serializeDate(dateValue)) : undefined; if (type === "startDate") { this.startDate = value } @@ -61,13 +67,78 @@ export class DateFilter extends Component { this.props.fieldOnchange({fieldDomainList: this.domain, startDate: this.startDate, endDate: this.endDate}); } - setDateRange(months) { - const today = new Date(); - const startDate = new Date(); - startDate.setMonth(startDate.getMonth() - months); - this.startDate = startDate.toISOString().split('T')[0]; - this.endDate = today.toISOString().split('T')[0]; - this.props.fieldOnchange({fieldDomainList: this.domain, startDate: this.startDate, endDate: this.endDate}); + setDateRange(direction) { + // 只允许 next 或 previous + if (!["next", "previous"].includes(direction)) { + return; + } + // 月份偏移量 + const monthOffset = direction === "next" ? 1 : -1; + // 当前时间(作为默认基准) + const now = luxon.DateTime.now(); + // 反序列化开始时间 + const start = this.startDate + ? (this.dateFieldType === "datetime" + ? deserializeDateTime(this.startDate) + : deserializeDate(this.startDate)) + : null; + // 反序列化结束时间 + const end = this.endDate + ? (this.dateFieldType === "datetime" + ? deserializeDateTime(this.endDate) + : deserializeDate(this.endDate)) + : null; + // 情况一:开始和结束时间都不存在,默认使用当前月 + if (!start && !end) { + const base = now.plus({ months: monthOffset }); + + // 当月开始 + const monthStart = base.startOf("month"); + // 当月结束 + const monthEnd = base.endOf("month"); + + this.startDate = this.dateFieldType === "datetime" + ? serializeDateTime(monthStart) + : serializeDate(monthStart); + + this.endDate = this.dateFieldType === "datetime" + ? serializeDateTime(monthEnd) + : serializeDate(monthEnd); + } + // 情况二:只存在开始时间 + else if (start && !end) { + const newStart = start.plus({ months: monthOffset }); + + this.startDate = this.dateFieldType === "datetime" + ? serializeDateTime(newStart) + : serializeDate(newStart); + } + // 情况三:只存在结束时间 + else if (!start && end) { + const newEnd = end.plus({ months: monthOffset }); + + this.endDate = this.dateFieldType === "datetime" + ? serializeDateTime(newEnd) + : serializeDate(newEnd); + } + // 情况四:开始和结束时间都存在 + else { + const newStart = start.plus({ months: monthOffset }); + const newEnd = end.plus({ months: monthOffset }); + this.startDate = this.dateFieldType === "datetime" + ? serializeDateTime(newStart) + : serializeDate(newStart); + + this.endDate = this.dateFieldType === "datetime" + ? serializeDateTime(newEnd) + : serializeDate(newEnd); + } + // 触发筛选条件更新 + this.props.fieldOnchange({ + fieldDomainList: this.domain, + startDate: this.startDate, + endDate: this.endDate, + }); } // 点击清空筛选时触发 diff --git a/header_search_panel/static/src/search/header_search/components/fields_filter/date_filter/date_filter.xml b/header_search_panel/static/src/search/header_search/components/fields_filter/date_filter/date_filter.xml index bf86c13a4..e3592cd38 100644 --- a/header_search_panel/static/src/search/header_search/components/fields_filter/date_filter/date_filter.xml +++ b/header_search_panel/static/src/search/header_search/components/fields_filter/date_filter/date_filter.xml @@ -5,6 +5,9 @@
+ @@ -12,26 +15,10 @@ - - - - - - - - - - - - +
- - - - - - -
diff --git a/header_search_panel/static/src/search/header_search/components/select_date_filter/select_date_filter.js b/header_search_panel/static/src/search/header_search/components/select_date_filter/select_date_filter.js index af3f645eb..85ada18d1 100644 --- a/header_search_panel/static/src/search/header_search/components/select_date_filter/select_date_filter.js +++ b/header_search_panel/static/src/search/header_search/components/select_date_filter/select_date_filter.js @@ -1,19 +1,17 @@ /** @odoo-module **/ - -import { Component } from "@odoo/owl"; -import { Domain } from "@web/core/domain"; -import {DateFilter} from "../fields_filter/date_filter/date_filter"; +import { Component, useState } from "@odoo/owl"; +import { DateTimeInput } from "@web/core/datetime/datetime_input"; +import { serializeDateTime, serializeDate, deserializeDate, deserializeDateTime } from "@web/core/l10n/dates"; // 选择日期筛选,用于自己选择不同时间字段进行筛选 export class SelectDateFilter extends Component { setup() { super.setup(); - // 默认选择第一个时间字段 - this.dateField = this.props.dateFields[0]; - // 开始时间 - this.startDate = undefined; - // 结束时间 - this.endDate = undefined; + this.state = useState({ + dateField: this.env.searchModel.headerSearchInfo?.DateFilter?.fieldName || this.props.dateFields[0], + startDate: this.env.searchModel.headerSearchInfo?.DateFilter?.startDate, + endDate: this.env.searchModel.headerSearchInfo?.DateFilter?.endDate, + }) } get dateFields() { @@ -25,11 +23,29 @@ export class SelectDateFilter extends Component { }); } + get dateFieldType() { + return this.env.searchModel.searchViewFields[this.state.dateField].type; + } + + get dateFrom() { + const dateValue = this.state.startDate; + return dateValue ? (this.dateFieldType === "datetime" ? deserializeDateTime(dateValue) : deserializeDate(dateValue)) : undefined; + } + + get dateTo() { + const dateValue = this.state.endDate; + return dateValue ? (this.dateFieldType === "datetime" ? deserializeDateTime(dateValue) : deserializeDate(dateValue)) : undefined; + } + // 设置筛选字段的值 - setActiveValues(ev) { - const value = ev.target.value; - if (ev.target.id === "select_start_date") { this.startDate = value} - if (ev.target.id === "select_end_date"){ this.endDate = value} + setActiveValues(dateValue, type) { + const value = dateValue ? (this.dateFieldType === "datetime" ? serializeDateTime(dateValue) : serializeDate(dateValue)) : undefined; + if (type === "startDate") { + this.state.startDate = value + } + if (type === "endDate") { + this.state.endDate = value + } } get domain(){ @@ -37,49 +53,121 @@ export class SelectDateFilter extends Component { // 时间筛选应该返回类似这样的domain // ["&", ("create_date", ">=", "2024-05-22 16:00:00"), ("create_date", "<=", "2024-05-23 15:59:59")] const domain = []; - if (this.startDate && this.endDate) {domain.push("&")} - if (this.startDate){domain.push([this.dateField, ">=", this.startDate])} - if (this.endDate){domain.push([this.dateField, "<=", this.endDate])} + if (this.state.startDate && this.state.endDate) {domain.push("&")} + if (this.state.startDate){domain.push([this.state.dateField, ">=", this.state.startDate])} + if (this.state.endDate){domain.push([this.state.dateField, "<=", this.state.endDate])} return domain.length === 0? []: domain } - // 选择时间字段变化 + applySelectDateFilter() { + this.env.searchModel.setSelectDateFilter( + this.state.dateField, + this.state.startDate, + this.state.endDate, + this.domain + ); + this.env.searchModel.applyHeaderFilters(); + } + dateFieldOnchange(ev){ - this.dateField = ev.target.value; - this.env.searchModel.setSelectDateFilter(this.dateField, this.domain); - this.env.searchModel.applyHeaderFilters(); + this.state.dateField = ev.target.value; + this.state.startDate = undefined; + this.state.endDate = undefined; + this.applySelectDateFilter() } - // 日期变化 - dateOnchange(ev) { - this.setActiveValues(ev); - this.env.searchModel.setSelectDateFilter(this.dateField, this.domain); - this.env.searchModel.applyHeaderFilters(); + startDateOnchange (startDate) { + this.setActiveValues(startDate, "startDate"); + this.applySelectDateFilter() } - setDateRange(months) { - const today = new Date(); - const startDate = new Date(); - startDate.setMonth(startDate.getMonth() - months); - this.startDate = startDate.toISOString().split('T')[0]; - this.endDate = today.toISOString().split('T')[0]; - this.env.searchModel.setSelectDateFilter(this.dateField, this.domain); - this.env.searchModel.applyHeaderFilters(); + endDateOnchange (endDate) { + this.setActiveValues(endDate, "endDate"); + this.applySelectDateFilter() + } + + setDateRange(direction) { + // 只允许 next 或 previous + if (!["next", "previous"].includes(direction)) { + return; + } + // 月份偏移量 + const monthOffset = direction === "next" ? 1 : -1; + // 当前时间(作为默认基准) + const now = luxon.DateTime.now(); + // 反序列化开始时间 + const start = this.state.startDate + ? (this.dateFieldType === "datetime" + ? deserializeDateTime(this.state.startDate) + : deserializeDate(this.state.startDate)) + : null; + // 反序列化结束时间 + const end = this.state.endDate + ? (this.dateFieldType === "datetime" + ? deserializeDateTime(this.state.endDate) + : deserializeDate(this.state.endDate)) + : null; + // 情况一:开始和结束时间都不存在,默认使用当前月 + if (!start && !end) { + const base = now.plus({ months: monthOffset }); + // 当月开始 + const monthStart = base.startOf("month"); + // 当月结束 + const monthEnd = base.endOf("month"); + this.state.startDate = this.dateFieldType === "datetime" + ? serializeDateTime(monthStart) + : serializeDate(monthStart); + + this.state.endDate = this.dateFieldType === "datetime" + ? serializeDateTime(monthEnd) + : serializeDate(monthEnd); + } + // 情况二:只存在开始时间 + else if (start && !end) { + const newStart = start.plus({ months: monthOffset }); + + this.state.startDate = this.dateFieldType === "datetime" + ? serializeDateTime(newStart) + : serializeDate(newStart); + } + // 情况三:只存在结束时间 + else if (!start && end) { + const newEnd = end.plus({ months: monthOffset }); + + this.state.endDate = this.dateFieldType === "datetime" + ? serializeDateTime(newEnd) + : serializeDate(newEnd); + } + // 情况四:开始和结束时间都存在 + else { + const newStart = start.plus({ months: monthOffset }); + const newEnd = end.plus({ months: monthOffset }); + this.state.startDate = this.dateFieldType === "datetime" + ? serializeDateTime(newStart) + : serializeDate(newStart); + + this.state.endDate = this.dateFieldType === "datetime" + ? serializeDateTime(newEnd) + : serializeDate(newEnd); + } + this.applySelectDateFilter() } // 点击重置按钮 resetFilter() { - this.dateField = this.props.dateFields[0]; - this.startDate = undefined; - this.endDate = undefined; + this.state.dateField = this.props.dateFields[0]; + this.state.startDate = undefined; + this.state.endDate = undefined; // 重新渲染 - this.env.searchModel.setSelectDateFilter(this.dateField, this.domain); - this.env.searchModel.applyHeaderFilters(); + this.applySelectDateFilter() } } SelectDateFilter.template = "header_search_panel.SelectDateFilter"; +SelectDateFilter.components = { + DateTimeInput, +}; SelectDateFilter.props = { // 时间字段列表 dateFields: { type: Array, required: true }, diff --git a/header_search_panel/static/src/search/header_search/components/select_date_filter/select_date_filter.xml b/header_search_panel/static/src/search/header_search/components/select_date_filter/select_date_filter.xml index ff45da0e7..4b8fcfbf7 100644 --- a/header_search_panel/static/src/search/header_search/components/select_date_filter/select_date_filter.xml +++ b/header_search_panel/static/src/search/header_search/components/select_date_filter/select_date_filter.xml @@ -5,10 +5,10 @@
-
- - @@ -18,26 +18,20 @@
- - + + + + +
- diff --git a/header_search_panel/static/src/search/header_search/header_search_filter.scss b/header_search_panel/static/src/search/header_search/header_search_filter.scss index 26091f318..090c7936d 100644 --- a/header_search_panel/static/src/search/header_search/header_search_filter.scss +++ b/header_search_panel/static/src/search/header_search/header_search_filter.scss @@ -33,34 +33,13 @@ padding-right: 10px; font-weight: bold; - .header-search-select { - display: flex; - align-items: center; - height: 100%; - position: relative; - border: 1px solid #ccc; /* 设置边框 */ - border-radius: 0.5rem; /* 设置边框圆角 */ - overflow: hidden; /* 防止溢出 */ - background-color: #fff; /* 设置背景颜色 */ - color: #333; /* 设置文字颜色 */ - select { - text-align: right; - margin-right: 2rem; /* 设置右侧的距离,预留出下拉箭头的距离 */ - margin-left: 1rem; - font-weight: bold; /* 设置字体加粗 */ - border: none; /* 移除默认边框 */ - background: transparent; /* 透明背景 */ - outline: none; /* 移除默认焦点样式 */ - appearance: none; /* 移除默认样式,如箭头 */ - } - } - - .header-search-select::after { - content: '▼'; /* 下拉箭头字符 */ - position: absolute; - top: 50%; - right: 0.5rem; /* 设置箭头与右侧的距离 */ - transform: translateY(-50%); /* 垂直居中 */ + .select-date-field { + padding: 0.1rem 1rem; + border: 0.1rem solid $o-community-color; + border-radius: 0.3rem; + background-color: transparent; + background-position: right 10px center; + color: $o-community-color; } } @@ -80,6 +59,8 @@ .o_datetime_input, .fast-date-filter a { width: auto; + min-width: 230px; + text-align: center; margin: 0.2rem; padding: 0.1rem 1rem; border: 0.1rem solid $o-community-color; /* 将边框颜色改为黑色 */ diff --git a/header_search_panel/static/src/search/search_model.js b/header_search_panel/static/src/search/search_model.js index 65612a148..1698de2cb 100644 --- a/header_search_panel/static/src/search/search_model.js +++ b/header_search_panel/static/src/search/search_model.js @@ -158,7 +158,11 @@ patch(SearchModel.prototype, { }, // 设置自选时间筛选 - setSelectDateFilter(fieldName, fieldDomain) { + setSelectDateFilter(fieldName, startDate, endDate, fieldDomain) { + // 设置日期筛选相关属性 + this.headerSearchInfo.DateFilter.fieldName = fieldName; + this.headerSearchInfo.DateFilter.startDate = startDate; + this.headerSearchInfo.DateFilter.endDate = endDate; this.headerSearchInfo.DateFilter.fieldDomain = fieldDomain; }, diff --git a/soong_workflow/views/soong_workflow_record.xml b/soong_workflow/views/soong_workflow_record.xml index d4f712fe0..cbbca6feb 100644 --- a/soong_workflow/views/soong_workflow_record.xml +++ b/soong_workflow/views/soong_workflow_record.xml @@ -57,6 +57,10 @@ + + + + diff --git a/yuthon_issue/models/inherit_room_booking.py b/yuthon_issue/models/inherit_room_booking.py index 55152e641..a53606139 100644 --- a/yuthon_issue/models/inherit_room_booking.py +++ b/yuthon_issue/models/inherit_room_booking.py @@ -9,6 +9,7 @@ class RoomBooking(models.Model): is_issue = fields.Boolean(string="是否关联议题", default=True) issue_meeting_line_ids = fields.One2many('issue.meeting.line', 'meeting_booking_id', string="关联议题明细行") number_of_meetings = fields.Integer(string='会议次数') + minutes_id = fields.Many2one('issue.meeting.minutes', string='会议纪要流程') @api.constrains('start_datetime') def _check_start_datetime(self): @@ -21,6 +22,7 @@ class RoomBooking(models.Model): if meet.issue_library_id.is_boss == True: meet.issue_library_id.boss_date = self.start_datetime + timedelta(hours=8) + def bottom_meeting_approval(self): library_data = [] for library in self.issue_meeting_line_ids: @@ -39,6 +41,8 @@ class RoomBooking(models.Model): 'res_model': 'issue.meeting.minutes', 'context': { 'default_meeting_id': self.id, + 'default_room_users_ids': [(6, 0, self.room_users_ids.ids)], + 'default_host': self.host.id, 'default_meeting_type_id': self.meeting_type_id.id, 'default_meeting_date': self.start_datetime, 'default_number_of_meetings': self.number_of_meetings, diff --git a/yuthon_issue/models/issue_meeting_minutes.py b/yuthon_issue/models/issue_meeting_minutes.py index f6c9cb788..6a467dfb4 100644 --- a/yuthon_issue/models/issue_meeting_minutes.py +++ b/yuthon_issue/models/issue_meeting_minutes.py @@ -15,6 +15,8 @@ class IssueMeetingMinutes(models.Model): meeting_id = fields.Many2one('room.booking', string='会议名称', required=True) meeting_type_id = fields.Many2one('room.meeting.type', string="会议类型") meeting_date = fields.Datetime(string="会议时间") + room_users_ids = fields.Many2many('res.users', string="出席人员") + host = fields.Many2one('hr.employee', string="主持人") code = fields.Char(string='编号', required=True, copy=False, default=lambda self: self.env['ir.sequence'].next_by_code('issue_meeting_minutes_code')) meeting_minutes_ids = fields.One2many('issue.meeting.minutes.line', 'meeting_minutes_id', string="会议纪要明细") @@ -41,6 +43,13 @@ class IssueMeetingMinutes(models.Model): else: record.computed_meeting_name = False + @api.constrains('meeting_id') + def _check_meeting_id(self): + for record in self: + if record.meeting_id: + record.meeting_id.minutes_id = self.id + + class IssueMeetingMinutesLine(models.Model): _name = 'issue.meeting.minutes.line' _description = '会议纪要明细行' diff --git a/yuthon_issue/views/inherit_room_booking.xml b/yuthon_issue/views/inherit_room_booking.xml index 89f4a625c..cb9d4684d 100644 --- a/yuthon_issue/views/inherit_room_booking.xml +++ b/yuthon_issue/views/inherit_room_booking.xml @@ -11,6 +11,13 @@ + + + + +