Odoo 15 – 基于hr_org_chart创建小部件 – SCSS不显示res.partner

huangapple go评论73阅读模式
英文:

Odoo 15 - Create widget based on hr_org_chart - SCSS don't visible od res.partner

问题

你的问题可能是由于SCSS文件的路径或命名问题导致的。请确保你的Odoo模块正确配置了SCSS文件的路径,以便在res.partner模型中加载它们。

首先,确保company_chart模块已经正确安装和启用。

然后,检查以下几个地方是否存在问题:

  1. SCSS文件路径:确保variables.scsscompany_chart.scss文件位于正确的路径下,也就是在company_chart模块的static/src/scss/目录中。

  2. SCSS文件命名:确保文件名的大小写和拼写与模块中的引用保持一致。比如,variables.scss应该与"company_chart/static/src/scss/variables.scss"中的路径一致。

  3. Manifest文件:在你的__manifest__.py文件中,确保'web.assets_backend'部分包含了正确的SCSS文件路径:

    'web.assets_backend': [
        'company_chart/static/src/scss/company_chart.scss',
        # ...
    ],
    

    同样,确保'web._assets_primary_variables'包含正确的variables.scss路径:

    'web._assets_primary_variables': [
        'company_chart/static/src/scss/variables.scss',
        # ...
    ],
    
  4. 重新加载模块:如果你已经更正了文件路径和命名,并且company_chart模块已启用,请确保在Odoo中重新加载该模块,以确保新的SCSS文件能够生效。

如果仍然存在问题,可能需要检查Odoo日志以查看是否有与SCSS文件加载相关的错误消息。如果日志中没有错误消息,那么问题可能涉及到其他方面,需要更详细的调试和分析。

最后,确保在浏览器中清除缓存,以确保新的SCSS文件能够加载并应用到res.partner模型中的小部件中。

英文:

I try to create widget to show company structure in odoo so i base on hr_org_chart (https://github.com/odoo/odoo/tree/15.0/addons/hr_org_chart), because it work as i want, with one thing show users but i want to see companies.

It start working me but on res.parner my widget don't use scss:

Odoo 15 – 基于hr_org_chart创建小部件 – SCSS不显示res.partner

when i use hr_org_widget in that same model (res.partner) i also don't have scss:
Odoo 15 – 基于hr_org_chart创建小部件 – SCSS不显示res.partner

in hr.employee show properly:

Odoo 15 – 基于hr_org_chart创建小部件 – SCSS不显示res.partner

My __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;
});

What i do wrong that scss from assets don't load at my widget in res.partner ?

答案1

得分: 0

我忘记在XML中添加了以下内容:<div id="o_employee_right">在表单视图中:

<div id="o_employee_right">
    <h4 class="o_org_chart_title mb16 mt0">组织图表</h4>
    <field name="partner_relations" widget="company_chart"/>
</div>

现在它可以工作了!

英文:

Ok i forgot to add in xml : <div id="o_employee_right"> in form view:

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

Now it works!

huangapple
  • 本文由 发表于 2023年7月13日 18:05:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76678192.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定