diff --git a/contact-center/app/src/main/java/com/cskefu/cc/basic/Constants.java b/contact-center/app/src/main/java/com/cskefu/cc/basic/Constants.java index 82e5f3db..7fe891cb 100644 --- a/contact-center/app/src/main/java/com/cskefu/cc/basic/Constants.java +++ b/contact-center/app/src/main/java/com/cskefu/cc/basic/Constants.java @@ -226,4 +226,9 @@ public class Constants { public static final String LICENSEIDS = "LICENSEIDS"; public static final String METAKV_DATATYPE_STRING = "string"; + public static final String SHORTID = "shortId"; + public static final String LICENSES = "licenses"; + public static final String ADDDATE = "addDate"; + public static final String LICENSE = "license"; + public static final String UPDATETIME = "updateTime"; } diff --git a/contact-center/app/src/main/java/com/cskefu/cc/controller/admin/LicenseCtrl.java b/contact-center/app/src/main/java/com/cskefu/cc/controller/admin/LicenseCtrl.java new file mode 100644 index 00000000..ba6ea315 --- /dev/null +++ b/contact-center/app/src/main/java/com/cskefu/cc/controller/admin/LicenseCtrl.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd. + * , 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.controller.admin; + +import com.chatopera.store.sdk.exceptions.InvalidResponseException; +import com.cskefu.cc.basic.Constants; +import com.cskefu.cc.controller.Handler; +import com.cskefu.cc.exception.MetaKvInvalidKeyException; +import com.cskefu.cc.model.User; +import com.cskefu.cc.proxy.LicenseProxy; +import com.cskefu.cc.util.Menu; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import org.apache.commons.lang3.StringUtils; +import org.json.JSONArray; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; + +import java.util.Date; +import java.util.List; + +@Controller +@RequestMapping("/admin/license") +public class LicenseCtrl extends Handler { + private final static Logger logger = LoggerFactory.getLogger(LicenseCtrl.class); + + @Autowired + private LicenseProxy licenseProxy; + + @RequestMapping("/index") + @Menu(type = "admin", subtype = "license") + public ModelAndView index(ModelMap map, HttpServletRequest request) { + User user = super.getUser(request); + if (user.isSuperadmin()) { + + try { + List licenses = licenseProxy.getLicensesFromStore(); + map.addAttribute(Constants.UPDATETIME, new Date()); + map.addAttribute(Constants.LICENSES, licenses); + } catch (InvalidResponseException e) { + throw new RuntimeException(e); + } + + return request(super.createView("/admin/license/index")); + } else { + return request(super.createView("/public/error")); + } + } + + @RequestMapping("/add") + @Menu(type = "admin", subtype = "license") + public ModelAndView add(ModelMap map, HttpServletRequest request) { + User user = super.getUser(request); + if (user.isSuperadmin()) { + return request(super.createView("/admin/license/add")); + } else { + return request(super.createView("/public/error")); + } + } + + /** + * 保存新的证书 + * + * @param map + * @param request + * @param licenseShortId + * @return + */ + @RequestMapping("/save") + @Menu(type = "admin", subtype = "license") + public ModelAndView save(ModelMap map, + HttpServletRequest request, + @Valid String licenseShortId) throws MetaKvInvalidKeyException { + User user = super.getUser(request); + logger.info("[save] licenseShortId {}", licenseShortId); + + if (user.isSuperadmin()) { + // 验证该证书不在当前证书列表中 + JSONArray currents = licenseProxy.getLicensesInMetakv(); + String msg = ""; + boolean isAddedBefore = false; + + for (int i = 0; i < currents.length(); i++) { + JSONObject item = (JSONObject) currents.get(i); + if (StringUtils.equals(item.getString("shortId"), licenseShortId)) { + isAddedBefore = true; + break; + } + } + + if (isAddedBefore) { + msg = "already_added"; + return request(super.createView( + "redirect:/admin/license/index.html?msg=" + msg)); + } + + // 验证该证书存在 + try { + JSONObject licenseData = licenseProxy.getLicenseFromStore(licenseShortId); + JSONObject licenseKvData = new JSONObject(); + licenseKvData.put(Constants.SHORTID, licenseData.getJSONObject(Constants.LICENSE).getString(Constants.SHORTID)); + licenseKvData.put(Constants.ADDDATE, new Date()); + + // 添加该证书 + currents.put(0, licenseKvData); + licenseProxy.createOrUpdateMetaKv(Constants.LICENSEIDS, currents.toString(), Constants.METAKV_DATATYPE_STRING); + + // 跳转回到证书列表 + List licenses = licenseProxy.getLicensesFromStore(); + map.addAttribute(Constants.LICENSES, licenses); + map.addAttribute("updateTime", new Date()); + + return request(super.createView("/admin/license/index")); + } catch (InvalidResponseException e) { + logger.warn("[save] error in getLicenseFromStore", e); + msg = "invalid_id"; + return request(super.createView( + "redirect:/admin/license/index.html?msg=" + msg)); + } + + + } else { + return request(super.createView("/public/error")); + } + } +} diff --git a/contact-center/app/src/main/java/com/cskefu/cc/exception/MetaKvInvalidKeyException.java b/contact-center/app/src/main/java/com/cskefu/cc/exception/MetaKvInvalidKeyException.java new file mode 100644 index 00000000..fafbd11a --- /dev/null +++ b/contact-center/app/src/main/java/com/cskefu/cc/exception/MetaKvInvalidKeyException.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd. + * , 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) 2019-Jun. 2023 Chatopera Inc, , + * Licensed under the Apache License, Version 2.0, + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.cskefu.cc.exception; + +public class MetaKvInvalidKeyException extends Exception{ + public MetaKvInvalidKeyException(final String s){ + super(s); + } +} diff --git a/contact-center/app/src/main/java/com/cskefu/cc/exception/MetaKvNotExistException.java b/contact-center/app/src/main/java/com/cskefu/cc/exception/MetaKvNotExistException.java new file mode 100644 index 00000000..dd9e3e07 --- /dev/null +++ b/contact-center/app/src/main/java/com/cskefu/cc/exception/MetaKvNotExistException.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd. + * , 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) 2019-Jun. 2023 Chatopera Inc, , + * Licensed under the Apache License, Version 2.0, + * http://www.apache.org/licenses/LICENSE-2.0 + */ +package com.cskefu.cc.exception; + +public class MetaKvNotExistException extends Exception{ + public MetaKvNotExistException(final String s){ + super(s); + } +} diff --git a/contact-center/app/src/main/java/com/cskefu/cc/model/Metakv.java b/contact-center/app/src/main/java/com/cskefu/cc/model/MetaKv.java similarity index 96% rename from contact-center/app/src/main/java/com/cskefu/cc/model/Metakv.java rename to contact-center/app/src/main/java/com/cskefu/cc/model/MetaKv.java index 9e206e42..0de0916e 100644 --- a/contact-center/app/src/main/java/com/cskefu/cc/model/Metakv.java +++ b/contact-center/app/src/main/java/com/cskefu/cc/model/MetaKv.java @@ -10,7 +10,7 @@ import java.util.Date; @Entity @Table(name = "cs_metakv") @org.hibernate.annotations.Proxy(lazy = false) -public class Metakv implements java.io.Serializable { +public class MetaKv implements java.io.Serializable { @Id private String metakey; diff --git a/contact-center/app/src/main/java/com/cskefu/cc/persistence/repository/MetakvRepository.java b/contact-center/app/src/main/java/com/cskefu/cc/persistence/repository/MetaKvRepository.java similarity index 81% rename from contact-center/app/src/main/java/com/cskefu/cc/persistence/repository/MetakvRepository.java rename to contact-center/app/src/main/java/com/cskefu/cc/persistence/repository/MetaKvRepository.java index 717c697f..f180c902 100644 --- a/contact-center/app/src/main/java/com/cskefu/cc/persistence/repository/MetakvRepository.java +++ b/contact-center/app/src/main/java/com/cskefu/cc/persistence/repository/MetaKvRepository.java @@ -10,13 +10,13 @@ */ package com.cskefu.cc.persistence.repository; -import com.cskefu.cc.model.Metakv; +import com.cskefu.cc.model.MetaKv; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; -public interface MetakvRepository extends JpaRepository { +public interface MetaKvRepository extends JpaRepository { - Optional findFirstByMetakey(final String p1); + Optional findFirstByMetakey(final String p1); } diff --git a/contact-center/app/src/main/java/com/cskefu/cc/proxy/LicenseProxy.java b/contact-center/app/src/main/java/com/cskefu/cc/proxy/LicenseProxy.java index e3b3a622..d202b88c 100644 --- a/contact-center/app/src/main/java/com/cskefu/cc/proxy/LicenseProxy.java +++ b/contact-center/app/src/main/java/com/cskefu/cc/proxy/LicenseProxy.java @@ -16,25 +16,33 @@ import com.chatopera.store.sdk.exceptions.InvalidResponseException; import com.cskefu.cc.basic.Constants; import com.cskefu.cc.basic.MainContext; import com.cskefu.cc.basic.MainUtils; -import com.cskefu.cc.model.Metakv; -import com.cskefu.cc.persistence.repository.MetakvRepository; +import com.cskefu.cc.exception.MetaKvInvalidKeyException; +import com.cskefu.cc.exception.MetaKvNotExistException; +import com.cskefu.cc.model.MetaKv; +import com.cskefu.cc.persistence.repository.MetaKvRepository; import com.cskefu.cc.util.Base62; +import com.cskefu.cc.util.DateConverter; +import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; +import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.stereotype.Service; -import java.util.Date; -import java.util.Optional; +import java.text.ParseException; +import java.util.*; +/** + * 证书服务 + */ @Service public class LicenseProxy { private final static Logger logger = LoggerFactory.getLogger(LicenseProxy.class); @Autowired - private MetakvRepository metkvRes; + private MetaKvRepository metaKvRes; @Autowired private QuotaWdClient quotaWdClient; @@ -65,24 +73,65 @@ public class LicenseProxy { /** * Init local data for License */ - Optional metaServerinstIdOpt = metkvRes.findFirstByMetakey(Constants.LICENSE_SERVER_INST_ID); + Optional metaServerinstIdOpt = metaKvRes.findFirstByMetakey(Constants.LICENSE_SERVER_INST_ID); if (metaServerinstIdOpt.isEmpty()) { // 没有 serverinstId 信息,初始化 final String serverinstId = MainUtils.getUUID(); - createMetakv(Constants.LICENSE_SERVER_INST_ID, serverinstId, Constants.METAKV_DATATYPE_STRING); + createMetaKv(Constants.LICENSE_SERVER_INST_ID, serverinstId, Constants.METAKV_DATATYPE_STRING); } - Optional metaServicenameOpt = metkvRes.findFirstByMetakey(Constants.LICENSE_SERVICE_NAME); + Optional metaServicenameOpt = metaKvRes.findFirstByMetakey(Constants.LICENSE_SERVICE_NAME); if (metaServicenameOpt.isEmpty()) { // 没有 Service Name 信息,初始化 final String serviceName = generateLicenseServiceName(); - createMetakv(Constants.LICENSE_SERVICE_NAME, serviceName, Constants.METAKV_DATATYPE_STRING); + createMetaKv(Constants.LICENSE_SERVICE_NAME, serviceName, Constants.METAKV_DATATYPE_STRING); } - Optional metaLicensesOpt = metkvRes.findFirstByMetakey(Constants.LICENSEIDS); + Optional metaLicensesOpt = metaKvRes.findFirstByMetakey(Constants.LICENSEIDS); if (metaLicensesOpt.isEmpty()) { // 没有 license 信息,初始化 - createMetakv(Constants.LICENSEIDS, (new JSONArray()).toString(), Constants.METAKV_DATATYPE_STRING); + createMetaKv(Constants.LICENSEIDS, (new JSONArray()).toString(), Constants.METAKV_DATATYPE_STRING); + } + } + + /** + * 从 MetaKv 表中取得数据 MetaKv + * + * @param key + * @return + * @throws MetaKvNotExistException + */ + public MetaKv retrieveMetaKv(final String key) throws MetaKvNotExistException, MetaKvInvalidKeyException { + + if (StringUtils.isBlank(key)) { + throw new MetaKvInvalidKeyException("Key must not be empy"); + } + + Optional kvOpt = metaKvRes.findFirstByMetakey(key); + if (kvOpt.isEmpty()) { + throw new MetaKvNotExistException(key + " not exist"); + } else { + return kvOpt.get(); + } + } + + /** + * 创建或更新 MetaKv + * UpdateOnExist + * + * @param key + * @param value + * @param datatype + */ + public MetaKv createOrUpdateMetaKv(final String key, final String value, final String datatype) throws MetaKvInvalidKeyException { + try { + MetaKv kv = retrieveMetaKv(key); + kv.setMetavalue(value); + kv.setUpdatetime(new Date()); + metaKvRes.save(kv); + return kv; + } catch (MetaKvNotExistException e) { + return createMetaKv(key, value, datatype); } } @@ -94,16 +143,17 @@ public class LicenseProxy { * @param value * @param datatype */ - public void createMetakv(final String key, final String value, final String datatype) { + public MetaKv createMetaKv(final String key, final String value, final String datatype) { Date now = new Date(); - Metakv metakv = new Metakv(); + MetaKv metakv = new MetaKv(); metakv.setCreatetime(now); metakv.setUpdatetime(now); metakv.setMetakey(key); metakv.setMetavalue(value); metakv.setDatatype(datatype); - metkvRes.save(metakv); + metaKvRes.save(metakv); + return metakv; } /** @@ -119,4 +169,81 @@ public class LicenseProxy { return sb.toString(); } + + /** + * 从数据库及证书商店获得证书列表信息 + * + * @return + */ + public List getLicensesFromStore() throws InvalidResponseException { + List result = new ArrayList<>(); + + try { + JSONArray ja = new JSONArray((retrieveMetaKv(Constants.LICENSEIDS).getMetavalue())); + HashMap addDates = new HashMap<>(); + List licenseIds = new ArrayList<>(); + for (int i = 0; i < ja.length(); i++) { + JSONObject obj = ((JSONObject) ja.get(i)); + licenseIds.add(obj.getString(Constants.SHORTID)); + addDates.put(obj.getString(Constants.SHORTID), obj.getString(Constants.ADDDATE)); + } + + Response resp = quotaWdClient.getLicensesInfo(licenseIds); + JSONArray data = (JSONArray) resp.getData(); + + for (int i = 0; i < data.length(); i++) { + JSONObject lic = (JSONObject) data.get(i); + try { + Date addDate = DateConverter.parseCSTAsChinaTimezone(addDates.get(lic.getJSONObject(Constants.LICENSE).getString(Constants.SHORTID))); + lic.put(Constants.ADDDATE, addDate); + } catch (ParseException e) { + logger.info("[getLicensesFromStore] can not resolve add date"); + } + result.add(lic); + } + + } catch (MetaKvNotExistException e) { + logger.info("[getLicenses] no LICENSEIDS data in MySQL DB"); + } catch (MetaKvInvalidKeyException e) { + throw new RuntimeException(e); + } + + return result; + } + + /** + * 获得在 MetaKV 表中的 license 信息 + * + * @return JSONArray + */ + public JSONArray getLicensesInMetakv() { + try { + String value = retrieveMetaKv(Constants.LICENSEIDS).getMetavalue(); + return new JSONArray(value); + } catch (MetaKvNotExistException e) { + return new JSONArray(); + } catch (MetaKvInvalidKeyException e) { + return new JSONArray(); + } + } + + /** + * @param licenseShortId + * @return + * @throws InvalidResponseException + */ + public JSONObject getLicenseFromStore(final String licenseShortId) throws InvalidResponseException { + Response resp = quotaWdClient.getLicenseInfo(licenseShortId); + if (resp.getRc() == 0) { + JSONArray data = (JSONArray) resp.getData(); + if (data.length() != 1) + throw new InvalidResponseException("Unexpected data in Response."); + + return (JSONObject) (data).get(0); + } else { + throw new InvalidResponseException("Unexpected Response."); + } + + } + } diff --git a/contact-center/app/src/main/java/com/cskefu/cc/util/DateConverter.java b/contact-center/app/src/main/java/com/cskefu/cc/util/DateConverter.java index 1a419fa4..8942a975 100644 --- a/contact-center/app/src/main/java/com/cskefu/cc/util/DateConverter.java +++ b/contact-center/app/src/main/java/com/cskefu/cc/util/DateConverter.java @@ -1,54 +1,74 @@ /* - * Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd. - * , Licensed under the Chunsong Public + * Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd. + * , 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, , Licensed under the Apache License, Version 2.0, + * Copyright (C) 2018- Jun. 2023 Chatopera Inc, , 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.util; import org.apache.commons.beanutils.converters.DateTimeConverter; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.Date; - -public class DateConverter extends DateTimeConverter { - - public DateConverter() { - } - - public DateConverter(Object defaultValue) { - super(defaultValue); - } - - /* (non-Javadoc) - * @see org.apache.commons.beanutils.converters.AbstractConverter#getDefaultType() - */ - @SuppressWarnings("rawtypes") - protected Class getDefaultType() { - return Date.class; - } - - /* - * (non-Javadoc) - * @see org.apache.commons.beanutils.converters.DateTimeConverter#convertToType(java.lang.Class, java.lang.Object) - */ - @SuppressWarnings("rawtypes") - @Override - protected Object convertToType(Class arg0, Object arg1) throws Exception { - if (arg1 == null) { - return null; - } - String value = arg1.toString().trim(); - if (value.length() == 0) { - return null; - } - return super.convertToType(arg0, arg1); - } +import java.util.Locale; + +public class DateConverter extends DateTimeConverter { + + final public static String ZONE_ID_DEFAULT = "Asia/Shanghai"; + // format date string like `Wed Aug 30 16:30:23 CST 2023` to Date + public static SimpleDateFormat TIMEZONE_CHINA_FORMAT_DEFAULT = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US); + + public DateConverter() { + } + + public DateConverter(Object defaultValue) { + super(defaultValue); + } + + /* (non-Javadoc) + * @see org.apache.commons.beanutils.converters.AbstractConverter#getDefaultType() + */ + @SuppressWarnings("rawtypes") + protected Class getDefaultType() { + return Date.class; + } + + /* + * (non-Javadoc) + * @see org.apache.commons.beanutils.converters.DateTimeConverter#convertToType(java.lang.Class, java.lang.Object) + */ + @SuppressWarnings("rawtypes") + @Override + protected Object convertToType(Class arg0, Object arg1) throws Exception { + if (arg1 == null) { + return null; + } + String value = arg1.toString().trim(); + if (value.length() == 0) { + return null; + } + return super.convertToType(arg0, arg1); + } + + /** + * Java将CST的时间字符串转换成需要的日期格式字符串 + * https://blog.csdn.net/qq_44868502/article/details/103511505 + * (new Date()).toString() 与 String to Date 的转化 + * + * @param dstr + * @return + * @throws ParseException + */ + static public Date parseCSTAsChinaTimezone(final String dstr) throws ParseException { + return (Date) TIMEZONE_CHINA_FORMAT_DEFAULT.parse(dstr); + } } \ No newline at end of file diff --git a/contact-center/app/src/main/java/com/cskefu/cc/util/PugHelper.java b/contact-center/app/src/main/java/com/cskefu/cc/util/PugHelper.java index f0b1d424..540cbb81 100644 --- a/contact-center/app/src/main/java/com/cskefu/cc/util/PugHelper.java +++ b/contact-center/app/src/main/java/com/cskefu/cc/util/PugHelper.java @@ -12,6 +12,7 @@ package com.cskefu.cc.util; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; +import org.apache.commons.lang3.StringUtils; import java.text.SimpleDateFormat; import java.util.*; @@ -42,8 +43,39 @@ public class PugHelper { return new String(charr); } + /** + * 在字符串中替换一些字符为 *, 起到混淆、加密、遮盖的敏感信息的目的 + * + * @param prev + * @return + */ + public String messupStringWithStars(final String prev) { + StringBuffer sb = new StringBuffer(); + + if (prev.length() >= 6) { + sb.append("***"); + int initial = prev.length() - 4; + for (int i = initial; i < prev.length(); i++) { + sb.append(prev.charAt(i)); + } + } else { // < 6 + if (prev.length() <= 2 && prev.length() > 0) { + return "***"; + } else { // 2 < length < 6 + sb.append("***"); + int initial = prev.length() - 2; + for (int i = initial; i < prev.length(); i++) { + sb.append(prev.charAt(i)); + } + } + } + + return sb.toString(); + } + /** * 将 String 转化为 JSONArray + * * @param str * @return */ diff --git a/contact-center/app/src/main/resources/templates/admin/include/left.pug b/contact-center/app/src/main/resources/templates/admin/include/left.pug index 0b10bb6c..450595f0 100644 --- a/contact-center/app/src/main/resources/templates/admin/include/left.pug +++ b/contact-center/app/src/main/resources/templates/admin/include/left.pug @@ -51,6 +51,13 @@ ul.layui-nav.layui-nav-tree(lay-filter='demo') dd(class={'layui-this': subtype == 'interf'}) a(href='/admin/weixin/interf.html') 接口管理 | –> + if user.superadmin + li.layui-nav-item.layui-nav-itemed + a.layui-nav-title(href='javascript:;') 人工智能 + dl.layui-nav-child + if models.contains("chatbot") && (user.roleAuthMap["A09"] || user.admin) + dd + a(href='javascript:void(0)',data-title="智能机器人",onclick="openChatbot()",data-href="/admin/system/chatbot/index.html",class="iframe_btn",data-id="chatbotIntegrationWin", data-type="tabAdd") 智能机器人 if user.superadmin li.layui-nav-item.layui-nav-itemed a.layui-nav-title(href='javascript:;') 系统设置 @@ -61,15 +68,14 @@ ul.layui-nav.layui-nav-tree(lay-filter='demo') a(href='/admin/sysdic/index.html') 字典管理 dd(class={'layui-this': subtype == 'metadata'}) a(href='/admin/metadata/index.html') 元数据 - if models.contains("chatbot") && (user.roleAuthMap["A09"] || user.admin) - dd - a(href='javascript:void(0)',data-title="智能机器人",onclick="openChatbot()",data-href="/admin/system/chatbot/index.html",class="iframe_btn",data-id="chatbotIntegrationWin", data-type="tabAdd") 智能机器人 dd(class={'layui-this': subtype == 'template'}) a(href='/admin/template/index.html') 系统模板 - dd(class={'layui-this': subtype == 'email'}) - a(href='/admin/email/index.html') 邮件通知设置 - dd(class={'layui-this': subtype == 'sms'}) - a(href='/admin/sms/index.html') 短信通知设置 + dd(class={'layui-this': subtype == 'license'}) + a(href='/admin/license/index.html') 使用授权证书 + //dd(class={'layui-this': subtype == 'email'}) + // a(href='/admin/email/index.html') 邮件通知设置 + //dd(class={'layui-this': subtype == 'sms'}) + // a(href='/admin/sms/index.html') 短信通知设置 script. function openChatbot() { diff --git a/contact-center/app/src/main/resources/templates/admin/license/add.pug b/contact-center/app/src/main/resources/templates/admin/license/add.pug new file mode 100644 index 00000000..39fcd5fd --- /dev/null +++ b/contact-center/app/src/main/resources/templates/admin/license/add.pug @@ -0,0 +1,31 @@ +//- Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd. +//- , 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. +.uk-layui-form + form.layui-form(action='/admin/license/save.html', method='post') + .layui-form-item(style='margin-top:10px;') + .layui-inline + label.layui-form-label(style='width:150px;') 证书短标识: + .layui-input-inline + input.layui-input(type='text', name='licenseShortId', required, lay-verify='required', autocomplete='off') + .layui-form-mid.layui-word-aux + font(color='red') * + .layui-form-button + .layui-button-block + button.layui-btn(lay-submit, lay-filter='formNewLicense') 立即提交 + button.layui-btn.layui-btn-original(type='reset') 重置 + +script. + layui.use('form', function () { + var form = layui.form(); + form.render(); //更新全部 + }); + layui.use('element', function () { + var element = layui.element(); + }); + diff --git a/contact-center/app/src/main/resources/templates/admin/license/index.pug b/contact-center/app/src/main/resources/templates/admin/license/index.pug new file mode 100644 index 00000000..cd3ca935 --- /dev/null +++ b/contact-center/app/src/main/resources/templates/admin/license/index.pug @@ -0,0 +1,78 @@ +//- Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd. +//- , 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. +extends /admin/include/layout.pug +block content + .row: .col-lg-12 + h1.site-h1(style='background-color:#FFFFFF;') + | 使用授权证书列表 (#{licenses.size()}) + | ,更新时间 #{pugHelper.formatDate('yyyy-MM-dd HH:mm:ss', updateTime)} + span(style='float:right;') + button.layui-btn.layui-btn-small.green(href='/admin/license/add.html', data-toggle='ajax', data-width='550', data-height='450', data-title='添加使用授权证书') + | 添加使用授权证书 + + .row(style='padding:5px;') + .col-lg-12 + table.layui-table(lay-skin='line') + colgroup + col(width='10%') + col(width='10%') + col(width='15%') + col(width='10%') + col(width='15%') + col(width='10%') + col(width='10%') + col(width='1%') + thead + tr + th 证书标识 + th 产品标识 + th 产品名称 + th 有效期截止 + th 配额剩余 + th 所属人昵称 + th 添加时间 + th(style='white-space:nowrap;', nowrap) 操作 + tbody + for item in licenses + tr + td= pugHelper.messupStringWithStars(item.license.shortId) + td= item.product.shortId + td= item.product.name + td= item.license.effectivedateend + td= item.license.quotaeffectiveremaining + td= item.user.nickname + td= pugHelper.formatDate('yyyy-MM-dd HH:mm:ss', item.addDate) + td(style="white-space:nowrap;" nowrap="nowrap") + a(href="/admin/license/edit.html?id=" + item.license.shortId, data-toggle="ajax", data-width="550", data-height="450", data-title="编辑使用授权证书") + i.layui-icon  + span 编辑 + a(href="/admin/license/delete.html?id=" + item.license.shortId style="margin-left:10px;" data-toggle="tip" title="请确认是否删除使用授权证书?") + i.layui-icon(style="color:red;") ဆ + span 删除 + .row(style='padding:5px;') + .col-lg-12#page(style='text-align:center;') + + script. + layui.use(['laypage', 'layer'], function () { + var laypage = layui.laypage + , layer = layui.layer; + + // laypage({ + // cont: 'page' + // , pages: #{emailList.totalPages} //总页数 + // , curr: #{emailList.number + 1} + // , groups: 5 //连续显示分页数 + // , jump: function (data, first) { + // if (!first) { + // location.href = "/admin/email/index.html?p=" + data.curr; + // } + // } + // }); + }); + diff --git a/contact-center/config/sql/002.mysql-create-schemas.sql b/contact-center/config/sql/002.mysql-create-schemas.sql index 2b8774b2..ecce3082 100644 --- a/contact-center/config/sql/002.mysql-create-schemas.sql +++ b/contact-center/config/sql/002.mysql-create-schemas.sql @@ -2229,7 +2229,6 @@ CREATE TABLE `uk_organ` ( -- Records of uk_organ -- ---------------------------- INSERT INTO `uk_organ` VALUES ('2c9e80867d65eb5c017d65f17ceb0019', '售前坐席A组', null, null, null, null, null, null, '4028a0866f9403f1016f9405a05d000e', '1', ''); -INSERT INTO `uk_organ` VALUES ('40288296874ae16101874ae4f2670016', '机器人平台', null, null, null, null, null, null, '4028a0866f9403f1016f9405a05d000e', '0', ''); INSERT INTO `uk_organ` VALUES ('4028a0866f9403f1016f9405a05d000e', '我的企业', null, null, null, null, 'cskefu', null, '0', '0', ''); -- ----------------------------