1
0
mirror of https://github.com/chatopera/cosin.git synced 2025-06-16 18:30:03 +08:00

https://gitee.com/cskefu/cskefu/issues/I836RO add webim channel creation as billing resource

Signed-off-by: Hai Liang Wang <hai@chatopera.com>
This commit is contained in:
Hai Liang Wang 2023-09-25 09:43:07 +08:00
parent 3cb64fa664
commit 2e4a71c175
6 changed files with 186 additions and 55 deletions

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cskefu.cc.aspect;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.exception.BillingQuotaException;
import com.cskefu.cc.exception.BillingResourceException;
import com.cskefu.cc.model.Channel;
import com.cskefu.cc.model.User;
import com.cskefu.cc.proxy.LicenseProxy;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ChannelAspect {
private final static Logger logger = LoggerFactory.getLogger(ChannelAspect.class);
@Autowired
private LicenseProxy licenseProxy;
@Before("execution(* com.cskefu.cc.persistence.repository.ChannelRepository.save(..))")
public void beforeSave(final JoinPoint joinPoint) throws BillingResourceException, BillingQuotaException {
final Channel channel = (Channel) joinPoint.getArgs()[0];
logger.info("[beforeSave] before channel id {}, type {}", channel.getId(), channel.getType());
if (StringUtils.isBlank(channel.getId())) {
// create new Channel
if (StringUtils.equals(channel.getType(), MainContext.ChannelType.WEBIM.toString())) {
// create new WEBIM channel
licenseProxy.writeDownResourceUsageInStore(MainContext.BillingResource.CHANNELWEBIM, 1);
}
} else {
// update existed Channel
}
}
}

View File

@ -1,15 +1,15 @@
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.admin.channel;
@ -18,6 +18,7 @@ import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.controller.Handler;
import com.cskefu.cc.exception.BillingQuotaException;
import com.cskefu.cc.model.*;
import com.cskefu.cc.persistence.repository.ConsultInviteRepository;
import com.cskefu.cc.persistence.repository.OrganRepository;
@ -27,6 +28,8 @@ import com.cskefu.cc.proxy.OrganProxy;
import com.cskefu.cc.util.Base62;
import com.cskefu.cc.util.Menu;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Controller;
@ -37,6 +40,8 @@ import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
@ -48,6 +53,7 @@ import java.util.Map;
@Controller
@RequestMapping("/admin/im")
public class ChannelController extends Handler {
private final static Logger logger = LoggerFactory.getLogger(ChannelController.class);
@Autowired
private ChannelRepository snsAccountRes;
@ -93,40 +99,59 @@ public class ChannelController extends Handler {
return request(super.createView("/admin/channel/im/add"));
}
/**
* 创建新的网站渠道
*
* @param request
* @param channel
* @return
* @throws NoSuchAlgorithmException
*/
@RequestMapping("/save")
@Menu(type = "admin", subtype = "weixin")
@Menu(type = "admin", subtype = "im")
public ModelAndView save(HttpServletRequest request,
@Valid Channel channel) throws NoSuchAlgorithmException {
Organ currentOrgan = super.getOrgan(request);
String status = "new_webim_fail";
if (StringUtils.isNotBlank(channel.getBaseURL())) {
channel.setSnsid(Base62.encode(channel.getBaseURL()).toLowerCase());
int count = snsAccountRes.countBySnsid(channel.getSnsid());
if (count == 0) {
status = "new_webim_success";
channel.setType(MainContext.ChannelType.WEBIM.toString());
channel.setCreatetime(new Date());
User curr = super.getUser(request);
channel.setCreater(curr.getId());
channel.setOrgan(currentOrgan.getId());
try {
channel.setSnsid(Base62.encode(channel.getBaseURL()).toLowerCase());
int count = snsAccountRes.countBySnsid(channel.getSnsid());
if (count == 0) {
status = "new_webim_success";
channel.setType(MainContext.ChannelType.WEBIM.toString());
channel.setCreatetime(new Date());
User curr = super.getUser(request);
channel.setCreater(curr.getId());
channel.setOrgan(currentOrgan.getId());
snsAccountRes.save(channel);
snsAccountRes.save(channel);
/**
* 同时创建CousultInvite 记录
*/
CousultInvite coultInvite = invite.findBySnsaccountid(channel.getSnsid());
if (coultInvite == null) {
coultInvite = new CousultInvite();
coultInvite.setSnsaccountid(channel.getSnsid());
coultInvite.setCreate_time(new Date());
coultInvite.setName(channel.getName());
coultInvite.setOwner(channel.getCreater());
coultInvite.setSkill(false); // 不启动技能组
coultInvite.setConsult_skill_fixed(false); // 不绑定唯一技能组
coultInvite.setAi(false);
coultInvite.setAifirst(false);
invite.save(coultInvite);
/**
* 同时创建CousultInvite 记录
*/
CousultInvite coultInvite = invite.findBySnsaccountid(channel.getSnsid());
if (coultInvite == null) {
coultInvite = new CousultInvite();
coultInvite.setSnsaccountid(channel.getSnsid());
coultInvite.setCreate_time(new Date());
coultInvite.setName(channel.getName());
coultInvite.setOwner(channel.getCreater());
coultInvite.setSkill(false); // 不启动技能组
coultInvite.setConsult_skill_fixed(false); // 不绑定唯一技能组
coultInvite.setAi(false);
coultInvite.setAifirst(false);
invite.save(coultInvite);
}
}
} catch (Exception e) {
if (e instanceof UndeclaredThrowableException) {
logger.error("[save] BillingQuotaException", e);
if (StringUtils.startsWith(e.getCause().getMessage(), BillingQuotaException.SUFFIX)) {
status = e.getCause().getMessage();
}
} else {
logger.error("[save] err", e);
}
}
}

View File

@ -11,80 +11,136 @@
* Licensed under the Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0
*/
function processUserAddOrUpdateResult(responsecode, cb){
/**
* 处理系统用户的创建的返回值
* @param responsecode
* @param cb
*/
function processUserAddOrUpdateResult(responsecode, cb) {
switch (responsecode) {
case 'username_exist':
layer.msg('用户名存在,请重新填写',{icon: 2, time: 3000});
layer.msg('用户名存在,请重新填写', {icon: 2, time: 3000});
// 清空用户名
$('input[name="username"]').val("");
break;
case 'email_exist':
layer.msg('邮件存在,请重新填写',{icon: 2, time: 3000});
layer.msg('邮件存在,请重新填写', {icon: 2, time: 3000});
// 清空邮件
$('input[name="email"]').val("");
break;
case 'mobile_exist':
layer.msg('手机存在,请重新填写',{icon: 2, time: 3000});
layer.msg('手机存在,请重新填写', {icon: 2, time: 3000});
// 清空手机号
$('input[name="mobile"]').val("");
break;
case 'sip_account_exist':
layer.msg('SIP地址已经存在请重新填写',{icon: 2, time: 3000});
layer.msg('SIP地址已经存在请重新填写', {icon: 2, time: 3000});
// 清空SIP
$('input[name="sipaccount"]').val("");
break;
case 'extension_binded':
layer.msg('分机号已经被其他用户绑定',{icon: 2, time: 3000});
layer.msg('分机号已经被其他用户绑定', {icon: 2, time: 3000});
$('input[name="extensionid"]').val("");
break;
case 'extension_not_exist':
layer.msg('绑定分机不存在',{icon: 2, time: 3000});
layer.msg('绑定分机不存在', {icon: 2, time: 3000});
$('input[name="extensionid"]').val("");
break;
case 'pbxhost_not_exist':
layer.msg('指定的呼叫中心语音平台不存在',{icon: 2, time: 3000});
layer.msg('指定的呼叫中心语音平台不存在', {icon: 2, time: 3000});
$('input[name="pbxhostid"]').val("");
break;
case 't1':
layer.msg('当前用户坐席就绪或对话未结束,不能切换为非坐席',{icon: 2, time: 3000});
layer.msg('当前用户坐席就绪或对话未结束,不能切换为非坐席', {icon: 2, time: 3000});
break;
case 'new_user_success':
layer.msg('新用户创建成功',{icon: 1, time: 1000});
layer.msg('新用户创建成功', {icon: 1, time: 1000});
cb();
break;
case 'edit_user_success':
layer.msg('用户编辑成功',{icon: 1, time: 1000});
layer.msg('用户编辑成功', {icon: 1, time: 1000});
cb();
break;
default:
handleGeneralCodeInQueryPathOrApiResp(responsecode, cb);
}
}
/**
* 处理在 RedirectURL, API 中返回的 code 信息 status, msg, etc.
* code 为约定的返回值通过下面的函数进行展示
* @param code
* @param cb
*/
function handleGeneralCodeInQueryPathOrApiResp(code, cb) {
switch (code) {
case 'billingquotaexception.no_license_found':
layer.msg('【使用授权证书】证书不存在,联系系统超级管理员导入。',{icon: 2, time: 5000});
layer.msg('【使用授权证书】证书不存在,联系系统超级管理员导入。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break;
case 'billingquotaexception.response_unexpected':
layer.msg('【使用授权证书】证书商店返回异常,稍后再试。',{icon: 2, time: 5000});
layer.msg('【使用授权证书】证书商店返回异常,稍后再试。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break;
case 'billingquotaexception.invalid_request_body':
layer.msg('【使用授权证书】请求证书商店参数不合法,请获取最新软件代码。',{icon: 2, time: 5000});
layer.msg('【使用授权证书】请求证书商店参数不合法,请获取最新软件代码。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break;
case 'billingquotaexception.license_invalid':
layer.msg('【使用授权证书】证书商店中不存在该证书,请联系系统超级管理员导入。',{icon: 2, time: 5000});
layer.msg('【使用授权证书】证书商店中不存在该证书,请联系系统超级管理员导入。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break;
case 'billingquotaexception.product_invalid':
layer.msg('【使用授权证书】产品或产品款式不存在,请联系系统超级管理员导入新证书。',{icon: 2, time: 5000});
layer.msg('【使用授权证书】产品或产品款式不存在,请联系系统超级管理员导入新证书。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break;
case 'billingquotaexception.license_expired_or_exhausted':
layer.msg('【使用授权证书】证书过期或耗尽,请升级证书或绑定新证书。',{icon: 2, time: 5000});
layer.msg('【使用授权证书】证书过期或耗尽,请升级证书或绑定新证书。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break;
case 'billingquotaexception.license_disabled_serverinst':
layer.msg('【使用授权证书】证书商店禁用了本服务实例。',{icon: 2, time: 5000});
layer.msg('【使用授权证书】证书商店禁用了本服务实例。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break;
case 'billingquotaexception.license_unsupport_refund':
layer.msg('【使用授权证书】目前使用的证书不支持回退配额。',{icon: 2, time: 5000});
layer.msg('【使用授权证书】目前使用的证书不支持回退配额。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break;
case 'billingquotaexception.license_quota_inadequate':
layer.msg('【使用授权证书】本次操作需要使用的配额资源超过证书中剩余配额,请联系系统超级管理员升级证书。',{icon: 2, time: 5000});
layer.msg('【使用授权证书】本次操作需要使用的配额资源超过证书中剩余配额,请联系系统超级管理员升级证书。', {
icon: 2,
time: 5000
});
if (cb && (typeof (x) === 'function')) {
cb()
}
break;
case 'billingquotaexception.internal_error':
layer.msg('【使用授权证书】系统错误,稍后再试。',{icon: 2, time: 5000});
layer.msg('【使用授权证书】系统错误,稍后再试。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break;
default:
console.log("[handleGeneralCodeInQueryPathOrApiResp] none code matched", code);
if (cb && (typeof (x) === 'function')) {
cb("no_code_matched");
}
}
}

View File

@ -63,13 +63,13 @@ block content
layui.use('layer', function () {
var layer = layui.layer;
console.log(window.location.href)
var status = '#{status}';
if (status == 'new_webim_success')
layer.msg('网站添加成功', {icon: 1, time: 1000})
else if (status == 'new_webim_fail')
layer.msg('网站添加失败', {icon: 2, time: 3000})
else
handleGeneralCodeInQueryPathOrApiResp(status);
});
layui.use(['laypage', 'layer'], function () {
var laypage = layui.laypage

View File

@ -33,6 +33,7 @@ html(xmlns='http://www.w3.org/1999/xhtml', xmlns:th='http://www.thymeleaf.org',
script(src='/js/echarts.common.min.js')
script(language='javascript', src='/js/theme/wonderland.js')
script(src='/layui.js')
script(src="/js/CSKeFu_Admin.v1.js")
script(src='/js/cskefu.js')
if userExpTelemetry == 'on'
script(src='https://www.googletagmanager.com/gtag/js?id=G-SBBX10RKTC' async)

View File

@ -38,8 +38,6 @@ html(xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xm
script(src="/js/moment-timezone.js")
script(src="/js/moment-timezone-with-data.js")
script(src="/layui.js")
//- #894 和原生Map行为不一致
//- <script src="/js/utils.js"></script>
script(src="/js/cskefu.js")
script(src="/im/js/socket.io.js")
script(src="/js/CSKeFu_IM.v1.js")