diff --git a/keke_window_title/__init__.py b/keke_window_title/__init__.py
new file mode 100644
index 000000000..cde864bae
--- /dev/null
+++ b/keke_window_title/__init__.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+from . import models
diff --git a/keke_window_title/__manifest__.py b/keke_window_title/__manifest__.py
new file mode 100644
index 000000000..d071aa53c
--- /dev/null
+++ b/keke_window_title/__manifest__.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+{
+ 'license': 'LGPL-3',
+ 'name': "自定义窗口标题和图标",
+ 'summary': "自定义窗口标题和图标",
+ 'version': '1.0',
+ 'depends': ['base_setup'],
+ 'data': [
+ 'templates/web_layout.xml',
+ 'views/res_config.xml',
+ ],
+ 'assets': {
+ 'web.assets_backend': [
+ 'keke_window_title/static/src/js/keke_window_title.js',
+ ],
+ },
+ 'installable': True,
+ 'auto_install': False,
+ 'application': False,
+}
\ No newline at end of file
diff --git a/keke_window_title/models/__init__.py b/keke_window_title/models/__init__.py
new file mode 100644
index 000000000..6a905aa87
--- /dev/null
+++ b/keke_window_title/models/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+
+from . import ir_ui_view
+from . import res_config
+from . import res_company
diff --git a/keke_window_title/models/ir_ui_view.py b/keke_window_title/models/ir_ui_view.py
new file mode 100644
index 000000000..633dbc950
--- /dev/null
+++ b/keke_window_title/models/ir_ui_view.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+import logging
+
+from odoo import api, fields, models, _
+
+_logger = logging.getLogger(__name__)
+
+class View(models.Model):
+ _inherit = 'ir.ui.view'
+
+ @api.model
+ def _render_template(self, template, values=None):
+ if template in ['web.login', 'web.webclient_bootstrap']:
+ if not values:
+ values = {}
+ values["title"] = self.env['ir.config_parameter'].sudo().get_param("web.base.title", "")
+ return super(View, self)._render_template(template, values)
diff --git a/keke_window_title/models/res_company.py b/keke_window_title/models/res_company.py
new file mode 100644
index 000000000..bfaefbdc0
--- /dev/null
+++ b/keke_window_title/models/res_company.py
@@ -0,0 +1,20 @@
+from odoo import models, fields
+
+
+class ResCompany(models.Model):
+
+ _inherit = 'res.company'
+
+ #----------------------------------------------------------
+ # Fields
+ #----------------------------------------------------------
+
+ favicon = fields.Binary(
+ string="Company Favicon",
+ attachment=True
+ )
+
+ background_image = fields.Binary(
+ string='Apps Menu Background Image',
+ attachment=True
+ )
diff --git a/keke_window_title/models/res_config.py b/keke_window_title/models/res_config.py
new file mode 100644
index 000000000..0e28039d3
--- /dev/null
+++ b/keke_window_title/models/res_config.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+
+import logging
+
+from odoo import api, fields, models, _
+
+_logger = logging.getLogger(__name__)
+
+CONFIG_PARAM_KEKE_WINDOW_TITLE = "web.base.title"
+
+class ResConfigSettings(models.TransientModel):
+ _inherit = 'res.config.settings'
+
+ keke_window_title = fields.Char('Window Title')
+
+ theme_favicon = fields.Binary(
+ related='company_id.favicon',
+ readonly=False
+ )
+
+ @api.model
+ def get_values(self):
+ res = super(ResConfigSettings, self).get_values()
+ ir_config = self.env['ir.config_parameter'].sudo()
+ keke_window_title = ir_config.get_param(CONFIG_PARAM_KEKE_WINDOW_TITLE, default='')
+ res.update(
+ keke_window_title=keke_window_title
+ )
+ return res
+
+ def set_values(self):
+ super(ResConfigSettings, self).set_values()
+ ir_config = self.env['ir.config_parameter'].sudo()
+ ir_config.set_param(CONFIG_PARAM_KEKE_WINDOW_TITLE, self.keke_window_title or "")
diff --git a/keke_window_title/static/src/js/web_window_title.js b/keke_window_title/static/src/js/web_window_title.js
new file mode 100644
index 000000000..11eb79c99
--- /dev/null
+++ b/keke_window_title/static/src/js/web_window_title.js
@@ -0,0 +1,12 @@
+/** @odoo-module alias=web.window.title **/
+
+import { WebClient } from "@web/webclient/webclient";
+import {patch} from "@web/core/utils/patch";
+
+patch(WebClient.prototype, {
+ setup() {
+ const title = document.title;
+ super.setup();
+ this.title.setParts({ zopenerp: title });
+ }
+});
diff --git a/keke_window_title/templates/web_layout.xml b/keke_window_title/templates/web_layout.xml
new file mode 100644
index 000000000..0d6b85232
--- /dev/null
+++ b/keke_window_title/templates/web_layout.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/keke_window_title/views/res_config.xml b/keke_window_title/views/res_config.xml
new file mode 100644
index 000000000..324d0f397
--- /dev/null
+++ b/keke_window_title/views/res_config.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+ res.config.settings.web.window.title
+ res.config.settings
+
+
+
+
窗口设置
+
+
+
+
窗口标题
+
+ 自定义 Web 窗口标题
+
+
+
+
+
+
+
窗口图标
+
+ 自定义 Web 窗口图标
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file