mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 15:35:55 +08:00
commit
48d68a2318
|
@ -1,25 +1,23 @@
|
|||
# include nginx-rebuild.conf
|
||||
server {
|
||||
server_name YOUR_DOMAIN;
|
||||
listen 80;
|
||||
# HTTPS
|
||||
#listen 443 ssl http2;
|
||||
#ssl_certificate ssl.crt;
|
||||
#ssl_certificate_key ssl.key;
|
||||
# PROXY
|
||||
proxy_redirect http:// $scheme://;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
location / {
|
||||
proxy_pass http://localhost:18080;
|
||||
etag on;
|
||||
}
|
||||
location /assets {
|
||||
proxy_pass http://localhost:18080/assets;
|
||||
expires 90d;
|
||||
}
|
||||
#location /h5-app {
|
||||
# alias /data/rebuild/h5-app;
|
||||
# etag on;
|
||||
#}
|
||||
}
|
||||
server_name YOUR_DOMAIN;
|
||||
listen 80;
|
||||
# HTTPS
|
||||
#listen 443 ssl http2;
|
||||
#ssl_certificate /path/to/ssl.crt;
|
||||
#ssl_certificate_key /path/to/ssl.key;
|
||||
# PROXY
|
||||
proxy_redirect http:// $scheme://;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:18080;
|
||||
etag on;
|
||||
}
|
||||
location /h5app {
|
||||
alias /path/to/public/h5app;
|
||||
try_files $uri $uri/ /h5app/index.html;
|
||||
etag on;
|
||||
}
|
||||
}
|
||||
|
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -42,3 +42,7 @@ node
|
|||
|
||||
.DS_Store
|
||||
test.*
|
||||
|
||||
# Build
|
||||
|
||||
**/public/h5app/
|
||||
|
|
2
@rbv
2
@rbv
|
@ -1 +1 @@
|
|||
Subproject commit fa267c9c6721819f19208a3afd0f6dff6b14f620
|
||||
Subproject commit 28379ae7d7f3d76b203f889f877ec7b6deb690b7
|
|
@ -452,7 +452,7 @@ public class FormsBuilder extends FormsManager {
|
|||
.append(" where ")
|
||||
.append(entity.getPrimaryField().getName())
|
||||
.append(" = ?");
|
||||
return Application.getQueryFactory().createQuery(sql.toString(), user).setParameter(1, id).record();
|
||||
return Application.createQuery(sql.toString(), user).setParameter(1, id).record();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,6 +15,8 @@ import com.rebuild.core.UserContextHolder;
|
|||
import com.rebuild.core.metadata.EntityHelper;
|
||||
import com.rebuild.core.metadata.MetadataHelper;
|
||||
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
|
||||
import com.rebuild.core.privileges.OperationDeniedException;
|
||||
import com.rebuild.core.privileges.UserHelper;
|
||||
import com.rebuild.core.privileges.UserService;
|
||||
import com.rebuild.core.service.BaseService;
|
||||
import com.rebuild.core.service.DataSpecificationNoRollbackException;
|
||||
|
@ -252,6 +254,10 @@ public class ApprovalStepService extends BaseService {
|
|||
final ID opUser = UserContextHolder.getUser();
|
||||
final ApprovalState useState = isRevoke ? ApprovalState.REVOKED : ApprovalState.CANCELED;
|
||||
|
||||
if (isRevoke && !UserHelper.isAdmin(opUser)) {
|
||||
throw new OperationDeniedException(Language.L("仅管理员可撤销审批"));
|
||||
}
|
||||
|
||||
Record step = EntityHelper.forNew(EntityHelper.RobotApprovalStep, opUser);
|
||||
step.setID("recordId", recordId);
|
||||
step.setID("approvalId", approvalId == null ? APPROVAL_NOID : approvalId);
|
||||
|
|
|
@ -73,7 +73,7 @@ public abstract class BulkOperator extends HeavyTask<Integer> {
|
|||
entity.getPrimaryField().getName(), entity.getName(), sqlWhere);
|
||||
|
||||
// NOTE 注意没有分页
|
||||
Query query = Application.getQueryFactory().createQuery(sql, context.getOpUser());
|
||||
Query query = Application.createQuery(sql, context.getOpUser());
|
||||
Object[][] array = QueryHelper.readArray(query);
|
||||
Set<ID> ids = new HashSet<>();
|
||||
for (Object[] o : array) {
|
||||
|
|
|
@ -53,7 +53,7 @@ public class ProjectConfigService extends BaseConfigurationService implements Ad
|
|||
|
||||
@Override
|
||||
public int delete(ID projectId) {
|
||||
Object[] count = Application.createQuery(
|
||||
Object[] count = Application.createQueryNoFilter(
|
||||
"select count(taskId) from ProjectTask where projectId = ?")
|
||||
.setParameter(1, projectId)
|
||||
.unique();
|
||||
|
@ -77,9 +77,12 @@ public class ProjectConfigService extends BaseConfigurationService implements Ad
|
|||
|
||||
// 使用模板
|
||||
if (useTemplate == TEMPLATE_DEFAULT) {
|
||||
ID id1 = createPlan(project.getPrimary(), Language.L("待处理"), 1000, ProjectPlanConfigService.FLOW_STATUS_START, null);
|
||||
ID id2 = createPlan(project.getPrimary(), Language.L("进行中"), 2000, ProjectPlanConfigService.FLOW_STATUS_PROCESSING, null);
|
||||
ID id3 = createPlan(project.getPrimary(), Language.L("已完成"), 3000, ProjectPlanConfigService.FLOW_STATUS_END, new ID[]{id1, id2});
|
||||
ID id1 = createPlan(project.getPrimary(),
|
||||
Language.L("待处理"), 1000, ProjectPlanConfigService.FLOW_STATUS_START, null);
|
||||
ID id2 = createPlan(project.getPrimary(),
|
||||
Language.L("进行中"), 2000, ProjectPlanConfigService.FLOW_STATUS_PROCESSING, null);
|
||||
ID id3 = createPlan(project.getPrimary(),
|
||||
Language.L("已完成"), 3000, ProjectPlanConfigService.FLOW_STATUS_END, new ID[]{id1, id2});
|
||||
updateFlowNexts(id1, new ID[]{id2, id3});
|
||||
updateFlowNexts(id2, new ID[]{id1, id3});
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import com.rebuild.core.UserContextHolder;
|
|||
import com.rebuild.core.configuration.ConfigBean;
|
||||
import com.rebuild.core.metadata.EntityHelper;
|
||||
import com.rebuild.core.privileges.OperationDeniedException;
|
||||
import com.rebuild.core.service.DataSpecificationException;
|
||||
import com.rebuild.core.service.notification.Message;
|
||||
import com.rebuild.core.service.notification.MessageBuilder;
|
||||
import com.rebuild.core.support.i18n.Language;
|
||||
|
@ -50,9 +51,16 @@ public class ProjectTaskService extends BaseTaskService {
|
|||
final ID user = UserContextHolder.getUser();
|
||||
checkInMembers(user, record.getID("projectId"));
|
||||
|
||||
record.setLong("taskNumber", getNextTaskNumber(record.getID("projectId")));
|
||||
applyFlowStatue(record);
|
||||
record.setInt("seq", getNextSeqViaMidValue(record.getID("projectPlanId")));
|
||||
ID projectId = record.getID("projectId");
|
||||
ID projectPlanId = record.getID("projectPlanId");
|
||||
ConfigBean p = ProjectManager.instance.getPlanOfProject(projectPlanId, projectId);
|
||||
if (p.getInteger("flowStatus") == ProjectPlanConfigService.FLOW_STATUS_PROCESSING) {
|
||||
throw new DataSpecificationException(Language.L("该任务面板不可新建任务"));
|
||||
}
|
||||
|
||||
record.setLong("taskNumber", getNextTaskNumber(projectId));
|
||||
applyFlowStatus(record);
|
||||
record.setInt("seq", getNextSeqViaMidValue(projectPlanId));
|
||||
|
||||
record = super.create(record);
|
||||
|
||||
|
@ -68,17 +76,26 @@ public class ProjectTaskService extends BaseTaskService {
|
|||
checkInMembers(user, record.getPrimary());
|
||||
|
||||
// 自动完成
|
||||
int flowStatus = applyFlowStatue(record);
|
||||
int newFlowStatus = applyFlowStatus(record);
|
||||
|
||||
if (flowStatus == ProjectPlanConfigService.FLOW_STATUS_END) {
|
||||
if (newFlowStatus == ProjectPlanConfigService.FLOW_STATUS_END) {
|
||||
record.setDate("endTime", CalendarUtils.now());
|
||||
} else if (record.hasValue("status")) {
|
||||
int status = record.getInt("status");
|
||||
|
||||
// 处理完成时间
|
||||
if (status == 0) {
|
||||
record.setNull("endTime");
|
||||
record.setInt("seq", getSeqInStatus(record.getPrimary(), false));
|
||||
} else {
|
||||
|
||||
// 检查工作流
|
||||
Object[] flowStatus = Application.getQueryFactory()
|
||||
.uniqueNoFilter(record.getPrimary(), "projectPlanId.flowStatus");
|
||||
if ((int) flowStatus[0] == ProjectPlanConfigService.FLOW_STATUS_PROCESSING) {
|
||||
throw new DataSpecificationException(Language.L("该任务面板不可完成任务"));
|
||||
}
|
||||
|
||||
record.setDate("endTime", CalendarUtils.now());
|
||||
record.setInt("seq", getSeqInStatus(record.getPrimary(), true));
|
||||
}
|
||||
|
@ -141,13 +158,13 @@ public class ProjectTaskService extends BaseTaskService {
|
|||
*/
|
||||
synchronized
|
||||
private int getSeqInStatus(ID taskId, boolean desc) {
|
||||
Object[] taskStatus = Application.createQuery(
|
||||
Object[] taskStatus = Application.createQueryNoFilter(
|
||||
"select status,projectPlanId from ProjectTask where taskId = ?")
|
||||
.setParameter(1, taskId)
|
||||
.unique();
|
||||
if (taskStatus == null) return 1;
|
||||
|
||||
Object[] seq = Application.createQuery(
|
||||
Object[] seq = Application.createQueryNoFilter(
|
||||
"select " + (desc ? "max" : "min") + "(seq) from ProjectTask where status = ? and projectPlanId = ?")
|
||||
.setParameter(1, taskStatus[0])
|
||||
.setParameter(2, taskStatus[1])
|
||||
|
@ -162,7 +179,7 @@ public class ProjectTaskService extends BaseTaskService {
|
|||
*
|
||||
* @param newOrUpdate
|
||||
*/
|
||||
private int applyFlowStatue(Record newOrUpdate) {
|
||||
private int applyFlowStatus(Record newOrUpdate) {
|
||||
if (newOrUpdate.hasValue("projectPlanId")) {
|
||||
ConfigBean c = ProjectManager.instance.getPlanOfProject(
|
||||
newOrUpdate.getID("projectPlanId"), newOrUpdate.getID("projectId"));
|
||||
|
@ -178,11 +195,10 @@ public class ProjectTaskService extends BaseTaskService {
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param taskId
|
||||
*/
|
||||
private void sendNotification(ID taskId) {
|
||||
Object[] task = Application.getQueryFactory().uniqueNoFilter(taskId, "executor", "taskName");
|
||||
if (task[0] == null) return;
|
||||
|
||||
String msg = Language.L("有一个新任务分派给你") + " \n> " + task[1];
|
||||
Application.getNotifications().send(
|
||||
MessageBuilder.createMessage((ID) task[0], msg, Message.TYPE_PROJECT, taskId));
|
||||
|
|
|
@ -40,6 +40,7 @@ public class QueryFactory {
|
|||
/**
|
||||
* @param ajql
|
||||
* @return
|
||||
* @see #createQueryNoFilter(String)
|
||||
*/
|
||||
public Query createQuery(String ajql) {
|
||||
return createQuery(ajql, UserContextHolder.getUser());
|
||||
|
@ -54,14 +55,6 @@ public class QueryFactory {
|
|||
return createQuery(ajql, Application.getPrivilegesManager().createQueryFilter(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ajql
|
||||
* @return
|
||||
*/
|
||||
public Query createQueryNoFilter(String ajql) {
|
||||
return createQuery(ajql, RoleBaseQueryFilter.ALLOWED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ajql
|
||||
* @param filter
|
||||
|
@ -76,11 +69,25 @@ public class QueryFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param sql
|
||||
* 1.无权限实体查询(无权限实体使用 #createQuery 除管理员外将查不到数据)
|
||||
* 2.有权限实体查询单不应用角色(权限)
|
||||
*
|
||||
* @param ajql
|
||||
* @return
|
||||
* @see #createQuery(String)
|
||||
*/
|
||||
public Query createQueryNoFilter(String ajql) {
|
||||
return createQuery(ajql, RoleBaseQueryFilter.ALLOWED);
|
||||
}
|
||||
|
||||
/**
|
||||
* 原生 SQL 查询
|
||||
*
|
||||
* @param rawSql
|
||||
* @return
|
||||
*/
|
||||
public NativeQuery createNativeQuery(String sql) {
|
||||
return aPMFactory.createNativeQuery(sql)
|
||||
public NativeQuery createNativeQuery(String rawSql) {
|
||||
return aPMFactory.createNativeQuery(rawSql)
|
||||
.setTimeout(QUERY_TIMEOUT)
|
||||
.setSlowLoggerTime(SLOW_LOGGER_TIME);
|
||||
}
|
||||
|
@ -129,11 +136,6 @@ public class QueryFactory {
|
|||
return createQueryNoFilter(sql).setParameter(1, recordId).unique();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param recordId
|
||||
* @param fields
|
||||
* @return
|
||||
*/
|
||||
private String buildUniqueSql(ID recordId, String... fields) {
|
||||
Assert.notNull(recordId, "[recordId] cannot be null");
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ public class FieldWriteback extends FieldAggregation {
|
|||
} else {
|
||||
String sql = String.format("select %s from %s where %s = ?",
|
||||
targetEntity.getPrimaryField().getName(), targetFieldEntity[1], targetFieldEntity[0]);
|
||||
Object[][] array = Application.getQueryFactory().createQueryNoFilter(sql)
|
||||
Object[][] array = Application.createQueryNoFilter(sql)
|
||||
.setParameter(1, operatingContext.getAnyRecord().getPrimary())
|
||||
.array();
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ public class BatchOperatorQuery extends SetUser {
|
|||
int pageNo = queryData.getIntValue("pageNo");
|
||||
int pageSize = queryData.getIntValue("pageSize");
|
||||
|
||||
Object[][] array = Application.getQueryFactory().createQuery(sql, getUser())
|
||||
Object[][] array = Application.createQuery(sql, getUser())
|
||||
.setLimit(pageSize, pageNo * pageSize - pageSize)
|
||||
.setTimeout(60)
|
||||
.array();
|
||||
|
|
|
@ -66,11 +66,11 @@ public class DataListBuilderImpl implements DataListBuilder {
|
|||
public JSON getJSONResult() {
|
||||
int totalRows = 0;
|
||||
if (queryParser.isNeedReload()) {
|
||||
Object[] count = Application.getQueryFactory().createQuery(queryParser.toCountSql(), user).unique();
|
||||
Object[] count = Application.createQuery(queryParser.toCountSql(), user).unique();
|
||||
totalRows = ObjectUtils.toInt(count[0]);
|
||||
}
|
||||
|
||||
Query query = Application.getQueryFactory().createQuery(queryParser.toSql(), user);
|
||||
Query query = Application.createQuery(queryParser.toSql(), user);
|
||||
int[] limits = queryParser.getSqlLimit();
|
||||
Object[][] data = query.setLimit(limits[0], limits[1]).array();
|
||||
|
||||
|
|
|
@ -43,6 +43,10 @@ public class AppUtils {
|
|||
public static final String SK_LOCALE = WebUtils.KEY_PREFIX + ".LOCALE";
|
||||
public static final String CK_LOCALE = "rb.locale";
|
||||
|
||||
// RbMob
|
||||
public static final String HF_CLIENT = "X-Client";
|
||||
public static final String HF_LOCALE = "X-ClientLocale";
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see BootApplication#getContextPath()
|
||||
|
@ -106,6 +110,9 @@ public class AppUtils {
|
|||
*/
|
||||
public static String getReuqestLocale(HttpServletRequest request) {
|
||||
String locale = (String) ServletUtils.getSessionAttribute(request, SK_LOCALE);
|
||||
if (locale == null) {
|
||||
locale = StringUtils.defaultIfBlank(request.getHeader(HF_LOCALE), null);
|
||||
}
|
||||
if (locale == null) {
|
||||
locale = RebuildConfiguration.get(ConfigurationItem.DefaultLanguage);
|
||||
}
|
||||
|
@ -171,7 +178,7 @@ public class AppUtils {
|
|||
* @return
|
||||
*/
|
||||
public static boolean isRbMobile(HttpServletRequest request) {
|
||||
String UA = request.getHeader("X-Client");
|
||||
String UA = request.getHeader(HF_CLIENT);
|
||||
return UA != null && UA.startsWith("RB/Mobile-");
|
||||
}
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ public class HttpUtils {
|
|||
* @throws IOException
|
||||
*/
|
||||
public static File readBinary(String url) throws IOException {
|
||||
File tmp = RebuildConfiguration.getFileOfTemp("download." + UUID.randomUUID().toString());
|
||||
File tmp = RebuildConfiguration.getFileOfTemp("download." + UUID.randomUUID());
|
||||
boolean success = readBinary(url, tmp, Collections.singletonMap(HttpHeaders.USER_AGENT, RB_UA));
|
||||
return success && tmp.exists() ? tmp : null;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
|||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.thymeleaf.exceptions.TemplateInputException;
|
||||
|
@ -92,9 +93,16 @@ public class RebuildWebConfigurer implements WebMvcConfigurer, ErrorViewResolver
|
|||
.excludePathPatterns("/gw/api/**")
|
||||
.excludePathPatterns("/language/**")
|
||||
.excludePathPatterns("/assets/**")
|
||||
.excludePathPatterns("/h5app/**")
|
||||
.excludePathPatterns("/*.txt");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/h5app/**")
|
||||
.addResourceLocations("classpath:/public/h5app/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
|
||||
// URL 参数
|
||||
|
@ -113,11 +121,6 @@ public class RebuildWebConfigurer implements WebMvcConfigurer, ErrorViewResolver
|
|||
return createError(request, (Exception) request.getAttribute(ServletUtils.ERROR_EXCEPTION), status, model);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request
|
||||
* @param ex
|
||||
* @return
|
||||
*/
|
||||
private ModelAndView createError(HttpServletRequest request, Exception ex, HttpStatus status, Map<String, Object> model) {
|
||||
// IGNORED
|
||||
if (request.getRequestURI().contains("/assets/")) return null;
|
||||
|
@ -164,12 +167,12 @@ public class RebuildWebConfigurer implements WebMvcConfigurer, ErrorViewResolver
|
|||
}
|
||||
|
||||
/**
|
||||
* 获取请求/引用地址
|
||||
* 获取请求+引用地址
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
static String getRequestUrls(HttpServletRequest request) {
|
||||
protected static String getRequestUrls(HttpServletRequest request) {
|
||||
String reqUrl = request.getRequestURL().toString();
|
||||
String refUrl = ServletUtils.getReferer(request);
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
if (requestEntry.isHtmlRequest()) {
|
||||
sendRedirect(response, "/user/login", requestUri);
|
||||
} else {
|
||||
ServletUtils.writeJson(response, RespBody.error(HttpStatus.FORBIDDEN.value()).toJSONString());
|
||||
ServletUtils.writeJson(response, RespBody.error(HttpStatus.UNAUTHORIZED.value()).toJSONString());
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -189,43 +189,45 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
* @see AppUtils#getReuqestLocale(HttpServletRequest)
|
||||
*/
|
||||
private String detectLocale(HttpServletRequest request, HttpServletResponse response) {
|
||||
String rbmobLocale = request.getHeader(AppUtils.HF_LOCALE);
|
||||
if (rbmobLocale != null) return rbmobLocale;
|
||||
|
||||
// 0. Session
|
||||
String locale = (String) ServletUtils.getSessionAttribute(request, AppUtils.SK_LOCALE);
|
||||
String havingLocale = (String) ServletUtils.getSessionAttribute(request, AppUtils.SK_LOCALE);
|
||||
|
||||
String urlLocale = request.getParameter("locale");
|
||||
if (StringUtils.isNotBlank(urlLocale) && !urlLocale.equals(locale)) {
|
||||
if (StringUtils.isNotBlank(urlLocale) && !urlLocale.equals(havingLocale)) {
|
||||
urlLocale = Application.getLanguage().available(urlLocale);
|
||||
|
||||
if (urlLocale != null) {
|
||||
locale = urlLocale;
|
||||
havingLocale = urlLocale;
|
||||
|
||||
ServletUtils.setSessionAttribute(request, AppUtils.SK_LOCALE, locale);
|
||||
ServletUtils.addCookie(response, AppUtils.CK_LOCALE, locale,
|
||||
ServletUtils.setSessionAttribute(request, AppUtils.SK_LOCALE, havingLocale);
|
||||
ServletUtils.addCookie(response, AppUtils.CK_LOCALE, havingLocale,
|
||||
CommonsCache.TS_DAY * 90, null, StringUtils.defaultIfBlank(AppUtils.getContextPath(), "/"));
|
||||
|
||||
if (Application.devMode()) {
|
||||
Application.getLanguage().refresh();
|
||||
}
|
||||
if (Application.devMode()) Application.getLanguage().refresh();
|
||||
}
|
||||
}
|
||||
if (locale != null) return locale;
|
||||
if (havingLocale != null) return havingLocale;
|
||||
|
||||
// 1. Cookie
|
||||
locale = ServletUtils.readCookie(request, AppUtils.CK_LOCALE);
|
||||
if (locale == null) {
|
||||
havingLocale = ServletUtils.readCookie(request, AppUtils.CK_LOCALE);
|
||||
if (havingLocale == null) {
|
||||
// 2. User-Local
|
||||
locale = request.getLocale().toString();
|
||||
havingLocale = request.getLocale().toString();
|
||||
}
|
||||
|
||||
// 3. Default
|
||||
if ((locale = Application.getLanguage().available(locale)) == null) {
|
||||
locale = RebuildConfiguration.get(ConfigurationItem.DefaultLanguage);
|
||||
if ((havingLocale = Application.getLanguage().available(havingLocale)) == null) {
|
||||
havingLocale = RebuildConfiguration.get(ConfigurationItem.DefaultLanguage);
|
||||
}
|
||||
|
||||
ServletUtils.setSessionAttribute(request, AppUtils.SK_LOCALE, locale);
|
||||
return locale;
|
||||
ServletUtils.setSessionAttribute(request, AppUtils.SK_LOCALE, havingLocale);
|
||||
return havingLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,18 +11,21 @@ import cn.devezhao.commons.CodecUtils;
|
|||
import cn.devezhao.commons.ObjectUtils;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.rebuild.api.RespBody;
|
||||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.configuration.ConfigBean;
|
||||
import com.rebuild.core.configuration.ConfigurationException;
|
||||
import com.rebuild.core.service.project.ProjectManager;
|
||||
import com.rebuild.core.support.i18n.Language;
|
||||
import com.rebuild.utils.AppUtils;
|
||||
import com.rebuild.utils.JSONUtils;
|
||||
import com.rebuild.web.BaseController;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -37,7 +40,7 @@ import java.util.regex.Pattern;
|
|||
* @author devezhao
|
||||
* @since 2020/6/29
|
||||
*/
|
||||
@Controller
|
||||
@RestController
|
||||
@RequestMapping("/project/")
|
||||
public class ProjectController extends BaseController {
|
||||
|
||||
|
@ -80,6 +83,31 @@ public class ProjectController extends BaseController {
|
|||
return mv;
|
||||
}
|
||||
|
||||
@GetMapping("{projectId}/details")
|
||||
public RespBody getPlans(@PathVariable String projectId, HttpServletRequest request) throws IOException {
|
||||
final ID user = getRequestUser(request);
|
||||
|
||||
JSONObject details;
|
||||
try {
|
||||
ConfigBean p = ProjectManager.instance.getProject(ID.valueOf(projectId), user);
|
||||
details = JSONUtils.toJSONObject(
|
||||
new String[] { "projectName", "isMember" },
|
||||
new Object[] { p.getString("projectName"), p.get("members", Set.class).contains(user) });
|
||||
|
||||
} catch (ConfigurationException ex) {
|
||||
return RespBody.error(ex.getLocalizedMessage(), 403);
|
||||
}
|
||||
|
||||
ConfigBean[] plans = ProjectManager.instance.getPlansOfProject(ID.valueOf(projectId));
|
||||
JSONArray array = new JSONArray();
|
||||
for (ConfigBean cb : plans) {
|
||||
array.add(cb.toJSON());
|
||||
}
|
||||
details.put("projectPlans", array);
|
||||
|
||||
return RespBody.ok(details);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see com.rebuild.web.general.ListAndViewRedirection
|
||||
*/
|
||||
|
|
|
@ -70,18 +70,18 @@ public class ProjectTaskController extends BaseController {
|
|||
return null;
|
||||
}
|
||||
|
||||
ConfigBean cfg = ProjectManager.instance.getProjectByTask(taskId2, user);
|
||||
ConfigBean project = ProjectManager.instance.getProjectByTask(taskId2, user);
|
||||
|
||||
ModelAndView mv = createModelAndView("/project/task-view");
|
||||
mv.getModel().put("id", taskId2.toLiteral());
|
||||
mv.getModel().put("projectIcon", cfg.getString("iconName"));
|
||||
mv.getModel().put("isMember", cfg.get("members", Set.class).contains(user));
|
||||
mv.getModel().put("isManageable", ProjectHelper.isManageable(taskId2, user));
|
||||
mv.getModel().put("projectIcon", project.getString("iconName"));
|
||||
mv.getModel().put("isMember", project.get("members", Set.class).contains(user));
|
||||
return mv;
|
||||
}
|
||||
|
||||
@RequestMapping("tasks/list")
|
||||
public JSON taskList(@IdParam(name = "plan") ID planId, HttpServletRequest request) {
|
||||
final ID user = getRequestUser(request);
|
||||
String queryWhere = "projectPlanId = ?";
|
||||
|
||||
// 关键词搜索
|
||||
|
@ -125,7 +125,7 @@ public class ProjectTaskController extends BaseController {
|
|||
|
||||
JSONArray alist = new JSONArray();
|
||||
for (Object[] o : tasks) {
|
||||
alist.add(formatTask(o, true));
|
||||
alist.add(formatTask(o, user));
|
||||
}
|
||||
|
||||
return JSONUtils.toJSONObject(
|
||||
|
@ -139,19 +139,19 @@ public class ProjectTaskController extends BaseController {
|
|||
"select " + BASE_FIELDS + " from ProjectTask where taskId = ?")
|
||||
.setParameter(1, taskId)
|
||||
.unique();
|
||||
return formatTask(task, true);
|
||||
return formatTask(task, null);
|
||||
}
|
||||
|
||||
@GetMapping("tasks/details")
|
||||
public JSON taskDetails(@IdParam(name = "task") ID taskId) {
|
||||
public JSON taskDetails(@IdParam(name = "task") ID taskId, HttpServletRequest request) {
|
||||
final ID user = getRequestUser(request);
|
||||
|
||||
Object[] task = Application.createQueryNoFilter(
|
||||
"select " + BASE_FIELDS + ",projectId,description,attachments,relatedRecord from ProjectTask where taskId = ?")
|
||||
"select " + BASE_FIELDS + ",description,attachments,relatedRecord from ProjectTask where taskId = ?")
|
||||
.setParameter(1, taskId)
|
||||
.unique();
|
||||
JSONObject details = formatTask(task, true);
|
||||
JSONObject details = formatTask(task, user);
|
||||
|
||||
// 状态面板
|
||||
details.put("projectId", task[11]);
|
||||
details.put("description", task[12]);
|
||||
String attachments = (String) task[13];
|
||||
details.put("attachments", JSON.parseArray(attachments));
|
||||
|
@ -168,24 +168,33 @@ public class ProjectTaskController extends BaseController {
|
|||
}
|
||||
|
||||
private static final String BASE_FIELDS =
|
||||
"projectId.projectCode,taskNumber,taskId,taskName,createdOn,deadline,executor,status,seq,priority,endTime";
|
||||
"projectId,projectPlanId,taskNumber,taskId,taskName,createdOn,deadline,executor,status,seq,priority,endTime";
|
||||
|
||||
private JSONObject formatTask(Object[] o, boolean appendTags) {
|
||||
String taskNumber = o[1].toString();
|
||||
if (StringUtils.isNotBlank((String) o[0])) taskNumber = o[0] + "-" + taskNumber;
|
||||
private JSONObject formatTask(Object[] o, ID user) {
|
||||
final ConfigBean project = ProjectManager.instance.getProject((ID) o[0], user);
|
||||
|
||||
String createdOn = I18nUtils.formatDate((Date) o[4]);
|
||||
String deadline = I18nUtils.formatDate((Date) o[5]);
|
||||
String endTime = I18nUtils.formatDate((Date) o[10]);
|
||||
String taskNumber = String.format("%s-%s", project.getString("projectCode"), o[2]);
|
||||
String createdOn = I18nUtils.formatDate((Date) o[5]);
|
||||
String deadline = I18nUtils.formatDate((Date) o[6]);
|
||||
String endTime = I18nUtils.formatDate((Date) o[11]);
|
||||
|
||||
Object[] executor = o[6] == null ? null : new Object[]{o[6], UserHelper.getName((ID) o[6])};
|
||||
Object[] executor = o[7] == null ? null : new Object[]{o[7], UserHelper.getName((ID) o[7])};
|
||||
|
||||
JSONObject data = JSONUtils.toJSONObject(
|
||||
new String[] { "id", "taskNumber", "taskName", "createdOn", "deadline", "executor", "status", "seq", "priority", "endTime" },
|
||||
new Object[] { o[2], taskNumber, o[3], createdOn, deadline, executor, o[7], o[8], o[9], endTime });
|
||||
new String[] { "id", "taskNumber", "taskName", "createdOn", "deadline", "executor", "status", "seq", "priority", "endTime", "projectId" },
|
||||
new Object[] { o[3], taskNumber, o[4], createdOn, deadline, executor, o[8], o[9], o[10], endTime, o[0] });
|
||||
// 标签
|
||||
data.put("tags", TaskTagController.getTaskTags((ID) o[3]));
|
||||
|
||||
if (appendTags) {
|
||||
data.put("tags", TaskTagController.getTaskTags((ID) o[2]));
|
||||
if (user != null) {
|
||||
// 项目信息
|
||||
ConfigBean plan = ProjectManager.instance.getPlanOfProject((ID) o[1], (ID) o[0]);
|
||||
data.put("planName", String.format("%s (%s)",
|
||||
project.getString("projectName"), plan.getString("planName")));
|
||||
data.put("planFlow", plan.getInteger("flowStatus"));
|
||||
// 权限
|
||||
data.put("projectMember", project.get("members", Set.class).contains(user));
|
||||
data.put("isManageable", ProjectHelper.isManageable((ID) o[3], user));
|
||||
}
|
||||
|
||||
return data;
|
||||
|
@ -199,8 +208,7 @@ public class ProjectTaskController extends BaseController {
|
|||
return sort;
|
||||
}
|
||||
|
||||
// -- for EntityView
|
||||
|
||||
// for View of Entity
|
||||
@GetMapping("alist")
|
||||
public RespBody getProjectAndPlans(HttpServletRequest request) {
|
||||
final ID user = getRequestUser(request);
|
||||
|
@ -230,6 +238,8 @@ public class ProjectTaskController extends BaseController {
|
|||
@IdParam(name = "task", required = false) ID taskId,
|
||||
HttpServletRequest request) {
|
||||
Assert.isTrue(relatedId != null || taskId != null, Language.L("无效请求参数"));
|
||||
|
||||
final ID user = getRequestUser(request);
|
||||
String queryWhere = String.format("relatedRecord = '%s'", relatedId);
|
||||
|
||||
// 关键词搜索
|
||||
|
@ -248,30 +258,16 @@ public class ProjectTaskController extends BaseController {
|
|||
queryWhere = String.format("taskId = '%s'", taskId);
|
||||
}
|
||||
|
||||
String querySql = "select " + BASE_FIELDS + ",projectPlanId,projectId from ProjectTask where " + queryWhere;
|
||||
String querySql = "select " + BASE_FIELDS + " from ProjectTask where " + queryWhere;
|
||||
|
||||
Object[][] tasks = Application.createQueryNoFilter(querySql)
|
||||
.setLimit(pageSize, pageNo * pageSize - pageSize)
|
||||
.array();
|
||||
|
||||
JSONArray alist = new JSONArray();
|
||||
JSONArray array = new JSONArray();
|
||||
for (Object[] o : tasks) {
|
||||
JSONObject formatted = formatTask(o, false);
|
||||
formatted.put("taskNumber", String.format("%s-%d", o[0], o[1] ));
|
||||
|
||||
Object executor = o[6] == null ? null : new Object[] { o[6], UserHelper.getName((ID) o[6]) };
|
||||
formatted.put("executor", executor);
|
||||
|
||||
ID projectPlanId = (ID) o[11];
|
||||
ID projectId = (ID) o[12];
|
||||
ConfigBean project = ProjectManager.instance.getProject(projectId, null);
|
||||
ConfigBean plan = ProjectManager.instance.getPlanOfProject(projectPlanId, projectId);
|
||||
formatted.put("planName", String.format("%s (%s)",
|
||||
project.getString("projectName"), plan.getString("planName")));
|
||||
formatted.put("planFlow", plan.getInteger("flowStatus"));
|
||||
|
||||
alist.add(formatted);
|
||||
array.add(formatTask(o, user));
|
||||
}
|
||||
return alist;
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,9 +106,9 @@ public class TaskTagController extends BaseController {
|
|||
*/
|
||||
static JSONArray getTaskTags(ID taskId) {
|
||||
Object[][] tags = Application.createQueryNoFilter(
|
||||
"select tagId.tagName,tagId.color,relationId from ProjectTaskTagRelation where taskId = ? order by createdOn")
|
||||
"select tagId.tagName,tagId.color,relationId,tagId from ProjectTaskTagRelation where taskId = ? order by createdOn")
|
||||
.setParameter(1, taskId)
|
||||
.array();
|
||||
return JSONUtils.toJSONObjectArray(new String[] { "name", "color" , "rid" }, tags);
|
||||
return JSONUtils.toJSONObjectArray(new String[] { "name", "color" , "rid", "id" }, tags);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ spring:
|
|||
multipart.enabled: false
|
||||
web:
|
||||
resources:
|
||||
static-locations: classpath:/web/assets
|
||||
static-locations: classpath:/web/assets/
|
||||
mvc:
|
||||
static-path-pattern: /assets/**
|
||||
thymeleaf:
|
||||
|
|
|
@ -1157,7 +1157,7 @@
|
|||
"注册信息已提交,审批结果将通过邮件通知你":"注册信息已提交,审批结果将通过邮件通知你",
|
||||
"注册成功":"注册成功",
|
||||
"注册验证码":"注册验证码",
|
||||
"注销登录":"注销登录",
|
||||
"退出":"退出",
|
||||
"流程结束":"流程结束",
|
||||
"流程设计":"流程设计",
|
||||
"测试发送":"测试发送",
|
||||
|
|
11
src/main/resources/public/h5app/index.html
Normal file
11
src/main/resources/public/h5app/index.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="minimal-ui, width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<title>REBUILD</title>
|
||||
</head>
|
||||
<body>
|
||||
<i>Free version does not support H5 App feature. <a href="https://getrebuild.com/docs/rbv-features" target="_blank">(View details)</a></i>
|
||||
</body>
|
||||
</html>
|
|
@ -29,7 +29,7 @@
|
|||
<div class="user-id" th:data-user="${user.getId()}">[[${user.getEmail() ?: bundle.L('邮箱未设置')}]]</div>
|
||||
</div>
|
||||
<a class="dropdown-item" th:href="@{/settings/user}"><i class="icon zmdi zmdi-account-box"></i>[[${bundle.L('个人设置')}]]</a>
|
||||
<a class="dropdown-item" th:href="@{/user/logout}"><i class="icon zmdi zmdi-power"></i>[[${bundle.L('注销登录')}]]</a>
|
||||
<a class="dropdown-item" th:href="@{/user/logout}"><i class="icon zmdi zmdi-power"></i>[[${bundle.L('退出')}]]</a>
|
||||
<div class="use-theme">
|
||||
<div>[[${bundle.L('选择主题')}]] <sup class="rbv"></sup></div>
|
||||
<ul class="list-inline list-unstyled mt-1">
|
||||
|
|
|
@ -11364,20 +11364,14 @@ canvas {
|
|||
color: #404040;
|
||||
border-radius: 99px;
|
||||
background: #f7f7f7;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
width: 320px;
|
||||
border-width: 0;
|
||||
padding: 4px 15px;
|
||||
text-align: left;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.rb-top-header .search-input-gs:focus {
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
}
|
||||
|
||||
.rb-top-header .search-input-gs::placeholder {
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
color: #aaa;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
|
|
@ -3781,11 +3781,11 @@ a.select-lang:hover {
|
|||
}
|
||||
|
||||
.use-theme ul li a.theme-dark {
|
||||
background-color: #112034 !important;
|
||||
background-color: #2d333b !important;
|
||||
}
|
||||
|
||||
.use-theme ul li a.theme-blue {
|
||||
background-color: #4285f4 !important;
|
||||
background-color: #4873c0 !important;
|
||||
}
|
||||
|
||||
.use-theme ul li a.theme-green {
|
||||
|
|
|
@ -18,7 +18,7 @@ let __TaskContent
|
|||
let __TaskComment
|
||||
|
||||
$(document).ready(() => {
|
||||
renderRbcomp(<TaskForm id={wpc.taskId} editable={wpc.isMember} isManageable={wpc.isManageable} />, 'task-contents', function () {
|
||||
renderRbcomp(<TaskForm id={wpc.taskId} editable={wpc.isMember} />, 'task-contents', function () {
|
||||
__TaskContent = this
|
||||
})
|
||||
if (wpc.isMember) {
|
||||
|
@ -45,7 +45,7 @@ class TaskForm extends React.Component {
|
|||
<div className="col-10">
|
||||
<ValueTaskName taskName={this.state.taskName} $$$parent={this} />
|
||||
</div>
|
||||
{this.props.editable && this.props.isManageable && (
|
||||
{this.props.editable && this.state.isManageable && (
|
||||
<div className="col-2 text-right">
|
||||
<button className="btn btn-secondary" style={{ minWidth: 80, marginTop: 2 }} data-toggle="dropdown">
|
||||
{$L('操作')} <i className="icon zmdi zmdi-more-vert"></i>
|
||||
|
@ -63,7 +63,7 @@ class TaskForm extends React.Component {
|
|||
<i className="icon zmdi zmdi-square-o" /> {$L('状态')}
|
||||
</label>
|
||||
<div className="col-12 col-sm-9">
|
||||
<ValueStatus status={this.state.status} $$$parent={this} />
|
||||
<ValueStatus status={this.state.status} readonly={this.state.planFlow === 2} $$$parent={this} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group row">
|
||||
|
@ -256,7 +256,7 @@ class ValueStatus extends ValueComp {
|
|||
<div className="form-control-plaintext">
|
||||
<span className="status-checkbox">
|
||||
<label className="custom-control custom-checkbox custom-control-inline" onClick={(e) => $stopEvent(e)}>
|
||||
<input className="custom-control-input" type="checkbox" ref={(c) => (this._status = c)} onChange={(e) => this._handleChangeStatus(e)} />
|
||||
<input className="custom-control-input" type="checkbox" disabled={this.props.readonly} ref={(c) => (this._status = c)} onChange={(e) => this._handleChangeStatus(e)} />
|
||||
<span className="custom-control-label">{this.state.status > 0 ? $L('已完成') : $L('未完成')}</span>
|
||||
</label>
|
||||
</span>
|
||||
|
@ -644,7 +644,7 @@ class ValueTags extends ValueComp {
|
|||
</div>
|
||||
</span>
|
||||
) : (
|
||||
tags.length === 0 && <div className="form-control-plaintext text-muted">{$L('无')}</div>
|
||||
tags.length === 0 && <span className="text-muted" style={{ display: 'inline-block', paddingTop: 5 }}>{$L('无')}</span>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -234,9 +234,11 @@ class ApprovalUsersForm extends RbFormHandler {
|
|||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="form-group">
|
||||
<RbAlertBox message={$L('当前审批流程无可用审批人')} />
|
||||
</div>
|
||||
!this.state.isLastStep && (
|
||||
<div className="form-group">
|
||||
<RbAlertBox message={$L('当前审批流程无可用审批人')} />
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
{ccHas && (
|
||||
<div className="form-group">
|
||||
|
@ -505,7 +507,7 @@ class ApprovalStepViewer extends React.Component {
|
|||
{!this.state.steps && <RbSpinner fully={true} />}
|
||||
<ul className="timeline approved-steps">
|
||||
{(this.state.steps || []).map((item, idx) => {
|
||||
return idx === 0 ? this.renderSubmitter(item, idx) : this.renderApprovers(item, idx, stateLast)
|
||||
return idx === 0 ? this.renderSubmitter(item) : this.renderApprover(item, stateLast)
|
||||
})}
|
||||
{stateLast >= 10 && (
|
||||
<li className="timeline-item last">
|
||||
|
@ -520,10 +522,10 @@ class ApprovalStepViewer extends React.Component {
|
|||
)
|
||||
}
|
||||
|
||||
renderSubmitter(s, idx) {
|
||||
renderSubmitter(s) {
|
||||
return (
|
||||
<li className="timeline-item state0" key={`step-${idx}`}>
|
||||
{this.__formatTime(s.createdOn)}
|
||||
<li className="timeline-item state0" key={`step-${$random()}`}>
|
||||
{this._formatTime(s.createdOn)}
|
||||
<div className="timeline-content">
|
||||
<div className="timeline-avatar">
|
||||
<img src={`${rb.baseUrl}/account/user-avatar/${s.submitter}`} alt="Avatar" />
|
||||
|
@ -545,8 +547,7 @@ class ApprovalStepViewer extends React.Component {
|
|||
)
|
||||
}
|
||||
|
||||
renderApprovers(s, idx, lastState) {
|
||||
const kp = 'step-' + idx + '-'
|
||||
renderApprover(s, stateLast) {
|
||||
const sss = []
|
||||
let nodeState = 0
|
||||
if (s[0].signMode === 'OR') {
|
||||
|
@ -559,11 +560,11 @@ class ApprovalStepViewer extends React.Component {
|
|||
const approverName = item.approver === rb.currentUser ? $L('你') : item.approverName
|
||||
let aMsg = $L('等待 %s 审批', approverName)
|
||||
if (item.state >= 10) aMsg = $L('由 %s %s', approverName, STATE_NAMES[item.state])
|
||||
if ((nodeState >= 10 || lastState >= 10) && item.state < 10) aMsg = `${approverName} ${$L('未进行审批')}`
|
||||
if ((nodeState >= 10 || stateLast >= 10) && item.state < 10) aMsg = `${approverName} ${$L('未进行审批')}`
|
||||
|
||||
sss.push(
|
||||
<li className={'timeline-item state' + item.state} key={kp + sss.length}>
|
||||
{this.__formatTime(item.approvedTime || item.createdOn)}
|
||||
<li className={'timeline-item state' + item.state} key={`step-${$random()}`}>
|
||||
{this._formatTime(item.approvedTime || item.createdOn)}
|
||||
<div className="timeline-content">
|
||||
<div className="timeline-avatar">
|
||||
<img src={`${rb.baseUrl}/account/user-avatar/${item.approver}`} alt="Avatar" />
|
||||
|
@ -585,13 +586,13 @@ class ApprovalStepViewer extends React.Component {
|
|||
const sm = s[0].signMode
|
||||
const clazz = sm === 'OR' || sm === 'AND' ? 'joint' : 'no-joint'
|
||||
return (
|
||||
<div key={kp} className={clazz} _title={sm === 'OR' ? $L('或签') : sm === 'AND' ? $L('会签') : null}>
|
||||
<div className={clazz} _title={sm === 'OR' ? $L('或签') : sm === 'AND' ? $L('会签') : null}>
|
||||
{sss}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
__formatTime(time) {
|
||||
_formatTime(time) {
|
||||
time = time.split(' ')
|
||||
return (
|
||||
<div className="timeline-date">
|
||||
|
@ -608,7 +609,9 @@ class ApprovalStepViewer extends React.Component {
|
|||
RbHighbar.create($L('未查询到流程详情'))
|
||||
this.hide()
|
||||
this.__noStepFound = true
|
||||
} else this.setState({ steps: res.data })
|
||||
} else {
|
||||
this.setState({ steps: res.data })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -617,7 +620,9 @@ class ApprovalStepViewer extends React.Component {
|
|||
if (this.__noStepFound === true) {
|
||||
RbHighbar.create($L('未查询到流程详情'))
|
||||
this.hide()
|
||||
} else $(this._dlg).modal({ show: true, keyboard: true })
|
||||
} else {
|
||||
$(this._dlg).modal({ show: true, keyboard: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ class LightTaskList extends RelatedList {
|
|||
<div className="row header-title">
|
||||
<div className="col-7 title">
|
||||
<label className="custom-control custom-control-sm custom-checkbox custom-control-inline">
|
||||
<input className="custom-control-input" type="checkbox" defaultChecked={item.status > 0} disabled={item.planFlow === 2} onClick={() => this._toggleStatus(item)} />
|
||||
<input className="custom-control-input" type="checkbox" defaultChecked={item.status > 0} disabled={item.planFlow === 2 || !item.projectMember} onClick={() => this._toggleStatus(item)} />
|
||||
<span className="custom-control-label"></span>
|
||||
</label>
|
||||
<a href={`${rb.baseUrl}/app/list-and-view?id=${item.id}`} target="_blank" title={$L('打开')}>
|
||||
|
|
|
@ -10,9 +10,10 @@
|
|||
<link rel="stylesheet" type="text/css" th:href="@{/assets/css/rb-base.css}" />
|
||||
<title>REBUILD</title>
|
||||
<style type="text/css">
|
||||
.zmdi.err404,
|
||||
.zmdi.err403,
|
||||
.zmdi.err400,
|
||||
.zmdi.err401,
|
||||
.zmdi.err403,
|
||||
.zmdi.err404,
|
||||
.zmdi.err600 {
|
||||
color: #4285f4 !important;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
type: 'TaskView',
|
||||
taskId: '[[${id}]]',
|
||||
isMember: '[[${isMember}]]' === 'true',
|
||||
isManageable: '[[${isManageable}]]' === 'true',
|
||||
}
|
||||
</script>
|
||||
<script th:src="@{/assets/js/project/task-view.js}" type="text/babel"></script>
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.junit.jupiter.api.Test;
|
|||
public class QueryFactoryTest extends TestSupport {
|
||||
|
||||
@Test
|
||||
public void testBaseQuery() {
|
||||
void testBaseQuery() {
|
||||
String sql = "select loginName from User";
|
||||
Filter filter = Application.getPrivilegesManager().createQueryFilter(SIMPLE_USER);
|
||||
Object[][] array = Application.getQueryFactory().createQuery(sql, filter).array();
|
||||
|
@ -33,7 +33,7 @@ public class QueryFactoryTest extends TestSupport {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testQueryAllDT() {
|
||||
void testQueryAllDT() {
|
||||
Entity allDT = MetadataHelper.getEntity(TestAllFields);
|
||||
StringBuilder sql = new StringBuilder("select ");
|
||||
for (Field f : allDT.getFields()) {
|
||||
|
@ -51,8 +51,14 @@ public class QueryFactoryTest extends TestSupport {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testNoUser() {
|
||||
void testNoUser() {
|
||||
Assertions.assertThrows(AccessDeniedException.class,
|
||||
() -> Application.getQueryFactory().createQuery("select loginName from User").array());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createNativeQuery() {
|
||||
Object[] x = Application.getQueryFactory().createNativeQuery("select current_date").unique();
|
||||
System.out.println(x[0]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue