mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 23:45:55 +08:00
commit
b8b4e500a3
|
@ -157,7 +157,7 @@ public abstract class ChartData extends SetUser<ChartData> implements ChartSpec
|
|||
private Field getField(JSONObject item) {
|
||||
String field = item.getString("field");
|
||||
if (!getSourceEntity().containsField(field)) {
|
||||
throw new ChartsException("字段 [" + field.toUpperCase() + " ] 已被删除");
|
||||
throw new ChartsException("字段 [" + field.toUpperCase() + " ] 已被删除,请调整图表配置");
|
||||
}
|
||||
return getSourceEntity().getField(field);
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@ public class FeedsHelper {
|
|||
/**
|
||||
* URL 提取
|
||||
*/
|
||||
public static final Pattern URL_PATTERN = Pattern.compile("((www|https?:\\/\\/)[-a-zA-Z0-9+&@#/%?=~_|!:,.;]{5,300})");
|
||||
public static final Pattern URL_PATTERN = Pattern.compile("((www|https?://)[-a-zA-Z0-9+&@#/%?=~_|!:,.;]{5,300})");
|
||||
|
||||
/**
|
||||
* 格式化动态内容
|
||||
|
@ -202,7 +202,8 @@ public class FeedsHelper {
|
|||
ID user = ID.valueOf(at.substring(1));
|
||||
if (user.getEntityCode() == EntityHelper.User && Application.getUserStore().existsUser(user)) {
|
||||
String fullName = Application.getUserStore().getUser(user).getFullName();
|
||||
content = content.replace(at, String.format("<a data-id=\"%s\">@%s</a>", user, fullName));
|
||||
content = content.replace(at,
|
||||
String.format("<a data-id=\"%s\">@%s</a>", user, fullName));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,8 @@
|
|||
/*
|
||||
rebuild - Building your business-systems freely.
|
||||
Copyright (C) 2019 devezhao <zhaofang123@gmail.com>
|
||||
Copyright (c) REBUILD <https://getrebuild.com/> and its owners. All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
rebuild is dual-licensed under commercial and open source licenses (GPLv3).
|
||||
See LICENSE and COMMERCIAL in the project root for license information.
|
||||
*/
|
||||
|
||||
package com.rebuild.server.business.rbstore;
|
||||
|
@ -103,7 +92,8 @@ public class MetaSchemaGenerator {
|
|||
}
|
||||
schemaEntity.put("fields", metaFields);
|
||||
|
||||
// 布局相关(仅管理员)
|
||||
// 布局相关(仅管理员的)
|
||||
|
||||
JSONObject putLayouts = new JSONObject();
|
||||
Object[][] layouts = Application.createQueryNoFilter(
|
||||
"select applyType,config from LayoutConfig where belongEntity = ? and createdBy = ?")
|
||||
|
@ -119,13 +109,14 @@ public class MetaSchemaGenerator {
|
|||
}
|
||||
schemaEntity.put("layouts", putLayouts);
|
||||
|
||||
// 过滤器(仅管理员)
|
||||
// 过滤器(仅管理员的)
|
||||
|
||||
JSONObject putFilters = new JSONObject();
|
||||
Object[][] filters = Application.createQueryNoFilter(
|
||||
"select filterName,config from FilterConfig where belongEntity = ? and createdBy = ?")
|
||||
.setParameter(1, entity.getName())
|
||||
.setParameter(2, UserService.ADMIN_USER)
|
||||
.array();
|
||||
JSONObject putFilters = new JSONObject();
|
||||
for (Object[] filter : filters) {
|
||||
String name = (String) filter[0];
|
||||
JSONObject config = JSON.parseObject((String) filter[1]);
|
||||
|
@ -134,7 +125,7 @@ public class MetaSchemaGenerator {
|
|||
}
|
||||
}
|
||||
schemaEntity.put("filters", putFilters);
|
||||
|
||||
|
||||
return schemaEntity;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,8 @@
|
|||
/*
|
||||
rebuild - Building your business-systems freely.
|
||||
Copyright (C) 2019 devezhao <zhaofang123@gmail.com>
|
||||
Copyright (c) REBUILD <https://getrebuild.com/> and its owners. All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
rebuild is dual-licensed under commercial and open source licenses (GPLv3).
|
||||
See LICENSE and COMMERCIAL in the project root for license information.
|
||||
*/
|
||||
|
||||
package com.rebuild.server.business.rbstore;
|
||||
|
@ -40,10 +29,9 @@ public class RBStore {
|
|||
private static final Log LOG = LogFactory.getLog(RBStore.class);
|
||||
|
||||
/**
|
||||
* RB 仓库地址。
|
||||
* 源地址:https://raw.githubusercontent.com/getrebuild/rebuild-datas/master/
|
||||
* RB 仓库地址 https://github.com/getrebuild/rebuild-datas/
|
||||
*/
|
||||
public static final String DATA_REPO = "https://cdn.jsdelivr.net/gh/getrebuild/rebuild-datas/";
|
||||
private static final String DATA_REPO = "https://getrebuild.com/gh/getrebuild/rebuild-datas/";
|
||||
|
||||
/**
|
||||
* for Classification
|
||||
|
|
|
@ -44,7 +44,7 @@ public class SendNotification implements TriggerAction {
|
|||
|
||||
private static final Log LOG = LogFactory.getLog(SendNotification.class);
|
||||
|
||||
// 内部消息
|
||||
// 通知
|
||||
@SuppressWarnings("unused")
|
||||
private static final int TYPE_NOTIFICATION = 1;
|
||||
// 邮件
|
||||
|
|
|
@ -74,17 +74,17 @@ public class AesPreferencesConfigurer extends PreferencesPlaceholderConfigurer i
|
|||
}
|
||||
}
|
||||
|
||||
// PRIVATE
|
||||
// SPEC MYSQL PORT
|
||||
String mysqlPort = System.getProperty("mysql.port");
|
||||
if (StringUtils.isNotBlank(mysqlPort)) {
|
||||
String dbUrl = props.getProperty("db.url");
|
||||
dbUrl = dbUrl.replace("3306", "4653");
|
||||
dbUrl = dbUrl.replace("3306", mysqlPort);
|
||||
props.put("db.url", dbUrl);
|
||||
}
|
||||
|
||||
// MUST NOT BE NULL
|
||||
setIfEmpty(props, ConfigurableItem.CacheHost, "127.0.0.1");
|
||||
setIfEmpty(props, ConfigurableItem.CachePort, "16379");
|
||||
setIfEmpty(props, ConfigurableItem.CachePort, "6379");
|
||||
|
||||
propsHold = (Properties) props.clone();
|
||||
|
||||
|
|
|
@ -351,7 +351,7 @@ public class EasyMeta implements BaseMeta {
|
|||
* @return
|
||||
*/
|
||||
public static String getLabel(BaseMeta meta) {
|
||||
return meta.getDescription();
|
||||
return StringUtils.defaultIfBlank(meta.getDescription(), meta.getName().toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -100,7 +100,7 @@ public class MessageBuilder {
|
|||
* @param md2html
|
||||
* @param xss
|
||||
* @return
|
||||
* @see MarkdownUtils#parse(String)
|
||||
* @see MarkdownUtils#render(String)
|
||||
*/
|
||||
public static String formatMessage(String message, boolean md2html, boolean xss) {
|
||||
if (xss) {
|
||||
|
@ -111,14 +111,14 @@ public class MessageBuilder {
|
|||
Matcher atMatcher = AT_PATTERN.matcher(message);
|
||||
while (atMatcher.find()) {
|
||||
String at = atMatcher.group();
|
||||
String atLabel = parseAtsId(at.substring(1));
|
||||
String atLabel = parseAtId(at.substring(1));
|
||||
if (atLabel != null && !atLabel.equals(at)) {
|
||||
message = message.replace(at, atLabel);
|
||||
}
|
||||
}
|
||||
|
||||
if (md2html) {
|
||||
message = MarkdownUtils.parse(message);
|
||||
message = MarkdownUtils.render(message);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ public class MessageBuilder {
|
|||
* @param atid
|
||||
* @return
|
||||
*/
|
||||
protected static String parseAtsId(String atid) {
|
||||
protected static String parseAtId(String atid) {
|
||||
if (!ID.isId(atid)) {
|
||||
return atid;
|
||||
}
|
||||
|
|
|
@ -265,7 +265,8 @@ public class CommonsUtils {
|
|||
if (text == null || StringUtils.isBlank(text.toString())) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
return StringEscapeUtils.escapeHtml(text.toString());
|
||||
String escape = StringEscapeUtils.escapeHtml(text.toString());
|
||||
return escape.replace(">", ">"); // `>` for MD
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,19 +1,8 @@
|
|||
/*
|
||||
rebuild - Building your business-systems freely.
|
||||
Copyright (C) 2019 devezhao <zhaofang123@gmail.com>
|
||||
Copyright (c) REBUILD <https://getrebuild.com/> and its owners. All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
rebuild is dual-licensed under commercial and open source licenses (GPLv3).
|
||||
See LICENSE and COMMERCIAL in the project root for license information.
|
||||
*/
|
||||
|
||||
package com.rebuild.utils;
|
||||
|
@ -43,10 +32,12 @@ public class MarkdownUtils {
|
|||
private static final HtmlRenderer RENDERER = HtmlRenderer.builder(OPTIONS).build();
|
||||
|
||||
/**
|
||||
* MD 渲染,支持表格
|
||||
*
|
||||
* @param md
|
||||
* @return
|
||||
*/
|
||||
public static String parse(String md) {
|
||||
public static String render(String md) {
|
||||
Node document = PARSER.parse(md);
|
||||
return RENDERER.render(document);
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@ public class FileManagerControll extends BaseControll {
|
|||
willDeletes.add(fileId);
|
||||
}
|
||||
Application.getCommonService().delete(willDeletes.toArray(new ID[0]));
|
||||
|
||||
writeSuccess(response);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
-- !!! NOTICE !!!
|
||||
-- IF YOU USING MYSQL 5.7 OR ABOVE, YOU SHOULD REMOVED THESE SQL_MODES IN my.cnf/my.ini FIRST.
|
||||
-- !!! MYSQL VERSION NOTICE !!!
|
||||
-- IN 5.7 OR ABOVE, YOU SHOULD REMOVED THESE SQL_MODES IN my.cnf/my.ini FIRST.
|
||||
-- ONLY_FULL_GROUP_BY
|
||||
-- IN 8.0 OR ABOVE, ONLY SUPPORTS mysql_native_password AUTHENTICATION MODE
|
||||
-- default_authentication_plugin=mysql_native_password
|
||||
|
||||
-- #1 database/user
|
||||
-- 首次使用请移除以下注释以创建数据库和用户
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<script src="${baseUrl}/assets/lib/widget/bootstrap-datetimepicker.min.js"></script>
|
||||
<script src="${baseUrl}/assets/lib/jquery.html5uploader.js"></script>
|
||||
<script src="${baseUrl}/assets/lib/qiniu.min.js"></script>
|
||||
<script src="${baseUrl}/assets/lib/widget/select2.min.js"></script>
|
||||
<script src="${baseUrl}/assets/lib/widget/select2.min.js?v=4.0.13"></script>
|
||||
<script src="${baseUrl}/assets/lib/jquery-ui.min.js"></script>
|
||||
<script src="${baseUrl}/assets/lib/react/babel.js?v=6.26.0"></script>
|
||||
<script src="${baseUrl}/assets/lib/react/react.development.js?v=16.10.2"></script>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="${baseUrl}/assets/lib/widget/perfect-scrollbar.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="${baseUrl}/assets/lib/widget/bootstrap-datetimepicker.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="${baseUrl}/assets/lib/animate.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="${baseUrl}/assets/lib/widget/select2.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="${baseUrl}/assets/lib/widget/select2.min.css?v=4.0.13">
|
||||
<link rel="stylesheet" type="text/css" href="${baseUrl}/assets/lib/widget/mprogress.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="${baseUrl}/assets/lib/jquery-ui.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="${baseUrl}/assets/css/rb-base.css">
|
||||
|
|
|
@ -12067,7 +12067,7 @@ canvas {
|
|||
}
|
||||
|
||||
.rb-icons-nav>li.dropdown>a .indicator,
|
||||
.unread-flag {
|
||||
.indicator-primary {
|
||||
background-color: #4285f4;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
|
|
|
@ -35,6 +35,7 @@ body {
|
|||
box-shadow: 0 3px .3077rem rgba(0, 0, 0, .1);
|
||||
border-width: 0;
|
||||
border-radius: 0;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.dropdown-menu.primary>.dropdown-item:hover,
|
||||
|
@ -315,8 +316,8 @@ a.btn {
|
|||
display: block;
|
||||
}
|
||||
|
||||
.rb-color-header .dropdown .icon {
|
||||
color: #fff !important;
|
||||
.rb-color-header .dropdown > a > .icon {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.logo-img {
|
||||
|
@ -385,6 +386,11 @@ a.btn {
|
|||
color: #737373;
|
||||
}
|
||||
|
||||
.adv-search button .indicator-primary {
|
||||
top: 3px;
|
||||
right: 3px;
|
||||
}
|
||||
|
||||
.input-search .input-group-btn.plus {
|
||||
margin-right: -36px;
|
||||
margin-top: -1px;
|
||||
|
@ -1193,7 +1199,7 @@ i.split.ui-draggable-dragging {
|
|||
}
|
||||
|
||||
.data-list .table tbody tr td.user-avatar {
|
||||
padding: 6px 10px;
|
||||
padding: 3px 10px;
|
||||
}
|
||||
|
||||
.data-list .table tbody tr td.user-avatar img {
|
||||
|
@ -1430,6 +1436,10 @@ th.column-fixed {
|
|||
.main-content>.nav-tabs-classic>li.nav-item a.nav-link {
|
||||
padding: 11px 15px;
|
||||
min-width: 101px;
|
||||
max-width: 245px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sortable-box-title {
|
||||
|
@ -1754,6 +1764,7 @@ th.column-fixed {
|
|||
|
||||
.adv-search .dropdown-item div.action a:hover {
|
||||
color: #4285f4 !important;
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* AdvFilter */
|
||||
|
@ -1922,6 +1933,8 @@ div.dataTables_wrapper div.paging_sizes select {
|
|||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.zicon,
|
||||
|
@ -2663,6 +2676,11 @@ form {
|
|||
padding-left: 18px;
|
||||
}
|
||||
|
||||
.notification-list .notification.focus {
|
||||
outline: 2px solid #fbbc05;
|
||||
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
.select2-sm .select2-container--default .select2-selection--single,
|
||||
.select2-sm .select2-container--default .select2-selection--multiple {
|
||||
min-height: 36px;
|
||||
|
@ -3381,4 +3399,28 @@ a.icon-link>.zmdi {
|
|||
.btn {
|
||||
min-width: 88px;
|
||||
}
|
||||
}
|
||||
|
||||
.mr-zero {
|
||||
margin-right: -15px;
|
||||
}
|
||||
|
||||
.ml-zero {
|
||||
margin-left: -15px;
|
||||
}
|
||||
|
||||
/* text overflow */
|
||||
|
||||
.aside-header .title,
|
||||
.dept-tree ul li a,
|
||||
.dropdown-item,
|
||||
.modal-header .modal-title,
|
||||
.view-header .title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-tabs>li.nav-item a.nav-link {
|
||||
max-width: 200px;
|
||||
}
|
|
@ -46,7 +46,8 @@ body {
|
|||
display: inline-block;
|
||||
margin: 0;
|
||||
font-weight: 300;
|
||||
font-size: 1.538rem
|
||||
font-size: 1.538rem;
|
||||
max-width: 80%;
|
||||
}
|
||||
|
||||
.view-header>span>.close {
|
||||
|
@ -96,7 +97,6 @@ body {
|
|||
|
||||
.nav-tabs>li.nav-item a.nav-link {
|
||||
padding: 11px 10px;
|
||||
max-width: 130px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
|
|
@ -7,10 +7,10 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
/* eslint-disable react/no-string-refs */
|
||||
|
||||
const wpc = window.__PageConfig
|
||||
|
||||
let esourceFilter
|
||||
$(document).ready(() => {
|
||||
$(window).trigger('resize')
|
||||
//$('.navbar-brand').attr('href', 'javascript:;')
|
||||
|
||||
$('.chart-type>a, .chart-option .zicon').tooltip({ html: true, container: '.config-aside' })
|
||||
if (wpc.chartOwningAdmin !== true) $('.admin-show').remove()
|
||||
|
@ -52,7 +52,7 @@ $(document).ready(() => {
|
|||
}
|
||||
}).disableSelection()
|
||||
|
||||
let saveFilter = function (filter) {
|
||||
const saveFilter = function (filter) {
|
||||
esourceFilter = filter
|
||||
render_preview()
|
||||
}
|
||||
|
@ -60,25 +60,31 @@ $(document).ready(() => {
|
|||
renderRbcomp(<AdvFilter title="设置过滤条件" entity={wpc.sourceEntity} filter={esourceFilter} inModal={true} confirm={saveFilter} canNoFilters={true} />)
|
||||
})
|
||||
|
||||
let cts = $('.chart-type > a').click(function () {
|
||||
let _this = $(this)
|
||||
if (_this.hasClass('active') === false) return
|
||||
const cts = $('.chart-type > a').click(function () {
|
||||
const $this = $(this)
|
||||
if ($this.hasClass('active') === false) return
|
||||
cts.removeClass('select')
|
||||
_this.addClass('select')
|
||||
$this.addClass('select')
|
||||
render_option()
|
||||
})
|
||||
$('.chart-option .custom-control').click(function () {
|
||||
render_option()
|
||||
})
|
||||
|
||||
// 保存按钮
|
||||
$('.rb-toggle-left-sidebar').attr('title', '完成').off('click').on('click', () => {
|
||||
let cfg = build_config()
|
||||
const cfg = build_config()
|
||||
if (!cfg) { RbHighbar.create('当前图表无数据'); return }
|
||||
let _data = { config: JSON.stringify(cfg), title: cfg.title, belongEntity: cfg.entity, chartType: cfg.type }
|
||||
_data.metadata = { entity: 'ChartConfig', id: wpc.chartId }
|
||||
const data = {
|
||||
config: JSON.stringify(cfg),
|
||||
title: cfg.title,
|
||||
belongEntity: cfg.entity,
|
||||
chartType: cfg.type,
|
||||
metadata: { entity: 'ChartConfig', id: wpc.chartId }
|
||||
}
|
||||
|
||||
let dash = $urlp('dashid') || ''
|
||||
$.post('/dashboard/chart-save?dashid=' + dash, JSON.stringify(_data), function (res) {
|
||||
const dash = $urlp('dashid') || ''
|
||||
$.post(`/dashboard/chart-save?dashid=${dash}`, JSON.stringify(data), function (res) {
|
||||
if (res.error_code === 0) {
|
||||
wpc.chartConfig = cfg
|
||||
location.href = (dash ? ('home?d=' + dash) : 'home') + '#' + res.data.id
|
||||
|
@ -88,26 +94,27 @@ $(document).ready(() => {
|
|||
}).tooltip({ placement: 'right' }).find('.zmdi').addClass('zmdi-arrow-left')
|
||||
|
||||
if (wpc.chartConfig && wpc.chartConfig.axis) {
|
||||
$(wpc.chartConfig.axis.dimension).each((idx, item) => { add_axis('.J_axis-dim', item) })
|
||||
$(wpc.chartConfig.axis.numerical).each((idx, item) => { add_axis('.J_axis-num', item) })
|
||||
$(wpc.chartConfig.axis.dimension).each((idx, item) => add_axis('.J_axis-dim', item))
|
||||
$(wpc.chartConfig.axis.numerical).each((idx, item) => add_axis('.J_axis-num', item))
|
||||
$('.chart-type>a[data-type="' + wpc.chartConfig.type + '"]').trigger('click')
|
||||
esourceFilter = wpc.chartConfig.filter
|
||||
|
||||
let option = wpc.chartConfig.option || {}
|
||||
const option = wpc.chartConfig.option || {}
|
||||
for (let k in option) {
|
||||
let opt = $('.chart-option input[data-name=' + k + ']')
|
||||
const opt = $('.chart-option input[data-name=' + k + ']')
|
||||
if (opt.length > 0) {
|
||||
if (opt.attr('type') === 'checkbox') {
|
||||
if (option[k] === 'true') opt.trigger('click')
|
||||
if (option[k] === 'true' || option[k] === true) opt.trigger('click')
|
||||
} else {
|
||||
opt.val(option[k])
|
||||
}
|
||||
else opt.val(option[k])
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!wpc.chartId) $('<h4 class="chart-undata must-center">当前图表无数据</h4>').appendTo('#chart-preview')
|
||||
|
||||
window.onbeforeunload = function () {
|
||||
let ccfg = build_config()
|
||||
const ccfg = build_config()
|
||||
if (!ccfg && !wpc.chartId); // New and unconfig
|
||||
else if (JSON.stringify(ccfg) === JSON.stringify(wpc.chartConfig)); // Unchanged
|
||||
else return false
|
||||
|
@ -121,18 +128,19 @@ $(document).ready(() => {
|
|||
|
||||
const CTs = { SUM: '求和', AVG: '平均值', MAX: '最大值', MIN: '最小值', COUNT: '计数', Y: '按年', Q: '按季', M: '按月', D: '按日', H: '按时' }
|
||||
let dlgAxisProps
|
||||
let add_axis = ((target, axis) => {
|
||||
let el = $($('#axis-ietm').html()).appendTo($(target))
|
||||
// 添加维度
|
||||
const add_axis = ((target, axis) => {
|
||||
const el = $($('#axis-ietm').html()).appendTo($(target))
|
||||
let fName = null
|
||||
let fLabel = null
|
||||
let fType = null
|
||||
let calc = null
|
||||
let sort = null
|
||||
|
||||
let isNumAxis = $(target).hasClass('J_axis-num')
|
||||
const isNumAxis = $(target).hasClass('J_axis-num')
|
||||
// in-load
|
||||
if (axis.field) {
|
||||
let field = $('.fields [data-field="' + axis.field + '"]')
|
||||
const field = $('.fields [data-field="' + axis.field + '"]')
|
||||
fName = axis.field
|
||||
fLabel = field.text()
|
||||
fType = field.data('type')
|
||||
|
@ -162,25 +170,26 @@ let add_axis = ((target, axis) => {
|
|||
if (fType === 'date') el.find('.J_text, .J_num').remove()
|
||||
else el.find('.J_text, .J_num, .J_date, .dropdown-divider').remove()
|
||||
}
|
||||
let aopts = el.find('.dropdown-menu .dropdown-item').click(function () {
|
||||
let _this = $(this)
|
||||
if (_this.hasClass('disabled') || _this.parent().hasClass('disabled')) return false
|
||||
|
||||
let calc = _this.data('calc')
|
||||
let sort = _this.data('sort')
|
||||
const aopts = el.find('.dropdown-menu .dropdown-item').click(function () {
|
||||
const $this = $(this)
|
||||
if ($this.hasClass('disabled') || $this.parent().hasClass('disabled')) return false
|
||||
|
||||
const calc = $this.data('calc')
|
||||
const sort = $this.data('sort')
|
||||
if (calc) {
|
||||
el.find('span').text(fLabel + (' (' + _this.text() + ')'))
|
||||
el.find('span').text(fLabel + (' (' + $this.text() + ')'))
|
||||
el.attr('data-calc', calc)
|
||||
aopts.each(function () { if ($(this).data('calc')) $(this).removeClass('text-primary') })
|
||||
_this.addClass('text-primary')
|
||||
$this.addClass('text-primary')
|
||||
render_preview()
|
||||
} else if (sort) {
|
||||
el.attr('data-sort', sort)
|
||||
aopts.each(function () { if ($(this).data('sort')) $(this).removeClass('text-primary') })
|
||||
_this.addClass('text-primary')
|
||||
$this.addClass('text-primary')
|
||||
render_preview()
|
||||
} else {
|
||||
let state = { isNumAxis: isNumAxis, label: el.attr('data-label'), scale: el.attr('data-scale') }
|
||||
const state = { isNumAxis: isNumAxis, label: el.attr('data-label'), scale: el.attr('data-scale') }
|
||||
state.callback = (s) => {
|
||||
el.attr({ 'data-label': s.label, 'data-scale': s.scale })
|
||||
render_preview()
|
||||
|
@ -194,7 +203,7 @@ let add_axis = ((target, axis) => {
|
|||
if (sort) el.find('.dropdown-menu li[data-sort="' + sort + '"]').addClass('text-primary')
|
||||
|
||||
el.attr({ 'data-type': fType, 'data-field': fName })
|
||||
el.find('span').text(fLabel + (calc ? (' (' + CTs[calc] + ')') : ''))
|
||||
el.find('span').text(fLabel + (calc ? ` (${CTs[calc]})` : ''))
|
||||
el.find('a.del').click(() => {
|
||||
el.remove()
|
||||
render_option()
|
||||
|
@ -203,16 +212,16 @@ let add_axis = ((target, axis) => {
|
|||
})
|
||||
|
||||
// 图表选项
|
||||
let render_option = (() => {
|
||||
let cts = $('.chart-type>a').removeClass('active')
|
||||
let dimsAxis = $('.J_axis-dim .item').length
|
||||
let numsAxis = $('.J_axis-num .item').length
|
||||
const render_option = (() => {
|
||||
const cts = $('.chart-type>a').removeClass('active')
|
||||
const dimsAxis = $('.J_axis-dim .item').length
|
||||
const numsAxis = $('.J_axis-num .item').length
|
||||
|
||||
cts.each(function () {
|
||||
let _this = $(this)
|
||||
let dims = (_this.data('allow-dims') || '0|0').split('|')
|
||||
let nums = (_this.data('allow-nums') || '0|0').split('|')
|
||||
if (dimsAxis >= ~~dims[0] && dimsAxis <= ~~dims[1] && numsAxis >= ~~nums[0] && numsAxis <= ~~nums[1]) _this.addClass('active')
|
||||
const $this = $(this)
|
||||
const dims = ($this.data('allow-dims') || '0|0').split('|')
|
||||
const nums = ($this.data('allow-nums') || '0|0').split('|')
|
||||
if (dimsAxis >= ~~dims[0] && dimsAxis <= ~~dims[1] && numsAxis >= ~~nums[0] && numsAxis <= ~~nums[1]) $this.addClass('active')
|
||||
})
|
||||
// FUNNEL
|
||||
if ((dimsAxis === 1 && numsAxis === 1) || (dimsAxis === 0 && numsAxis > 1));
|
||||
|
@ -227,14 +236,15 @@ let render_option = (() => {
|
|||
const ct = select.data('type')
|
||||
// Option
|
||||
$('.chart-option>div').addClass('hide')
|
||||
let ctOpt = $('.J_opt-' + ct)
|
||||
const ctOpt = $('.J_opt-' + ct)
|
||||
if (ctOpt.length === 0) $('.J_opt-UNDEF').removeClass('hide')
|
||||
else ctOpt.removeClass('hide')
|
||||
|
||||
// Sort
|
||||
let sorts = $('.axis-editor .J_sort').removeClass('disabled')
|
||||
if (ct === 'INDEX') sorts.addClass('disabled')
|
||||
else if (ct === 'FUNNEL') {
|
||||
const sorts = $('.axis-editor .J_sort').removeClass('disabled')
|
||||
if (ct === 'INDEX') {
|
||||
sorts.addClass('disabled')
|
||||
} else if (ct === 'FUNNEL') {
|
||||
if (numsAxis >= 1 && dimsAxis >= 1) $('.J_numerical .J_sort').addClass('disabled')
|
||||
else sorts.addClass('disabled')
|
||||
}
|
||||
|
@ -244,14 +254,14 @@ let render_option = (() => {
|
|||
|
||||
// 生成预览
|
||||
let render_preview_chart = null
|
||||
let render_preview = (() => {
|
||||
const render_preview = (() => {
|
||||
$setTimeout(() => {
|
||||
if (render_preview_chart) {
|
||||
ReactDOM.unmountComponentAtNode(document.getElementById('chart-preview'))
|
||||
render_preview_chart = null
|
||||
}
|
||||
|
||||
let cfg = build_config()
|
||||
const cfg = build_config()
|
||||
if (!cfg) {
|
||||
$('#chart-preview').html('<h4 class="chart-undata must-center">当前图表无数据</h4>')
|
||||
return
|
||||
|
@ -259,28 +269,29 @@ let render_preview = (() => {
|
|||
|
||||
$('#chart-preview').empty()
|
||||
// eslint-disable-next-line no-undef
|
||||
let c = detectChart(cfg)
|
||||
const c = detectChart(cfg)
|
||||
if (c) renderRbcomp(c, 'chart-preview', function () { render_preview_chart = this })
|
||||
else $('#chart-preview').html('<h4 class="chart-undata must-center">不支持的图表类型</h4>')
|
||||
|
||||
}, 400, 'chart-preview')
|
||||
})
|
||||
|
||||
let build_config = (() => {
|
||||
let cfg = { entity: wpc.sourceEntity, title: $val('#chart-title') || '未命名图表' }
|
||||
// 构造配置
|
||||
const build_config = (() => {
|
||||
const cfg = { entity: wpc.sourceEntity, title: $val('#chart-title') || '未命名图表' }
|
||||
cfg.type = $('.chart-type>a.select').data('type')
|
||||
if (!cfg.type) return
|
||||
|
||||
let dims = []
|
||||
let nums = []
|
||||
$('.J_axis-dim>span').each((idx, item) => { dims.push(__build_axisItem(item, false)) })
|
||||
$('.J_axis-num>span').each((idx, item) => { nums.push(__build_axisItem(item, true)) })
|
||||
const dims = []
|
||||
const nums = []
|
||||
$('.J_axis-dim>span').each((idx, item) => dims.push(__buildAxisItem(item, false)))
|
||||
$('.J_axis-num>span').each((idx, item) => nums.push(__buildAxisItem(item, true)))
|
||||
if (dims.length === 0 && nums.length === 0) return
|
||||
cfg.axis = { dimension: dims, numerical: nums }
|
||||
|
||||
let opts = {}
|
||||
$('.chart-option>div.active input').each(function () {
|
||||
let name = $(this).data('name')
|
||||
const opts = {}
|
||||
$('.chart-option input').each(function () {
|
||||
const name = $(this).data('name')
|
||||
if (name) opts[name] = $val(this)
|
||||
})
|
||||
cfg.option = opts
|
||||
|
@ -290,9 +301,14 @@ let build_config = (() => {
|
|||
if (rb.env === 'dev') console.log(cfg)
|
||||
return cfg
|
||||
})
|
||||
let __build_axisItem = ((item, isNum) => {
|
||||
|
||||
const __buildAxisItem = ((item, isNum) => {
|
||||
item = $(item)
|
||||
let x = { field: item.data('field'), sort: item.attr('data-sort') || '', label: item.attr('data-label') || '' }
|
||||
const x = {
|
||||
field: item.data('field'),
|
||||
sort: item.attr('data-sort') || '',
|
||||
label: item.attr('data-label') || ''
|
||||
}
|
||||
if (isNum) {
|
||||
x.calc = item.attr('data-calc')
|
||||
x.scale = item.attr('data-scale')
|
||||
|
@ -306,40 +322,44 @@ class DlgAxisProps extends RbFormHandler {
|
|||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<RbModal title="显示样式" ref={(c) => this._dlg = c}>
|
||||
<div className="form">
|
||||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">別名</label>
|
||||
<div className="col-sm-7">
|
||||
<input className="form-control form-control-sm" placeholder="默认" data-id="label" value={this.state.label || ''} onChange={this.handleChange} />
|
||||
</div>
|
||||
</div>
|
||||
{this.state.isNumAxis !== true ? null :
|
||||
return (
|
||||
<RbModal title="显示样式" ref={(c) => this._dlg = c}>
|
||||
<div className="form">
|
||||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">小数位</label>
|
||||
<label className="col-sm-3 col-form-label text-sm-right">別名</label>
|
||||
<div className="col-sm-7">
|
||||
<select className="form-control form-control-sm" value={this.state.scale || 2} data-id="scale" onChange={this.handleChange}>
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
</select>
|
||||
<input className="form-control form-control-sm" placeholder="默认" data-id="label" value={this.state.label || ''} onChange={this.handleChange} />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div className="form-group row footer">
|
||||
<div className="col-sm-7 offset-sm-3">
|
||||
<button className="btn btn-primary btn-space" type="button" onClick={() => this.saveProps()}>确定</button>
|
||||
<a className="btn btn-link btn-space" onClick={() => this.hide()}>取消</a>
|
||||
{this.state.isNumAxis !== true ? null :
|
||||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">小数位</label>
|
||||
<div className="col-sm-7">
|
||||
<select className="form-control form-control-sm" value={this.state.scale || 2} data-id="scale" onChange={this.handleChange}>
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div className="form-group row footer">
|
||||
<div className="col-sm-7 offset-sm-3">
|
||||
<button className="btn btn-primary btn-space" type="button" onClick={() => this.saveProps()}>确定</button>
|
||||
<a className="btn btn-link btn-space" onClick={() => this.hide()}>取消</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RbModal>)
|
||||
</RbModal>
|
||||
)
|
||||
}
|
||||
|
||||
saveProps() {
|
||||
this.state.callback(this.state)
|
||||
this.hide()
|
||||
|
|
|
@ -535,7 +535,7 @@ class FeedsSchedule extends BaseChart {
|
|||
|
||||
renderChart(data) {
|
||||
const table = (!data || data.length === 0) ?
|
||||
<div className="chart-undata must-center text-center"><i className="zmdi zmdi-check icon text-success"></i> 暂无待办日程<br />过期超过 30 天的日程将不再显示</div>
|
||||
<div className="chart-undata must-center"><i className="zmdi zmdi-check icon text-success"></i> 暂无待办日程<br />过期超过 30 天的日程将不再显示</div>
|
||||
:
|
||||
<div>
|
||||
<table className="table table-striped table-hover">
|
||||
|
|
|
@ -13,13 +13,14 @@ window.clickIcon = function (icon) {
|
|||
}
|
||||
|
||||
const wpc = window.__PageConfig
|
||||
|
||||
$(document).ready(function () {
|
||||
if (!wpc.metaId) $('.footer .alert').removeClass('hide')
|
||||
else $('.footer .J_action').removeClass('hide')
|
||||
|
||||
$('.J_tab-' + wpc.entity + ' a').addClass('active')
|
||||
|
||||
let _btn = $('.J_save').click(function () {
|
||||
const $btn = $('.J_save').click(function () {
|
||||
if (!wpc.metaId) return
|
||||
let _data = {
|
||||
entityLabel: $val('#entityLabel'),
|
||||
|
@ -33,7 +34,7 @@ $(document).ready(function () {
|
|||
if (Object.keys(_data).length === 0) { location.reload(); return }
|
||||
|
||||
_data.metadata = { entity: 'MetaEntity', id: wpc.metaId }
|
||||
_btn.button('loading')
|
||||
$btn.button('loading')
|
||||
$.post('../entity-update', JSON.stringify(_data), function (res) {
|
||||
if (res.error_code === 0) location.reload()
|
||||
else RbHighbar.error(res.error_msg)
|
||||
|
@ -45,8 +46,8 @@ $(document).ready(function () {
|
|||
})
|
||||
|
||||
$.get('/commons/metadata/fields?entity=' + wpc.entity, function (d) {
|
||||
let rs = d.data.map((item) => {
|
||||
let canName = item.type === 'NUMBER' || item.type === 'DECIMAL' ||
|
||||
const rs = d.data.map((item) => {
|
||||
const canName = item.type === 'NUMBER' || item.type === 'DECIMAL' ||
|
||||
item.type === 'TEXT' || item.type === 'EMAIL' || item.type === 'URL' || item.type === 'PHONE' ||
|
||||
item.type === 'SERIES' || item.type === 'PICKLIST' || item.type === 'CLASSIFICATION' ||
|
||||
item.type === 'DATE' || item.type === 'DATETIME'
|
||||
|
@ -54,7 +55,7 @@ $(document).ready(function () {
|
|||
id: item.name,
|
||||
text: item.label,
|
||||
disabled: canName === false,
|
||||
title: canName === false ? '此字段(类型)不支持作为名称字段使用' : ''
|
||||
title: canName === false ? '此字段(类型)不支持作为名称字段使用' : item.label
|
||||
}
|
||||
})
|
||||
let rsSort = []
|
||||
|
@ -64,12 +65,11 @@ $(document).ready(function () {
|
|||
rs.forEach((item) => {
|
||||
if (item.disabled === true) rsSort.push(item)
|
||||
})
|
||||
rs = rsSort
|
||||
|
||||
$('#nameField').select2({
|
||||
placeholder: '选择字段',
|
||||
allowClear: false,
|
||||
data: rs
|
||||
data: rsSort
|
||||
}).val(wpc.nameField).trigger('change')
|
||||
})
|
||||
})
|
|
@ -442,7 +442,7 @@ function __renderRichContent(e) {
|
|||
}
|
||||
|
||||
const ANN_OPTIONS = [[1, '动态页'], [2, '首页'], [4, '登录页']]
|
||||
const REM_OPTIONS = [[1, '内部消息'], [2, '邮件']]
|
||||
const REM_OPTIONS = [[1, '消息通知'], [2, '邮件']]
|
||||
function __findMaskTexts(mask, options) {
|
||||
const texts = []
|
||||
options.forEach((item) => {
|
||||
|
|
|
@ -537,7 +537,7 @@ class ScheduleOptions extends React.Component {
|
|||
<dd className="col-12 col-lg-9 mb-0" ref={(c) => this._scheduleRemind = c}>
|
||||
<label className="custom-control custom-checkbox custom-control-inline">
|
||||
<input className="custom-control-input" name="showOn" type="checkbox" value={1} disabled={this.props.readonly} />
|
||||
<span className="custom-control-label">内部消息</span>
|
||||
<span className="custom-control-label">消息通知</span>
|
||||
</label>
|
||||
<label className="custom-control custom-checkbox custom-control-inline">
|
||||
<input className="custom-control-input" name="showOn" type="checkbox" value={2} disabled={this.props.readonly} />
|
||||
|
@ -608,6 +608,7 @@ class FeedsEditDlg extends RbModalHandler {
|
|||
|
||||
_post = () => {
|
||||
const _data = this._editor.vals()
|
||||
if (!_data) return
|
||||
if (!_data.content) { RbHighbar.create('请输入动态内容'); return }
|
||||
_data.metadata = { entity: 'Feeds', id: this.props.id }
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
// ~~ 图片/文档预览
|
||||
|
||||
const TYPE_DOCS = ['.doc', '.docx', '.rtf', '.xls', '.xlsx', '.ppt', '.pptx', '.pdf']
|
||||
const TYPE_TEXTS = ['.txt', '.xml', '.json', '.md', '.yml', '.css', '.js', '.htm', '.html']
|
||||
const TYPE_TEXTS = ['.txt', '.xml', '.json', '.md', '.yml', '.css', '.js', '.htm', '.html', '.log', '.sql']
|
||||
const TYPE_IMGS = ['.jpg', '.jpeg', '.gif', '.png', '.bmp']
|
||||
const TYPE_AUDIOS = ['.mp3', '.wav', '.ogg', '.acc']
|
||||
const TYPE_VIDEOS = ['.mp4', '.webm']
|
||||
|
@ -94,7 +94,9 @@ class RbPreview extends React.Component {
|
|||
renderText() {
|
||||
return <div className="container fp-content">
|
||||
<div className="iframe text" onClick={this.__stopEvent}>
|
||||
{this.state.previewText ? <pre>{this.state.previewText}</pre> : <div className="must-center"><RbSpinner fully={true} /></div>}
|
||||
{(this.state.previewText || this.state.previewText === '')
|
||||
? <pre>{this.state.previewText || <i className="text-muted">无内容</i>}</pre>
|
||||
: <div className="must-center"><RbSpinner fully={true} /></div>}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ class FolderEditDlg extends RbFormHandler {
|
|||
this.disabled(true)
|
||||
$.post('/app/entity/record-save', JSON.stringify(_data), () => {
|
||||
this.hide()
|
||||
this.props.call && this.props.call()
|
||||
typeof this.props.call === 'function' && this.props.call()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -347,8 +347,9 @@ $(document).ready(() => {
|
|||
if (res.error_code === 0) {
|
||||
this.hide()
|
||||
filesList.loadData()
|
||||
} RbHighbar.error(res.error_msg)
|
||||
|
||||
} else {
|
||||
RbHighbar.error(res.error_msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
@ -64,13 +64,14 @@ class FilesList extends React.Component {
|
|||
|
||||
componentDidMount = () => this.loadData()
|
||||
loadData(entry, pageNo) {
|
||||
this.__lastEntry = entry = entry || this.__lastEntry
|
||||
this.__lastEntry = entry || this.__lastEntry
|
||||
this.__pageNo = pageNo || 1
|
||||
$.get(`/files/list-file?entry=${entry}&sort=${currentSort || ''}&q=${$encode(currentSearch || '')}&pageNo=${this.__pageNo}&pageSize=${PAGE_SIZE}`, (res) => {
|
||||
const _current = res.data || []
|
||||
let _files = this.__pageNo === 1 ? [] : this.state.files
|
||||
_files = [].concat(_files, _current)
|
||||
this.setState({ files: _files, currentLen: _current.length })
|
||||
const url = `/files/list-file?entry=${this.__lastEntry}&sort=${currentSort || ''}&q=${$encode(currentSearch || '')}&pageNo=${this.__pageNo}&pageSize=${PAGE_SIZE}`
|
||||
$.get(url, (res) => {
|
||||
const current = res.data || []
|
||||
let files = this.__pageNo === 1 ? [] : this.state.files
|
||||
files = [].concat(files, current)
|
||||
this.setState({ files: files, currentLen: current.length })
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ rebuild is dual-licensed under commercial and open source licenses (GPLv3).
|
|||
See LICENSE and COMMERCIAL in the project root for license information.
|
||||
*/
|
||||
|
||||
let focusItem
|
||||
$(document).ready(() => {
|
||||
let mList = <MessageList lazy={true} />
|
||||
if (window.__PageConfig && window.__PageConfig.type === 'Approval') mList = <ApprovalList />
|
||||
|
@ -16,10 +17,11 @@ $(document).ready(() => {
|
|||
mList.fetchList(1, $(this).data('type'))
|
||||
})
|
||||
|
||||
let ntype = location.hash || '#unread'
|
||||
ntype = $('.notification-type a[href="' + ntype + '"]')
|
||||
if (ntype.length === 0) ntype = $('.notification-type a[href="#unread"]')
|
||||
ntype.trigger('click')
|
||||
const ntype = (location.hash || '#unread').split('=')
|
||||
focusItem = ntype[1]
|
||||
let activeNav = $('.notification-type a[href="' + ntype[0] + '"]')
|
||||
if (ntype.length === 0) activeNav = $('.notification-type a[href="#unread"]')
|
||||
activeNav.trigger('click')
|
||||
})
|
||||
|
||||
// 消息列表
|
||||
|
@ -54,7 +56,7 @@ class MessageList extends React.Component {
|
|||
if (item[3]) clazz += ' notification-unread'
|
||||
if (append) clazz += ' append'
|
||||
|
||||
return <li className={clazz} key={item[4]} onClick={item[3] ? () => this.makeRead(item[4]) : null}>
|
||||
return <li id={item[4]} className={`${clazz} ${item[4] === focusItem ? 'focus' : ''}`} key={item[4]} onClick={item[3] ? () => this.makeRead(item[4]) : null}>
|
||||
<span className="a">
|
||||
<div className="image"><img src={`${rb.baseUrl}/account/user-avatar/${item[0][0]}`} title={item[0][1]} alt="Avatar" /></div>
|
||||
<div className="notification-info">
|
||||
|
@ -90,6 +92,7 @@ class MessageList extends React.Component {
|
|||
if (e && e.stopPropagation) e.stopPropagation()
|
||||
})
|
||||
setTimeout(() => $gotoSection(), 200)
|
||||
focusItem = null
|
||||
}
|
||||
|
||||
gotoPage(p) {
|
||||
|
|
|
@ -12,6 +12,9 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
/*! https://github.com/gabceb/jquery-browser-plugin */
|
||||
// eslint-disable-next-line
|
||||
!function (a) { "function" == typeof define && define.amd ? define(["jquery"], function (b) { return a(b) }) : "object" == typeof module && "object" == typeof module.exports ? module.exports = a(require("jquery")) : a(window.jQuery) }(function (a) { "use strict"; function b(a) { void 0 === a && (a = window.navigator.userAgent), a = a.toLowerCase(); var b = /(edge)\/([\w.]+)/.exec(a) || /(opr)[\/]([\w.]+)/.exec(a) || /(chrome)[ \/]([\w.]+)/.exec(a) || /(iemobile)[\/]([\w.]+)/.exec(a) || /(version)(applewebkit)[ \/]([\w.]+).*(safari)[ \/]([\w.]+)/.exec(a) || /(webkit)[ \/]([\w.]+).*(version)[ \/]([\w.]+).*(safari)[ \/]([\w.]+)/.exec(a) || /(webkit)[ \/]([\w.]+)/.exec(a) || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a) || /(msie) ([\w.]+)/.exec(a) || a.indexOf("trident") >= 0 && /(rv)(?::| )([\w.]+)/.exec(a) || a.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a) || [], c = /(ipad)/.exec(a) || /(ipod)/.exec(a) || /(windows phone)/.exec(a) || /(iphone)/.exec(a) || /(kindle)/.exec(a) || /(silk)/.exec(a) || /(android)/.exec(a) || /(win)/.exec(a) || /(mac)/.exec(a) || /(linux)/.exec(a) || /(cros)/.exec(a) || /(playbook)/.exec(a) || /(bb)/.exec(a) || /(blackberry)/.exec(a) || [], d = {}, e = { browser: b[5] || b[3] || b[1] || "", version: b[2] || b[4] || "0", versionNumber: b[4] || b[2] || "0", platform: c[0] || "" }; if (e.browser && (d[e.browser] = !0, d.version = e.version, d.versionNumber = parseInt(e.versionNumber, 10)), e.platform && (d[e.platform] = !0), (d.android || d.bb || d.blackberry || d.ipad || d.iphone || d.ipod || d.kindle || d.playbook || d.silk || d["windows phone"]) && (d.mobile = !0), (d.cros || d.mac || d.linux || d.win) && (d.desktop = !0), (d.chrome || d.opr || d.safari) && (d.webkit = !0), d.rv || d.iemobile) { var f = "msie"; e.browser = f, d[f] = !0 } if (d.edge) { delete d.edge; var g = "msedge"; e.browser = g, d[g] = !0 } if (d.safari && d.blackberry) { var h = "blackberry"; e.browser = h, d[h] = !0 } if (d.safari && d.playbook) { var i = "playbook"; e.browser = i, d[i] = !0 } if (d.bb) { var j = "blackberry"; e.browser = j, d[j] = !0 } if (d.opr) { var k = "opera"; e.browser = k, d[k] = !0 } if (d.safari && d.android) { var l = "android"; e.browser = l, d[l] = !0 } if (d.safari && d.kindle) { var m = "kindle"; e.browser = m, d[m] = !0 } if (d.safari && d.silk) { var n = "silk"; e.browser = n, d[n] = !0 } return d.name = e.browser, d.platform = e.platform, d } return window.jQBrowser = b(window.navigator.userAgent), window.jQBrowser.uaMatch = b, a && (a.browser = window.jQBrowser), window.jQBrowser });
|
||||
// select2 zh-CN
|
||||
// eslint-disable-next-line
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="请删除"+t+"个字符";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="请再输入至少"+t+"个字符";n='输入关键词搜索';return n},loadingMore:function(){return"载入更多结果"},maximumSelected:function(e){var t="最多只能选择"+e.maximum+"项";return t},noResults:function(){return"未找到结果"},searching:function(){return"搜索中..."}}}),{define:e.define,require:e.require}})();
|
||||
// extends jQuery
|
||||
(function ($) {
|
||||
$.fn.extend({
|
||||
|
|
|
@ -53,7 +53,7 @@ class BatchOperator extends RbFormHandler {
|
|||
}
|
||||
|
||||
getQueryData() {
|
||||
const qd = this.props.listRef.getLastQueryData()
|
||||
const qd = this.props.listRef.getLastQueryEntry()
|
||||
if (~~this.state.dataRange === 1) qd._selected = this.props.listRef.getSelectedIds(true).join('|')
|
||||
return qd
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ class RbList extends React.Component {
|
|||
|
||||
this.pageNo = 1
|
||||
this.pageSize = $storage.get('ListPageSize') || 20
|
||||
this.advFilter = $storage.get(this.__defaultFilterKey)
|
||||
this.advFilterId = $storage.get(this.__defaultFilterKey)
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -68,7 +68,7 @@ class RbList extends React.Component {
|
|||
const styles = { width: cWidth + 'px' }
|
||||
const clazz = `unselect ${item.unsort ? '' : 'sortable'} ${idx === 0 && supportFixedColumns ? 'column-fixed column-fixed-2nd' : ''}`
|
||||
return <th key={'column-' + item.field} style={styles} className={clazz} data-field={item.field}
|
||||
onClick={item.unsort ? null : this._sortField.bind(this, item.field)}>
|
||||
onClick={(e) => !item.unsort && this._sortField(item.field, e)}>
|
||||
<div style={styles}>
|
||||
<span style={{ width: (cWidth - 8) + 'px' }}>{item.label}</span>
|
||||
<i className={'zmdi ' + (item.sort || '')} />
|
||||
|
@ -147,6 +147,9 @@ class RbList extends React.Component {
|
|||
containment: '.rb-datatable-body',
|
||||
axis: 'x',
|
||||
helper: 'clone',
|
||||
start: function () {
|
||||
that.__columnResizing = true
|
||||
},
|
||||
stop: function (event, ui) {
|
||||
const field = $(event.target).parents('th').data('field')
|
||||
let left = ui.position.left - 0
|
||||
|
@ -161,6 +164,7 @@ class RbList extends React.Component {
|
|||
}
|
||||
}
|
||||
that.setState({ fields: fields }, () => $scroller.perfectScrollbar('update'))
|
||||
setTimeout(() => that.__columnResizing = false, 100)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -184,7 +188,7 @@ class RbList extends React.Component {
|
|||
pageNo: this.pageNo,
|
||||
pageSize: this.pageSize,
|
||||
filter: this.lastFilter,
|
||||
advFilter: this.advFilter,
|
||||
advFilter: this.advFilterId,
|
||||
sort: field_sort,
|
||||
reload: this.pageNo === 1
|
||||
}
|
||||
|
@ -298,6 +302,7 @@ class RbList extends React.Component {
|
|||
|
||||
// 排序
|
||||
_sortField(field, e) {
|
||||
if (this.__columnResizing) return // fix: firefox
|
||||
const fields = this.state.fields
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
if (fields[i].field === field) {
|
||||
|
@ -332,7 +337,7 @@ class RbList extends React.Component {
|
|||
* 设置高级过滤器ID
|
||||
*/
|
||||
setAdvFilter(id) {
|
||||
this.advFilter = id
|
||||
this.advFilterId = id
|
||||
this.pageNo = 1
|
||||
this.fetchList(this.__buildQuick())
|
||||
if (id) $storage.set(this.__defaultFilterKey, id)
|
||||
|
@ -343,15 +348,14 @@ class RbList extends React.Component {
|
|||
* 搜索
|
||||
*/
|
||||
search(filter, fromAdv) {
|
||||
const afHold = this.advFilter
|
||||
if (fromAdv === true) this.advFilter = null
|
||||
// 选择的过滤条件与当前的排他
|
||||
if (fromAdv === true) this.advFilterId = null
|
||||
this.pageNo = 1
|
||||
this.fetchList(filter)
|
||||
|
||||
// No keep last filter
|
||||
if (fromAdv === true) {
|
||||
this.advFilter = afHold
|
||||
this.lastFilter = null
|
||||
$('.J_advfilter .indicator-primary').remove()
|
||||
if (filter.items.length > 0) $('<i class="indicator-primary"></i>').appendTo('.J_advfilter')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -387,9 +391,9 @@ class RbList extends React.Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* 获取最后查询过滤数据
|
||||
* 获取最后查询条件
|
||||
*/
|
||||
getLastQueryData() {
|
||||
getLastQueryEntry() {
|
||||
return JSON.parse(JSON.stringify(this.__lastQueryEntry)) // Use clone
|
||||
}
|
||||
|
||||
|
|
|
@ -225,48 +225,51 @@ var __checkMessage = function () {
|
|||
else $('.J_notifications-top .indicator').addClass('hide')
|
||||
|
||||
if (__checkMessage__state !== res.data.unread) {
|
||||
__checkMessage__state = res.data.unread
|
||||
if (__checkMessage__state > 0) {
|
||||
if (!window.__doctitle) window.__doctitle = document.title
|
||||
document.title = '(' + __checkMessage__state + ') ' + window.__doctitle
|
||||
if (rb.env === 'dev') __showNotification()
|
||||
}
|
||||
__loadMessages__state = 0
|
||||
__loadMessages_state = false
|
||||
}
|
||||
__checkMessage__state = res.data.unread
|
||||
|
||||
setTimeout(__checkMessage, rb.env === 'dev' ? 60 * 10000 : 2000)
|
||||
})
|
||||
}
|
||||
var __loadMessages__state = 0
|
||||
var __loadMessages_state = false
|
||||
var __loadMessages = function () {
|
||||
if (__loadMessages__state === 1) return
|
||||
if (__loadMessages_state) return
|
||||
var dest = $('.rb-notifications .content ul').empty()
|
||||
if (dest.find('li').length === 0) {
|
||||
$('<li class="text-center mt-3 mb-3"><i class="zmdi zmdi-refresh zmdi-hc-spin fs-18"></i></li>').appendTo(dest)
|
||||
}
|
||||
|
||||
$.get('/notification/messages?pageSize=10&preview=true', function (res) {
|
||||
dest.empty()
|
||||
$(res.data).each(function (idx, item) {
|
||||
var o = $('<li class="notification"></li>').appendTo(dest)
|
||||
if (item[3] === true) o.addClass('notification-unread')
|
||||
o = $('<a class="a" href="' + rb.baseUrl + '/notifications#' + (item[3] ? 'unread' : 'all') + '"></a>').appendTo(o)
|
||||
o = $('<a class="a" href="' + rb.baseUrl + '/notifications#' + (item[3] ? 'unread=' : 'all=') + item[4] + '"></a>').appendTo(o)
|
||||
$('<div class="image"><img src="' + rb.baseUrl + '/account/user-avatar/' + item[0][0] + '" alt="Avatar"></div>').appendTo(o)
|
||||
o = $('<div class="notification-info"></div>').appendTo(o)
|
||||
$('<div class="text text-truncate">' + item[1] + '</div>').appendTo(o)
|
||||
$('<span class="date">' + item[2] + '</span>').appendTo(o)
|
||||
})
|
||||
__loadMessages__state = 1
|
||||
__loadMessages_state = true
|
||||
if (res.data.length === 0) $('<li class="text-center mt-4 mb-4 text-muted">暂无消息</li>').appendTo(dest)
|
||||
})
|
||||
}
|
||||
var __showNotification = function () {
|
||||
if (window.Notification) {
|
||||
if (window.Notification.permission === 'granted') {
|
||||
new Notification('你有 ' + __checkMessage__state + ' 条未读消息', {
|
||||
tag: 'rbNotification'
|
||||
var _Notification = window.Notification || window.mozNotification || window.webkitNotification
|
||||
if (_Notification) {
|
||||
if (_Notification.permission === 'granted') {
|
||||
new _Notification('你有 ' + __checkMessage__state + ' 条未读消息', {
|
||||
tag: 'rbNotification',
|
||||
icon: rb.baseUrl + '/assets/img/favicon.png',
|
||||
})
|
||||
} else {
|
||||
window.Notification.requestPermission()
|
||||
_Notification.requestPermission()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ class ContentSendNotification extends ActionContentSpec {
|
|||
<div className="col-12 col-lg-8 pt-1">
|
||||
<label className="custom-control custom-control-sm custom-radio custom-control-inline mb-1">
|
||||
<input className="custom-control-input" name="mtype" type="radio" onChange={() => this.setState({ type: 1 })} checked={this.state.type === 1} />
|
||||
<span className="custom-control-label">内部消息</span>
|
||||
<span className="custom-control-label">消息通知</span>
|
||||
</label>
|
||||
<label className="custom-control custom-control-sm custom-radio custom-control-inline mb-1">
|
||||
<input className="custom-control-input" name="mtype" type="radio" onChange={() => this.setState({ type: 2 })} checked={this.state.type === 2} />
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<%@ include file="/_include/Head.jsp"%>
|
||||
<title>待办</title>
|
||||
<title>待办通知</title>
|
||||
<style type="text/css">
|
||||
.notification-info .badge {
|
||||
border-radius: 99px;
|
||||
|
@ -26,7 +26,7 @@
|
|||
<div class="tab-container">
|
||||
<ul class="nav nav-tabs nav-tabs-classic notification-tab">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="../notifications"><span class="icon zmdi zmdi-notifications"></span> 通知</a>
|
||||
<a class="nav-link" href="../notifications"><span class="icon zmdi zmdi-notifications"></span> 消息</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="todo"><span class="icon zmdi zmdi-alarm-check"></span> 待办</a>
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
.vcode-row {
|
||||
height: 41px;
|
||||
max-width: 100%;
|
||||
}
|
||||
.vcode-row img {
|
||||
cursor: pointer;
|
||||
}
|
||||
.splash-footer *,
|
||||
|
@ -79,7 +81,7 @@
|
|||
<input class="form-control" type="text" placeholder="${bundle.lang('InputCaptcha')}">
|
||||
</div>
|
||||
<div class="col-6 text-right pl-0 pr-0">
|
||||
<img style="max-width:100%;margin-right:-15px" alt="${bundle.lang('Captcha')}" title="${bundle.lang('ClickReload')}">
|
||||
<img class="mw-100 mr-zero" alt="${bundle.lang('Captcha')}" title="${bundle.lang('ClickReload')}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row login-tools">
|
||||
|
|
|
@ -4,6 +4,16 @@
|
|||
<head>
|
||||
<%@ include file="/_include/Head.jsp"%>
|
||||
<title>${bundle.lang('UserSignup')}</title>
|
||||
<style type="text/css">
|
||||
.form-group.row {
|
||||
margin-left: -15px !important;
|
||||
margin-right: -15px !important;
|
||||
}
|
||||
.form-group.row .btn {
|
||||
height: 41px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="rb-splash-screen">
|
||||
<div class="rb-wrapper rb-login">
|
||||
|
@ -23,12 +33,12 @@
|
|||
<div class="form-group">
|
||||
<input class="form-control" id="sEmail" type="email" placeholder="${bundle.lang('Email')}" autocomplete="off">
|
||||
</div>
|
||||
<div class="form-group pt-0 row">
|
||||
<div class="form-group row pt-0">
|
||||
<div class="col-7">
|
||||
<input class="form-control" type="text" id="sVcode" placeholder="${bundle.lang('EmailVcode')}" autocomplete="off">
|
||||
</div>
|
||||
<div class="col-5 text-right pl-0">
|
||||
<button class="btn btn-secondary J_vcode-btn" style="height:41px;width:100%" type="button">${bundle.lang('GetVcode')}</button>
|
||||
<button class="btn btn-primary bordered J_vcode-btn" type="button">${bundle.lang('GetVcode')}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group login-submit">
|
||||
|
|
|
@ -1,19 +1,8 @@
|
|||
/*
|
||||
rebuild - Building your business-systems freely.
|
||||
Copyright (C) 2019 devezhao <zhaofang123@gmail.com>
|
||||
Copyright (c) REBUILD <https://getrebuild.com/> and its owners. All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
rebuild is dual-licensed under commercial and open source licenses (GPLv3).
|
||||
See LICENSE and COMMERCIAL in the project root for license information.
|
||||
*/
|
||||
|
||||
package com.rebuild.utils;
|
||||
|
@ -21,21 +10,54 @@ package com.rebuild.utils;
|
|||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* https://www.jianshu.com/p/191d1e21f7ed
|
||||
*
|
||||
* @author devezhao-mbp zhaofang123@gmail.com
|
||||
* @since 2019/05/16
|
||||
*/
|
||||
public class MarkdownUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testParse() throws Exception {
|
||||
String md = "[Click here](/admin/)";
|
||||
System.out.println(MarkdownUtils.parse(md));
|
||||
|
||||
md = "\n"
|
||||
+ "|COL1|COL2|COL3|"
|
||||
+ "\n|---|---|---|"
|
||||
+ "\n|data|data||"
|
||||
+ "\n[Table 1. caption]";
|
||||
System.out.println(MarkdownUtils.parse(md));
|
||||
public void testRender() throws Exception {
|
||||
render("hello" +
|
||||
"\n word");
|
||||
|
||||
render("# Head");
|
||||
render("## Head");
|
||||
|
||||
render("*A*");
|
||||
render("**A**");
|
||||
render("***A***");
|
||||
|
||||
render("***");
|
||||
|
||||
render("> P");
|
||||
render("> P" +
|
||||
">> P" +
|
||||
"\n>>> P");
|
||||
|
||||
render("`CODE`");
|
||||
render("```" +
|
||||
"\nCODE" +
|
||||
"\n```");
|
||||
|
||||
render("[Click here](/admin/)");
|
||||
render("![alt](/img.png)");
|
||||
|
||||
render("|COL1|COL2|COL3|"
|
||||
+ "\n|---|---|---|"
|
||||
+ "\n|data|data||"
|
||||
+ "\n[Table 1. caption]");
|
||||
|
||||
render("1. a" +
|
||||
"\n 1. a1" +
|
||||
"\n2. b");
|
||||
}
|
||||
|
||||
private void render(String md) {
|
||||
System.out.println("MD: ");
|
||||
System.out.println(md);
|
||||
System.out.println("HTML :");
|
||||
System.out.println(MarkdownUtils.render(md));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue