Odoo 15 - 基于 hr_org_chart 创建小部件 - SCSS 在 res.partner 中不可见

问题描述 投票:0回答:2

我尝试创建小部件来在odoo中显示公司结构,所以我基于hr_org_chart(https://github.com/odoo/odoo/tree/15.0/addons/hr_org_chart),因为它可以按我想要的方式工作,只需一个东西向用户展示,但我想看看公司。

它开始为我工作,但在

res.parner
我的小部件不使用scss:

当我在同一模型中使用 hr_org_widget 时(

res.partner
)我也没有 scss:

hr.employee
正确显示:

我的

__manifest__.py

    "depends": [
        "partner_multi_relation",
        "partner_multi_relation_customization",
    ],
    "auto_install": True,
    'data': [
        "views/res_partner_views.xml",
    ],
    "assets": {
        "web._assets_primary_variables": [
            "company_chart/static/src/scss/variables.scss",
        ],
        "web.assets_backend": [
            "company_chart/static/src/scss/company_chart.scss",
            "company_chart/static/src/js/company_chart.js",
        ],
        "web.assets_qweb": [
            "company_chart/static/src/xml/**/*",
        ],
    },
    "license": "LGPL-3",
}

variables.scss

$o-hr-org-chart-bg: white;
$o-hr-org-chart-border-color: $o-brand-secondary;

$o-hr-org-chart-entry-v-gap: 6px;
$o-hr-org-chart-entry-pic-size: 46px;
$o-hr-org-chart-entry-line-w: 1px;
$o-hr-org-chart-entry-border-color: darken($o-hr-org-chart-bg, 25%);

// MIXINS
@mixin o-hr-org-chart-line {
  content: "";
  background-color: $o-hr-org-chart-bg;
  border: 0px solid $o-hr-org-chart-entry-border-color;
}

company_chart.scss

// MOBILE LAYOUT CUSTOMIZATIONS
@include media-breakpoint-down(sm) {
  #o_employee_right {
    .o_org_chart_title {
      font-size: 20px;
      padding: 5px 0;
      border-bottom: 1px solid $o-hr-org-chart-border-color;
    }
  }
}

// SMALL DESKTOP LAYOUT
@include media-breakpoint-up(md) {
  #o_work_employee_container {
    display: flex;
    width: 100%;
  }
  #o_work_employee_main {
    flex: 1 1 60%;
  }
  #o_employee_right {
    flex: 0 1 35%;
    margin-left: 2%;
    padding-left: 2%;
    border-left: 1px solid $o-hr-org-chart-border-color;

    .o_org_chart_title {
      color: gray("600");
    }
  }
}

// MEDIUM DESKTOP LAYOUT
@include media-breakpoint-up(lg) {
  #o_employee_right {
    flex: 0 1 33%;
  }
}

// LARGE DESKTOP LAYOUT
@include media-breakpoint-up(xl) {
  #o_employee_right {
    flex: 0 1 30%;
  }
}

#o_employee_right {
  $tmp-gap-base: $o-hr-org-chart-entry-pic-size * 0.7;

  // ORGANIGRAM LINES
  .o_field_widget,
  .o_org_chart_group_up,
  .o_org_chart_group_down {
    position: relative;
    width: 100%;
  }

  .o_org_chart_group_up {
    &:before {
      @include o-hr-org-chart-line;
      border-left-width: $o-hr-org-chart-entry-line-w;
      height: calc(100% + #{$o-hr-org-chart-entry-pic-size * 0.5});
      @include o-position-absolute(
        $top: $o-hr-org-chart-entry-pic-size * 0.1 + 5px,
        $left: $o-hr-org-chart-entry-pic-size * 0.5 -
          $o-hr-org-chart-entry-line-w * 0.5
      );
    }
    .o_org_chart_entry:last-of-type {
      &:before {
        @include o-hr-org-chart-line;
        border-width: 0 0 $o-hr-org-chart-entry-line-w
          $o-hr-org-chart-entry-line-w;
        @include size(
          ($o-hr-org-chart-entry-pic-size * 0.5) -
            ($o-hr-org-chart-entry-v-gap * 2),
          $o-hr-org-chart-entry-pic-size * 0.5 + $o-hr-org-chart-entry-v-gap * 2
        );
        @include o-position-absolute(
          $left: $o-hr-org-chart-entry-pic-size * 0.5 -
            $o-hr-org-chart-entry-line-w * 0.5,
          $top: 100%
        );
      }
    }
  }

  .o_org_chart_group_up + .o_org_chart_entry_self {
    margin-left: $tmp-gap-base;

    & + .o_org_chart_group_down {
      padding-left: $tmp-gap-base * 2;

      &:before {
        margin-left: $tmp-gap-base;
      }
    }
  }

  .o_org_chart_group_down {
    padding-left: $tmp-gap-base;

    &:before {
      @include o-hr-org-chart-line;
      border-left-width: $o-hr-org-chart-entry-line-w;
      height: 100%;
      @include o-position-absolute(
        $top: $o-hr-org-chart-entry-v-gap * -1,
        $left: $tmp-gap-base * 0.5 + $o-hr-org-chart-entry-pic-size * 0.1 +
          $o-hr-org-chart-entry-line-w * 0.5
      );
    }

    .o_org_chart_entry {
      &:before {
        @include o-hr-org-chart-line;
        border-top-width: $o-hr-org-chart-entry-line-w;
        @include size($tmp-gap-base, 0);
        @include o-position-absolute(
          $left: $tmp-gap-base * -0.5 + $o-hr-org-chart-entry-pic-size * 0.1 +
            $o-hr-org-chart-entry-line-w * 0.5,
          $top: $o-hr-org-chart-entry-pic-size * 0.5
        );
      }

      &:last-of-type {
        &:before {
          height: 50%;
        }
      }

      &.o_org_chart_more {
        margin-top: $o-hr-org-chart-entry-v-gap;

        &:before {
          top: 15px;
        }
      }
    }
  }

  // ORGANIGRAM DESIGN
  .o_org_chart_entry {
    margin-bottom: $o-hr-org-chart-entry-v-gap;
    overflow: visible;
    margin-top: 0;

    &,
    .o_media_left,
    .media-body {
      position: relative;
    }

    .o_media_left {
      padding-right: 10px;
    }

    .media-body {
      vertical-align: middle;

      .badge {
        float: right;
        cursor: pointer;
        margin-right: 5px;
        color: gray("600");
        background: $o-hr-org-chart-bg;
        border: 1px solid gray("600");
        &:hover {
          color: $o-brand-primary;
          border-color: $o-brand-primary;
        }
        &:focus {
          outline: none;
        }
      }

      strong {
        display: block;
        line-height: 1.2;
        font-size: 11px;
        color: lighten(gray("600"), 15%);
      }
    }

    .o_media_object {
      display: block;
      width: $o-hr-org-chart-entry-pic-size * 0.8;
      height: $o-hr-org-chart-entry-pic-size * 0.8;
      margin: $o-hr-org-chart-entry-pic-size * 0.1;
      box-shadow: 0 0 0 $o-hr-org-chart-entry-line-w
        darken($o-hr-org-chart-bg, 20%);
      background-size: cover;
      background-position: center center;
      background-color: $o-view-background-color;

      &.card {
        height: 20px;
        box-shadow: none;
        border-color: transparent;
        padding: 0;
        position: relative;
        color: $body-color;

        .o_org_chart_show_more {
          line-height: 13px;
        }

        &:hover {
          border-color: $o-hr-org-chart-entry-border-color;
          color: $o-brand-primary;
        }
      }
    }

    &.o_org_chart_entry_manager,
    &.o_org_chart_entry_sub {
      .o_media_left {
        padding-right: 0;
      }
      .media-body > a {
        padding-left: 10px;
        max-width: 100%;
        display: block;

        .o_media_heading {
          color: lighten(gray("600"), 5%);
          font-size: 13px;
        }
      }

      &:hover {
        .o_media_object {
          box-shadow: 0 0 0 $o-hr-org-chart-entry-line-w * 2
            rgba($o-brand-primary, 0.6);
        }
        .media-body > a {
          .o_media_heading {
            color: $o-brand-primary;
          }
          strong {
            color: lighten(gray("600"), 5%);
          }
        }
      }
    }

    &.o_org_chart_entry_self {
      &:not(:first-child) {
        margin-top: $o-hr-org-chart-entry-v-gap * 1.5;
      }

      strong {
        color: $text-muted;
      }

      .o_media_object {
        width: $o-hr-org-chart-entry-pic-size;
        height: $o-hr-org-chart-entry-pic-size;
        margin: 0;
        border: $o-hr-org-chart-entry-line-w * 2 solid $o-brand-primary;
        box-shadow: inset 0 0 0 $o-hr-org-chart-entry-line-w * 2 white;
      }

      .media-body {
        opacity: 1;
      }
    }
  }
}

// POP OVER
.o_org_chart_popup.popover {
  max-width: 400px;
  margin-right: 5px;

  .popover-header {
    height: 47px;
    line-height: 33px;
    padding-right: 50px;

    > a {
      @include o-position-absolute($right: 14px);
    }

    span {
      @include size(30px, 30px);
      margin-right: 10px;
      border-radius: 100%;
      background-position: center;
      background-size: cover;
      float: left;
      box-shadow: 0 1px 1px;
    }
  }
  .table {
    margin-bottom: 0;
  }
}

// Right to Left specific style to flip the popover arrow
.o_rtl {
  .o_org_chart_popup.popover .arrow {
    left: 100%;
    -webkit-transform: matrix(-1, 0, 0, 1, 0, 0);
    -moz-transform: matrix(-1, 0, 0, 1, 0, 0);
    -o-transform: matrix(-1, 0, 0, 1, 0, 0);
    transform: matrix(-1, 0, 0, 1, 0, 0);
  }
}

company_chart.js

odoo.define("web.CompanyChart", function (require) {
  "use strict";

  var AbstractField = require("web.AbstractField");
  var concurrency = require("web.concurrency");
  var core = require("web.core");
  var field_registry = require("web.field_registry");
  var session = require("web.session");

  var QWeb = core.qweb;
  var _t = core._t;

  var CompanyChart = AbstractField.extend({
    events: {
      "click .o_employee_redirect": "_onEmployeeRedirect",
      "click .o_employee_sub_redirect": "_onEmployeeSubRedirect",
      "click .o_employee_more_managers": "_onEmployeeMoreManager",
    },
    /**
     * @constructor
     * @override
     */
    init: function (parent, options) {
      this._super.apply(this, arguments);
      this.dm = new concurrency.DropMisordered();
      this.employee = null;
    },

    //--------------------------------------------------------------------------
    // Private
    //--------------------------------------------------------------------------
    /**
     * Get the chart data through a rpc call.
     *
     * @private
     * @param {integer} employee_id
     * @returns {Promise}
     */
    _getOrgData: function () {
      var self = this;
      return this.dm
        .add(
          this._rpc({
            route: "/company/get_org_chart",
            params: {
              employee_id: this.employee,
              context: session.user_context,
            },
          })
        )
        .then(function (data) {
          return data;
        });
    },
    /**
     * Get subordonates of an employee through a rpc call.
     *
     * @private
     * @param {integer} employee_id
     * @returns {Promise}
     */
    _getSubordinatesData: function (employee_id, type) {
      return this.dm.add(
        this._rpc({
          route: "/company/get_subordinates",
          params: {
            employee_id: employee_id,
            subordinates_type: type,
            context: session.user_context,
          },
        })
      );
    },
    /**
     * @override
     * @private
     */
    _render: function () {
      if (!this.recordData.id) {
        return this.$el.html(
          QWeb.render("company_chart", {
            managers: [],
            children: [],
          })
        );
      } else if (!this.employee) {
        // the widget is either dispayed in the context of a res.partner form or a res.users form
        this.employee =
          this.recordData.employee_ids !== undefined
            ? this.recordData.employee_ids.res_ids[0]
            : this.recordData.id;
      }

      var self = this;
      return this._getOrgData().then(function (orgData) {
        if (_.isEmpty(orgData)) {
          orgData = {
            managers: [],
            children: [],
          };
        }
        orgData.view_employee_id = self.recordData.id;
        console.log(orgData)
        self.$el.html(QWeb.render("company_chart", orgData));
        self.$('[data-toggle="popover"]').each(function () {
          $(this).popover({
            html: true,
            title: function () {
              var $title = $(
                QWeb.render("company_chart_emp_popover_title", {
                  employee: {
                    name: $(this).data("emp-name"),
                    id: $(this).data("emp-id"),
                  },
                })
              );
              $title.on(
                "click",
                ".o_employee_redirect",
                _.bind(self._onEmployeeRedirect, self)
              );
              return $title;
            },
            container: this,
            placement: "left",
            trigger: "focus",
            content: function () {
              var $content = $(
                QWeb.render("company_chart_emp_popover_content", {
                  employee: {
                    id: $(this).data("emp-id"),
                    name: $(this).data("emp-name"),
                    direct_sub_count: parseInt(
                      $(this).data("emp-dir-subs"),
                      10
                    ),
                    indirect_sub_count: parseInt(
                      $(this).data("emp-ind-subs"),
                      10
                    ),
                  },
                })
              );
              $content.on(
                "click",
                ".o_employee_sub_redirect",
                _.bind(self._onEmployeeSubRedirect, self)
              );
              return $content;
            },
            template: QWeb.render("company_chart_emp_popover", {}),
          });
        });
      });
    },

    //--------------------------------------------------------------------------
    // Handlers
    //--------------------------------------------------------------------------

    _onEmployeeMoreManager: function (event) {
      event.preventDefault();
      this.employee = parseInt($(event.currentTarget).data("employee-id"), 10);
      this._render();
    },
    /**
     * Redirect to the employee form view.
     *
     * @private
     * @param {MouseEvent} event
     * @returns {Promise} action loaded
     */
    _onEmployeeRedirect: function (event) {
      var self = this;
      event.preventDefault();
      var employee_id = parseInt(
        $(event.currentTarget).data("employee-id"),
        10
      );
      return this._rpc({
        model: "res.partner",
        method: "get_formview_action",
        args: [employee_id],
      }).then(function (action) {
        return self.do_action(action);
      });
    },
    /**
     * Redirect to the sub employee form view.
     *
     * @private
     * @param {MouseEvent} event
     * @returns {Promise} action loaded
     */
    _onEmployeeSubRedirect: function (event) {
      event.preventDefault();
      var employee_id = parseInt(
        $(event.currentTarget).data("employee-id"),
        10
      );
      var employee_name = $(event.currentTarget).data("employee-name");
      var type = $(event.currentTarget).data("type") || "direct";
      var self = this;
      if (employee_id) {
        this._getSubordinatesData(employee_id, type).then(function (data) {
          var domain = [["id", "in", data]];
          return self
            ._rpc({
              model: "res.partner",
              method: "get_formview_action",
              args: [employee_id],
            })
            .then(function (action) {
              action = _.extend(action, {
                name: _t("Team"),
                view_mode: "kanban,list,form",
                views: [
                  [false, "kanban"],
                  [false, "list"],
                  [false, "form"],
                ],
                domain: domain,
                context: {
                  default_parent_id: employee_id,
                },
              });
              delete action.res_id;
              return self.do_action(action);
            });
        });
      }
    },
  });

  field_registry.add("company_chart", CompanyChart);

  return CompanyChart;
});

我做错了什么,资产中的 scss 没有加载到我的小部件中

res.partner

javascript css odoo odoo-15 odoo-website
2个回答
0
投票

好吧,我忘了在 xml 中添加:

<div id="o_employee_right">
在表单视图中:

<div id="o_employee_right">
    <h4 class="o_org_chart_title mb16 mt0">Organization Chart</h4>
    <field name="partner_relations" widget="company_chart"/>
</div>

现在可以了!


0
投票

您能否提供完整的模块,包括 xml 吗?

© www.soinside.com 2019 - 2024. All rights reserved.