提交 b1765c36 编写于 作者: 楼国栋

Merge branch 'feature/mp_weixin_menu' into 'develop'

微信公众号菜单配置功能

See merge request o2oa/o2oa!3469
......@@ -9,6 +9,8 @@ import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.program.center.core.entity.MPWeixinMenu;
import java.util.List;
/**
* Created by fancyLou on 3/12/21.
* Copyright © 2021 O2. All rights reserved.
......@@ -26,7 +28,15 @@ public class ActionDeleteMenu extends BaseAction {
if (menu == null) {
throw new ExceptionNotExist();
}
//同时删除下级菜单
List<MPWeixinMenu> list = emc.listEqual(MPWeixinMenu.class, MPWeixinMenu.parentId_FIELDNAME, menu.getId());
emc.beginTransaction(MPWeixinMenu.class);
if (list != null && !list.isEmpty()) {
for (int i = 0; i < list.size(); i++) {
MPWeixinMenu child = list.get(i);
emc.remove(child, CheckRemoveType.all);
}
}
emc.remove(menu, CheckRemoveType.all);
emc.commit();
Wo wo = new Wo();
......
package com.x.program.center.jaxrs.mpweixin;
import com.google.gson.JsonElement;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.entity.annotation.CheckPersistType;
import com.x.base.core.project.bean.WrapCopier;
import com.x.base.core.project.bean.WrapCopierFactory;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.tools.ListTools;
import com.x.organization.core.entity.Person;
import com.x.program.center.core.entity.MPWeixinMenu;
import org.apache.commons.lang3.StringUtils;
/**
* Created by fancyLou on 3/12/21.
* Copyright © 2021 O2. All rights reserved.
*/
public class ActionUpdateMenu extends BaseAction {
private static Logger logger = LoggerFactory.getLogger(ActionUpdateMenu.class);
ActionResult<Wo> execute(String id, JsonElement jsonElement) throws Exception {
ActionResult<Wo> result = new ActionResult<>();
logger.debug("update menu : {}.", jsonElement);
if (StringUtils.isBlank(id)) {
throw new ExceptionNotEmpty("id");
}
try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
MPWeixinMenu menu = emc.find(id, MPWeixinMenu.class);
Wi wi = this.convertToWrapIn(jsonElement, Wi.class);
if (StringUtils.isBlank(wi.getName())) {
throw new ExceptionNotEmpty("name");
}
String type = wi.getType();
if (StringUtils.isNotBlank(type)) { //type 为空,是空菜单,一般作为父菜单用的
if ("click".equals(type)) {
if (StringUtils.isBlank(wi.getKey())) {
throw new ExceptionNotEmpty("key");
}
if (StringUtils.isBlank(wi.getContent())) {
throw new ExceptionNotEmpty("content");
}
} else if ("view".equals(type)) {
if (StringUtils.isBlank(wi.getUrl())) {
throw new ExceptionNotEmpty("url");
}
} else if ("miniprogram".equals(type)) {
if (StringUtils.isBlank(wi.getUrl())) {
throw new ExceptionNotEmpty("url");
}
if (StringUtils.isBlank(wi.getAppid())) {
throw new ExceptionNotEmpty("appid");
}
if (StringUtils.isBlank(wi.getPagepath())) {
throw new ExceptionNotEmpty("pagepath");
}
} else if(WX_MSG_RECEIVE_EVENT_SUBSCRIBE.equals(type)) { //关注事件 添加了之后会发送文本消息
wi.setKey(WX_MSG_RECEIVE_EVENT_SUBSCRIBE);
if (StringUtils.isBlank(wi.getContent())) {
throw new ExceptionNotEmpty("content");
}
} else {
throw new ExceptionTypeNotSupport();
}
}
Wi.copier.copy(wi, menu);
emc.beginTransaction(MPWeixinMenu.class);
emc.check(menu, CheckPersistType.all);
emc.commit();
Wo wo = Wo.copier.copy(menu);
result.setData(wo);
return result;
}
}
public static class Wo extends MPWeixinMenu {
private static final long serialVersionUID = 3434938936805201380L;
static WrapCopier<MPWeixinMenu, Wo> copier = WrapCopierFactory.wo(MPWeixinMenu.class, Wo.class, null,
JpaObject.FieldsInvisible);
}
public static class Wi extends MPWeixinMenu {
private static final long serialVersionUID = 4704212776164514486L;
static WrapCopier<Wi, MPWeixinMenu> copier = WrapCopierFactory.wi(Wi.class, MPWeixinMenu.class, null,
ListTools.toList(JpaObject.FieldsUnmodify));
}
}
......@@ -117,6 +117,26 @@ public class MPWeixinAction extends StandardJaxrsAction {
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
@JaxrsMethodDescribe(value = "更新一个菜单项.", action = ActionUpdateMenu.class)
@POST
@Path("menu/update/{id}")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void menuUpdate(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request, @PathParam("id") String id,
JsonElement jsonElement) {
ActionResult<ActionUpdateMenu.Wo> result = new ActionResult<>();
try {
result = new ActionUpdateMenu().execute(id, jsonElement);
} catch (Exception e) {
logger.error(e);
result.error(e);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
@JaxrsMethodDescribe(value = "删除一个菜单项.", action = ActionDeleteMenu.class)
@DELETE
@Path("menu/delete/{id}")
......
<div class="menu_setting_area" data-o2-element="mpwxMenuNode">
<div style="margin: 30px 0 30px 0;font-size:16px;font-weight: 400;">⚠️ 微信公众号菜单功能需要先启用相关的配置文件[mpweixin.json],并到微信的公众号管理后台,开发模块中启用服务器配置!</div>
<!-- 编辑区 -->
<div class="menu_preview_area">
<div class="mobile_menu_preview">
<div class="mobile_hd tc">公众号</div>
<div class="mobile_bd">
<ul class="pre_menu_list grid_line" data-o2-element="mpwxMenuListNode">
<!-- 菜单展现 -->
</ul>
</div>
</div>
</div>
<div class="menu_form_area">
<div class="portable_editor to_left">
<div class="editor_inner">
<div class="global_mod float_layout menu_form_hd js_second_title_bar" data-o2-element="mpwxMenuFormHeaderNode">
<!-- 菜单名称 和 删除按钮 -->
</div>
<div class="menu_form_bd" data-o2-element="mpwxMenuFormNode">
<!-- 菜单表单内容 -->
</div>
</div>
</div>
</div>
<!-- 发布按钮 -->
<div class="btn-box" style="justify-content: start;margin-top: 30px;" >
<span class="btn btn_input btn_primary" data-o2-element="mpwxPublishBtnNode"><button>发布到微信公众号</button></span>
</div>
</div>
\ No newline at end of file
a {
color: #44b549;
text-decoration: none;
background-color: transparent;
outline: none;
cursor: pointer;
-webkit-transition: color 0.3s;
transition: color 0.3s;
-webkit-text-decoration-skip: objects;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 0.5em;
color: rgba(0, 0, 0, 0.85);
font-weight: 500;
}
ul, ol {
padding-left: 0;
list-style-type: none;
}
ol, ul, dl {
margin-top: 0;
margin-bottom: 0;
}
p {
margin-top: 0;
margin-bottom: 0;
}
input[type='radio'], input[type='checkbox'] {
-webkit-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
}
input[type='text'], input[type='password'], input[type='number'], textarea {
-webkit-appearance: none;
}
.menu_setting_area {
margin: 14px 30px 0;
}
.menu_preview_area {
float: left;
margin-right: 12px;
position: relative;
}
.menu_form_area {
display: table-cell;
vertical-align: top;
float: none;
width: auto;
min-width: 500px;
}
.menu_setting_area:after {
content: "\200B";
display: block;
height: 0;
clear: both;
}
.mobile_menu_preview {
width: 294px;
background-size: contain;
}
.mobile_menu_preview {
position: relative;
width: 317px;
height: 580px;
background: transparent url(../x_component_Setting/$Main/default/mpweixin/bg_mobile_head_default49d02c.png) no-repeat 0 0;
background-position: 0 0;
border: 1px solid #e7e7eb;
}
.mobile_menu_preview .mobile_hd {
color: #fff;
text-align: center;
padding-top: 30px;
font-size: 15px;
width: auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-wrap: normal;
margin: 0 30px;
}
.menu_preview_area .pre_menu_list {
position: absolute;
bottom: 0;
left: 0;
right: 0;
border-top: 1px solid #e7e7eb;
background: transparent url(../x_component_Setting/$Main/default/mpweixin/bg_mobile_foot_default49d02c.png) no-repeat 0 0;
background-position: 0 0;
background-repeat: no-repeat;
padding-left: 43px;
}
.pre_menu_item {
position: relative;
float: left;
line-height: 50px;
text-align: center;
}
.size1of3 {
width: 33.33%;
}
.menu_preview_area .pre_menu_item:first-child .pre_menu_link {
border-left-width: 0;
}
.pre_menu_item a {
display: block;
width: auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-wrap: normal;
color: #616161;
text-decoration: none;
}
.pre_menu_link {
border-left: 1px solid #e7e7eb;
}
.no_extra.grid_item {
float: none;
width: auto;
overflow: hidden;
}
.sub_pre_menu_box {
position: absolute;
left: 0;
width: 100%;
border: 1px solid #d0d0d0;
bottom: 60px;
background-color: #fafafa;
border-top-width: 0;
}
.menu_preview_area .sub_pre_menu_inner {
display: block;
border-top: 1px solid #e7e7eb;
width: auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-wrap: normal;
cursor: pointer;
}
.sub_pre_menu_list li a {
padding: 0 .5em;
}
.pre_menu_item a {
display: block;
width: auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-wrap: normal;
color: #616161;
text-decoration: none;
}
.menu_preview_area .pre_menu_item.current .pre_menu_link {
border: 1px solid #07c160;
line-height: 48px;
background-color: #fff;
color: #07c160;
}
.menu_preview_area .icon14_menu_add {
background: url(../x_component_Setting/$Main/default/mpweixin/index_z49d030.png) 0 0 no-repeat;
width: 14px;
height: 14px;
vertical-align: middle;
display: inline-block;
margin-top: -2px;
}
.menu_preview_area .sub_pre_menu_box {
bottom: 60px;
background-color: #fafafa;
border-top-width: 0;
}
.menu_preview_area .sub_pre_menu_list li:first-child {
border-top: 1px solid #d0d0d0;
}
.menu_preview_area .sub_pre_menu_list li {
line-height: 44px;
border: 1px solid transparent;
margin: 0 -1px -1px;
}
.menu_preview_area .sub_pre_menu_list li.current {
background-color: #fff;
border: 1px solid #07c160;
position: relative;
z-index: 1;
line-height: 45px;
}
.menu_preview_area .sub_pre_menu_list li.current a {
color: #07c160;
}
.sub_pre_menu_box .arrow {
position: absolute;
left: 50%;
margin-left: -6px;
}
.sub_pre_menu_box .arrow_in {
bottom: -5px;
display: inline-block;
width: 0;
height: 0;
border-width: 6px;
border-style: dashed;
border-color: transparent;
border-bottom-width: 0;
border-top-color: #fafafa;
border-top-style: solid;
}
.sub_pre_menu_box .arrow_out {
bottom: -6px;
display: inline-block;
width: 0;
height: 0;
border-width: 6px;
border-style: dashed;
border-color: transparent;
border-bottom-width: 0;
border-top-color: #d0d0d0;
border-top-style: solid;
}
.grid_line:after {
content: "\200B";
display: block;
height: 0;
clear: both;
}
.menu_setting_area:after {
content: "\200B";
display: block;
height: 0;
clear: both;
}
.portable_editor.to_left {
padding-left: 12px;
}
.portable_editor {
position: relative;
}
.menu_form_area .editor_inner {
min-height: 560px;
padding-bottom: 20px;
}
.portable_editor .editor_inner {
padding: 0 20px 5px;
background-color: #f4f5f9;
border: 1px solid #e7e7eb;
border-radius: 0;
-moz-border-radius: 0;
-webkit-border-radius: 0;
box-shadow: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
}
.menu_form_hd {
padding: 9px 0;
border-bottom: 1px solid #e7e7eb;
}
.global_mod.float_layout .global_info {
float: left;
}
.menu_form_hd h4 {
font-weight: 400;
}
.global_mod .global_extra {
text-align: right;
}
.global_mod.float_layout:after {
content: "\200B";
display: block;
height: 0;
clear: both;
}
.frm_textarea {
height: 80px;
margin: 4px 0;
}
.frm_input {
height: 22px;
margin: 4px 0;
}
.frm_input, .frm_textarea {
width: 100%;
background-color: transparent;
border: 0;
outline: 0;
}
.portable_editor .frm_control_group {
margin-bottom: 10px;
}
.portable_editor .frm_control_group {
margin-top: 30px;
margin-bottom: 30px;
padding-bottom: 0;
}
.menu_form_area .frm_label {
width: 5em;
}
.menu_content .frm_control_group {
margin-top: 0;
}
.frm_label {
float: left;
width: 5em;
margin-top: .3em;
margin-right: 1em;
font-size: 14px;
}
.portable_editor .frm_label .title {
font-weight: 400;
font-style: normal;
}
.frm_controls {
display: table-cell;
vertical-align: top;
float: none;
width: auto;
}
.frm_vertical_pt {
padding-top: .3em;
}
.frm_input_box.counter_in {
width: 228px;
padding-right: 60px;
}
.frm_textarea_box.counter_in {
width: 228px;
padding-right: 60px;
}
.frm_textarea_box {
display: inline-block;
position: relative;
line-height: 30px;
vertical-align: middle;
width: 278px;
font-size: 14px;
padding: 0 10px;
border: 1px solid #e7e7eb;
box-shadow: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
border-radius: 0;
-moz-border-radius: 0;
-webkit-border-radius: 0;
background-color: #fff;
}
.frm_input_box {
display: inline-block;
position: relative;
height: 30px;
line-height: 30px;
vertical-align: middle;
width: 278px;
font-size: 14px;
padding: 0 10px;
border: 1px solid #e7e7eb;
box-shadow: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
border-radius: 0;
-moz-border-radius: 0;
-webkit-border-radius: 0;
background-color: #fff;
}
.menu_form_area .frm_tips, .menu_form_area .frm_msg {
width: auto;
}
.frm_radio_label, .frm_checkbox_label {
display: inline-block;
text-align: left;
cursor: pointer;
margin-right: 1em;
}
.icon_radio {
background: url(../x_component_Setting/$Main/default/mpweixin/base_z49d030.png) 0 -140px no-repeat;
width: 16px;
height: 16px;
vertical-align: middle;
display: inline-block;
}
.icon_radio.selected, .selected .icon_radio {
background: url(../x_component_Setting/$Main/default/mpweixin/base_z49d030.png) 0 -160px no-repeat;
}
.icon_radio, .icon_checkbox {
margin-right: 3px;
margin-top: -2px;
*margin-top: 0;
}
.frm_radio, .frm_checkbox {
position: absolute;
left: -999em;
}
.frm_tips {
position: relative;
}
.frm_tips, .frm_msg {
padding-top: 4px;
width: 300px;
}
.frm_tips {
color: #9a9a9a;
}
.frm_msg.fail {
color: #fa5151;
}
.menu_content_tips {
padding-bottom: 10px;
}
.tips_global {
color: #9a9a9a;
}
.dn {
display: none;
}
.menu_content {
padding: 16px 20px;
border: 1px solid #e7e7eb;
background-color: #fff;
}
.btn-box {
padding: 20px 0 30px 0;
display: flex;
justify-content: center;
align-items: center;
}
.btn_primary {
background-color: #07c160;
background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0,#07c160),to(#07c160));
background-image: linear-gradient(to bottom,#07c160 0,#07c160 100%);
border-color: #07c160;
color: #fff;
}
.btn {
display: inline-block;
overflow: visible;
margin-left: .5em;
margin-right: .5em;
min-width: 80px !important;
padding: 0;
height: 30px;
line-height: 30px;
vertical-align: middle;
text-align: center;
text-decoration: none;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
font-size: 14px;
border-width: 1px;
border-style: solid;
cursor: pointer;
}
.btn button {
color: #fff;
width: 90%;
display: block;
height: 100%;
background-color: transparent;
border: 0;
outline: 0;
overflow: visible;
cursor: pointer;
}
\ No newline at end of file
......@@ -336,6 +336,11 @@ MWF.xApplication.Setting.MobileExplorer = new Class({
"text": this.app.lp.tab_mobile_style,
"icon": "style",
"action": "loadMobileStyleSetting"
},
{
"text": this.app.lp.tab_mobile_mpweixin_menu,
"icon": "style",
"action": "loadMPWeixinMenuSetting"
}
];
},
......@@ -363,6 +368,14 @@ MWF.xApplication.Setting.MobileExplorer = new Class({
json = null;
checkData();
}.bind(this));
//微信菜单数据
o2.Actions.load("x_program_center").MPWeixinAction.menuWeixinList(function (json) {
if (json.data && json.data.button) {
this.mpweixinListData = json.data.button;
} else {
this.mpweixinListData = [];
}
}.bind(this));
},
......@@ -391,6 +404,14 @@ MWF.xApplication.Setting.MobileExplorer = new Class({
}else{
this.loadDataBack = function(){this.loadMobileStyleSetting(item)}.bind(this);
}
},
loadMPWeixinMenuSetting: function(item) {
if (MWF.AC.isAdministrator()) if (this.proxyData && this.nativeData && this.imagesData){
this.mpweixinMenuSetting = new MWF.xApplication.Setting.MPWeixinMenuSettingDocument(this, this.contentAreaNode);
item.store("content", this.mpweixinMenuSetting);
}else{
this.loadDataBack = function(){this.loadMPWeixinMenuSetting(item)}.bind(this);
}
}
});
MWF.xApplication.Setting.CloudExplorer = new Class({
......
......@@ -18,6 +18,7 @@ MWF.xApplication.Setting.LP = {
"tab_mobile_connect": "连接配置",
"tab_mobile_module": "模块配置",
"tab_mobile_style": "样式配置",
"tab_mobile_mpweixin_menu": "公众号菜单配置",
"tab_ui_login": "登录页样式",
"tab_ui_index": "主页样式",
......@@ -169,6 +170,50 @@ MWF.xApplication.Setting.LP = {
"mobile_style_imgs_defaultTitle": "默认图片确认",
"mobile_style_imgs_defaultInfor": "您确定要将{name},替换成默认图像吗?",
"mobile_mpweixin_menu_msg_publish_2_wxmp": "注意!当前操作会把所有保存的菜单数据覆盖到微信公众号,确定要继续吗?",
"mobile_mpweixin_menu_msg_publish_success": "发布成功,会在24小时后在手机端同步显示!",
"mobile_mpweixin_menu_msg_first_max_len": "一级菜单最多只能创建3个!",
"mobile_mpweixin_menu_msg_sub_max_len": "二级菜单最多只能创建5个!",
"mobile_mpweixin_menu_msg_parent_no_save": "上级菜单数据未保存,请先保存数据!",
"mobile_mpweixin_menu_deleteBtnName_label": "删除菜单",
"mobile_mpweixin_menu_default_new_name": "新增菜单",
"mobile_mpweixin_menu_form_name_label": "菜单名称",
"mobile_mpweixin_menu_form_name_error_empty": "菜单名称不能为空!",
"mobile_mpweixin_menu_form_name_error_max_len": "菜单名称字数不能超过4个!",
"mobile_mpweixin_menu_form_name_error": "字数超过上限",
"mobile_mpweixin_menu_form_name_tips": "仅支持中英文和数字,字数不超过4个",
"mobile_mpweixin_menu_form_order_label": "菜单排序号",
"mobile_mpweixin_menu_form_order_error_empty": "菜单排序号不能为空!",
"mobile_mpweixin_menu_form_order_error_not_number": "菜单排序号只能输入数字!",
"mobile_mpweixin_menu_form_order_error_max_len": "菜单排序号字数不能超过6个!",
"mobile_mpweixin_menu_form_order_error": "字数超过上限",
"mobile_mpweixin_menu_form_order_tips": "仅支持数字,字数不超过6个,排序按照字符串排序",
"mobile_mpweixin_menu_form_radio_label": "菜单内容",
"mobile_mpweixin_menu_form_radio_type_msg": "发送消息",
"mobile_mpweixin_menu_form_radio_type_url": "跳转网页",
"mobile_mpweixin_menu_form_radio_type_miniprogram": "跳转小程序",
"mobile_mpweixin_menu_form_type_msg_tips": "点击该菜单会发送下列文字给用户,未认证订阅号不支持文字消息",
"mobile_mpweixin_menu_form_type_msg_label": "文字消息",
"mobile_mpweixin_menu_form_type_msg_error_empty": "文字消息内容不能为空!",
"mobile_mpweixin_menu_form_type_url_tips": "点击该菜单会跳到以下链接",
"mobile_mpweixin_menu_form_type_url_label": "页面地址",
"mobile_mpweixin_menu_form_type_url_error_empty": "页面地址不能为空!",
"mobile_mpweixin_menu_form_type_miniprogram_tips": "点击该菜单会跳到以下小程序",
"mobile_mpweixin_menu_form_type_miniprogram_appid_label": "小程序ID",
"mobile_mpweixin_menu_form_type_miniprogram_appid_placeholder": "小程序ID,请到微信的小程序管理后台查看",
"mobile_mpweixin_menu_form_type_miniprogram_appid_error_empty": "小程序ID不能为空!",
"mobile_mpweixin_menu_form_type_miniprogram_path_label": "小程序路径",
"mobile_mpweixin_menu_form_type_miniprogram_path_placeholder": "小程序路径,请到微信的小程序管理后台查看",
"mobile_mpweixin_menu_form_type_miniprogram_path_error_empty": "小程序路径不能为空!",
"mobile_mpweixin_menu_form_type_miniprogram_url_label": "备用网页",
"mobile_mpweixin_menu_form_type_miniprogram_url_placeholder": "备用网页,旧版微信会打开这个备用网页",
"mobile_mpweixin_menu_form_type_miniprogram_url_error_empty": "备用网页不能为空!",
"mobile_mpweixin_menu_save_success": "保存数据成功!",
"mobile_mpweixin_menu_delete_alert_msg": "确认要删除这条数据吗,会同时删除它的子菜单?",
"mobile_mpweixin_menu_delete_success": "删除数据成功!",
"save": "保存",
"alert": "提示",
"imgSize": "图片尺寸:",
"defaultImg": "默认图片",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册