mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-11-10 08:55:31 +08:00
enh: Grouping/Category
This commit is contained in:
parent
37cd265246
commit
2c3e47258e
9 changed files with 170 additions and 66 deletions
2
@rbv
2
@rbv
|
@ -1 +1 @@
|
|||
Subproject commit bd85df4926ea0f249117ad90f7a0cee621834ce4
|
||||
Subproject commit c3184f8196c0835c70942a2b9723838eebb2ebb6
|
|
@ -7,6 +7,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
|
||||
package com.rebuild.core.configuration.general;
|
||||
|
||||
import cn.devezhao.commons.CalendarUtils;
|
||||
import cn.devezhao.persist4j.Entity;
|
||||
import cn.devezhao.persist4j.Field;
|
||||
import cn.devezhao.persist4j.Query;
|
||||
|
@ -16,59 +17,67 @@ import com.alibaba.fastjson.JSONArray;
|
|||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.configuration.ConfigBean;
|
||||
import com.rebuild.core.metadata.easymeta.DisplayType;
|
||||
import com.rebuild.core.metadata.easymeta.EasyField;
|
||||
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
|
||||
import com.rebuild.core.metadata.impl.EasyEntityConfigProps;
|
||||
import com.rebuild.core.support.general.FieldValueHelper;
|
||||
import com.rebuild.utils.JSONUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 列表字段分类数据
|
||||
* 列表字段分类(分组)数据
|
||||
*
|
||||
* @author ZHAO
|
||||
* @since 07/23/2022
|
||||
*/
|
||||
public class DataListCategory {
|
||||
|
||||
public static final DataListCategory instance = new DataListCategory();
|
||||
|
||||
private DataListCategory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entity
|
||||
* @param user
|
||||
* @return
|
||||
*/
|
||||
public static JSON datas(Entity entity, ID user) {
|
||||
public JSON datas(Entity entity, ID user) {
|
||||
final Field categoryField = getFieldOfCategory(entity);
|
||||
if (categoryField == null) return null;
|
||||
|
||||
DisplayType dt = EasyMetaFactory.getDisplayType(categoryField);
|
||||
EasyField easyField = EasyMetaFactory.valueOf(categoryField);
|
||||
DisplayType dt = easyField.getDisplayType();
|
||||
|
||||
List<Object[]> clist = new ArrayList<>();
|
||||
List<Object[]> dataList = new ArrayList<>();
|
||||
|
||||
if (dt == DisplayType.MULTISELECT || dt == DisplayType.PICKLIST) {
|
||||
ConfigBean[] entries = MultiSelectManager.instance.getPickListRaw(categoryField, true);
|
||||
for (ConfigBean e : entries) {
|
||||
Object id = e.getID("id");
|
||||
if (dt == DisplayType.MULTISELECT) id = e.getLong("mask");
|
||||
|
||||
clist.add(new Object[] { e.getString("text"), id });
|
||||
dataList.add(new Object[] { e.getString("text"), id });
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// TODO 考虑支持更多分组字段类型,例如日期(但要考虑日期格式)
|
||||
|
||||
String sql;
|
||||
if (dt == DisplayType.N2NREFERENCE) {
|
||||
sql = MessageFormat.format(
|
||||
"select distinct referenceId from NreferenceItem where belongEntity = ''{0}'' and belongField = ''{1}''",
|
||||
entity.getName(), categoryField.getName());
|
||||
} else {
|
||||
String wrapField = categoryField.getName();
|
||||
if (dt == DisplayType.DATETIME) {
|
||||
wrapField = String.format("DATE_FORMAT(%s, '%%Y-%%m-%%d')", wrapField);
|
||||
}
|
||||
|
||||
sql = MessageFormat.format(
|
||||
"select distinct {0} from {1} where {0} is not null", categoryField.getName(), entity.getName());
|
||||
"select {0} from {1} where {2} is not null group by {0}",
|
||||
wrapField, entity.getName(), categoryField.getName());
|
||||
}
|
||||
|
||||
Query query = user == null
|
||||
|
@ -76,18 +85,38 @@ public class DataListCategory {
|
|||
: Application.getQueryFactory().createQuery(sql, user);
|
||||
Object[][] array = query.array();
|
||||
|
||||
String cf = EasyMetaFactory.valueOf(entity).getExtraAttr(EasyEntityConfigProps.ADV_LIST_SHOWCATEGORY);
|
||||
String[] ff = cf.split(":");
|
||||
String format = ff.length > 1 ? ff[1] : null;
|
||||
|
||||
Set<Object> unique = new HashSet<>();
|
||||
|
||||
for (Object[] o : array) {
|
||||
Object id = o[0];
|
||||
Object label = FieldValueHelper.getLabelNotry((ID) id);
|
||||
clist.add(new Object[] { label, id });
|
||||
}
|
||||
Object label;
|
||||
|
||||
// TODO 分类数据 code 排序
|
||||
clist.sort(Comparator.comparing(o -> o[0].toString()));
|
||||
if (dt == DisplayType.DATE || dt == DisplayType.DATETIME) {
|
||||
format = StringUtils.defaultIfBlank(format, CalendarUtils.UTC_DATE_FORMAT);
|
||||
if (id instanceof Date) {
|
||||
label = CalendarUtils.format(format, (Date) id);
|
||||
} else {
|
||||
label = id.toString().substring(0, format.length());
|
||||
}
|
||||
id = label;
|
||||
|
||||
} else {
|
||||
label = FieldValueHelper.getLabelNotry((ID) id);
|
||||
}
|
||||
|
||||
if (unique.contains(id)) continue;
|
||||
unique.add(id);
|
||||
|
||||
dataList.add(new Object[] { label, id });
|
||||
}
|
||||
}
|
||||
|
||||
JSONArray res = new JSONArray();
|
||||
for (Object[] o : clist) {
|
||||
for (Object[] o : dataList) {
|
||||
res.add(JSONUtils.toJSONObject(
|
||||
new String[] { "label", "id", "count" },
|
||||
new Object[] { o[0], o[1], 0 } ));
|
||||
|
@ -102,9 +131,10 @@ public class DataListCategory {
|
|||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
public static Field getFieldOfCategory(Entity entity) {
|
||||
public Field getFieldOfCategory(Entity entity) {
|
||||
String categoryField = EasyMetaFactory.valueOf(entity).getExtraAttr(EasyEntityConfigProps.ADV_LIST_SHOWCATEGORY);
|
||||
if (StringUtils.isBlank(categoryField) || !entity.containsField(categoryField)) return null;
|
||||
return entity.getField(categoryField);
|
||||
if (categoryField != null) categoryField = categoryField.split(":")[0];
|
||||
if (categoryField != null && entity.containsField(categoryField)) return entity.getField(categoryField);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -189,22 +189,22 @@ public class ProtocolFilterParser {
|
|||
*/
|
||||
protected String parseCategory(String entity, String value) {
|
||||
Entity rootEntity = MetadataHelper.getEntity(entity);
|
||||
Field classField = DataListCategory.getFieldOfCategory(rootEntity);
|
||||
if (classField == null) return "(9=9)";
|
||||
Field categoryField = DataListCategory.instance.getFieldOfCategory(rootEntity);
|
||||
if (categoryField == null) return "(9=9)";
|
||||
|
||||
DisplayType dt = EasyMetaFactory.getDisplayType(classField);
|
||||
DisplayType dt = EasyMetaFactory.getDisplayType(categoryField);
|
||||
|
||||
if (dt == DisplayType.MULTISELECT) {
|
||||
return String.format("%s && %d", classField.getName(), ObjectUtils.toInt(value));
|
||||
return String.format("%s && %d", categoryField.getName(), ObjectUtils.toInt(value));
|
||||
} else if (dt == DisplayType.N2NREFERENCE) {
|
||||
return String.format(
|
||||
"exists (select recordId from NreferenceItem where ^%s = recordId and belongField = '%s' and referenceId = '%s')",
|
||||
rootEntity.getPrimaryField().getName(), classField.getName(), StringEscapeUtils.escapeSql(value));
|
||||
rootEntity.getPrimaryField().getName(), categoryField.getName(), StringEscapeUtils.escapeSql(value));
|
||||
} else {
|
||||
return String.format("%s = '%s'", classField.getName(), StringEscapeUtils.escapeSql(value));
|
||||
return String.format("%s = '%s'", categoryField.getName(), StringEscapeUtils.escapeSql(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param relatedExpr
|
||||
* @param mainid
|
||||
|
|
|
@ -69,7 +69,7 @@ public class WidgetController extends BaseController implements ShareTo {
|
|||
|
||||
@GetMapping("widget-category-data")
|
||||
public RespBody getCategoryData(@PathVariable String entity, HttpServletRequest request) {
|
||||
JSON data = DataListCategory.datas(
|
||||
JSON data = DataListCategory.instance.datas(
|
||||
MetadataHelper.getEntity(entity), getRequestUser(request));
|
||||
return RespBody.ok(data);
|
||||
}
|
||||
|
|
|
@ -2216,7 +2216,6 @@
|
|||
"请至少添加 1 个查询字段":"请至少添加 1 个查询字段",
|
||||
"请填写固定值":"请填写固定值",
|
||||
"@%s 退回了你的 %s 审批,请重新审核":"@%s 退回了你的 %s 审批,请重新审核",
|
||||
"显示侧栏分类":"显示侧栏分类",
|
||||
"转换明细记录需选择主记录":"转换明细记录需选择主记录",
|
||||
"@%s 驳回了你的 %s 审批,请重新提交":"@%s 驳回了你的 %s 审批,请重新提交",
|
||||
"如有多个类型请使用逗号或空格分开":"如有多个类型请使用逗号或空格分开",
|
||||
|
@ -2265,7 +2264,7 @@
|
|||
"退回至":"退回至",
|
||||
"提交模式":"提交模式",
|
||||
"启用提交模式必须选择审批流程":"启用提交模式必须选择审批流程",
|
||||
"显示侧栏“分类”":"显示侧栏“分类”",
|
||||
"显示侧栏“分组”":"显示侧栏“分组”",
|
||||
"显示侧栏“常用查询”":"显示侧栏“常用查询”",
|
||||
"仅提交不审批。选择的审批流程至少配置一个审批人,否则会提交失败":"仅提交不审批。选择的审批流程至少配置一个审批人,否则会提交失败",
|
||||
"需要先添加 [记录转换](../transforms) 才能在此处选择":"需要先添加 [记录转换](../transforms) 才能在此处选择",
|
||||
|
@ -2273,7 +2272,6 @@
|
|||
"显示侧栏“图表”":"显示侧栏“图表”",
|
||||
"选择的审批流程至少配置一个审批人":"选择的审批流程至少配置一个审批人",
|
||||
"需要先添加 [审批流程](../approvals) 才能在此处选择":"需要先添加 [审批流程](../approvals) 才能在此处选择",
|
||||
"Category":"分类",
|
||||
"管理员撤销":"管理员撤销",
|
||||
"部分功能可能需要商业版才能正常运行":"部分功能可能需要商业版才能正常运行",
|
||||
"默认大小":"默认大小",
|
||||
|
@ -2379,5 +2377,8 @@
|
|||
"APP SECRET 已重置":"APP SECRET 已重置",
|
||||
"修改 API 秘钥":"修改 API 秘钥",
|
||||
"自动合并单元格":"自动合并单元格",
|
||||
"重置后第三方应用需更换新的 APP SECRET 使用":"重置后第三方应用需更换新的 APP SECRET 使用"
|
||||
"重置后第三方应用需更换新的 APP SECRET 使用":"重置后第三方应用需更换新的 APP SECRET 使用",
|
||||
"分组":"分组",
|
||||
"字段格式":"字段格式",
|
||||
"分组字段":"分组字段"
|
||||
}
|
||||
|
|
|
@ -44,6 +44,12 @@
|
|||
.form-group .switch-button-xs {
|
||||
margin-top: 7px;
|
||||
}
|
||||
.advListShowCategory-set {
|
||||
border-radius: 2px;
|
||||
border: 1px solid #eee;
|
||||
padding: 15px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -99,7 +99,8 @@ function modeSave(newOption, next) {
|
|||
})
|
||||
}
|
||||
|
||||
const CLASS_TYPES = ['PICKLIST', 'MULTISELECT', 'CLASSIFICATION', 'REFERENCE', 'N2NREFERENCE']
|
||||
// const CATE_TYPES = ['PICKLIST', 'MULTISELECT', 'CLASSIFICATION', 'DATE', 'DATETIME', 'REFERENCE', 'N2NREFERENCE']
|
||||
const CATE_TYPES = ['PICKLIST', 'MULTISELECT', 'CLASSIFICATION', 'REFERENCE', 'N2NREFERENCE']
|
||||
|
||||
// 模式选项
|
||||
class DlgMode1Option extends RbFormHandler {
|
||||
|
@ -109,7 +110,7 @@ class DlgMode1Option extends RbFormHandler {
|
|||
<div className="form">
|
||||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('显示侧栏“常用查询”')}</label>
|
||||
<div className="col-sm-7">
|
||||
<div className="col-sm-9">
|
||||
<div className="switch-button switch-button-xs">
|
||||
<input type="checkbox" id="advListHideFilters" defaultChecked={wpc.extConfig && !wpc.extConfig.advListHideFilters} />
|
||||
<span>
|
||||
|
@ -119,8 +120,8 @@ class DlgMode1Option extends RbFormHandler {
|
|||
</div>
|
||||
</div>
|
||||
<div className="form-group row bosskey-show">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('显示侧栏“分类”')}</label>
|
||||
<div className="col-sm-7">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('显示侧栏“分组”')}</label>
|
||||
<div className="col-sm-9">
|
||||
<div className="switch-button switch-button-xs">
|
||||
<input type="checkbox" id="advListShowCategory" defaultChecked={wpc.extConfig && wpc.extConfig.advListShowCategory} />
|
||||
<span>
|
||||
|
@ -128,23 +129,41 @@ class DlgMode1Option extends RbFormHandler {
|
|||
</span>
|
||||
</div>
|
||||
<div className="clearfix"></div>
|
||||
<div className={`J_advListShowCategory mt-2 ${this.state.advListShowCategory ? '' : 'hide'}`}>
|
||||
<select className="form-control form-control-sm">
|
||||
{this.state.advListShowCategoryFields &&
|
||||
this.state.advListShowCategoryFields.map((item) => {
|
||||
return (
|
||||
<option key={item.name} value={item.name}>
|
||||
{item.label}
|
||||
</option>
|
||||
)
|
||||
})}
|
||||
</select>
|
||||
<div className={`advListShowCategory-set ${this.state.advListShowCategory ? '' : 'hide'}`}>
|
||||
<div className="row">
|
||||
<div className="col-8">
|
||||
<label className="mb-1">{$L('分组字段')}</label>
|
||||
<select className="form-control form-control-sm">
|
||||
{this.state.advListShowCategoryFields &&
|
||||
this.state.advListShowCategoryFields.map((item) => {
|
||||
return (
|
||||
<option key={item.name} value={item.name}>
|
||||
{item.label}
|
||||
</option>
|
||||
)
|
||||
})}
|
||||
</select>
|
||||
</div>
|
||||
<div className={`col-4 pl-0 ${this.state.advListShowCategoryFormats ? '' : 'hide'}`}>
|
||||
<label className="mb-1">{$L('字段格式')}</label>
|
||||
<select className="form-control form-control-sm" disabled>
|
||||
{this.state.advListShowCategoryFormats &&
|
||||
this.state.advListShowCategoryFormats.map((item) => {
|
||||
return (
|
||||
<option key={item[0]} value={item[0]}>
|
||||
{item[1]}
|
||||
</option>
|
||||
)
|
||||
})}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('显示侧栏“图表”')}</label>
|
||||
<div className="col-sm-7">
|
||||
<div className="col-sm-9">
|
||||
<div className="switch-button switch-button-xs">
|
||||
<input type="checkbox" id="advListHideCharts" defaultChecked={wpc.extConfig && !wpc.extConfig.advListHideCharts} />
|
||||
<span>
|
||||
|
@ -155,7 +174,7 @@ class DlgMode1Option extends RbFormHandler {
|
|||
</div>
|
||||
<div className="form-group row bosskey-show">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('显示顶部查询面板')}</label>
|
||||
<div className="col-sm-7">
|
||||
<div className="col-sm-9">
|
||||
<div className="switch-button switch-button-xs">
|
||||
<input type="checkbox" id="advListFilterPane" defaultChecked={wpc.extConfig && wpc.extConfig.advListFilterPane} />
|
||||
<span>
|
||||
|
@ -165,7 +184,7 @@ class DlgMode1Option extends RbFormHandler {
|
|||
</div>
|
||||
</div>
|
||||
<div className="form-group row footer">
|
||||
<div className="col-sm-7 offset-sm-3" ref={(c) => (this._btns = c)}>
|
||||
<div className="col-sm-9 offset-sm-3" ref={(c) => (this._btns = c)}>
|
||||
<button className="btn btn-primary" type="button" onClick={this.save}>
|
||||
{$L('确定')}
|
||||
</button>
|
||||
|
@ -180,8 +199,9 @@ class DlgMode1Option extends RbFormHandler {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
let $catFields, $catFormats
|
||||
|
||||
const that = this
|
||||
let $class2
|
||||
$('#advListShowCategory').on('change', function () {
|
||||
if ($val(this)) {
|
||||
that.setState({ advListShowCategory: true })
|
||||
|
@ -189,19 +209,63 @@ class DlgMode1Option extends RbFormHandler {
|
|||
that.setState({ advListShowCategory: null })
|
||||
}
|
||||
|
||||
if (!$class2) {
|
||||
$class2 = $('.J_advListShowCategory select')
|
||||
if (!$catFields) {
|
||||
$catFields = $('.advListShowCategory-set select:eq(0)')
|
||||
$catFormats = $('.advListShowCategory-set select:eq(1)')
|
||||
|
||||
$.get(`/commons/metadata/fields?entity=${wpc.entityName}&deep=2`, (res) => {
|
||||
const _data = []
|
||||
res.data.forEach((item) => {
|
||||
if (CLASS_TYPES.includes(item.type)) _data.push(item)
|
||||
})
|
||||
res.data &&
|
||||
res.data.forEach((item) => {
|
||||
if (CATE_TYPES.includes(item.type) && !(item.name.includes('owningDept.') || item.name.includes('owningUser.'))) {
|
||||
_data.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
// FIELD:[FORMAT]
|
||||
let set = wpc.extConfig && wpc.extConfig.advListShowCategory ? wpc.extConfig.advListShowCategory : null
|
||||
if (set) set = set.split(':')
|
||||
|
||||
wpc.extConfig.advListShowCategory
|
||||
that.setState({ advListShowCategoryFields: _data }, () => {
|
||||
$class2
|
||||
.select2({ placeholder: $L('选择分类字段') })
|
||||
.val((wpc.extConfig && wpc.extConfig.advListShowCategory) || null)
|
||||
.trigger('change')
|
||||
$catFields
|
||||
.select2({
|
||||
placeholder: $L('选择分类字段'),
|
||||
allowClear: false,
|
||||
})
|
||||
.on('change', () => {
|
||||
const s = $catFields.val()
|
||||
const found = _data.find((x) => x.name === s)
|
||||
|
||||
let formats
|
||||
if (found && found.type === 'CLASSIFICATION') {
|
||||
formats = [
|
||||
[0, $L('%d 级分类', 1)],
|
||||
[1, $L('%d 级分类', 2)],
|
||||
[2, $L('%d 级分类', 3)],
|
||||
[3, $L('%d 级分类', 4)],
|
||||
]
|
||||
} else if (found && (found.type === 'DATE' || found.type === 'DATETIME')) {
|
||||
formats = [
|
||||
['yyyy', 'YYYY'],
|
||||
['yyyy-MM', 'YYYY-MM'],
|
||||
['yyyy-MM-dd', 'YYYY-MM-DD'],
|
||||
]
|
||||
}
|
||||
|
||||
that.setState({ advListShowCategoryFormats: formats }, () => {
|
||||
$catFormats.val(null).trigger('change')
|
||||
})
|
||||
})
|
||||
|
||||
$catFormats.select2({ placeholder: $L('默认') })
|
||||
|
||||
if (set) {
|
||||
$catFields.val(set[0]).trigger('change')
|
||||
setTimeout(() => {
|
||||
if (set[1]) $catFormats.val(set[1]).trigger('change')
|
||||
}, 200)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -216,10 +280,13 @@ class DlgMode1Option extends RbFormHandler {
|
|||
const o = {
|
||||
advListHideFilters: !$val('#advListHideFilters'),
|
||||
advListHideCharts: !$val('#advListHideCharts'),
|
||||
advListShowCategory: this.state.advListShowCategory ? $val('.J_advListShowCategory select') : null,
|
||||
advListFilterPane: $val('#advListFilterPane'),
|
||||
}
|
||||
|
||||
if (this.state.advListShowCategory) {
|
||||
o.advListShowCategory = `${$val('.advListShowCategory-set select:eq(0)')}:${$val('.advListShowCategory-set select:eq(1)') || ''}`
|
||||
}
|
||||
|
||||
this.disabled(true)
|
||||
modeSave(o, () => {
|
||||
this.hide()
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<div class="tab-container">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item" th:if="${advListHideFilters != 'true'}"><a class="nav-link" href="#asideFilters" data-toggle="tab">[[${bundle.L('常用查询')}]]</a></li>
|
||||
<li class="nav-item" th:if="${advListShowCategory}"><a class="nav-link J_load-category" href="#asideCategory" data-toggle="tab">[[${bundle.L('Category')}]]</a></li>
|
||||
<li class="nav-item" th:if="${advListShowCategory}"><a class="nav-link J_load-category" href="#asideCategory" data-toggle="tab">[[${bundle.L('分组')}]]</a></li>
|
||||
<li class="nav-item" th:if="${advListHideCharts != 'true'}"><a class="nav-link J_load-charts" href="#asideWidgets" data-toggle="tab">[[${bundle.L('图表')}]]</a></li>
|
||||
</ul>
|
||||
<div class="tab-content rb-scroller">
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<div class="tab-container">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item" th:if="${advListHideFilters != 'true'}"><a class="nav-link" href="#asideFilters" data-toggle="tab">[[${bundle.L('常用查询')}]]</a></li>
|
||||
<li class="nav-item" th:if="${advListShowCategory}"><a class="nav-link J_load-category" href="#asideCategory" data-toggle="tab">[[${bundle.L('Category')}]]</a></li>
|
||||
<li class="nav-item" th:if="${advListShowCategory}"><a class="nav-link J_load-category" href="#asideCategory" data-toggle="tab">[[${bundle.L('分组')}]]</a></li>
|
||||
<li class="nav-item" th:if="${advListHideCharts != 'true'}"><a class="nav-link J_load-charts" href="#asideWidgets" data-toggle="tab">[[${bundle.L('图表')}]]</a></li>
|
||||
</ul>
|
||||
<div class="tab-content rb-scroller">
|
||||
|
|
Loading…
Reference in a new issue