From 0de0a56fe1a485a29820d313e2f5ca230e4ff6f3 Mon Sep 17 00:00:00 2001 From: Admin Date: Thu, 15 Jan 2026 23:15:40 +0800 Subject: [PATCH 1/5] 2 --- yuthon_will_task/controllers/main.py | 113 +++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/yuthon_will_task/controllers/main.py b/yuthon_will_task/controllers/main.py index 57e74f74b..cd69c2b50 100644 --- a/yuthon_will_task/controllers/main.py +++ b/yuthon_will_task/controllers/main.py @@ -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': ''}) From e905c282dfc8d54e686269bd16289f471c41fed5 Mon Sep 17 00:00:00 2001 From: pengyuthon Date: Sun, 18 Jan 2026 18:04:04 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E6=8C=89=E9=92=AE=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/webclient/actions/client_actions.js | 39 +++++++- yuthon_wechat/models/wecom_apps.py | 98 +++++++++++++------ yuthon_will_task/models/yuthon_will_task.py | 21 +--- .../views/yuthon_will_task_views.xml | 2 +- 4 files changed, 112 insertions(+), 48 deletions(-) diff --git a/sun_badge_menu/static/src/webclient/actions/client_actions.js b/sun_badge_menu/static/src/webclient/actions/client_actions.js index 9036f0b1f..2d8e46fb8 100644 --- a/sun_badge_menu/static/src/webclient/actions/client_actions.js +++ b/sun_badge_menu/static/src/webclient/actions/client_actions.js @@ -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); diff --git a/yuthon_wechat/models/wecom_apps.py b/yuthon_wechat/models/wecom_apps.py index 40953572d..a9bf0f1eb 100644 --- a/yuthon_wechat/models/wecom_apps.py +++ b/yuthon_wechat/models/wecom_apps.py @@ -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 diff --git a/yuthon_will_task/models/yuthon_will_task.py b/yuthon_will_task/models/yuthon_will_task.py index dfe4620be..901eb3e05 100644 --- a/yuthon_will_task/models/yuthon_will_task.py +++ b/yuthon_will_task/models/yuthon_will_task.py @@ -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) diff --git a/yuthon_will_task/views/yuthon_will_task_views.xml b/yuthon_will_task/views/yuthon_will_task_views.xml index d2ee39c5a..72aea162a 100644 --- a/yuthon_will_task/views/yuthon_will_task_views.xml +++ b/yuthon_will_task/views/yuthon_will_task_views.xml @@ -24,7 +24,7 @@ -