合并并提交看板操作隐藏

This commit is contained in:
夜未央
2026-01-18 18:21:35 +08:00
15 changed files with 364 additions and 208 deletions
@@ -9,6 +9,7 @@ import { localization } from "@web/core/l10n/localization";
import {formatDate,formatDateTime} from "@web/core/l10n/dates";
import {parseDateTime,parseDate,} from "@web/core/l10n/dates";
import { renderToElement } from "@web/core/utils/render";
import { session } from "@web/session";
export class Ksdashboardgraph extends Component{
setup(){
@@ -16,6 +17,7 @@ export class Ksdashboardgraph extends Component{
this.actionService = useService("action");
this._rpc = useService("rpc");
this.state = useState({item_data:"",list_view_data:""})
this.isAdmin = session.is_system;
onMounted(() => this._update_view());
onPatched(() => this.update_list_view());
this.item = this.props.item
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="Ks_chart_list_container">
<t t-if="item.ks_dashboard_item_type == 'ks_list_view'">
<t t-call="ks_dashboard_ninja.Ksdashboardlistview"/>
@@ -9,50 +8,46 @@
<t t-call="Ks_gridstack_container"/>
</t>
</t>
<t t-name="Ks_gridstack_container">
<div class="grid-stack-item ks_chart_container ks_dashboarditem_id" t-att-id="chart_id" t-ref="ks_gridstack_container">
<div class="grid-stack-item-content ks_dashboarditem_chart_container ks_dashboard_item_hover card shadow"
t-att-title="ks_info">
<div class="p-3 py-3 d-flex flex-row align-items-center justify-content-between ">
<div class="d-flex align-items-center">
<h6 class="m-0 font-weight-bold h3 ks_chart_heading mr-3" t-att-title="ks_chart_title">
<t t-esc="ks_chart_title"/>
</h6>
<!-- <div >-->
<t t-if="ks_breadcrumb.length >= 1">
<nav class="ks_breadcrumb">
<t t-if="ks_breadcrumb.length >= 1">
<nav class="ks_breadcrumb">
<ul>
<li class="d-none" t-att-id="'item'+'_'+'-1'">
<span t-att-data-sequence = '-1' t-att-data-item-id="chart_id" t-on-click="ksOnDrillUp">
<t t-esc="ks_chart_title"/>
</span>
<span t-att-data-sequence = '-1' t-att-data-item-id="chart_id" t-on-click="ksOnDrillUp">
<t t-esc="ks_chart_title"/>
</span>
</li>
<t t-foreach="ks_breadcrumb" t-as="chart_breadcrumb" t-key="chart_breadcrumb_index">
<li class="d-none" t-att-id="chart_breadcrumb['name'] + '_' + chart_breadcrumb_index">
<li class="d-none" t-att-id="chart_breadcrumb['name'] + '_' + chart_breadcrumb_index">
<span t-att-data-sequence="chart_breadcrumb_index" t-att-data-item-id="chart_id" t-on-click="ksOnDrillUp">
<t t-esc="chart_breadcrumb['name']"/>
<t t-esc="chart_breadcrumb['name']"/>
</span>
</li>
</t>
</ul>
</nav>
</t>
</nav>
</t>
</div>
<!-- </div>-->
<img src="ks_dashboard_ninja/static/images/selected.svg" class="ks_img_display d-none"
width="30"/>
<!-- Dashboard Item Move/Copy Feature -->
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header ks_dashboard_item_header_hover chart_button_container d-md-flex d-none"
t-att-data-item_id="chart_id">
<t t-if="ksIsDashboardManager">
<button class="ks_dashboard_item_chart_info" title="More Info" type="button"
t-att-data-item_id="chart_id" t-if="isAdmin">
<t t-if="ksIsDashboardManager and isAdmin">
<button class="ks_dashboard_item_chart_info" title="More Info" type="button"
t-att-data-item-id="chart_id">
<i class="fa fa-info-circle"/>
</button>
<i class="fa fa-info-circle"/>
</button>
<t t-if="ks_dashboard_item_type != 'ks_map_view'">
<div class="ks_chart_inner_buttons">
<button title="Color Palette" data-bs-toggle="dropdown"
@@ -76,8 +71,6 @@
</ul>
</div>
</t>
<div class="ks_chart_inner_buttons">
<button title="Move/Duplicate" data-bs-toggle="dropdown"
class="ks_dashboard_item_action btn dropdown-toggle btn-xs" type="button"
@@ -109,101 +102,103 @@
</li>
</ul>
</div>
<button title="Quick Customize"
class="ks_dashboard_quick_edit_action_popup btn d-sm-block d-none"
type="button" t-att-data-item-id="chart_id">
<i class="fa fa-pencil"/>
</button>
<button class="ks_dashboard_item_customize d-block d-sm-none" title="Customize Item"
type="button" t-att-data-item-id="chart_id">
<i class="fa fa-pencil"/>
</button>
<button class="ks_dashboard_item_delete" title="Remove Item" type="button">
<i class="fa fa-times"/>
</button>
</t>
<t t-if="ksIsUser">
<div class="ks_chart_inner_buttons ks_dashboard_more_action"
<div class="ks_chart_inner_buttons ks_dashboard_more_action"
t-att-data-item-id="chart_id">
<button title="Export Chart" data-bs-toggle="dropdown"
<button title="Export Chart" data-bs-toggle="dropdown"
class="ks_dashboard_item_action btn dropdown-toggle btn-xs o-no-caret btn"
type="button"
aria-expanded="true">
<i class="fa fa-ellipsis-v"/>
</button>
<div role="menu" class="dropdown-menu dropdown-menu-right">
<!--Dynamic Rendering-->
<t t-call="ksMoreChartOptions"/>
</div>
<i class="fa fa-ellipsis-v"/>
</button>
<div role="menu" class="dropdown-menu dropdown-menu-right">
<!--Dynamic Rendering-->
<t t-call="ksMoreChartOptions"/>
</div>
</div>
</t>
<div class="ks_chart_inner_buttons dropdown">
<button title="Info" data-bs-toggle="dropdown"
<button title="Info" data-bs-toggle="dropdown"
class="ks_item_description btn dropdown-toggle btn-xs o-no-caret btn"
type="button"
t-att-style="'color:'+ ks_rgba_button_color + ';'"
aria-expanded="true">
<i class="fa fa-book"/>
</button>
<i class="fa fa-book"/>
</button>
<div role="menu" class="dropdown-menu dropdown-menu-right" style="width:20rem">
<!--Dynamic Rendering-->
<!--Dynamic Rendering-->
<div class="ks_chart_export_menu">
<div class="ks_chart_export_menu_header" style="margin-left:-10px">
<span>Info</span>
</div>
<div class="ks_chart_export_menu_header" style="margin-left:-10px">
<span>Info</span>
</div>
<div class="ks_info" style="margin-left:10px">
<span>Company: <t t-esc="ks_company"/></span>
</div>
<span>Company:
<t t-esc="ks_company"/>
</span>
</div>
<div class="ks_info" style="margin-left:10px">
<t t-if="ks_info">
<t t-foreach="ks_info" t-as="ks_description" t-key="ks_description_index">
<span><t t-esc="ks_description"/></span>
<br></br>
</t>
</t>
<t t-if="ks_info">
<t t-foreach="ks_info" t-as="ks_description" t-key="ks_description_index">
<span>
<t t-esc="ks_description"/>
</span>
<br></br>
</t>
</t>
</div>
</div>
</div>
</div>
</div>
</div>
<t t-if="ksIsDashboardManager">
<div class="dropdown d-md-none dn-setting-panel">
<button class="btn btn-secondary border-0" type="button" id="dropdownSettingButton"
<button class="btn btn-secondary border-0" type="button" id="dropdownSettingButton"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-cog"></i>
</button>
<i class="fa fa-cog"></i>
</button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownSettingButton">
<t t-if="ks_show_records &amp; ks_query_type=='custom'">
<a class="dropdown-item ks_dashboard_item_chart_info ks_info_display"
<t t-if="ks_show_records &amp; ks_query_type=='custom'">
<a class="dropdown-item ks_dashboard_item_chart_info ks_info_display"
t-att-data-item-id="chart_id">
<i class="fa fa-info-circle"/>
<i class="fa fa-info-circle"/>
More Info
</a>
</t>
</a>
</t>
<a class="dropdown-item ks_dashboard_item_customize" t-att-data-item-id="chart_id">
<i class="fa fa-pencil"></i>
<i class="fa fa-pencil"></i>
Customize Item
</a>
</a>
<a class="dropdown-item ks_dashboard_item_delete">
<i class="fa fa-times"></i>
<i class="fa fa-times"></i>
Remove Item
</a>
</div>
</div>
</a>
</div>
</div>
</t>
</div>
<t t-if="ks_ai_analysis">
<div class="ks_ai_explain_body">
<div class="card-body ks_chart_card_body"></div>
<div class="ks_ai_explanation">
<p><t t-esc="ks_ai_analysis_1"/></p>
<p><t t-esc="ks_ai_analysis_2"/></p>
<p>
<t t-esc="ks_ai_analysis_1"/>
</p>
<p>
<t t-esc="ks_ai_analysis_2"/>
</p>
</div>
<div class="ks_speaker" t-on-click="props.ks_speak">
<span class="fa fa-volume-up"/>
@@ -217,7 +212,6 @@
</div>
</div>
</t>
<t t-name="ksMoreChartOptions">
<div class="ks_chart_export_menu">
<div class="ks_chart_export_menu_header">
@@ -233,7 +227,6 @@
<i class="fa fa-file-code-o"/>
<span>Export to CSV</span>
</div>
<div t-att-data-chart-id="chart_id" class="ks_chart_pdf_export ks_chart_export_menu_item">
<i class="fa fa-file-pdf-o"/>
<span>Save as PDF</span>
@@ -6,7 +6,7 @@ import { formatInteger } from "@web/views/fields/formatters";
import { useService } from "@web/core/utils/hooks";
import { jsonrpc } from "@web/core/network/rpc_service";
import { _t } from "@web/core/l10n/translation";
import { session } from "@web/session";
export class Ksdashboardkpiview extends Component{
file_type_magic_word= {'/': 'jpg','R': 'gif','i': 'png','P': 'svg+xml'}
setup(){
@@ -15,6 +15,7 @@ export class Ksdashboardkpiview extends Component{
this.actionService = useService("action");
this.ks_kpi = useRef('ks_kpi')
this.state = useState({item_info_kpi1:{},item_info_kpi2:{},item_info_kpi3:{}})
this.isAdmin = session.is_system;
onMounted(() => this._update_view());
this.item = this.props.item
this.ks_dashboard_data = this.props.dashboard_data
@@ -113,7 +113,7 @@
<img src="ks_dashboard_ninja/static/images/selected.svg" class="ks_img_display d-none" width="30"/>
<!---->
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header_l6 ks_dashboard_item_header_hover"
t-att-data-item_id="state.item_info_kpi1.item.id">
t-att-data-item_id="state.item_info_kpi1.item.id" t-if="isAdmin">
<t t-if="state.item_info_kpi1.item.ksIsDashboardManager">
<!-- Dashboard Item Move/Copy Feature -->
<button title="Move/Duplicate" data-bs-toggle="dropdown"
@@ -305,7 +305,7 @@
</t>
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header_l6 ks_dashboard_item_header_hover"
t-att-data-item_id="state.item_info_kpi2.item.id">
t-att-data-item_id="state.item_info_kpi2.item.id" t-if="isAdmin">
<t t-if="state.item_info_kpi2.item.ksIsDashboardManager">
<!-- Dashboard Item Move/Copy Feature -->
<button title="Move/Duplicate" data-bs-toggle="dropdown"
@@ -489,7 +489,7 @@
</t>
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header_l6 ks_dashboard_item_header_hover"
t-att-data-item_id="state.item_info_kpi3.item.id">
t-att-data-item_id="state.item_info_kpi3.item.id" t-if="isAdmin">
<t t-if="state.item_info_kpi3.item.ksIsDashboardManager">
<!-- Dashboard Item Move/Copy Feature -->
<button title="Move/Duplicate" data-bs-toggle="dropdown"
@@ -37,7 +37,7 @@
<!-- -->
<!-- Dashboard Item Move/Copy Feature -->
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header ks_dashboard_item_header_hover chart_button_container d-md-flex d-none"
t-att-data-item_id="item_id">
t-att-data-item_id="item_id" >
<t t-if="ksIsDashboardManager">
<button title="Move/Duplicate" data-bs-toggle="dropdown" t-att-data-item-id="item_id"
class="ks_dashboard_item_action btn dropdown-toggle btn-xs" type="button"
@@ -5,7 +5,7 @@ import { loadBundle } from "@web/core/assets";
import { useService } from "@web/core/utils/hooks";
import { jsonrpc } from "@web/core/network/rpc_service";
import { _t } from "@web/core/l10n/translation";
import { session } from "@web/session";
export class Ksdashboardtile extends Component{
file_type_magic_word= {'/': 'jpg','R': 'gif','i': 'png','P': 'svg+xml'}
@@ -17,6 +17,7 @@ export class Ksdashboardtile extends Component{
this.ks_container_class = 'grid-stack-item';
this.ks_inner_container_class = 'grid-stack-item-content';
this.state = useState({data_count:""})
this.isAdmin = session.is_system;
this.item = this.props.item
this.file_type_magic_word= {'/': 'jpg','R': 'gif','i': 'png','P': 'svg+xml'}
this.ks_dashboard_data = this.props.dashboard_data
@@ -33,7 +33,7 @@
t-att-title="item.ks_info"
t-att-id="item.id">
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header ks_dashboard_item_header_hover"
t-att-data-item_id="item.id">
t-att-data-item_id="item.id" t-if="isAdmin">
<t t-if="item.ksIsDashboardManager">
<!-- Dashboard Item Move/Copy Feature -->
@@ -230,7 +230,7 @@
</div>
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header_l6 ks_dashboard_item_header_hover"
t-att-data-item_id="item.id">
t-att-data-item_id="item.id" t-if="isAdmin">
<t t-if="item.ksIsDashboardManager">
<!-- Dashboard Item Move/Copy Feature -->
<button title="Move/Duplicate" data-bs-toggle="dropdown"
@@ -383,7 +383,7 @@
t-att-title="item.ks_info" t-att-id="item.id">
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header ks_dashboard_item_header_hover"
t-att-data-item_id="item.id">
t-att-data-item_id="item.id" t-if="isAdmin">
<t t-if="item.ksIsDashboardManager">
<!-- Dashboard Item Move/Copy Feature -->
@@ -581,7 +581,7 @@
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header_l6 ks_dashboard_item_header_hover"
t-att-data-item_id="item.id">
t-att-data-item_id="item.id" t-if="isAdmin">
<t t-if="item.ksIsDashboardManager">
<!-- Dashboard Item Move/Copy Feature -->
<button title="Move/Duplicate" data-bs-toggle="dropdown"
@@ -756,7 +756,7 @@
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header_l2 ks_dashboard_item_header_hover"
t-att-data-item_id="item.id">
t-att-data-item_id="item.id" t-if="isAdmin">
<t t-if="item.ksIsDashboardManager">
<!-- Dashboard Item Move/Copy Feature -->
@@ -933,7 +933,7 @@
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header_l6 ks_dashboard_item_header_hover"
t-att-data-item_id="item.id">
t-att-data-item_id="item.id" t-if="isAdmin">
<t t-if="item.ksIsDashboardManager">
<!-- Dashboard Item Move/Copy Feature -->
<button title="Move/Duplicate" data-bs-toggle="dropdown"
@@ -1074,7 +1074,7 @@
<t t-name="ks_dashboard_item_layout_default">
<div t-att-id="item.id" t-att-class="'ks_item_click ' + ks_container_class">
<div class="ks_dashboard_item ks_dashboard_item_hover"
t-att-style="style_main_body">
t-att-style="style_main_body" t-if="isAdmin">
<t t-if="item.ksIsDashboardManager">
<div class="ks_dashboard_item_header ks_dashboard_item_header_hover">
<button type="button" title="Customize Item" class="ks_dashboard_item_customize">
@@ -7,7 +7,7 @@ import { useService } from "@web/core/utils/hooks";
import {Todoeditdialog,addtododialog} from "@ks_dashboard_ninja/components/ks_dashboard_to_do_item/editdialog";
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
import { _t } from "@web/core/l10n/translation";
import { session } from "@web/session";
export class Ksdashboardtodo extends Component{
setup(){
super.setup();
@@ -17,6 +17,7 @@ export class Ksdashboardtodo extends Component{
this.item = this.props.item
this.ks_dashboard_data = this.props.dashboard_data
this.prepare_item();
this.isAdmin = session.is_system;
}
@@ -1,9 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="Ksdashboardtodo">
<t t-name="Ksdashboardtodo">
<div class="grid-stack-item ks_dashboarditem_id" t-att-id="item_id">
<div class="grid-stack-item-content ks_list_view_container ks_dashboard_item_hover card shadow"
t-att-title="ks_info">
@@ -16,10 +13,9 @@
<t t-esc="ks_chart_title"/>
</h6>
</div>
<!-- Dashboard Item Move/Copy Feature -->
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header ks_dashboard_item_header_hover chart_button_container d-md-flex d-none"
t-att-data-item_id="item_id">
t-att-data-item_id="item_id" t-if="isAdmin">
<t t-if="ksIsDashboardManager">
<button title="Move/Duplicate" data-bs-toggle="dropdown"
t-att-data-item-id="item_id"
@@ -39,7 +35,7 @@
<option t-att-value="ks_dashboard['id']">
<t t-esc="ks_dashboard['name']"/>
</option>
</t>
</t>
</select>
</li>
<li class="mt-3">
@@ -58,7 +54,6 @@
type="button" t-att-data-item-id="item_id">
<i class="fa fa-pencil"/>
</button>
<button class="ks_dashboard_item_customize d-block text-white d-sm-none"
title="Customize Item"
t-att-style="'color:'+ ks_rgba_button_color + ' !important' + ';'"
@@ -73,77 +68,78 @@
</t>
<t t-if="ksIsUser">
<div class="ks_chart_inner_buttons">
<button title="Export List" data-bs-toggle="dropdown"
<button title="Export List" data-bs-toggle="dropdown"
class="ks_dashboard_item_action_export text-white btn dropdown-toggle btn-xs o-no-caret btn"
t-att-style="'color:'+ ks_rgba_button_color + ' !important' + ';'"
type="button"
aria-expanded="true">
<i class="fa fa-ellipsis-v"/>
</button>
<div role="menu" class="dropdown-menu dropdown-menu-right">
<!--Dynamic Rendering-->
<div class="ks_chart_export_menu">
<div class="ks_chart_export_menu_header">
<span>Export</span>
</div>
<div class="ks_chart_json_export ks_chart_export_menu_item"
<i class="fa fa-ellipsis-v"/>
</button>
<div role="menu" class="dropdown-menu dropdown-menu-right">
<!--Dynamic Rendering-->
<div class="ks_chart_export_menu">
<div class="ks_chart_export_menu_header">
<span>Export</span>
</div>
<div class="ks_chart_json_export ks_chart_export_menu_item"
t-att-data-item-id="item_id"
data-format="chart_xls">
<i class="fa fa-file-code-o"/>
<span>Export Item</span>
<i class="fa fa-file-code-o"/>
<span>Export Item</span>
</div>
</div>
</div>
</div>
</div>
</t>
<div class="ks_chart_inner_buttons dropdown">
<button title="Item description" data-bs-toggle="dropdown"
<button title="Item description" data-bs-toggle="dropdown"
class="ks_item_description btn dropdown-toggle btn-xs o-no-caret btn"
type="button"
t-att-style="'color:'+ ks_rgba_button_color + ';'"
aria-expanded="true">
<i class="fa fa-book"/>
</button>
<div role="menu" class="dropdown-menu dropdown-menu-right" style="width:20rem">
<!--Dynamic Rendering-->
<div class="ks_chart_export_menu">
<div class="ks_chart_export_menu_header" style="margin-left:-10px">
<span>Info</span>
</div>
<div class="ks_info" style="margin-left:10px">
<span>Company: <t t-esc="ks_company"/></span>
</div>
<div class="ks_info" style="margin-left:10px">
<t t-if="ks_info">
<t t-foreach="ks_info" t-as="ks_description" t-key="ks_description_index">
<span><t t-esc="ks_description"/></span>
<br></br>
</t>
</t>
<i class="fa fa-book"/>
</button>
<div role="menu" class="dropdown-menu dropdown-menu-right" style="width:20rem">
<!--Dynamic Rendering-->
<div class="ks_chart_export_menu">
<div class="ks_chart_export_menu_header" style="margin-left:-10px">
<span>Info</span>
</div>
<div class="ks_info" style="margin-left:10px">
<span>Company:
<t t-esc="ks_company"/>
</span>
</div>
<div class="ks_info" style="margin-left:10px">
<t t-if="ks_info">
<t t-foreach="ks_info" t-as="ks_description" t-key="ks_description_index">
<span>
<t t-esc="ks_description"/>
</span>
<br></br>
</t>
</t>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<t t-if="ksIsDashboardManager">
<div class="dropdown d-md-none dn-setting-panel">
<button class="btn btn-secondary border-0" type="button" id="dropdownSettingButton" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" >
<i class="fa fa-cog"></i>
</button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownSettingButton">
<a class="dropdown-item ks_dashboard_item_customize" >
<i class="fa fa-pencil"></i> Customize Item
</a>
<a class="dropdown-item ks_dashboard_item_delete" >
<i class="fa fa-times"></i> Remove Item
</a>
</div>
</div>
<button class="btn btn-secondary border-0" type="button" id="dropdownSettingButton" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" >
<i class="fa fa-cog"></i>
</button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownSettingButton">
<a class="dropdown-item ks_dashboard_item_customize" >
<i class="fa fa-pencil"></i> Customize Item
</a>
<a class="dropdown-item ks_dashboard_item_delete" >
<i class="fa fa-times"></i> Remove Item
</a>
</div>
</div>
</t>
</div>
<div class="card-header">
<div class="nav-tabs-navigation">
<div class="nav-tabs-wrapper">
@@ -172,7 +168,6 @@
<t t-esc="table_header"/>
</a>
</t>
</li>
<t t-set="ks_rec_count" t-value="ks_rec_count+1"/>
</t>
@@ -191,7 +186,6 @@
</li>
</ul>
</t>
</div>
</div>
</div>
@@ -202,16 +196,12 @@
</div>
</div>
</t>
<t t-name="ks_to_do_dashboard_inner_body">
<div class="container-fluid p-0">
<div>
<div>
<div class="card">
<t t-if="state.to_do_view_data['label']">
<div class="card-body">
<div class="tab-content">
<t t-set="ks_section_count" t-value="0"/>
@@ -232,7 +222,6 @@
<td class="ks_custom_check">
<div class="form-check">
<label class="form-check-label">
<t t-if="state.to_do_view_data['ks_content_active'][ks_href_id][ks_temp_count]=='True'">
<input class="form-check-input"
type="checkbox"
@@ -243,7 +232,6 @@
type="checkbox" value=""
checked=""/>
</t>
<span class="form-check-sign ks_do_item_active_handler" t-on-click="_onKsActiveHandler"
t-att-data-item-id="item_id"
t-att-data-content-id="state.to_do_view_data['ks_content_record_id'][ks_href_id][ks_temp_count]"
@@ -262,7 +250,6 @@
<t t-esc="table_row"/>
</td>
</t>
<t t-else="">
<td class="ks_description ks_do_item_line_through"
t-att-value="table_row"
@@ -294,14 +281,12 @@
<t t-set="ks_temp_count" t-value="ks_temp_count+1"/>
</tr>
</t>
</t>
</table>
</t>
<t t-else="">
<span class="nav-tabs-title">No Tasks Available</span>
</t>
<t t-set="ks_section_count" t-value="ks_section_count+1"/>
</div>
</t>
@@ -350,7 +335,6 @@
<t t-esc="table_row"/>
</td>
</t>
<t t-else="">
<td class="ks_description ks_do_item_line_through"
t-att-value="table_row"
@@ -382,7 +366,6 @@
<t t-set="ks_temp_count" t-value="ks_temp_count+1"/>
</tr>
</t>
</t>
</table>
</t>
@@ -404,10 +387,8 @@
</div>
</t>
</div>
</div>
</div>
</div>
</t>
</templates>
@@ -25,6 +25,41 @@ async function flushBadge(env, action) {
await env.services.action.restore(controller.jsId);
}
}
registry.category("actions").add("flush_badge", flushBadge);
const getWkfAction = (treeId, uid) => {
return {
name: '流程待办',
type: 'ir.actions.act_window',
res_model: 'soong.workflow.record',
views: [[treeId, 'tree']],
domain: [
['users_ids', 'in', uid],
['reclaim_state', '=', false],
['soong_state', '=', 'to_do'],
],
context: {
header_search_default_approve_state: 1,
header_search_default_to_do: 1,
check_employee: 1
}
}
}
async function flushBadgeWithWorkflow(env, action) {
await env.services.menu.reload();
if (action && action.params && 'menu_id' in action.params) {
env.services.menu.setCurrentMenu(action.params.menu_id);
}
// 跳转tree
const { tree_id, uid } = action.params;
if (tree_id && uid) {
return env.services.action.doAction(getWkfAction(tree_id, uid));
}
const controller = env.services.action.currentController;
if (controller) {
await env.services.action.restore(controller.jsId);
}
}
registry.category("actions").add("flush_badge_wkf", flushBadgeWithWorkflow);
@@ -2,10 +2,10 @@
<odoo>
<data>
<record id="paperformat_hr_leave_batch_small" model="report.paperformat">
<field name="name">Leave Batch Portrait</field>
<field name="format">A4</field>
<field name="name">Leave Batch A5 Landscape</field>
<field name="format">A5</field>
<field name="margin_top">5</field>
<field name="orientation">Portrait</field>
<field name="orientation">Landscape</field>
</record>
<record id="action_hr_leave_batch_print" model="ir.actions.report">
<field name="name">请假单</field>
@@ -1,9 +1,9 @@
<odoo>
<record id="paperformat_overtime_approval_small" model="report.paperformat">
<field name="name">Overtime Approval Portrait</field>
<field name="format">A4</field>
<field name="name">Overtime Approval A5 Landscape</field>
<field name="format">A5</field>
<field name="margin_top">5</field>
<field name="orientation">Portrait</field>
<field name="orientation">Landscape</field>
</record>
<record id="action_overtime_approval_print" model="ir.actions.report">
<field name="name">加班单</field>
+70 -28
View File
@@ -342,46 +342,88 @@ class WeComApps(models.Model):
return True, result_data
return False, result_data.get("errmsg", "")
# @api.model
# def generate_oauth_login_url(self, target_url, category='default'):
# """
# 生成企业微信OAuth登录链接,用于在企业微信消息中发送
#
# 参数:
# target_url: 登录成功后要跳转的目标URL(完整URL或相对路径)
#
# 返回:
# OAuth登录链接URL
# """
# base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
# # 如果target_url不是完整URL,补全为完整URL
# if not target_url.startswith('http'):
# if target_url.startswith('/'):
# target_url = f"{base_url}{target_url}"
# else:
# target_url = f"{base_url}/{target_url}"
# # 编码目标URL作为state参数
# encoded_target_url = quote(target_url, safe='')
# # 编码回调URI
# redirect_uri = quote(f'{base_url}/wechat/login_by_code', safe='')
#
# # 企业微信OAuth参数
# if category == 'oa':
# agent_id = self.env['wecom.apps'].search([('name', '=', '审批消息通知')])['agent_id']
# appid = self.env['wecom.apps'].search([('name', '=', '审批消息通知')])['corpid']
# else:
# appid = 'wwc955c117b738b052'
# agent_id = '1000120'
#
# # 生成OAuth登录链接
# oauth_url = (
# f'https://open.weixin.qq.com/connect/oauth2/authorize?'
# f'appid={appid}&'
# f'redirect_uri={redirect_uri}&'
# f'response_type=code&'
# f'scope=snsapi_base&'
# f'state={encoded_target_url}&'
# f'agentid={agent_id}#wechat_redirect'
# )
#
# return oauth_url
@api.model
def generate_oauth_login_url(self, target_url, category='default'):
def generate_oauth_login_url(self, target_url, user_id=None):
"""
生成企业微信OAuth登录链接,用于在企业微信消息中发送
user_id = record.employee_id.user_id.id if record.employee_id.user_id else None
url = self.sudo().env["wecom.apps"].generate_oauth_login_url(target_url, user_id=user_id)
生成企业微信免登录链接,用于在企业微信消息中发送
与 /wechat/login_by_user_id 接口联动
参数:
target_url: 登录成功后要跳转的目标URL(完整URL或相对路径)
user_id: 用户ID (res.users的id),必需参数
返回:
OAuth登录链接URL
免登录链接URL,格式: /wechat/login_by_user_id?user_id=xxx&redirect_url=xxx
"""
if not user_id:
_logger.warning("generate_oauth_login_url: user_id 参数未提供,无法生成免登录链接")
return target_url # 如果未提供user_id,返回原始URL
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
# 如果target_url不是完整URL,补全为完整URL
if not target_url.startswith('http'):
if target_url.startswith('/'):
target_url = f"{base_url}{target_url}"
else:
target_url = f"{base_url}/{target_url}"
# 编码目标URL作为state参数
# 编码目标URL作为redirect_url参数
encoded_target_url = quote(target_url, safe='')
# 编码回调URI
redirect_uri = quote(f'{base_url}/wechat/login_by_code', safe='')
# 企业微信OAuth参数
if category == 'oa':
agent_id = self.env['wecom.apps'].search([('name', '=', '审批消息通知')])['agent_id']
appid = self.env['wecom.apps'].search([('name', '=', '审批消息通知')])['corpid']
else:
appid = 'wwc955c117b738b052'
agent_id = '1000120'
# 生成OAuth登录链接
oauth_url = (
f'https://open.weixin.qq.com/connect/oauth2/authorize?'
f'appid={appid}&'
f'redirect_uri={redirect_uri}&'
f'response_type=code&'
f'scope=snsapi_base&'
f'state={encoded_target_url}&'
f'agentid={agent_id}#wechat_redirect'
# 生成免登录链接,使用 /wechat/login_by_user_id 接口
login_url = (
f'{base_url}/wechat/login_by_user_id?'
f'user_id={user_id}&'
f'redirect_url={encoded_target_url}'
)
return oauth_url
return login_url
+113
View File
@@ -154,3 +154,116 @@ class YuthonWillTask(http.Controller):
'code': 200,
'message': '数据创建成功'
})
@http.route('/phone/employee/self', type='http', auth="none", csrf=False, cors='*')
def phone_employee_self(self, **kw):
"""
relation: 'ilike'
"""
value = kw.get('value', False)
domain = []
if value:
domain.append(('name', 'ilike', value))
# users_id = int(kw.get('users_id'))
# user = request.env['res.users'].sudo().browse(int(users_id))
# employee_id = user.with_company(user.company_id.id).employee_id.id
records = request.env['hr.employee'].sudo().search(domain, limit=15)
data = records.read([])
return json.dumps({'data': data, 'code': 200, 'message': ''})
@http.route('/phone/employee/driver', type='http', auth="none", csrf=False, cors='*')
def phone_employee_driver(self, **kw):
"""
relation: 'ilike', '=', '!='
"""
feild = kw.get('feild', False)
relation = kw.get('relation', False)
value = kw.get('value', False)
domain = []
if feild and value and relation:
domain.append((feild, relation, value))
# users_id = int(kw.get('users_id'))
# user = request.env['res.users'].sudo().browse(int(users_id))
# employee_id = user.with_company(user.company_id.id).employee_id.id
records = request.env['hr.employee'].sudo().search(domain, limit=15)
data = records.read([])
return json.dumps({'data': data, 'code': 200, 'message': ''})
@http.route('/phone/task/time', type='http', auth="none", csrf=False, cors='*')
def phone_task_time(self, **kw):
"""
relation: 'ilike'
"""
value = kw.get('value', False)
domain = []
if value:
domain.append(('name', 'ilike', value))
# users_id = int(kw.get('users_id'))
# user = request.env['res.users'].sudo().browse(int(users_id))
# employee_id = user.with_company(user.company_id.id).employee_id.id
records = request.env['yuthon.task.time'].sudo().search(domain, limit=15)
data = records.read([])
return json.dumps({'data': data, 'code': 200, 'message': ''})
@http.route('/phone/task/create', type='http', auth="none", csrf=False, cors='*')
def phone_task_create(self, **kw):
"""
record_id : 记录id(根据这个判断是否创建还是更新,创建的时候不传,更新的时候传)
request_hour_from:开始时间
request_hour_to: 结束时间
priority: 优先级
name: 任务内容
remarks: 备注
employee_ids: 关联员工
employee_ids2: 关联司机
task_time_ids: 提醒
address: 地址
start_date: 任务日期
"""
employee_ids = kw.get('employee_ids', [])
employee_ids2 = kw.get('employee_ids2', [])
task_time_ids = kw.get('task_time_ids', [])
if not isinstance(task_time_ids, list):
return json.dumps({'data': '', 'code': 201, 'message': '提醒参数错误'})
if not isinstance(employee_ids2, list):
return json.dumps({'data': '', 'code': 201, 'message': '司机参数错误'})
if not isinstance(employee_ids, list):
return json.dumps({'data': '', 'code': 201, 'message': '关联员工参数错误'})
data = {
'request_hour_from': kw.get('request_hour_from', False),
'request_hour_to': kw.get('request_hour_to', False),
'priority': kw.get('priority', False),
'name': kw.get('name', False),
'remarks': kw.get('remarks', False),
'employee_ids': [(6, 0, employee_ids)],
'employee_ids2': [(6, 0, employee_ids2)],
'task_time_ids': [(6, 0, task_time_ids)],
'address': kw.get('address', False),
'start_date': kw.get('start_date', False)
}
record_id = kw.get('record_id', False)
if record_id:
# 获取要更新的日程
record = request.env['yuthon.task.time'].sudo().browse(int(record_id))
record.sudo().write(data)
else:
#创建日程
users_id = int(kw.get('users_id'))
user = request.env['res.users'].sudo().browse(int(users_id))
request.env.user = user
record = request.env['yuthon.task.time'].sudo().create(data)
# users_id = int(kw.get('users_id'))
# user = request.env['res.users'].sudo().browse(int(users_id))
# employee_id = user.with_company(user.company_id.id).employee_id.id
return json.dumps({'data': record.id, 'code': 200, 'message': ''})
@http.route('/phone/task/unlink', type='http', auth="none", csrf=False, cors='*')
def phone_task_unlink(self, **kw):
record_id = kw.get('record_id', False)
if record_id:
# 获取要更新的日程
record = request.env['yuthon.task.time'].sudo().browse(int(record_id))
record.sudo().unlink()
else:
return json.dumps({'data': '', 'code': 201, 'message': '记录不存在'})
return json.dumps({'data': 'success', 'code': 200, 'message': ''})
+4 -17
View File
@@ -59,24 +59,11 @@ class YuthonWillTask(models.Model):
is_this_company = fields.Boolean(string='本公司', default=True)
task_state = fields.Selection([('will', '待办'), ('done', '已办'), ('cancel', '取消')], default='will', string='状态', store=True)
users_ids = fields.Many2many(
'res.users',
relation='yuthon_will_task_users_rel', #
column1='task_id',
column2='user_id',
string='用户',
store=True,
index=True,
default=lambda self: self.env.user
)
users_ids = fields.Many2many('res.users', relation='yuthon_will_task_users_rel', column1='task_id', column2='user_id',
string='用户', store=True, index=True, default=lambda self: self.env.user)
self_users_ids = fields.Many2many(
'res.users',
relation='yuthon_will_task_current_users_rel',
column1='task_id',
column2='user_id',
string="当前经办人",
store=True, default=lambda self: [(6, 0, [self.env.user.id])]
self_users_ids = fields.Many2many('res.users',
relation='yuthon_will_task_current_users_rel',column1='task_id', column2='user_id', string="当前经办人", store=True, default=lambda self: [(6, 0, [self.env.user.id])]
)
employee_id = fields.Many2one('hr.employee', string="经办人", default=lambda self: self.env.user.employee_id)