Merge branch 'main' of https://dd3skj.picp.vip/JyuHsin/zhgh_cug_v4
@@ -9,6 +9,8 @@ import com.budwk.app.sys.models.Sys_config;
|
||||
import com.budwk.app.sys.services.SysConfigService;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.integration.jedis.pubsub.PubSubService;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
@@ -32,6 +34,8 @@ public class SysConfController {
|
||||
private SysConfigService sysConfigService;
|
||||
@Inject
|
||||
private PubSubService pubSubService;
|
||||
@Inject
|
||||
private Dao dao;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/sys/conf/index.html")
|
||||
@@ -40,6 +44,18 @@ public class SysConfController {
|
||||
|
||||
}
|
||||
|
||||
private void ensureAppImageConfig(String configKey, String note) {
|
||||
if (sysConfigService.fetch(configKey) != null) {
|
||||
return;
|
||||
}
|
||||
Sys_config conf = new Sys_config();
|
||||
conf.setConfigKey(configKey);
|
||||
conf.setConfigValue("");
|
||||
conf.setNote(note);
|
||||
conf.setCreatedBy(SecurityUtil.getUserId());
|
||||
sysConfigService.insert(conf);
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("json")
|
||||
@SaCheckPermission("sys.manager.conf.add")
|
||||
@@ -73,13 +89,31 @@ public class SysConfController {
|
||||
@SLog(tag = "修改参数", msg = "${conf.configKey}:${conf.configValue}")
|
||||
public Object editDo(@Param("..") Sys_config conf) {
|
||||
try {
|
||||
ensureConfigValueColumn(conf);
|
||||
conf.setUpdatedBy(SecurityUtil.getUserId());
|
||||
if (sysConfigService.updateIgnoreNull(conf) > 0) {
|
||||
pubSubService.fire(RedisConstant.PLATFORM_REDIS_PREFIX + "web:platform", "sys_config");
|
||||
}
|
||||
return Result.success();
|
||||
} catch (Exception e) {
|
||||
return Result.error();
|
||||
log.error("Update sys config failed: " + (conf == null ? "" : conf.getConfigKey()), e);
|
||||
return Result.error("save failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureConfigValueColumn(Sys_config conf) {
|
||||
if (conf == null || (!"AppHomeImg".equals(conf.getConfigKey())
|
||||
&& !"AppFeaturedActivityImg".equals(conf.getConfigKey())
|
||||
&& !"AppFestivalBenefitImg".equals(conf.getConfigKey()))) {
|
||||
return;
|
||||
}
|
||||
String configValue = Strings.sNull(conf.getConfigValue());
|
||||
if (configValue.length() <= 100) {
|
||||
return;
|
||||
}
|
||||
String dbType = Strings.sNull(dao.getJdbcExpert().getDatabaseType()).toLowerCase();
|
||||
if (dbType.contains("mysql")) {
|
||||
dao.execute(Sqls.create("ALTER TABLE `sys_config` MODIFY COLUMN `configValue` TEXT"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +140,8 @@ public class SysConfController {
|
||||
@SaCheckPermission("sys.manager.conf")
|
||||
public Object data(@Param("pageNumber") int pageNumber, @Param("pageSize") int pageSize, @Param("pageOrderName") String pageOrderName, @Param("pageOrderBy") String pageOrderBy) {
|
||||
try {
|
||||
ensureAppImageConfig("AppFeaturedActivityImg", "精彩活动页顶部图片");
|
||||
ensureAppImageConfig("AppFestivalBenefitImg", "节日福利页顶部图片");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (Strings.isNotBlank(pageOrderName) && Strings.isNotBlank(pageOrderBy)) {
|
||||
cnd.orderBy(pageOrderName, PageUtil.getOrder(pageOrderBy));
|
||||
|
||||
@@ -6,7 +6,7 @@ import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.basic.models.ActivityUserScope;
|
||||
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
@@ -32,6 +32,8 @@ public class SysH5IndexController {
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private ActivityBasicScopeService activityBasicScopeService;
|
||||
|
||||
@At
|
||||
@Ok("beetl:/platform/zhghh5/sys/home/index.html")
|
||||
@@ -40,6 +42,20 @@ public class SysH5IndexController {
|
||||
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("beetl:/platform/zhghh5/sys/home/featuredActivity.html")
|
||||
@SaCheckLogin
|
||||
public void featuredActivity() {
|
||||
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("beetl:/platform/zhghh5/sys/home/festivalBenefit.html")
|
||||
@SaCheckLogin
|
||||
public void festivalBenefit() {
|
||||
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("beetl:/platform/zhghh5/index/mine/index.html")
|
||||
@SaCheckLogin
|
||||
@@ -88,8 +104,7 @@ public class SysH5IndexController {
|
||||
}
|
||||
|
||||
if (allowUserGroupId != null) {
|
||||
int count = dao.count(ActivityUserScope.class, Cnd.where("groupId", "=", allowUserGroupId).and("userId", "=", userId));
|
||||
if (count > 0) {
|
||||
if (activityBasicScopeService.isUserInGroup(allowUserGroupId, userId)) {
|
||||
allowActivityList.add(activity);
|
||||
continue;
|
||||
}
|
||||
@@ -97,7 +112,9 @@ public class SysH5IndexController {
|
||||
|
||||
if (StrUtil.isNotBlank(allowUserSql)){
|
||||
Sql sql = Sqls.create(allowUserSql).setParam("userId", userId);
|
||||
NutMap nutMap = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map());
|
||||
sql.setCallback(Sqls.callback.map());
|
||||
dao.execute(sql);
|
||||
NutMap nutMap = (NutMap) sql.getResult();
|
||||
if (Lang.isNotEmpty(nutMap) && StrUtil.isNotBlank(nutMap.getString("userId"))) {
|
||||
allowActivityList.add(activity);
|
||||
}
|
||||
|
||||
@@ -6,13 +6,16 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.useragent.UserAgent;
|
||||
import cn.hutool.http.useragent.UserAgentUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.sys.models.Sys_home_template;
|
||||
import com.budwk.app.sys.models.Sys_menu;
|
||||
import com.budwk.app.sys.services.SysMenuService;
|
||||
import com.budwk.app.sys.services.SysUserService;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.basic.models.ActivityUserScope;
|
||||
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
@@ -56,6 +59,8 @@ public class SysHomeController {
|
||||
private SysUserService sysUserService;
|
||||
@Inject
|
||||
private RedisService redisService;
|
||||
@Inject
|
||||
private ActivityBasicScopeService activityBasicScopeService;
|
||||
|
||||
@At("")
|
||||
@Ok("re")
|
||||
@@ -223,8 +228,7 @@ public class SysHomeController {
|
||||
}
|
||||
|
||||
if (allowUserGroupId != null) {
|
||||
int count = dao.count(ActivityUserScope.class, Cnd.where("groupId", "=", allowUserGroupId).and("userId", "=", userId));
|
||||
if (count > 0) {
|
||||
if (activityBasicScopeService.isUserInGroup(allowUserGroupId, userId)) {
|
||||
allowActivityList.add(activity);
|
||||
continue;
|
||||
}
|
||||
@@ -232,7 +236,9 @@ public class SysHomeController {
|
||||
|
||||
if (StrUtil.isNotBlank(allowUserSql)) {
|
||||
Sql sql = Sqls.create(allowUserSql).setParam("userId", userId);
|
||||
NutMap nutMap = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map());
|
||||
sql.setCallback(Sqls.callback.map());
|
||||
dao.execute(sql);
|
||||
NutMap nutMap = (NutMap) sql.getResult();
|
||||
if (Lang.isNotEmpty(nutMap) && StrUtil.isNotBlank(nutMap.getString("userId"))) {
|
||||
allowActivityList.add(activity);
|
||||
}
|
||||
@@ -257,6 +263,20 @@ public class SysHomeController {
|
||||
// return Result.success(hasPermisiionList);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckLogin
|
||||
@ApiOperation("首页工作模板")
|
||||
@Ok("json")
|
||||
public Result listHomeTemplate() {
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
return Result.success(Collections.emptyList());
|
||||
}
|
||||
FieldFilter fieldFilter = FieldFilter.locked(Sys_home_template.class, "allowUserSql|classPath");
|
||||
List<Sys_home_template> list = Daos.ext(dao, fieldFilter).query(Sys_home_template.class,
|
||||
Cnd.NEW().desc("top").desc("sortNo"));
|
||||
return Result.success(list);
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@SaCheckLogin
|
||||
|
||||
@@ -340,8 +340,11 @@ public class SysUserController {
|
||||
@At
|
||||
@Ok("json")
|
||||
@SaCheckLogin
|
||||
public Result subAppMenus(@Param("appId") String appId) {
|
||||
public Result subAppMenus(@Param("appId") String appId, @Param("platform") String platform) {
|
||||
List<Sys_menu> menus = sysUserService.getMenus(SecurityUtil.getUserId());
|
||||
if (StrUtil.isNotBlank(platform)) {
|
||||
menus = menus.stream().filter(menu -> platform.equals(menu.getPlatform())).toList();
|
||||
}
|
||||
List<Sys_menu> list = SysMenuUtil.createTreeMenus(menus, appId);
|
||||
if (ObjectUtil.isEmpty(list)) {
|
||||
List<Sys_menu> self = menus.stream().filter(menu -> menu.getId().equals(appId)).toList();
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.budwk.app.sys.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.sys.models.Sys_home_template;
|
||||
import com.budwk.app.sys.param.SysHomeTemplatePageForm;
|
||||
import com.budwk.app.sys.services.SysHomeTemplateService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/sys/worktemplate")
|
||||
@Ok("json:full")
|
||||
@Api(value = "首页工作模板")
|
||||
public class SysWorkTemplateController {
|
||||
|
||||
@Inject
|
||||
private SysHomeTemplateService sysHomeTemplateService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/sys/worktemplate/index.html")
|
||||
@SaCheckPermission("sys.worktemplate")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("sys.worktemplate")
|
||||
@ApiOperation("分页数据")
|
||||
public Result pageData(@Valid SysHomeTemplatePageForm pageForm) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and(Cnd.likeEX(Sys_home_template::getName, pageForm.getName()));
|
||||
cnd.desc(Sys_home_template::getSortNo);
|
||||
Pagination pagination = sysHomeTemplateService.listPage(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("sys.worktemplate")
|
||||
@ApiOperation("启用")
|
||||
public Result enable(@Valid String id) {
|
||||
sysHomeTemplateService.update(Chain.make("enable", 1), Cnd.where("id", "=", id));
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("sys.worktemplate")
|
||||
@ApiOperation("关闭")
|
||||
public Result disable(@Valid String id) {
|
||||
sysHomeTemplateService.update(Chain.make("enable", 0), Cnd.where("id", "=", id));
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("sys.worktemplate")
|
||||
@ApiOperation("修改模板名称")
|
||||
public Result updateTemplateName(@Valid String id, String templateName) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
sysHomeTemplateService.update(Chain.make("templateName", templateName), Cnd.where("id", "=", id));
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("sys.worktemplate")
|
||||
@ApiOperation("修改模板图标")
|
||||
public Result updateTemplateIcon(@Valid String id, String templateIcon) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
sysHomeTemplateService.update(Chain.make("templateIcon", templateIcon), Cnd.where("id", "=", id));
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("sys.worktemplate")
|
||||
@ApiOperation("置顶")
|
||||
public Result topUp(@Valid String id) {
|
||||
Sys_home_template sysHomeTemplate = new Sys_home_template();
|
||||
sysHomeTemplate.setId(id);
|
||||
sysHomeTemplate.setTop(true);
|
||||
sysHomeTemplateService.updateIgnoreNull(sysHomeTemplate);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("sys.worktemplate")
|
||||
@ApiOperation("取消置顶")
|
||||
public Result cancelTopUp(@Valid String id) {
|
||||
Sys_home_template sysHomeTemplate = new Sys_home_template();
|
||||
sysHomeTemplate.setId(id);
|
||||
sysHomeTemplate.setTop(false);
|
||||
sysHomeTemplateService.updateIgnoreNull(sysHomeTemplate);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,7 +22,7 @@ public class Sys_config extends BaseModel implements Serializable {
|
||||
private String configKey;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
private String configValue;
|
||||
|
||||
@Column
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.budwk.app.sys.models;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.nutz.dao.entity.annotation.*;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Table
|
||||
@Comment("首页工作模板")
|
||||
public class Sys_home_template extends BaseModel {
|
||||
|
||||
@Name
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@Comment("主键ID,和业务ID保持一致")
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
@Comment("模板名称")
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
@Comment("展示模板名称")
|
||||
private String templateName;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 255)
|
||||
@Comment("模板图标")
|
||||
private String templateIcon;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 255)
|
||||
@Comment("模板封面")
|
||||
private String cover;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
@Comment("模板内容")
|
||||
private String content;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 1000)
|
||||
@Comment("模板链接")
|
||||
private String url;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 1000)
|
||||
@Comment("h5模板链接")
|
||||
private String h5Url;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.INT)
|
||||
@Comment("面向人员分组ID")
|
||||
private Integer allowUserGroupId;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 1000)
|
||||
@Comment("允许查看的人员sql")
|
||||
private String allowUserSql;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Comment("是否启用")
|
||||
@Default("0")
|
||||
private Boolean enable;
|
||||
|
||||
@Column
|
||||
@Comment("类路径")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 500)
|
||||
private String classPath;
|
||||
|
||||
@Column
|
||||
@Comment("是否置顶")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("0")
|
||||
private Boolean top;
|
||||
|
||||
@Column
|
||||
@Comment("是否推送大图")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("0")
|
||||
private Boolean push;
|
||||
|
||||
@Column
|
||||
@Comment("排序号")
|
||||
@Default("0")
|
||||
private Integer sortNo;
|
||||
|
||||
@Column
|
||||
@Comment("开始时间")
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date startDate;
|
||||
|
||||
@Column
|
||||
@Comment("结束时间")
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date endDate;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.budwk.app.sys.param;
|
||||
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@ApiModel("系统首页工作模板管理查询参数")
|
||||
public class SysHomeTemplatePageForm extends PageForm {
|
||||
|
||||
@ApiModelProperty("模板名称")
|
||||
private String name;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.budwk.app.sys.services;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.sys.models.Sys_home_template;
|
||||
|
||||
public interface SysHomeTemplateService extends BaseService<Sys_home_template> {
|
||||
}
|
||||
@@ -42,6 +42,8 @@ import java.nio.file.Files;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -50,6 +52,8 @@ import java.util.regex.Pattern;
|
||||
public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements SysFileService {
|
||||
|
||||
static String IMG_BASE64_PATTERN = "<img\\s+[^>]*src\\s*=\\s*['\"](data:image/[^'\"]+;base64,[^'\"]+)['\"][^>]*>";
|
||||
private static final int DOWNLOAD_FILE_CACHE_LIMIT = 2000;
|
||||
private final Map<String, Sys_file> downloadFileCache = new ConcurrentHashMap<>();
|
||||
|
||||
public SysFileServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
@@ -77,7 +81,13 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
||||
|
||||
@Override
|
||||
public void download(String id, HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
Sys_file sys_file = this.fetch(id);
|
||||
if (handleCachedFileRequest(id, request, response)) {
|
||||
return;
|
||||
}
|
||||
Sys_file sys_file = fetchDownloadFile(id);
|
||||
if (!ObjectUtil.isEmpty(sys_file) && handleCachedImageRequest(sys_file, request, response)) {
|
||||
return;
|
||||
}
|
||||
if (ObjectUtil.isEmpty(sys_file)) {
|
||||
sendErrorResponse(response, "文件记录不存在");
|
||||
return;
|
||||
@@ -88,16 +98,108 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
||||
sendErrorResponse(response, "找不到存储的文件");
|
||||
return;
|
||||
}
|
||||
CommonDownloadUtil.download(sys_file.getName(), IoUtil.readBytes(FileUtil.getInputStream(file)), response);
|
||||
byte[] bytes = IoUtil.readBytes(FileUtil.getInputStream(file));
|
||||
if (writeImageResponse(sys_file, bytes, response)) {
|
||||
return;
|
||||
}
|
||||
CommonDownloadUtil.download(sys_file.getName(), bytes, response);
|
||||
} else if (sys_file.getEngine().equals(SysFileEngineTypeEnum.MINIO.getValue())) {
|
||||
byte[] bytes = SysFileMinIoUtil.getFileBytes(sys_file.getBucket(), sys_file.getStoragePath());
|
||||
if (writeImageResponse(sys_file, bytes, response)) {
|
||||
return;
|
||||
}
|
||||
CommonDownloadUtil.download(sys_file.getName(), bytes, response);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleCachedFileRequest(String id, HttpServletRequest request, HttpServletResponse response) {
|
||||
String etag = buildFileEtag(id);
|
||||
if (etag.equals(request.getHeader("If-None-Match"))) {
|
||||
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
setImageCacheHeaders(response, etag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Sys_file fetchDownloadFile(String id) {
|
||||
if (StrUtil.isBlank(id)) {
|
||||
return null;
|
||||
}
|
||||
Sys_file cached = downloadFileCache.get(id);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
Sys_file sysFile = this.fetch(id);
|
||||
if (sysFile != null) {
|
||||
if (downloadFileCache.size() >= DOWNLOAD_FILE_CACHE_LIMIT) {
|
||||
downloadFileCache.clear();
|
||||
}
|
||||
downloadFileCache.put(id, sysFile);
|
||||
}
|
||||
return sysFile;
|
||||
}
|
||||
|
||||
private boolean handleCachedImageRequest(Sys_file sysFile, HttpServletRequest request, HttpServletResponse response) {
|
||||
if (!isImage(sysFile)) {
|
||||
return false;
|
||||
}
|
||||
String etag = buildFileEtag(sysFile);
|
||||
if (etag.equals(request.getHeader("If-None-Match"))) {
|
||||
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
setImageCacheHeaders(response, etag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean writeImageResponse(Sys_file sysFile, byte[] bytes, HttpServletResponse response) throws IOException {
|
||||
if (!isImage(sysFile)) {
|
||||
return false;
|
||||
}
|
||||
setImageCacheHeaders(response, buildFileEtag(sysFile));
|
||||
response.setHeader("Content-Disposition", "inline;filename=" + java.net.URLEncoder.encode(sysFile.getName(), java.nio.charset.StandardCharsets.UTF_8));
|
||||
response.setHeader("Content-Length", String.valueOf(bytes.length));
|
||||
response.setContentType(getImageContentType(sysFile));
|
||||
IoUtil.write(response.getOutputStream(), true, bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setImageCacheHeaders(HttpServletResponse response, String etag) {
|
||||
response.setHeader("Cache-Control", "public, max-age=604800, immutable");
|
||||
response.setHeader("ETag", etag);
|
||||
response.setDateHeader("Expires", System.currentTimeMillis() + 604800000L);
|
||||
}
|
||||
|
||||
private String buildFileEtag(Sys_file sysFile) {
|
||||
return buildFileEtag(sysFile.getId());
|
||||
}
|
||||
|
||||
private String buildFileEtag(String id) {
|
||||
return "\"" + id + "\"";
|
||||
}
|
||||
|
||||
private boolean isImage(Sys_file sysFile) {
|
||||
String suffix = StrUtil.blankToDefault(sysFile.getSuffix(), FileUtil.extName(sysFile.getName())).toLowerCase();
|
||||
return "jpg".equals(suffix) || "jpeg".equals(suffix) || "png".equals(suffix) || "gif".equals(suffix) || "webp".equals(suffix) || "bmp".equals(suffix) || "svg".equals(suffix);
|
||||
}
|
||||
|
||||
private String getImageContentType(Sys_file sysFile) {
|
||||
String suffix = StrUtil.blankToDefault(sysFile.getSuffix(), FileUtil.extName(sysFile.getName())).toLowerCase();
|
||||
return switch (suffix) {
|
||||
case "jpg", "jpeg" -> "image/jpeg";
|
||||
case "png" -> "image/png";
|
||||
case "gif" -> "image/gif";
|
||||
case "webp" -> "image/webp";
|
||||
case "bmp" -> "image/bmp";
|
||||
case "svg" -> "image/svg+xml";
|
||||
default -> "application/octet-stream";
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] download(String id) throws IOException {
|
||||
Sys_file sys_file = this.fetch(id);
|
||||
Sys_file sys_file = fetchDownloadFile(id);
|
||||
if (ObjectUtil.isEmpty(sys_file)) {
|
||||
throw new IOException("文件记录不存在");
|
||||
}
|
||||
@@ -147,7 +249,7 @@ public class SysFileServiceImpl extends BaseServiceImpl<Sys_file> implements Sys
|
||||
|
||||
@Override
|
||||
public Sys_file detail(String id) {
|
||||
return fetch(id);
|
||||
return fetchDownloadFile(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.budwk.app.sys.services.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.models.Sys_home_template;
|
||||
import com.budwk.app.sys.services.SysHomeTemplateService;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class SysHomeTemplateServiceImpl extends BaseServiceImpl<Sys_home_template> implements SysHomeTemplateService {
|
||||
|
||||
public SysHomeTemplateServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.budwk.app.web.commons.filter;
|
||||
|
||||
import org.nutz.lang.Strings;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
public class StaticResourceCacheFilter implements Filter {
|
||||
|
||||
private static final int ONE_YEAR_SECONDS = 31536000;
|
||||
private static final int SEVEN_DAYS_SECONDS = 604800;
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
HttpServletResponse response = (HttpServletResponse) res;
|
||||
applyCacheHeaders(request, response);
|
||||
chain.doFilter(req, res);
|
||||
}
|
||||
|
||||
private void applyCacheHeaders(HttpServletRequest request, HttpServletResponse response) {
|
||||
String path = Strings.sNull(request.getRequestURI());
|
||||
String contextPath = Strings.sNull(request.getContextPath());
|
||||
if (!contextPath.isBlank() && path.startsWith(contextPath)) {
|
||||
path = path.substring(contextPath.length());
|
||||
}
|
||||
if (!isStaticResourcePath(path)) {
|
||||
return;
|
||||
}
|
||||
response.setHeader("Vary", "Accept-Encoding");
|
||||
if (hasVersionQuery(request)) {
|
||||
setPublicCache(response, ONE_YEAR_SECONDS, true);
|
||||
return;
|
||||
}
|
||||
if (path.startsWith("/components/")) {
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
return;
|
||||
}
|
||||
if (path.startsWith("/favicon/") || "/favicon.ico".equals(path)) {
|
||||
setPublicCache(response, SEVEN_DAYS_SECONDS, false);
|
||||
return;
|
||||
}
|
||||
if (isCacheableAsset(path)) {
|
||||
setPublicCache(response, SEVEN_DAYS_SECONDS, false);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isStaticResourcePath(String path) {
|
||||
return path.startsWith("/assets/") || path.startsWith("/components/") || path.startsWith("/favicon/") || "/favicon.ico".equals(path);
|
||||
}
|
||||
|
||||
private boolean hasVersionQuery(HttpServletRequest request) {
|
||||
String version = request.getParameter("v");
|
||||
return version != null && !version.isBlank();
|
||||
}
|
||||
|
||||
private boolean isCacheableAsset(String path) {
|
||||
String lowerPath = path.toLowerCase(Locale.ROOT);
|
||||
return lowerPath.endsWith(".js")
|
||||
|| lowerPath.endsWith(".css")
|
||||
|| lowerPath.endsWith(".png")
|
||||
|| lowerPath.endsWith(".jpg")
|
||||
|| lowerPath.endsWith(".jpeg")
|
||||
|| lowerPath.endsWith(".gif")
|
||||
|| lowerPath.endsWith(".webp")
|
||||
|| lowerPath.endsWith(".svg")
|
||||
|| lowerPath.endsWith(".ico")
|
||||
|| lowerPath.endsWith(".woff")
|
||||
|| lowerPath.endsWith(".woff2")
|
||||
|| lowerPath.endsWith(".ttf")
|
||||
|| lowerPath.endsWith(".eot")
|
||||
|| lowerPath.endsWith(".otf")
|
||||
|| lowerPath.endsWith(".map");
|
||||
}
|
||||
|
||||
private void setPublicCache(HttpServletResponse response, int maxAgeSeconds, boolean immutable) {
|
||||
String cacheControl = "public, max-age=" + maxAgeSeconds;
|
||||
if (immutable) {
|
||||
cacheControl += ", immutable";
|
||||
}
|
||||
response.setHeader("Cache-Control", cacheControl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.budwk.app.web.commons.filter;
|
||||
|
||||
import org.nutz.boot.AppContext;
|
||||
import org.nutz.boot.starter.WebFilterFace;
|
||||
import org.nutz.ioc.Ioc;
|
||||
import org.nutz.ioc.impl.PropertiesProxy;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@IocBean
|
||||
public class StaticResourceCacheFilterStarter implements WebFilterFace {
|
||||
|
||||
@Inject("refer:$ioc")
|
||||
protected Ioc ioc;
|
||||
|
||||
@Inject
|
||||
protected PropertiesProxy conf;
|
||||
|
||||
@Inject
|
||||
protected AppContext appContext;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "staticResourceCacheFilterStarter";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPathSpec() {
|
||||
return "/*";
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<DispatcherType> getDispatches() {
|
||||
return EnumSet.of(DispatcherType.REQUEST);
|
||||
}
|
||||
|
||||
@IocBean(name = "staticResourceCacheFilter")
|
||||
public StaticResourceCacheFilter createStaticResourceCacheFilter() {
|
||||
return new StaticResourceCacheFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter getFilter() {
|
||||
return ioc.get(StaticResourceCacheFilter.class, "staticResourceCacheFilter");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getInitParameters() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
@@ -149,7 +149,7 @@ public class CommonController {
|
||||
@ApiOperation("系统配置")
|
||||
public Result getConfigKey(String key) {
|
||||
Sys_config configKey = sysDictService.dao().fetch(Sys_config.class, Cnd.where("configKey", "=", key));
|
||||
return Result.success().addData(configKey.getConfigValue());
|
||||
return Result.success().addData(configKey == null ? "" : configKey.getConfigValue());
|
||||
}
|
||||
|
||||
@At
|
||||
|
||||
@@ -5,9 +5,12 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.sys.models.Sys_home_template;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.zhgh.activity.culture.models.ActivityTissue;
|
||||
import com.budwk.app.zhgh.activity.culture.models.ActivityTissuePerson;
|
||||
import com.budwk.app.zhgh.activity.culture.service.ActivityCultureService;
|
||||
@@ -86,11 +89,56 @@ public class ActivityCultureInfoManageController {
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("activity.culture.infoManage.school")
|
||||
public Result setTemplate(@Valid String id) {
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
return Result.error("无权操作");
|
||||
}
|
||||
ActivityTissue tissue = activityCultureService.fetch(id);
|
||||
if (tissue == null) {
|
||||
return Result.error("活动不存在");
|
||||
}
|
||||
if (tissue.getActivity_type() == null || tissue.getActivity_type() != 40001) {
|
||||
return Result.error("仅校工会文化活动可设为模板");
|
||||
}
|
||||
Sys_home_template oldHomeTemplate = activityCultureService.dao().fetch(Sys_home_template.class, id);
|
||||
Sys_home_template sysHomeTemplate = tissue.covertToSysHomeTemplate();
|
||||
if (oldHomeTemplate != null) {
|
||||
sysHomeTemplate.setTop(oldHomeTemplate.getTop());
|
||||
sysHomeTemplate.setPush(oldHomeTemplate.getPush());
|
||||
sysHomeTemplate.setSortNo(oldHomeTemplate.getSortNo());
|
||||
if (oldHomeTemplate.getTemplateName() != null) {
|
||||
sysHomeTemplate.setTemplateName(oldHomeTemplate.getTemplateName());
|
||||
}
|
||||
if (oldHomeTemplate.getTemplateIcon() != null) {
|
||||
sysHomeTemplate.setTemplateIcon(oldHomeTemplate.getTemplateIcon());
|
||||
}
|
||||
}
|
||||
activityCultureService.dao().insertOrUpdate(sysHomeTemplate);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("activity.culture.infoManage.school")
|
||||
public Result cancelTemplate(@Valid String id) {
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
return Result.error("无权操作");
|
||||
}
|
||||
activityCultureService.dao().delete(Sys_home_template.class, id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SLog(tag = "文化活动", msg = "删除了一条活动")
|
||||
@SaCheckPermission(value = {"activity.culture.infoManage.school", "activity.culture.infoManage.union", "activity.culture.infoManage.club"}, mode = SaMode.OR)
|
||||
public Result doDelete(@Valid String id) {
|
||||
if (activityCultureService.dao().fetch(Sys_home_template.class, id) != null) {
|
||||
return Result.error("该活动已设为模板,请先取消模板后再删除");
|
||||
}
|
||||
activityCultureService.delete(id);
|
||||
activityCultureService.dao().clear(ActivityTissuePerson.class, Cnd.where(ActivityTissuePerson::getTissueId, "=", id));
|
||||
activityCultureService.dao().delete(Sys_home_activity.class, id);
|
||||
|
||||
@@ -5,6 +5,7 @@ import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import com.budwk.app.base.model.CustomFormField;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.sys.models.Sys_home_template;
|
||||
import com.budwk.app.sys.services.SysHomeConvert;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -291,4 +292,29 @@ public class ActivityTissue extends BaseModel implements Serializable, SysHomeCo
|
||||
sysHomeActivity.setClassPath(this.getClass().getPackageName() + this.getClass().getName());
|
||||
return sysHomeActivity;
|
||||
}
|
||||
|
||||
public Sys_home_template covertToSysHomeTemplate() {
|
||||
Sys_home_template sysHomeTemplate = new Sys_home_template();
|
||||
sysHomeTemplate.setId(this.getId());
|
||||
sysHomeTemplate.setName(this.getName());
|
||||
sysHomeTemplate.setTemplateName(this.getName());
|
||||
sysHomeTemplate.setCover(this.getCover());
|
||||
sysHomeTemplate.setContent(this.getActivityContent());
|
||||
if (this.getActivity_type() == 40001) {
|
||||
sysHomeTemplate.setUrl("/platform/activity/culture/applyActivity/school?mode=edit&id=" + this.getId());
|
||||
} else if (this.getActivity_type() == 40002) {
|
||||
sysHomeTemplate.setUrl("/platform/activity/culture/applyActivity/union?mode=edit&id=" + this.getId());
|
||||
} else {
|
||||
sysHomeTemplate.setUrl("/platform/activity/culture/applyActivity/club?mode=edit&id=" + this.getId());
|
||||
}
|
||||
sysHomeTemplate.setH5Url("");
|
||||
if (Lang.isNotEmpty(this.getApplyStartTime())) {
|
||||
sysHomeTemplate.setStartDate(DateUtil.parseDate(this.getApplyStartTime()));
|
||||
sysHomeTemplate.setEndDate(DateUtil.parseDate(this.getApplyEndTime()));
|
||||
}
|
||||
sysHomeTemplate.setAllowUserGroupId(this.getGroupId());
|
||||
sysHomeTemplate.setEnable(this.getIsUnseal());
|
||||
sysHomeTemplate.setClassPath(this.getClass().getPackageName() + this.getClass().getName());
|
||||
return sysHomeTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,8 @@ public class ActivityCultureServiceImpl extends BaseServiceImpl<ActivityTissue>
|
||||
t.taskParentId,
|
||||
t.variable taskVariable,
|
||||
IF((SELECT taskName FROM wf_process_task tt WHERE tt.id = t.taskParentId) = 'startTask', 1, 0) canRevoke,
|
||||
(select MAX(id) from wf_process_task where processInstanceId = ins.id and taskName = 'startTask') AS startTaskId
|
||||
(select MAX(id) from wf_process_task where processInstanceId = ins.id and taskName = 'startTask') AS startTaskId,
|
||||
IF(sht.id IS NULL, 0, 1) AS isTemplate
|
||||
FROM
|
||||
activity_tissue tissue
|
||||
LEFT JOIN sys_union uni ON uni.id = tissue.unionId
|
||||
@@ -118,6 +119,7 @@ public class ActivityCultureServiceImpl extends BaseServiceImpl<ActivityTissue>
|
||||
LEFT JOIN `wf_process_instance` ins ON ins.businessNo = tissue.id
|
||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||
LEFT JOIN sys_home_template sht ON sht.id = tissue.id
|
||||
$condition
|
||||
""");
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.budwk.app.zhgh.activity.sports.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
@@ -9,6 +10,7 @@ import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
|
||||
import com.budwk.app.zhgh.activity.basic.models.ActivityEvent;
|
||||
import com.budwk.app.zhgh.activity.sports.models.ActivitySchool;
|
||||
import com.budwk.app.zhgh.activity.sports.models.ActivitySchoolEvent;
|
||||
@@ -51,6 +53,9 @@ public class ActivitySportsInfoManageController {
|
||||
@Inject
|
||||
private Dao dao;
|
||||
|
||||
@Inject
|
||||
private ActivityBasicScopeService activityBasicScopeService;
|
||||
|
||||
@At
|
||||
@SaCheckPermission("activity.sports.info")
|
||||
public Object pageData(PageForm page,
|
||||
@@ -128,7 +133,7 @@ public class ActivitySportsInfoManageController {
|
||||
|
||||
|
||||
@At
|
||||
@SaCheckPermission("activity.sports.info")
|
||||
@SaCheckPermission(value = {"activity.sports.info", "activity.sports.new"}, mode = SaMode.OR)
|
||||
public Object getEventApply(@Param(value = "activityId") String activityId,
|
||||
@Param(value = "eventId") String[] eventId) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
@@ -149,7 +154,7 @@ public class ActivitySportsInfoManageController {
|
||||
|
||||
@At
|
||||
@SLog(tag = "体育活动", msg = "修改活动")
|
||||
@SaCheckPermission("activity.sports.info")
|
||||
@SaCheckPermission(value = {"activity.sports.info", "activity.sports.new"}, mode = SaMode.OR)
|
||||
public Result doEdit(@Param(value = "data") ActivitySchool activitySchool,
|
||||
@Param(value = "events") ActivitySchoolEvent[] events) {
|
||||
activitySportsService.doEdit(activitySchool, events);
|
||||
@@ -160,7 +165,7 @@ public class ActivitySportsInfoManageController {
|
||||
|
||||
@At
|
||||
@SLog(tag = "体育活动", msg = "添加活动")
|
||||
@SaCheckPermission("activity.sports.info")
|
||||
@SaCheckPermission(value = {"activity.sports.info", "activity.sports.new"}, mode = SaMode.OR)
|
||||
public Result doAdd(@Param(value = "data") ActivitySchool activitySchool,
|
||||
@Param(value = "events") ActivitySchoolEvent[] events) {
|
||||
String id = activitySportsService.doAdd(activitySchool, events);
|
||||
@@ -170,7 +175,7 @@ public class ActivitySportsInfoManageController {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("activity.sports.info")
|
||||
@SaCheckPermission(value = {"activity.sports.info", "activity.sports.new"}, mode = SaMode.OR)
|
||||
public Result findOne(String id) {
|
||||
NutMap nutMap = (NutMap) dao.execute(Sqls.create("SELECT * FROM `activity_school` WHERE id = @id").setParam("id", id)
|
||||
.setCallback(Sqls.callback.map())).getResult();
|
||||
@@ -199,7 +204,7 @@ public class ActivitySportsInfoManageController {
|
||||
|
||||
@At
|
||||
@ApiOperation("根据比赛项目基础表统一赋年龄限制")
|
||||
@SaCheckPermission("activity.sports.info")
|
||||
@SaCheckPermission(value = {"activity.sports.info", "activity.sports.new"}, mode = SaMode.OR)
|
||||
public Object doAssignmentDate(ActivitySchoolEvent[] events) {
|
||||
for (ActivitySchoolEvent event : events) {
|
||||
ActivityEvent activityEvent = dao.fetch(ActivityEvent.class,event.getEventId());
|
||||
@@ -212,6 +217,28 @@ public class ActivitySportsInfoManageController {
|
||||
return Result.success(events);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("获取分工会人数限制")
|
||||
@SaCheckPermission(value = {"activity.sports.info", "activity.sports.new"}, mode = SaMode.OR)
|
||||
public Result getUnionLimit(@Param(value = "activityScopeId") String activityScopeId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
gh.id,
|
||||
gh.name,
|
||||
gh.unioncode,
|
||||
(select count(1) from `vw_user` where unionid = gh.id $cnd) as teacherCount,
|
||||
NULL as ratio,
|
||||
NULL as limitCount
|
||||
FROM
|
||||
sys_union gh
|
||||
order by gh.unioncode
|
||||
""");
|
||||
if (StrUtil.isNotBlank(activityScopeId)) {
|
||||
sql.setVar("cnd", "AND id in (" + activityBasicScopeService.buildGroupUserIdSubSqlText(Integer.valueOf(activityScopeId)) + ")");
|
||||
}
|
||||
return Result.success(activitySportsService.listMap(sql));
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@Ok("void")
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.budwk.app.zhgh.activity.sports.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/activity/sports/new")
|
||||
@Ok("json:full")
|
||||
@Api(tags = "新建体育活动")
|
||||
public class ActivitySportsNewController {
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:platform/zhgh/activity/sports/new/index.html")
|
||||
@SaCheckPermission(value = {"activity.sports.info", "activity.sports.new"}, mode = SaMode.OR)
|
||||
public void index() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.budwk.app.zhgh.activity.trainSignUp.controller.manage;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/trainSignUp/applyActivity")
|
||||
@Ok("json:full")
|
||||
@Api(tags = "品牌活动新建活动")
|
||||
public class TrainSignUpApplyActivityController {
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/activity/trainSignUp/applyActivity/index.html")
|
||||
@SaCheckPermission("trainSignUp.applyActivity")
|
||||
public void index() {
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,21 @@
|
||||
package com.budwk.app.zhgh.activity.trainSignUp.controller.manage;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.sys.models.Sys_home_template;
|
||||
import com.budwk.app.sys.models.Sys_union;
|
||||
import com.budwk.app.sys.models.Sys_unit;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.models.*;
|
||||
import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpActivityService;
|
||||
@@ -72,7 +77,54 @@ public class TrainSignUpManageController {
|
||||
cnd.andEX("year", "=", year);
|
||||
cnd.and(Cnd.likeEX("activityName", activityName));
|
||||
cnd.orderBy("createdAt", "desc");
|
||||
return Result.success().addData(trainSignUpActivityManageService.pageData(pageForm, cnd));
|
||||
Pagination<TrainSignUpActivity> pagination = trainSignUpActivityManageService.pageData(pageForm, cnd);
|
||||
List<TrainSignUpActivity> list = pagination.getList(TrainSignUpActivity.class);
|
||||
if (list != null && !list.isEmpty()) {
|
||||
List<String> ids = list.stream().map(TrainSignUpActivity::getId).toList();
|
||||
List<Sys_home_template> templateList = dao.query(Sys_home_template.class, Cnd.where("id", "in", ids));
|
||||
List<String> templateIds = templateList.stream().map(Sys_home_template::getId).toList();
|
||||
list.forEach(activity -> activity.setIsTemplate(templateIds.contains(activity.getId())));
|
||||
}
|
||||
return Result.success().addData(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("设为模板")
|
||||
@SaCheckPermission("trainSignUp.manage")
|
||||
public Result setTemplate(String id) {
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
return Result.error("无权操作");
|
||||
}
|
||||
TrainSignUpActivity activity = trainSignUpActivityManageService.fetch(id);
|
||||
if (activity == null) {
|
||||
return Result.error("活动不存在");
|
||||
}
|
||||
Sys_home_template oldHomeTemplate = dao.fetch(Sys_home_template.class, id);
|
||||
Sys_home_template sysHomeTemplate = activity.covertToSysHomeTemplate();
|
||||
if (oldHomeTemplate != null) {
|
||||
sysHomeTemplate.setTop(oldHomeTemplate.getTop());
|
||||
sysHomeTemplate.setPush(oldHomeTemplate.getPush());
|
||||
sysHomeTemplate.setSortNo(oldHomeTemplate.getSortNo());
|
||||
if (oldHomeTemplate.getTemplateName() != null) {
|
||||
sysHomeTemplate.setTemplateName(oldHomeTemplate.getTemplateName());
|
||||
}
|
||||
if (oldHomeTemplate.getTemplateIcon() != null) {
|
||||
sysHomeTemplate.setTemplateIcon(oldHomeTemplate.getTemplateIcon());
|
||||
}
|
||||
}
|
||||
dao.insertOrUpdate(sysHomeTemplate);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("取消模板")
|
||||
@SaCheckPermission("trainSignUp.manage")
|
||||
public Result cancelTemplate(String id) {
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
return Result.error("无权操作");
|
||||
}
|
||||
dao.delete(Sys_home_template.class, id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@@ -80,6 +132,9 @@ public class TrainSignUpManageController {
|
||||
@SaCheckPermission("trainSignUp.manage")
|
||||
@SLog(tag = "品牌活动-活动管理", msg = "删除活动")
|
||||
public Result onDelete(String id) {
|
||||
if (dao.fetch(Sys_home_template.class, id) != null) {
|
||||
return Result.error("该活动已设为模板,请先取消模板后再删除");
|
||||
}
|
||||
Trans.exec(() -> {
|
||||
trainSignUpActivityManageService.delete(id);
|
||||
dao.clear(TrainSignUpCourse.class, Cnd.where("activityId", "=", id));
|
||||
@@ -106,7 +161,7 @@ public class TrainSignUpManageController {
|
||||
|
||||
@At
|
||||
@ApiOperation("查询单个活动")
|
||||
@SaCheckPermission("trainSignUp")
|
||||
@SaCheckPermission(value = {"trainSignUp", "trainSignUp.manage", "trainSignUp.applyActivity", "h5.trainSignUp.apply"}, mode = SaMode.OR)
|
||||
public Result findOne(@Param("id") @NotNull String id) {
|
||||
NutMap dataMap = trainSignUpActivityManageService.findOne(id, null, "");
|
||||
String activityStartTime = dataMap.getString("activityStartTime");
|
||||
@@ -154,7 +209,7 @@ public class TrainSignUpManageController {
|
||||
@At
|
||||
@Ok("json:full")
|
||||
@ApiOperation("品牌活动新增/修改")
|
||||
@SaCheckPermission("trainSignUp.manage")
|
||||
@SaCheckPermission(value = {"trainSignUp.manage", "trainSignUp.applyActivity"}, mode = SaMode.OR)
|
||||
@SLog(tag = "品牌活动-活动管理", msg = "新增/修改活动")
|
||||
public Result doHandle(TrainSignUpActivity activity) {
|
||||
if (StrUtil.isBlank(activity.getId())) {
|
||||
@@ -168,7 +223,7 @@ public class TrainSignUpManageController {
|
||||
@At
|
||||
@Ok("json:full")
|
||||
@ApiOperation("获取分工会人数限制")
|
||||
@SaCheckPermission("trainSignUp.manage")
|
||||
@SaCheckPermission(value = {"trainSignUp.manage", "trainSignUp.applyActivity"}, mode = SaMode.OR)
|
||||
public Result getUnionLimit(@Param(value = "activityScopeId") String activityScopeId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
@@ -192,7 +247,7 @@ public class TrainSignUpManageController {
|
||||
@At
|
||||
@Ok("json:full")
|
||||
@ApiOperation("获取报名人员数量")
|
||||
@SaCheckPermission("trainSignUp.manage")
|
||||
@SaCheckPermission(value = {"trainSignUp.manage", "trainSignUp.applyActivity"}, mode = SaMode.OR)
|
||||
public Result getRegisterUserCount(@Param(value = "courseId") String courseId) {
|
||||
return Result.success().addData(dao.count(TrainSignUpUser.class, Cnd.where("courseId", "=", courseId)));
|
||||
}
|
||||
@@ -200,7 +255,7 @@ public class TrainSignUpManageController {
|
||||
@At
|
||||
@Ok("json:full")
|
||||
@ApiOperation("获取历史活动列表")
|
||||
@SaCheckPermission("trainSignUp.manage")
|
||||
@SaCheckPermission(value = {"trainSignUp.manage", "trainSignUp.applyActivity"}, mode = SaMode.OR)
|
||||
public Result getHistoricalActList() {
|
||||
List<TrainSignUpActivity> query = dao.query(TrainSignUpActivity.class, Cnd.NEW().desc("activityStartTime"));
|
||||
return Result.success().addData(query);
|
||||
@@ -209,7 +264,7 @@ public class TrainSignUpManageController {
|
||||
@At
|
||||
@Ok("json:full")
|
||||
@ApiOperation("查询分工会和社团")
|
||||
@SaCheckPermission("trainSignUp.manage")
|
||||
@SaCheckPermission(value = {"trainSignUp.manage", "trainSignUp.applyActivity"}, mode = SaMode.OR)
|
||||
public Result selectUnitAndClub() {
|
||||
List<NutMap> result = new ArrayList<>();
|
||||
List<Sys_unit> unitList = dao.query(Sys_unit.class, Cnd.NEW().asc(Sys_unit::getUnitcode));
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.budwk.app.zhgh.activity.trainSignUp.models;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.sys.models.Sys_home_template;
|
||||
import com.budwk.app.sys.services.SysHomeConvert;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -109,6 +110,8 @@ public class TrainSignUpActivity extends BaseModel implements Serializable, SysH
|
||||
@Many(field = "activityId")
|
||||
private List<TrainSignUpTypeLimit> typeLimits;
|
||||
|
||||
private Boolean isTemplate;
|
||||
|
||||
@Column
|
||||
@Comment("活动类型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
@@ -141,4 +144,23 @@ public class TrainSignUpActivity extends BaseModel implements Serializable, SysH
|
||||
sysHomeActivity.setClassPath(this.getClass().getPackageName() + this.getClass().getName());
|
||||
return sysHomeActivity;
|
||||
}
|
||||
|
||||
public Sys_home_template covertToSysHomeTemplate() {
|
||||
Sys_home_template sysHomeTemplate = new Sys_home_template();
|
||||
sysHomeTemplate.setId(this.getId());
|
||||
sysHomeTemplate.setName(this.getActivityName());
|
||||
sysHomeTemplate.setTemplateName(this.getActivityName());
|
||||
sysHomeTemplate.setCover(this.getCover());
|
||||
sysHomeTemplate.setContent(this.getIntroduce());
|
||||
sysHomeTemplate.setUrl("/platform/trainSignUp/applyActivity?mode=edit&id=" + this.getId());
|
||||
sysHomeTemplate.setH5Url("");
|
||||
if (Lang.isNotEmpty(this.getActivitySignUpStartTime())) {
|
||||
sysHomeTemplate.setStartDate(this.getActivitySignUpStartTime());
|
||||
sysHomeTemplate.setEndDate(this.getActivitySignUpEndTime());
|
||||
}
|
||||
sysHomeTemplate.setAllowUserGroupId(this.getActivityGroupId());
|
||||
sysHomeTemplate.setEnable(!this.isDisabled());
|
||||
sysHomeTemplate.setClassPath(this.getClass().getPackageName() + this.getClass().getName());
|
||||
return sysHomeTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,12 +105,12 @@ public class AssetManageController {
|
||||
@SLog(type = "assetManage", tag = "资产管理", msg = "编辑了一条资产信息")
|
||||
@SaCheckPermission("asset.manage")
|
||||
public Result doEdit(Asset asset) {
|
||||
Asset fetch = assetService.fetch(asset.getId());
|
||||
assetService.update(asset);
|
||||
|
||||
//增加折旧表记录
|
||||
Asset fetch = assetService.fetch(asset.getId());
|
||||
//如果资产类型不等于原来的或者预计报废时间不等于原来的
|
||||
if (!fetch.getAssetCategoryId().equals(asset.getAssetCategoryId()) || !fetch.getAssetRetiredAssetsDate().equals(asset.getAssetRetiredAssetsDate())) {
|
||||
if (!ObjectUtil.equal(fetch.getAssetCategoryId(), asset.getAssetCategoryId()) || !ObjectUtil.equal(fetch.getAssetRetiredAssetsDate(), asset.getAssetRetiredAssetsDate())) {
|
||||
assetDepreciationRecordService.clear(Cnd.where("assetId", "=", asset.getId()));
|
||||
AssetDepreciationRecord record = assetDepreciationRecordService.initAssetDepreciationRecord(asset.getAssetUnitPrice(), asset.getAssetQuantity(), asset.getAssetUsedDate(), asset.getAssetRetiredAssetsDate());
|
||||
if (ObjectUtil.isNotEmpty(record)) {
|
||||
|
||||
@@ -70,7 +70,7 @@ public class Asset extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Comment("单价")
|
||||
@ColDefine(customType = "decimal(10,2)")
|
||||
@ColDefine(customType = "decimal(18,2)")
|
||||
private BigDecimal assetUnitPrice;
|
||||
|
||||
@Column
|
||||
|
||||
@@ -43,22 +43,22 @@ public class AssetDepreciationRecord extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Comment("资产全部的价值")
|
||||
@ColDefine(customType = "decimal(10,2)")
|
||||
@ColDefine(customType = "decimal(18,2)")
|
||||
private BigDecimal assetAllMoney;
|
||||
|
||||
@Column
|
||||
@Comment("剩余价值")
|
||||
@ColDefine(customType = "decimal(10,2)")
|
||||
@ColDefine(customType = "decimal(18,2)")
|
||||
private BigDecimal assetSurplusMoney;
|
||||
|
||||
@Column
|
||||
@Comment("累计折旧多少钱")
|
||||
@ColDefine(customType = "decimal(10,2)")
|
||||
@ColDefine(customType = "decimal(18,2)")
|
||||
private BigDecimal assetDepreciationMoney;
|
||||
|
||||
@Column
|
||||
@Comment("平均一个月多少钱")
|
||||
@ColDefine(customType = "decimal(10,2)")
|
||||
@ColDefine(customType = "decimal(18,2)")
|
||||
private BigDecimal assetAverageMonthMoney;
|
||||
|
||||
@Column
|
||||
|
||||
@@ -53,6 +53,16 @@ public class AssetDepreciationRecordServiceImpl extends BaseServiceImpl<AssetDep
|
||||
//计算资产使用时间到现在使用了几个月
|
||||
long usedMonth = ChronoUnit.MONTHS.between(assetUsedDateLocalDate, LocalDate.now());
|
||||
AssetDepreciationRecord record = new AssetDepreciationRecord();
|
||||
BigDecimal assetAllMoney = assetUnitPrice.multiply(new BigDecimal(assetQuantity));
|
||||
if (wholeMonth <= 0) {
|
||||
record.setAssetRetiredAssetsDate(assetRetiredAssetsDate);
|
||||
record.setAssetRemainingMonths(0);
|
||||
record.setAssetAllMoney(assetAllMoney);
|
||||
record.setAssetAverageMonthMoney(assetAllMoney);
|
||||
record.setAssetSurplusMoney(BigDecimal.ZERO);
|
||||
record.setAssetDepreciationMoney(assetAllMoney);
|
||||
return record;
|
||||
}
|
||||
//如果折旧到期时间小于现在时间直接设为0
|
||||
if (assetRetiredAssetsDateLocalDate.isBefore(LocalDate.now())) {
|
||||
//预计折旧到期时间
|
||||
@@ -60,12 +70,12 @@ public class AssetDepreciationRecordServiceImpl extends BaseServiceImpl<AssetDep
|
||||
//资产剩余的月
|
||||
record.setAssetRemainingMonths(0);
|
||||
//资产全部的金额
|
||||
record.setAssetAllMoney(assetUnitPrice.multiply(new BigDecimal(assetQuantity)));
|
||||
record.setAssetAllMoney(assetAllMoney);
|
||||
//资产平均每月价值
|
||||
record.setAssetAverageMonthMoney(record.getAssetAllMoney().divide(new BigDecimal(wholeMonth), 2, RoundingMode.DOWN));
|
||||
//剩余价值
|
||||
record.setAssetSurplusMoney(BigDecimal.ZERO);
|
||||
record.setAssetDepreciationMoney(assetUnitPrice.multiply(new BigDecimal(assetQuantity)));
|
||||
record.setAssetDepreciationMoney(assetAllMoney);
|
||||
return record;
|
||||
} else if (wholeMonth - usedMonth >= 0) {
|
||||
//预计折旧到期时间
|
||||
@@ -73,13 +83,13 @@ public class AssetDepreciationRecordServiceImpl extends BaseServiceImpl<AssetDep
|
||||
//资产剩余的月
|
||||
record.setAssetRemainingMonths((int) (wholeMonth - usedMonth < 0 ? 0 : wholeMonth - usedMonth));
|
||||
//资产全部的金额
|
||||
record.setAssetAllMoney(assetUnitPrice.multiply(new BigDecimal(assetQuantity)));
|
||||
record.setAssetAllMoney(assetAllMoney);
|
||||
//资产平均每月价值
|
||||
record.setAssetAverageMonthMoney(record.getAssetAllMoney().divide(new BigDecimal(wholeMonth), 2, RoundingMode.DOWN));
|
||||
//剩余价值
|
||||
if (usedMonth == 0) {
|
||||
//如果等于0代表一个月都没用到直接设为全部的金额
|
||||
record.setAssetSurplusMoney(assetUnitPrice.multiply(new BigDecimal(assetQuantity)));
|
||||
record.setAssetSurplusMoney(assetAllMoney);
|
||||
} else {
|
||||
record.setAssetSurplusMoney(record.getAssetAverageMonthMoney().multiply(BigDecimal.valueOf(record.getAssetRemainingMonths())));
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
package com.budwk.app.zhgh.dayofficework.buildHome.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
|
||||
import com.budwk.app.sys.models.Sys_union;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.buildHome.models.BuildHomeLittleHouse;
|
||||
@@ -22,10 +21,12 @@ import com.deepoove.poi.config.Configure;
|
||||
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
|
||||
import io.swagger.annotations.Api;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
@@ -34,7 +35,6 @@ import org.nutz.mvc.annotation.Ok;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -67,9 +67,14 @@ public class BuildHomeLittleHouseController {
|
||||
public Result pageData(BuildHomeLittleHousePageForm pageForm) {
|
||||
Sql sql = Sqls.create("select * from build_home_little_house $condition");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("unionId", "=", SecurityUtil.getUnionId());
|
||||
if (!isSysAdmin()) {
|
||||
cnd.and("unionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
cnd.where().andLike("unitName", pageForm.getSearchKeyword());
|
||||
SqlExpressionGroup searchGroup = new SqlExpressionGroup();
|
||||
searchGroup.orLike("unitName", pageForm.getSearchKeyword());
|
||||
searchGroup.orLike("unionName", pageForm.getSearchKeyword());
|
||||
cnd.where().and(searchGroup);
|
||||
}
|
||||
cnd.asc("sortNum");
|
||||
sql.setCondition(cnd);
|
||||
@@ -77,12 +82,19 @@ public class BuildHomeLittleHouseController {
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("buildHome.littleHouse")
|
||||
public Result currentUserOrg() {
|
||||
return Result.success(getCurrentUserOrg());
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("buildHome.littleHouse")
|
||||
public Result save(BuildHomeLittleHouse house) {
|
||||
if (house.getId() == null) {
|
||||
house.setUnionId(SecurityUtil.getUnionId());
|
||||
house.setUnionName(SecurityUtil.getUnionId());
|
||||
fillCurrentUserOrg(house);
|
||||
} else {
|
||||
keepOriginalOrg(house);
|
||||
}
|
||||
dao.insertOrUpdate(house);
|
||||
return Result.success();
|
||||
@@ -102,22 +114,64 @@ public class BuildHomeLittleHouseController {
|
||||
return Result.success(house);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("buildHome.littleHouse")
|
||||
public Result saveCoordinate(Long id, Double mapX, Double mapY) {
|
||||
if (!isSysAdmin()) {
|
||||
return Result.error("仅系统管理员可以采集坐标");
|
||||
}
|
||||
if (id == null) {
|
||||
return Result.error("小家记录ID不能为空");
|
||||
}
|
||||
if (!isValidCoordinate(mapX) || !isValidCoordinate(mapY)) {
|
||||
return Result.error("坐标范围必须在0到100之间");
|
||||
}
|
||||
BuildHomeLittleHouse house = dao.fetch(BuildHomeLittleHouse.class, id);
|
||||
if (house == null) {
|
||||
return Result.error("未找到小家记录");
|
||||
}
|
||||
dao.update(BuildHomeLittleHouse.class, Chain.make("mapX", mapX).add("mapY", mapY), Cnd.where("id", "=", id));
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("buildHome.littleHouse")
|
||||
public Result clearCoordinate(Long id) {
|
||||
if (!isSysAdmin()) {
|
||||
return Result.error("仅系统管理员可以清空坐标");
|
||||
}
|
||||
if (id == null) {
|
||||
return Result.error("小家记录ID不能为空");
|
||||
}
|
||||
BuildHomeLittleHouse house = dao.fetch(BuildHomeLittleHouse.class, id);
|
||||
if (house == null) {
|
||||
return Result.error("未找到小家记录");
|
||||
}
|
||||
dao.update(BuildHomeLittleHouse.class, Chain.make("mapX", null).add("mapY", null), Cnd.where("id", "=", id));
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At("/exportXlsx")
|
||||
@SaCheckPermission("buildHome.littleHouse")
|
||||
@Ok("void")
|
||||
public void exportXlsx(HttpServletResponse response) {
|
||||
try {
|
||||
boolean sysAdmin = isSysAdmin();
|
||||
String unionId = SecurityUtil.getUnionId();
|
||||
Cnd cnd = Cnd.where("unionId", "=", unionId);
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (!sysAdmin) {
|
||||
cnd.and("unionId", "=", unionId);
|
||||
}
|
||||
cnd.asc("sortNum");
|
||||
|
||||
Sys_union union = dao.fetch(Sys_union.class, unionId);
|
||||
if (union == null) {
|
||||
if (!sysAdmin && union == null) {
|
||||
throw new BaseException("未找到ID为 " + unionId + " 的工会信息");
|
||||
}
|
||||
|
||||
// 准备文档数据Map
|
||||
Map<String, Object> docMap = new HashMap<>();
|
||||
docMap.put("unionName", union.getName()); // 工会名称
|
||||
docMap.put("unionName", sysAdmin ? "全部工会" : union.getName()); // 工会名称
|
||||
docMap.put("date", DateUtil.today()); // 当前日期
|
||||
|
||||
// 查询小家建设数据并设置序号
|
||||
@@ -151,4 +205,50 @@ public class BuildHomeLittleHouseController {
|
||||
}
|
||||
}
|
||||
|
||||
private void fillCurrentUserOrg(BuildHomeLittleHouse house) {
|
||||
Map<String, String> currentUserOrg = getCurrentUserOrg();
|
||||
house.setUnionId(currentUserOrg.get("unionId"));
|
||||
house.setUnionName(currentUserOrg.get("unionName"));
|
||||
house.setUnitId(currentUserOrg.get("unitId"));
|
||||
house.setUnitName(currentUserOrg.get("unitName"));
|
||||
}
|
||||
|
||||
private void keepOriginalOrg(BuildHomeLittleHouse house) {
|
||||
BuildHomeLittleHouse oldHouse = dao.fetch(BuildHomeLittleHouse.class, house.getId());
|
||||
if (oldHouse == null) {
|
||||
fillCurrentUserOrg(house);
|
||||
return;
|
||||
}
|
||||
house.setUnionId(oldHouse.getUnionId());
|
||||
house.setUnionName(oldHouse.getUnionName());
|
||||
house.setUnitId(oldHouse.getUnitId());
|
||||
house.setUnitName(oldHouse.getUnitName());
|
||||
}
|
||||
|
||||
private Map<String, String> getCurrentUserOrg() {
|
||||
Map<String, String> currentUserOrg = new HashMap<>();
|
||||
View_user user = dao.fetch(View_user.class, Cnd.where("id", "=", SecurityUtil.getUserId()));
|
||||
|
||||
String unionId = user != null && StrUtil.isNotBlank(user.getUnionId()) ? user.getUnionId() : SecurityUtil.getUnionId();
|
||||
String unionName = user != null ? user.getUnionName() : null;
|
||||
if (StrUtil.isBlank(unionName) && StrUtil.isNotBlank(unionId)) {
|
||||
Sys_union union = dao.fetch(Sys_union.class, unionId);
|
||||
unionName = union != null ? union.getName() : unionId;
|
||||
}
|
||||
|
||||
currentUserOrg.put("unionId", unionId);
|
||||
currentUserOrg.put("unionName", unionName);
|
||||
currentUserOrg.put("unitId", user != null ? user.getUnitId() : SecurityUtil.getUnitId());
|
||||
currentUserOrg.put("unitName", user != null ? user.getUnitName() : null);
|
||||
return currentUserOrg;
|
||||
}
|
||||
|
||||
private boolean isSysAdmin() {
|
||||
return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name());
|
||||
}
|
||||
|
||||
private boolean isValidCoordinate(Double value) {
|
||||
return value != null && value >= 0 && value <= 100;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.budwk.app.zhgh.dayofficework.buildHome.models;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.nutz.dao.entity.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("build_home_little_house")
|
||||
@@ -22,6 +25,11 @@ public class BuildHomeLittleHouse extends BaseModel {
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String unitName;
|
||||
|
||||
@Column
|
||||
@Comment("单位ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String unitId;
|
||||
|
||||
@Column
|
||||
@Comment("分工会ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@@ -52,6 +60,21 @@ public class BuildHomeLittleHouse extends BaseModel {
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String openTime;
|
||||
|
||||
@Column
|
||||
@Comment("图片视频资料")
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
private List<JSONObject> mediaFiles;
|
||||
|
||||
@Column
|
||||
@Comment("地图X坐标百分比")
|
||||
@ColDefine(type = ColType.FLOAT, width = 8, precision = 4)
|
||||
private Double mapX;
|
||||
|
||||
@Column
|
||||
@Comment("地图Y坐标百分比")
|
||||
@ColDefine(type = ColType.FLOAT, width = 8, precision = 4)
|
||||
private Double mapY;
|
||||
|
||||
@Column
|
||||
@Comment("排序")
|
||||
@ColDefine(type = ColType.INT)
|
||||
|
||||
@@ -0,0 +1,570 @@
|
||||
package com.budwk.app.zhgh.dayofficework.caredata;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/careData/leader")
|
||||
@Api("Leader dashboard")
|
||||
@Ok("json:full")
|
||||
public class CareDataLeaderCon {
|
||||
|
||||
private static final int FINISHED_STATE = 20;
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/careData/leader/indexOverlay.html")
|
||||
@SaCheckPermission("careData.union")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At("proposal")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/careData/leader/proposalOverlay.html")
|
||||
@SaCheckPermission("careData.union")
|
||||
public void proposal() {
|
||||
}
|
||||
|
||||
@At("condolence")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/careData/leader/condolenceOverlay.html")
|
||||
@SaCheckPermission("careData.union")
|
||||
public void condolence() {
|
||||
}
|
||||
|
||||
@At("baseUnion")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/careData/leader/baseUnionOverlay.html")
|
||||
@SaCheckPermission("careData.union")
|
||||
public void baseUnion() {
|
||||
}
|
||||
|
||||
@At("club")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/careData/leader/clubOverlay.html")
|
||||
@SaCheckPermission("careData.union")
|
||||
public void club() {
|
||||
}
|
||||
|
||||
@At("dataMetric")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/careData/leader/dataMetricOverlay.html")
|
||||
@SaCheckPermission("careData.union")
|
||||
public void dataMetric() {
|
||||
}
|
||||
|
||||
@At("assetData")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/careData/leader/assetDataOverlay.html")
|
||||
@SaCheckPermission("careData.union")
|
||||
public void assetData() {
|
||||
}
|
||||
|
||||
@At("staffHome")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/careData/leader/staffHomeOverlay.html")
|
||||
@SaCheckPermission("careData.union")
|
||||
public void staffHome() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("careData.union")
|
||||
public Result proposalData(String sessionId) {
|
||||
String currentSessionId = StrUtil.blankToDefault(sessionId, latestSessionId());
|
||||
if (StrUtil.isBlank(currentSessionId)) {
|
||||
return Result.success(NutMap.NEW());
|
||||
}
|
||||
|
||||
NutMap session = sessionInfo(currentSessionId);
|
||||
List<NutMap> caseResults = caseResultData(currentSessionId);
|
||||
NutMap overview = overviewData(currentSessionId, caseResults);
|
||||
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("session", session)
|
||||
.addv("overview", overview)
|
||||
.addv("caseResults", caseResults));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("careData.union")
|
||||
public Result condolenceData(Integer year) {
|
||||
int targetYear = year == null ? LocalDate.now().getYear() : year;
|
||||
List<NutMap> rows = condolenceTypeRows(targetYear);
|
||||
long total = rows.stream().mapToLong(row -> row.getLong("count", 0L)).sum();
|
||||
List<NutMap> sortedRows = new ArrayList<>(rows);
|
||||
sortedRows.sort((left, right) -> Long.compare(right.getLong("count", 0L), left.getLong("count", 0L)));
|
||||
List<NutMap> topRows = new ArrayList<>();
|
||||
int index = 1;
|
||||
for (NutMap row : sortedRows) {
|
||||
if (index > 5) {
|
||||
break;
|
||||
}
|
||||
long count = row.getLong("count", 0L);
|
||||
topRows.add(NutMap.NEW()
|
||||
.addv("index", index++)
|
||||
.addv("typeId", row.getString("id", ""))
|
||||
.addv("typeCode", row.getString("code", ""))
|
||||
.addv("name", row.getString("name", ""))
|
||||
.addv("count", count)
|
||||
.addv("rate", percent(count, total))
|
||||
.addv("rateValue", percentValue(count, total)));
|
||||
}
|
||||
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("year", targetYear)
|
||||
.addv("total", total)
|
||||
.addv("types", topRows));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("careData.union")
|
||||
public Result baseUnionData() {
|
||||
return Result.success(NutMap.NEW().addv("unions", baseUnionRows()));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("careData.union")
|
||||
public Result clubData() {
|
||||
return Result.success(NutMap.NEW().addv("clubs", clubRows()));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("careData.union")
|
||||
public Result dataMetricData(Integer year) {
|
||||
int targetYear = year == null ? LocalDate.now().getYear() : year;
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("year", targetYear)
|
||||
.addv("budgetTotal", schoolBudgetTotal(targetYear))
|
||||
.addv("tourCount", tourCount(targetYear))
|
||||
.addv("honorCount", honorCount(targetYear))
|
||||
.addv("difficultCount", difficultCount(targetYear))
|
||||
.addv("reimburseTotal", reimburseTotal(targetYear)));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("careData.union")
|
||||
public Result assetDataData() {
|
||||
List<NutMap> states = assetUsageStateRows();
|
||||
long total = states.stream().mapToLong(row -> row.getLong("value", 0L)).sum();
|
||||
return Result.success(NutMap.NEW()
|
||||
.addv("total", total)
|
||||
.addv("states", states));
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("careData.union")
|
||||
public Result staffHomeData() {
|
||||
return Result.success(NutMap.NEW().addv("houses", littleHouseRows()));
|
||||
}
|
||||
|
||||
private List<NutMap> littleHouseRows() {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
id,
|
||||
unionName,
|
||||
unitName,
|
||||
address,
|
||||
mediaFiles,
|
||||
mapX,
|
||||
mapY,
|
||||
sortNum
|
||||
FROM build_home_little_house
|
||||
WHERE mapX IS NOT NULL
|
||||
AND mapY IS NOT NULL
|
||||
$unionFilter
|
||||
ORDER BY sortNum ASC, id ASC
|
||||
""");
|
||||
if (canViewAllUnionData()) {
|
||||
sql.setVar("unionFilter", "");
|
||||
} else {
|
||||
sql.setVar("unionFilter", "AND unionId = @unionId");
|
||||
sql.setParam("unionId", SecurityUtil.getUnionId());
|
||||
}
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
private String latestSessionId() {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT id
|
||||
FROM teacher_congress_session
|
||||
ORDER BY startDate DESC
|
||||
LIMIT 1
|
||||
""");
|
||||
return firstMap(sql).getString("id", "");
|
||||
}
|
||||
|
||||
private List<NutMap> condolenceTypeRows(int year) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t.id,
|
||||
t.code,
|
||||
t.name,
|
||||
COUNT(info.id) AS count
|
||||
FROM condolence_type t
|
||||
LEFT JOIN condolence info ON info.type = t.id
|
||||
AND YEAR(info.createTime) = @year
|
||||
$unionFilter
|
||||
WHERE t.enable = 1
|
||||
GROUP BY t.id, t.code, t.name, t.sortNum
|
||||
ORDER BY count DESC, t.sortNum ASC, t.code ASC
|
||||
""");
|
||||
sql.setParam("year", year);
|
||||
if (canViewAllUnionData()) {
|
||||
sql.setVar("unionFilter", "");
|
||||
} else {
|
||||
sql.setVar("unionFilter", "AND info.applyUnionId = @unionId");
|
||||
sql.setParam("unionId", SecurityUtil.getUnionId());
|
||||
}
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
private List<NutMap> baseUnionRows() {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
un.id,
|
||||
un.name AS unionname,
|
||||
un.unionCode,
|
||||
(
|
||||
SELECT COUNT(1)
|
||||
FROM vw_user u
|
||||
WHERE u.member = 1
|
||||
AND u.unionId = un.id
|
||||
) AS value
|
||||
FROM sys_union un
|
||||
WHERE un.delFlag = 0
|
||||
$unionFilter
|
||||
ORDER BY un.unionCode
|
||||
""");
|
||||
if (canViewAllUnionData()) {
|
||||
sql.setVar("unionFilter", "");
|
||||
} else {
|
||||
sql.setVar("unionFilter", "AND un.id = @unionId");
|
||||
sql.setParam("unionId", SecurityUtil.getUnionId());
|
||||
}
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
private List<NutMap> clubRows() {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
c.id,
|
||||
c.clubName,
|
||||
c.clubCode,
|
||||
(
|
||||
SELECT COUNT(1)
|
||||
FROM club_user cu
|
||||
WHERE cu.clubId = c.id
|
||||
AND cu.delFlag = 0
|
||||
) AS value
|
||||
FROM sys_club c
|
||||
WHERE c.delFlag = 0
|
||||
AND c.dismiss = 0
|
||||
ORDER BY c.clubCode
|
||||
""");
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
private List<NutMap> assetUsageStateRows() {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
IFNULL(NULLIF(TRIM(t1.assetUsageStateName), ''), @emptyName) AS name,
|
||||
SUM(IFNULL(t1.assetQuantity, 0)) AS value
|
||||
FROM `asset` t1
|
||||
WHERE 1 = 1
|
||||
$unionFilter
|
||||
GROUP BY IFNULL(NULLIF(TRIM(t1.assetUsageStateName), ''), @emptyName)
|
||||
ORDER BY value DESC, name ASC
|
||||
""");
|
||||
sql.setParam("emptyName", "\u672a\u586b\u5199");
|
||||
if (canViewAllUnionData()) {
|
||||
sql.setVar("unionFilter", "");
|
||||
} else {
|
||||
sql.setVar("unionFilter", "AND t1.assetUseUnionId = @unionId");
|
||||
sql.setParam("unionId", SecurityUtil.getUnionId());
|
||||
}
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
private BigDecimal schoolBudgetTotal(int year) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT IFNULL(SUM(totalQuota), 0) AS total
|
||||
FROM outlay_manage_school
|
||||
WHERE delFlag = 0
|
||||
AND `year` = @year
|
||||
""");
|
||||
sql.setParam("year", year);
|
||||
return firstMap(sql).getAs("total", BigDecimal.class);
|
||||
}
|
||||
|
||||
private long tourCount(int year) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(DISTINCT t.id) AS count
|
||||
FROM tour_ledger t
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = t.id
|
||||
WHERE t.delFlag = 0
|
||||
AND t.`year` = @year
|
||||
AND (ins.id IS NULL OR ins.state = @finished)
|
||||
$unionFilter
|
||||
""");
|
||||
sql.setParam("year", year);
|
||||
sql.setParam("finished", FINISHED_STATE);
|
||||
if (canViewAllUnionData()) {
|
||||
sql.setVar("unionFilter", "");
|
||||
} else {
|
||||
sql.setVar("unionFilter", "AND t.unionId = @unionId");
|
||||
sql.setParam("unionId", SecurityUtil.getUnionId());
|
||||
}
|
||||
return firstMap(sql).getLong("count", 0L);
|
||||
}
|
||||
|
||||
private long honorCount(int year) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(h.id) AS count
|
||||
FROM honor h
|
||||
WHERE h.delFlag = 0
|
||||
AND YEAR(h.grantDate) = @year
|
||||
$unionFilter
|
||||
""");
|
||||
sql.setParam("year", year);
|
||||
if (canViewAllUnionData()) {
|
||||
sql.setVar("unionFilter", "");
|
||||
} else {
|
||||
sql.setVar("unionFilter", "AND h.unionId = @unionId");
|
||||
sql.setParam("unionId", SecurityUtil.getUnionId());
|
||||
}
|
||||
return firstMap(sql).getLong("count", 0L);
|
||||
}
|
||||
|
||||
private long difficultCount(int year) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT COUNT(DISTINCT info.id) AS count
|
||||
FROM difficult_help_info info
|
||||
INNER JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
WHERE info.delFlag = 0
|
||||
AND ins.state = @finished
|
||||
AND YEAR(info.applyTime) = @year
|
||||
$unionFilter
|
||||
""");
|
||||
sql.setParam("year", year);
|
||||
sql.setParam("finished", FINISHED_STATE);
|
||||
if (canViewAllUnionData()) {
|
||||
sql.setVar("unionFilter", "");
|
||||
} else {
|
||||
sql.setVar("unionFilter", "AND info.unionId = @unionId");
|
||||
sql.setParam("unionId", SecurityUtil.getUnionId());
|
||||
}
|
||||
return firstMap(sql).getLong("count", 0L);
|
||||
}
|
||||
|
||||
private BigDecimal reimburseTotal(int year) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
IFNULL(SUM(
|
||||
CASE
|
||||
WHEN info.realMoney IS NOT NULL THEN info.realMoney
|
||||
WHEN info.money IS NOT NULL THEN info.money
|
||||
WHEN info.condolenceMoney IS NOT NULL THEN info.condolenceMoney
|
||||
ELSE 0
|
||||
END
|
||||
), 0) AS total
|
||||
FROM union_reimburse info
|
||||
WHERE info.delFlag = 0
|
||||
AND info.stateId IN (2, 3)
|
||||
AND YEAR(info.createTime) = @year
|
||||
$unionFilter
|
||||
""");
|
||||
sql.setParam("year", year);
|
||||
if (canViewAllUnionData()) {
|
||||
sql.setVar("unionFilter", "");
|
||||
} else {
|
||||
sql.setVar("unionFilter", "AND info.unionId = @unionId");
|
||||
sql.setParam("unionId", SecurityUtil.getUnionId());
|
||||
}
|
||||
return firstMap(sql).getAs("total", BigDecimal.class);
|
||||
}
|
||||
|
||||
private boolean canViewAllUnionData() {
|
||||
return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
|
||||
}
|
||||
|
||||
private NutMap sessionInfo(String sessionId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT id, fullName
|
||||
FROM teacher_congress_session
|
||||
WHERE id = @sessionId
|
||||
""");
|
||||
sql.setParam("sessionId", sessionId);
|
||||
return firstMap(sql);
|
||||
}
|
||||
|
||||
private NutMap overviewData(String sessionId, List<NutMap> caseResults) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
COUNT(info.id) AS total,
|
||||
SUM(CASE WHEN ins.state = @finished THEN 1 ELSE 0 END) AS doneCount
|
||||
FROM proposal_info info
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
WHERE info.sessionId = @sessionId
|
||||
""");
|
||||
sql.setParam("sessionId", sessionId);
|
||||
sql.setParam("finished", FINISHED_STATE);
|
||||
NutMap overview = firstMap(sql);
|
||||
|
||||
long filedCount = 0L;
|
||||
long rejectedCount = 0L;
|
||||
long suggestionCount = 0L;
|
||||
for (NutMap item : caseResults) {
|
||||
String name = item.getString("name", "");
|
||||
long count = item.getLong("count", 0L);
|
||||
if (containsAny(name, "\u4e0d\u4e88", "\u4e0d\u7acb\u6848")) {
|
||||
rejectedCount += count;
|
||||
} else if (containsAny(name, "\u610f\u89c1", "\u5efa\u8bae")) {
|
||||
suggestionCount += count;
|
||||
} else if (name.contains("\u7acb\u6848")) {
|
||||
filedCount += count;
|
||||
}
|
||||
}
|
||||
|
||||
long total = overview.getLong("total", 0L);
|
||||
long doneCount = overview.getLong("doneCount", 0L);
|
||||
long satisfiedCount = satisfiedCount(sessionId);
|
||||
|
||||
return NutMap.NEW()
|
||||
.addv("total", total)
|
||||
.addv("filedCount", filedCount)
|
||||
.addv("suggestionCount", suggestionCount)
|
||||
.addv("rejectedCount", rejectedCount)
|
||||
.addv("doneCount", doneCount)
|
||||
.addv("satisfiedRate", percent(satisfiedCount, doneCount));
|
||||
}
|
||||
|
||||
private List<NutMap> caseResultData(String sessionId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
d.code,
|
||||
d.name,
|
||||
COUNT(info.id) AS count
|
||||
FROM sys_dict parent
|
||||
INNER JOIN sys_dict d ON d.parentId = parent.id AND d.disabled = 0
|
||||
LEFT JOIN proposal_info info ON info.caseFilingResult = d.code AND info.sessionId = @sessionId
|
||||
WHERE parent.code = 'PROPOSAL_CASE_FILING_RESULT'
|
||||
GROUP BY d.id, d.code, d.name, d.location
|
||||
ORDER BY d.location
|
||||
""");
|
||||
sql.setParam("sessionId", sessionId);
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
private long satisfiedCount(String sessionId) {
|
||||
List<NutMap> dicts = feedbackDicts();
|
||||
List<NutMap> rows = feedbackRows(sessionId);
|
||||
return dicts.stream()
|
||||
.filter(dict -> {
|
||||
String name = dict.getString("name", "");
|
||||
return name.contains("\u6ee1\u610f") && !name.contains("\u4e0d\u6ee1\u610f");
|
||||
})
|
||||
.mapToLong(dict -> rows.stream()
|
||||
.filter(row -> dict.getString("code", "").equals(row.getString("feedbackCode", "")))
|
||||
.count())
|
||||
.sum();
|
||||
}
|
||||
|
||||
private List<NutMap> feedbackDicts() {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT d.code, d.name
|
||||
FROM sys_dict parent
|
||||
INNER JOIN sys_dict d ON d.parentId = parent.id AND d.disabled = 0
|
||||
WHERE parent.code = 'PROPOSAL_FEEDBACK'
|
||||
ORDER BY d.location
|
||||
""");
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
private List<NutMap> feedbackRows(String sessionId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
t.variable
|
||||
FROM proposal_info info
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id
|
||||
AND t.taskState = 20
|
||||
AND t.taskName = 'feedback'
|
||||
WHERE ins.state = @finished
|
||||
AND info.sessionId = @sessionId
|
||||
GROUP BY info.id, t.variable
|
||||
""");
|
||||
sql.setParam("sessionId", sessionId);
|
||||
sql.setParam("finished", FINISHED_STATE);
|
||||
List<NutMap> rawRows = listMap(sql);
|
||||
List<NutMap> rows = new ArrayList<>();
|
||||
for (NutMap row : rawRows) {
|
||||
String variableStr = row.getString("variable", "");
|
||||
if (StrUtil.isBlank(variableStr)) {
|
||||
continue;
|
||||
}
|
||||
NutMap variable = Json.fromJson(NutMap.class, variableStr);
|
||||
rows.add(NutMap.NEW().addv("feedbackCode", variable.getString("tf_feedback", "")));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
private List<NutMap> listMap(Sql sql) {
|
||||
sql.setCallback(Sqls.callback.maps());
|
||||
dao.execute(sql);
|
||||
return sql.getList(NutMap.class);
|
||||
}
|
||||
|
||||
private NutMap firstMap(Sql sql) {
|
||||
sql.setCallback(Sqls.callback.map());
|
||||
dao.execute(sql);
|
||||
NutMap map = sql.getObject(NutMap.class);
|
||||
return map == null ? NutMap.NEW() : map;
|
||||
}
|
||||
|
||||
private boolean containsAny(String text, String... keywords) {
|
||||
if (StrUtil.isBlank(text)) {
|
||||
return false;
|
||||
}
|
||||
for (String keyword : keywords) {
|
||||
if (text.contains(keyword)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String percent(long count, long total) {
|
||||
if (total <= 0) {
|
||||
return "0%";
|
||||
}
|
||||
BigDecimal value = BigDecimal.valueOf(count)
|
||||
.multiply(BigDecimal.valueOf(100))
|
||||
.divide(BigDecimal.valueOf(total), 1, RoundingMode.HALF_UP);
|
||||
return value.stripTrailingZeros().toPlainString() + "%";
|
||||
}
|
||||
|
||||
private BigDecimal percentValue(long count, long total) {
|
||||
if (total <= 0) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return BigDecimal.valueOf(count)
|
||||
.multiply(BigDecimal.valueOf(100))
|
||||
.divide(BigDecimal.valueOf(total), 1, RoundingMode.HALF_UP)
|
||||
.stripTrailingZeros();
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,43 @@ public class HonorManageController {
|
||||
|
||||
}
|
||||
|
||||
@At("/h5")
|
||||
@SaCheckLogin
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/honor/manage/index.html")
|
||||
public void h5() {
|
||||
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckLogin
|
||||
public Result h5Data(HonorPageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
h.id,
|
||||
h.userName,
|
||||
h.applyUnionName,
|
||||
h.unionName,
|
||||
h.grantDate,
|
||||
h.photoFiles,
|
||||
prize.`name` AS prizeName,
|
||||
type.`name` AS typeName,
|
||||
type.queryTypeCode AS typeQueryTypeCode
|
||||
FROM
|
||||
`honor` h
|
||||
LEFT JOIN honor_basic_settings prize ON prize.id = h.prize
|
||||
LEFT JOIN honor_basic_settings type ON type.id = h.honorType
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
Integer year = pageForm.getYear() == null ? Calendar.getInstance().get(Calendar.YEAR) : pageForm.getYear();
|
||||
cnd.andEX("YEAR(h.grantDate)", "=", year);
|
||||
cnd.andEX("h.honorType", "=", pageForm.getHonorType());
|
||||
cnd.desc("h.grantDate");
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = honorViService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("honor.manage")
|
||||
public Result pageData(HonorPageForm pageForm) {
|
||||
|
||||
@@ -222,5 +222,10 @@ public class Honor extends BaseModel {
|
||||
@Comment("附件")
|
||||
private List<JSONObject> files;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
@Comment("荣誉照片")
|
||||
private List<JSONObject> photoFiles;
|
||||
|
||||
private String loginname;
|
||||
}
|
||||
|
||||
@@ -92,8 +92,22 @@ public class CondolenceMineController {
|
||||
condolence info
|
||||
LEFT JOIN condolence_type type ON info.type = type.id
|
||||
LEFT JOIN `wf_process_instance` ins ON ins.businessNo = info.id
|
||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
id,
|
||||
processInstanceId,
|
||||
taskName,
|
||||
displayName,
|
||||
taskType,
|
||||
performType,
|
||||
taskState,
|
||||
finishTime,
|
||||
taskParentId,
|
||||
variable,
|
||||
ROW_NUMBER() OVER (PARTITION BY processInstanceId ORDER BY createdAt DESC, id DESC) AS rn
|
||||
FROM wf_process_task
|
||||
WHERE taskState = 10
|
||||
) t ON t.processInstanceId = ins.id AND t.rn = 1
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
ALTER TABLE `asset`
|
||||
MODIFY COLUMN `assetUnitPrice` DECIMAL(18, 2) NULL COMMENT '单价';
|
||||
|
||||
ALTER TABLE `asset_depreciation_record`
|
||||
MODIFY COLUMN `assetAllMoney` DECIMAL(18, 2) NULL COMMENT '资产全部的价值',
|
||||
MODIFY COLUMN `assetSurplusMoney` DECIMAL(18, 2) NULL COMMENT '剩余价值',
|
||||
MODIFY COLUMN `assetDepreciationMoney` DECIMAL(18, 2) NULL COMMENT '累计折旧多少钱',
|
||||
MODIFY COLUMN `assetAverageMonthMoney` DECIMAL(18, 2) NULL COMMENT '平均一个月多少钱';
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE `build_home_little_house`
|
||||
ADD COLUMN `mapX` DECIMAL(8,4) NULL COMMENT '地图X坐标百分比' AFTER `mediaFiles`,
|
||||
ADD COLUMN `mapY` DECIMAL(8,4) NULL COMMENT '地图Y坐标百分比' AFTER `mapX`;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE `build_home_little_house`
|
||||
ADD COLUMN `unitId` VARCHAR(32) NULL COMMENT '单位ID' AFTER `unitName`,
|
||||
ADD COLUMN `mediaFiles` JSON NULL COMMENT '图片视频资料' AFTER `openTime`;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `honor`
|
||||
ADD COLUMN `photoFiles` JSON NULL COMMENT '荣誉照片' AFTER `files`;
|
||||
@@ -0,0 +1,64 @@
|
||||
-- Home work template menu. Prefer a sibling of sys.homeActivity, then sys.manager, then sys.
|
||||
INSERT INTO sys_menu (
|
||||
id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled,
|
||||
permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt,
|
||||
delFlag, platform, moduleId, picIcon, initialPinyinName, isRecommendApp, isRecommendService
|
||||
)
|
||||
SELECT
|
||||
'e6ed122326a8492fa7f415f97eaf4f01',
|
||||
parent.id,
|
||||
CONCAT(parent.path, LPAD(IFNULL(child.maxNo, 0) + 1, 4, '0')),
|
||||
'Work Template',
|
||||
'Work Template',
|
||||
'menu',
|
||||
'/platform/sys/worktemplate',
|
||||
'data-pjax',
|
||||
'',
|
||||
1,
|
||||
0,
|
||||
'sys.worktemplate',
|
||||
NULL,
|
||||
IFNULL(child.maxLocation, 0) + 1,
|
||||
0,
|
||||
'',
|
||||
UNIX_TIMESTAMP(NOW()) * 1000,
|
||||
'',
|
||||
UNIX_TIMESTAMP(NOW()) * 1000,
|
||||
0,
|
||||
'PC',
|
||||
NULL,
|
||||
NULL,
|
||||
'g',
|
||||
0,
|
||||
0
|
||||
FROM (
|
||||
SELECT p.*
|
||||
FROM sys_menu p
|
||||
WHERE p.id = (SELECT h.parentId FROM sys_menu h WHERE h.permission = 'sys.homeActivity' LIMIT 1)
|
||||
OR p.permission IN ('sys.manager', 'sys')
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN p.id = (SELECT h.parentId FROM sys_menu h WHERE h.permission = 'sys.homeActivity' LIMIT 1) THEN 0
|
||||
WHEN p.permission = 'sys.manager' THEN 1
|
||||
ELSE 2
|
||||
END
|
||||
LIMIT 1
|
||||
) parent
|
||||
LEFT JOIN (
|
||||
SELECT parentId,
|
||||
MAX(CAST(RIGHT(path, 4) AS UNSIGNED)) AS maxNo,
|
||||
MAX(location) AS maxLocation
|
||||
FROM sys_menu
|
||||
GROUP BY parentId
|
||||
) child ON child.parentId = parent.id
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM sys_menu WHERE permission = 'sys.worktemplate'
|
||||
);
|
||||
|
||||
INSERT INTO sys_role_menu (roleId, menuId)
|
||||
SELECT r.id, m.id
|
||||
FROM sys_role r
|
||||
JOIN sys_menu m ON m.permission = 'sys.worktemplate'
|
||||
LEFT JOIN sys_role_menu rm ON rm.roleId = r.id AND rm.menuId = m.id
|
||||
WHERE r.code = 'SYSADMIN'
|
||||
AND rm.roleId IS NULL;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `sys_config`
|
||||
MODIFY COLUMN `configValue` TEXT;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `sys_home_template`
|
||||
ADD COLUMN `templateIcon` varchar(255) DEFAULT NULL COMMENT 'template icon' AFTER `templateName`;
|
||||
@@ -0,0 +1,6 @@
|
||||
ALTER TABLE `sys_home_template`
|
||||
ADD COLUMN `templateName` varchar(50) DEFAULT NULL COMMENT 'display template name' AFTER `name`;
|
||||
|
||||
UPDATE `sys_home_template`
|
||||
SET `templateName` = `name`
|
||||
WHERE (`templateName` IS NULL OR `templateName` = '');
|
||||
@@ -0,0 +1,25 @@
|
||||
CREATE TABLE IF NOT EXISTS `sys_home_template` (
|
||||
`id` varchar(32) NOT NULL COMMENT 'business id',
|
||||
`name` varchar(50) DEFAULT NULL COMMENT 'template name',
|
||||
`templateName` varchar(50) DEFAULT NULL COMMENT 'display template name',
|
||||
`templateIcon` varchar(255) DEFAULT NULL COMMENT 'template icon',
|
||||
`cover` varchar(255) DEFAULT NULL COMMENT 'template cover',
|
||||
`content` text COMMENT 'template content',
|
||||
`url` varchar(1000) DEFAULT NULL COMMENT 'pc url',
|
||||
`h5Url` varchar(1000) DEFAULT NULL COMMENT 'h5 url',
|
||||
`allowUserGroupId` int DEFAULT NULL COMMENT 'allowed user group id',
|
||||
`allowUserSql` varchar(1000) DEFAULT NULL COMMENT 'allowed user sql',
|
||||
`enable` tinyint(1) DEFAULT 0 COMMENT 'enabled',
|
||||
`classPath` varchar(500) DEFAULT NULL COMMENT 'source class path',
|
||||
`top` tinyint(1) DEFAULT 0 COMMENT 'top flag',
|
||||
`push` tinyint(1) DEFAULT 0 COMMENT 'push flag',
|
||||
`sortNo` int DEFAULT 0 COMMENT 'sort number',
|
||||
`startDate` datetime DEFAULT NULL COMMENT 'start date',
|
||||
`endDate` datetime DEFAULT NULL COMMENT 'end date',
|
||||
`createdBy` varchar(32) DEFAULT NULL,
|
||||
`createdAt` bigint DEFAULT NULL,
|
||||
`updatedBy` varchar(32) DEFAULT NULL,
|
||||
`updatedAt` bigint DEFAULT NULL,
|
||||
`delFlag` tinyint(1) DEFAULT 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='home work template';
|
||||
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 557 KiB |
|
After Width: | Height: | Size: 557 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 994 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 19 KiB |
@@ -18,6 +18,7 @@
|
||||
recognition: null,
|
||||
listening: false,
|
||||
menus: null,
|
||||
platform: "PC",
|
||||
parentMap: {},
|
||||
lastText: "",
|
||||
pendingMatches: [],
|
||||
@@ -128,7 +129,39 @@
|
||||
}
|
||||
}
|
||||
|
||||
function getMenus() {
|
||||
function getCurrentPlatform() {
|
||||
const $button = $("#voice-menu-btn")
|
||||
return String(($button.data("platform") || state.platform || "PC")).toUpperCase()
|
||||
}
|
||||
|
||||
function setCurrentPlatform(platform) {
|
||||
const nextPlatform = String(platform || "PC").toUpperCase()
|
||||
if (state.platform !== nextPlatform) {
|
||||
state.menus = null
|
||||
state.parentMap = {}
|
||||
}
|
||||
state.platform = nextPlatform
|
||||
return state.platform
|
||||
}
|
||||
|
||||
function filterMenusByPlatform(menus, platform) {
|
||||
const currentPlatform = String(platform || "PC").toUpperCase()
|
||||
return (menus || []).filter(function (menu) {
|
||||
return String(menu.platform || "PC").toUpperCase() === currentPlatform
|
||||
})
|
||||
}
|
||||
|
||||
function setMenus(menus, platform) {
|
||||
state.parentMap = {}
|
||||
state.menus = filterMenusByPlatform(flattenMenus(menus, "", []), platform).filter(function (menu) {
|
||||
return menu.href
|
||||
})
|
||||
return state.menus
|
||||
}
|
||||
|
||||
function getMenus(platform) {
|
||||
platform = String(platform || getCurrentPlatform()).toUpperCase()
|
||||
setCurrentPlatform(platform)
|
||||
const cached = state.menus
|
||||
if (cached && cached.length) {
|
||||
return $.Deferred().resolve(cached).promise()
|
||||
@@ -136,35 +169,22 @@
|
||||
|
||||
const storeMenus = getStoreMenus()
|
||||
if (storeMenus && storeMenus.length) {
|
||||
state.menus = flattenMenus(storeMenus, "", []).filter(function (menu) {
|
||||
return menu.href
|
||||
})
|
||||
return $.Deferred().resolve(state.menus).promise()
|
||||
return $.Deferred().resolve(setMenus(storeMenus, platform)).promise()
|
||||
}
|
||||
|
||||
return $.get("/platform/sys/user/getLogonUser").then(function (res) {
|
||||
if (res && res.code === 0 && res.data && res.data.menus) {
|
||||
state.parentMap = {}
|
||||
state.menus = flattenMenus(res.data.menus, "", []).filter(function (menu) {
|
||||
return menu.href
|
||||
})
|
||||
return state.menus
|
||||
return setMenus(res.data.menus, platform)
|
||||
}
|
||||
const sessionMenus = getSessionMenus()
|
||||
if (sessionMenus && sessionMenus.length) {
|
||||
state.menus = flattenMenus(sessionMenus, "", []).filter(function (menu) {
|
||||
return menu.href
|
||||
})
|
||||
return state.menus
|
||||
return setMenus(sessionMenus, platform)
|
||||
}
|
||||
return []
|
||||
}, function () {
|
||||
const sessionMenus = getSessionMenus()
|
||||
if (sessionMenus && sessionMenus.length) {
|
||||
state.menus = flattenMenus(sessionMenus, "", []).filter(function (menu) {
|
||||
return menu.href
|
||||
})
|
||||
return state.menus
|
||||
return setMenus(sessionMenus, platform)
|
||||
}
|
||||
return []
|
||||
})
|
||||
@@ -409,7 +429,7 @@
|
||||
})
|
||||
return
|
||||
}
|
||||
getMenus().then(function (menus) {
|
||||
getMenus(getCurrentPlatform()).then(function (menus) {
|
||||
const matches = matchMenus(state.lastText, menus)
|
||||
runAfterRecognitionEnd(function () {
|
||||
chooseMenu(matches)
|
||||
@@ -423,6 +443,7 @@
|
||||
|
||||
function init() {
|
||||
$(document).on("click", "#voice-menu-btn", function () {
|
||||
setCurrentPlatform($(this).data("platform") || "PC")
|
||||
start()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
:on-exceed="handleExceed"
|
||||
:on-remove="handleRemove"
|
||||
:before-upload="beforeUpload"
|
||||
:limit="upload_number"
|
||||
:limit="uploadLimitNumber"
|
||||
:accept="fileAccept"
|
||||
:multiple="true"
|
||||
>
|
||||
@@ -31,7 +31,7 @@
|
||||
:on-remove="handleRemove"
|
||||
:before-upload="beforeUpload"
|
||||
:on-exceed="handleExceed"
|
||||
:limit="upload_number"
|
||||
:limit="uploadLimitNumber"
|
||||
:accept="fileAccept"
|
||||
:multiple="true"
|
||||
list-type="picture-card"
|
||||
@@ -71,7 +71,7 @@
|
||||
:on-remove="handleRemove"
|
||||
:on-exceed="handleExceed"
|
||||
:before-upload="beforeUpload"
|
||||
:limit="upload_number"
|
||||
:limit="uploadLimitNumber"
|
||||
:accept="fileAccept"
|
||||
class="drag-upload"
|
||||
:class="{ 'drag-upload-disabled': uploadMode !== 'pc' }"
|
||||
@@ -123,7 +123,7 @@ module.exports = {
|
||||
},
|
||||
// 上传数量
|
||||
upload_number: {
|
||||
type: Number,
|
||||
type: [Number, String],
|
||||
default: 1,
|
||||
required: false
|
||||
},
|
||||
@@ -198,8 +198,12 @@ module.exports = {
|
||||
action() {
|
||||
return this.upload_result_type === "id" ? this.upload_return_id_api : this.upload_dynamic_return_url_api
|
||||
},
|
||||
uploadLimitNumber() {
|
||||
const number = Number(this.upload_number)
|
||||
return Number.isFinite(number) && number > 0 ? number : 1
|
||||
},
|
||||
upload_tips() {
|
||||
const uploadNumber = this.upload_number
|
||||
const uploadNumber = this.uploadLimitNumber
|
||||
const fileAccept = this.fileAccept
|
||||
const fileSize = this.upload_size
|
||||
|
||||
@@ -359,10 +363,12 @@ module.exports = {
|
||||
|
||||
handleRemove(file, fileList) {
|
||||
if (this.upload_result_category === "interval") {
|
||||
if (this.upload_result_type === "id") {
|
||||
}
|
||||
if (this.upload_result_type === "url") {
|
||||
}
|
||||
const resultIntervalValue = fileList
|
||||
.map((item) => item.response && item.response.data ? item.response.data : item.url || item.data)
|
||||
.filter((item) => item)
|
||||
.join(",")
|
||||
this.$emit("update:value", resultIntervalValue)
|
||||
return
|
||||
}
|
||||
|
||||
if (this.upload_result_category === "array") {
|
||||
@@ -381,13 +387,11 @@ module.exports = {
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.$emit("update:value", fileList)
|
||||
}
|
||||
},
|
||||
|
||||
handleExceed(files, fileList) {
|
||||
this.$message.warning("最多只能上传" + this.upload_number + "个文件")
|
||||
this.$message.warning("最多只能上传" + this.uploadLimitNumber + "个文件")
|
||||
},
|
||||
|
||||
// 上传事件
|
||||
@@ -562,8 +566,8 @@ module.exports = {
|
||||
const originFileList = this.fileList || []
|
||||
console.log(data.files)
|
||||
|
||||
if (this.upload_number) {
|
||||
if (originFileList.length + data.files.length > this.upload_number) {
|
||||
if (this.uploadLimitNumber) {
|
||||
if (originFileList.length + data.files.length > this.uploadLimitNumber) {
|
||||
this.$message.error("上传文件数量超出限制")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
<script src="${base!}/components/plugins/sysDict/DictData.js"></script>
|
||||
<script src="${base!}/assets/platform/js/util/commonUtil.js"></script>
|
||||
<script src="${base!}/assets/platform/js/util/coordinateUtil.js"></script>
|
||||
<script src="${base!}/assets/platform/js/util/voiceMenuNavigator.js"></script>
|
||||
<script src="${base!}/assets/platform/js/main.js"></script>
|
||||
<script src="${base!}/assets/platform/js/mixin/styleMixin.js"></script>
|
||||
<script src="${base!}/assets/platform/js/tool/businessTool.js"></script>
|
||||
@@ -167,10 +168,20 @@
|
||||
func && typeof func === "function" && func()
|
||||
}
|
||||
|
||||
function returnH5Home(activeTab = "home") {
|
||||
if (window.store && typeof window.store.commit === "function") {
|
||||
window.store.commit("setActiveTarBar", activeTab || "home")
|
||||
}
|
||||
window.location.replace("/platform/h5/home")
|
||||
}
|
||||
|
||||
Vue.mixin({
|
||||
methods: {
|
||||
historyBack: function(func = ()=>{}) {
|
||||
historyBack(func);
|
||||
},
|
||||
returnH5Home: function(activeTab = "home") {
|
||||
returnH5Home(activeTab)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -397,19 +408,49 @@
|
||||
</script>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
Vue.component("rich-text", httpVueLoader("/components/plugins/sysRichTextView/index.vue?v=" + new Date().getTime()))
|
||||
Vue.component("h5-file-upload", httpVueLoader("/components/plugins/sysUpload/h5Index.vue?v=" + new Date().getTime()))
|
||||
Vue.component("h5-signature", httpVueLoader("/components/plugins/sysSignature/h5Index.vue?v=" + new Date().getTime()))
|
||||
Vue.component("text-editor", httpVueLoader("/components/plugins/sysTextEditor/index.vue?v=" + new Date().getTime()))
|
||||
Vue.component("dict-tag", httpVueLoader("/components/plugins/sysDict/DictTag.vue?v=" + new Date().getTime()))
|
||||
Vue.component("svg-icon", httpVueLoader("/components/plugins/sysSvgIcon/index.vue?v=" + new Date().getTime()))
|
||||
Vue.component("year-van-dropdown-item", httpVueLoader("/components/plugins/vantMore/yearVanDropDownItem.vue?v=" + new Date().getTime()))
|
||||
Vue.component("van-text-dialog", httpVueLoader("/components/plugins/vantMore/vantTextDialog.vue?v=" + new Date().getTime()))
|
||||
Vue.component("enum-tag", httpVueLoader("/components/plugins/sysEnum/EnumTag.vue?v=" + new Date().getTime()))
|
||||
Vue.component("table-list", httpVueLoader("/components/plugins/h5/TableList.vue?v=" + new Date().getTime()))
|
||||
Vue.component("table-column", httpVueLoader("/components/plugins/h5/TableColumn.vue?v=" + new Date().getTime()))
|
||||
Vue.component("file-preview", httpVueLoader("/components/plugins/sysFilePreview/H5Index.vue?v=" + new Date().getTime()))
|
||||
const h5ComponentVersion = "20260524"
|
||||
Vue.component("rich-text", httpVueLoader("/components/plugins/sysRichTextView/index.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("h5-file-upload", httpVueLoader("/components/plugins/sysUpload/h5Index.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("h5-signature", httpVueLoader("/components/plugins/sysSignature/h5Index.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("text-editor", httpVueLoader("/components/plugins/sysTextEditor/index.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("dict-tag", httpVueLoader("/components/plugins/sysDict/DictTag.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("svg-icon", httpVueLoader("/components/plugins/sysSvgIcon/index.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("year-van-dropdown-item", httpVueLoader("/components/plugins/vantMore/yearVanDropDownItem.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("van-text-dialog", httpVueLoader("/components/plugins/vantMore/vantTextDialog.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("enum-tag", httpVueLoader("/components/plugins/sysEnum/EnumTag.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("table-list", httpVueLoader("/components/plugins/h5/TableList.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("table-column", httpVueLoader("/components/plugins/h5/TableColumn.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("file-preview", httpVueLoader("/components/plugins/sysFilePreview/H5Index.vue?v=" + h5ComponentVersion))
|
||||
</script>
|
||||
<style>
|
||||
.h5-voice-menu {
|
||||
position: fixed;
|
||||
right: 16px;
|
||||
bottom: calc(76px + env(safe-area-inset-bottom));
|
||||
z-index: 21000;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
background: #1989fa;
|
||||
box-shadow: 0 6px 18px rgba(25, 137, 250, 0.35);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.h5-voice-menu.is-listening {
|
||||
background: #ff976a;
|
||||
box-shadow: 0 6px 18px rgba(255, 151, 106, 0.38);
|
||||
}
|
||||
|
||||
.h5-voice-menu .voice-menu-text {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-page page-showtabbar">
|
||||
@@ -417,6 +458,10 @@
|
||||
<div id="container">${layoutContent}</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="h5-voice-menu" id="voice-menu-btn" data-platform="H5" title="语音打开菜单">
|
||||
<i class="fa fa-microphone"></i>
|
||||
<span class="voice-menu-text">语音</span>
|
||||
</button>
|
||||
<script nonce="${cspNonce!}">
|
||||
toggleShowBar()
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<!doctype html>
|
||||
<html lang="${lang,escape}">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>数智工会领导驾驶舱</title>
|
||||
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/css/root.css?v=20260524"/>
|
||||
<script src="${base!}/assets/platform/plugins/vue/vue.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/plugins/axios/axios.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/plugins/jquery/jquery.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/js/util/commonUtil.js?v=20260524"></script>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
Vue.config.devtools = false
|
||||
|
||||
const store = {
|
||||
state: {
|
||||
user: JSON.parse(window.sessionStorage.getItem("user") || "null") || {permissions: [], roles: []}
|
||||
}
|
||||
}
|
||||
|
||||
window.ELEMENT = window.ELEMENT || {
|
||||
Message: {
|
||||
error(message) {
|
||||
console.error(message || "操作失败")
|
||||
}
|
||||
},
|
||||
Loading: {
|
||||
service() {
|
||||
return {
|
||||
close() {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vue.prototype.$commonUtil = commonUtil
|
||||
Vue.prototype.$auth = commonUtil.authService()
|
||||
Vue.prototype.$axios = commonUtil.axiosService()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
${layoutContent!}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,164 @@
|
||||
<!doctype html>
|
||||
<html lang="${lang,escape}">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"/>
|
||||
<title>智慧工会</title>
|
||||
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/plugins/vant/index.css?v=20260524"/>
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/css/common.css?v=20260524"/>
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/css/h5.css?v=20260524"/>
|
||||
|
||||
<script src="${base!}/assets/platform/plugins/vue/vue.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/plugins/vant/index.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/plugins/axios/axios.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/plugins/jquery/jquery.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/js/util/commonUtil.js?v=20260524"></script>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
Vue.config.devtools = true
|
||||
|
||||
if (vant.Form && vant.Form.props && vant.Form.props.showErrorMessage) {
|
||||
vant.Form.props.showErrorMessage.default = false
|
||||
}
|
||||
if (vant.ActionSheet && vant.ActionSheet.props && vant.ActionSheet.props.lazyRender) {
|
||||
vant.ActionSheet.props.lazyRender.default = false
|
||||
}
|
||||
vant.Toast.allowMultiple()
|
||||
if (vant.Lazyload) {
|
||||
Vue.use(vant.Lazyload)
|
||||
}
|
||||
|
||||
window.loadScriptOnce = function(src) {
|
||||
window.__scriptLoadingMap = window.__scriptLoadingMap || {}
|
||||
if (window.__scriptLoadingMap[src]) {
|
||||
return window.__scriptLoadingMap[src]
|
||||
}
|
||||
window.__scriptLoadingMap[src] = new Promise(function(resolve, reject) {
|
||||
const existing = document.querySelector('script[src="' + src + '"]')
|
||||
if (existing) {
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
const script = document.createElement("script")
|
||||
script.src = src
|
||||
script.onload = function() {
|
||||
resolve()
|
||||
}
|
||||
script.onerror = function() {
|
||||
reject(new Error("script load failed: " + src))
|
||||
}
|
||||
document.head.appendChild(script)
|
||||
})
|
||||
return window.__scriptLoadingMap[src]
|
||||
}
|
||||
|
||||
window.loadStyleOnce = function(href) {
|
||||
window.__styleLoadingMap = window.__styleLoadingMap || {}
|
||||
if (window.__styleLoadingMap[href]) {
|
||||
return window.__styleLoadingMap[href]
|
||||
}
|
||||
window.__styleLoadingMap[href] = new Promise(function(resolve, reject) {
|
||||
const existing = document.querySelector('link[href="' + href + '"]')
|
||||
if (existing) {
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
const link = document.createElement("link")
|
||||
link.rel = "stylesheet"
|
||||
link.href = href
|
||||
link.onload = function() {
|
||||
resolve()
|
||||
}
|
||||
link.onerror = function() {
|
||||
reject(new Error("style load failed: " + href))
|
||||
}
|
||||
document.head.appendChild(link)
|
||||
})
|
||||
return window.__styleLoadingMap[href]
|
||||
}
|
||||
|
||||
const store = {
|
||||
state: {
|
||||
user: JSON.parse(window.sessionStorage.getItem("user") || "null"),
|
||||
room: "${@auth.getPrincipalProperty('loginname')}:${@auth.getSessionId()}",
|
||||
activeTarBar: null
|
||||
},
|
||||
commit(type, payload) {
|
||||
if (type === "setUser") {
|
||||
this.state.user = payload
|
||||
} else if (type === "setActiveTarBar") {
|
||||
this.state.activeTarBar = payload
|
||||
}
|
||||
},
|
||||
dispatch(type) {
|
||||
if (type === "logout") {
|
||||
window.localStorage.removeItem("zhgh-h5-vuex")
|
||||
window.location.href = "/platform/login/logout"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.ELEMENT = window.ELEMENT || {
|
||||
Message: {
|
||||
error(message) {
|
||||
vant.Toast.fail(message || "操作失败")
|
||||
}
|
||||
},
|
||||
Loading: {
|
||||
service() {
|
||||
const loading = vant.Toast.loading({
|
||||
duration: 0,
|
||||
forbidClick: true,
|
||||
message: "处理中,请稍候"
|
||||
})
|
||||
return {
|
||||
close() {
|
||||
loading.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function historyBack(func) {
|
||||
if (window.history.length > 1) {
|
||||
window.history.back()
|
||||
} else {
|
||||
window.location.href = "/platform/h5/home"
|
||||
}
|
||||
func && typeof func === "function" && func()
|
||||
}
|
||||
|
||||
function returnH5Home(activeTab = "home") {
|
||||
store.commit("setActiveTarBar", activeTab || "home")
|
||||
window.location.replace("/platform/h5/home")
|
||||
}
|
||||
|
||||
Vue.mixin({
|
||||
methods: {
|
||||
historyBack: function(func = function(){}) {
|
||||
historyBack(func)
|
||||
},
|
||||
returnH5Home: function(activeTab = "home") {
|
||||
returnH5Home(activeTab)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Vue.prototype.$commonUtil = commonUtil
|
||||
Vue.prototype.$auth = commonUtil.authService()
|
||||
Vue.prototype.$axios = commonUtil.axiosService()
|
||||
Vue.prototype.$downLoad = commonUtil.downLoadService.bind(commonUtil)
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-page">
|
||||
<div class="page-wrapper">
|
||||
<div id="container">${layoutContent}</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -709,7 +709,7 @@
|
||||
</div>
|
||||
|
||||
<div class="v4-user-section">
|
||||
<button type="button" class="v4-voice-menu" id="voice-menu-btn" title="语音打开菜单">
|
||||
<button type="button" class="v4-voice-menu" id="voice-menu-btn" data-platform="PC" title="语音打开菜单">
|
||||
<i class="fa fa-microphone"></i>
|
||||
<span class="voice-menu-text">语音</span>
|
||||
</button>
|
||||
|
||||
@@ -1513,7 +1513,7 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
<div class="oa-hero-section">
|
||||
<!-- 背景图 -->
|
||||
<div class="oa-background-image">
|
||||
<img src="${config.AppHomeImg!}" alt=""/>
|
||||
<img :src="homeBannerList[0] || ''" alt=""/>
|
||||
</div>
|
||||
|
||||
<!-- 搜索和统计区域 -->
|
||||
@@ -2020,6 +2020,7 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
recommendServices: [],
|
||||
favoriteItems: [],
|
||||
recommendApps: [],
|
||||
homeBannerList: "${config.AppHomeImg!}".split(",").map(item => item.trim()).filter(item => item),
|
||||
|
||||
// 工会网站新闻
|
||||
websiteNews: {},
|
||||
|
||||
@@ -73,7 +73,7 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
<!-- 首页banner -->
|
||||
<div class="section-banner">
|
||||
<div class="banner-img">
|
||||
<img src="${config.AppHomeImg!}" alt=""/>
|
||||
<img :src="homeBannerList[0] || ''" alt=""/>
|
||||
<stats></stats>
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,6 +87,8 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<work-template v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN'])"></work-template>
|
||||
|
||||
<jcdt :list="websiteNews"></jcdt>
|
||||
</div>
|
||||
|
||||
@@ -94,6 +96,7 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("act.js"){}#-->
|
||||
<!--#include("template.js"){}#-->
|
||||
<!--#include("jcdt.js"){}#-->
|
||||
<!--#include("entry.js"){}#-->
|
||||
<!--#include("user.js"){}#-->
|
||||
@@ -104,11 +107,13 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
el: '#v4-home-app',
|
||||
data(){
|
||||
return{
|
||||
websiteNews: []
|
||||
websiteNews: [],
|
||||
homeBannerList: "${config.AppHomeImg!}".split(",").map(item => item.trim()).filter(item => item)
|
||||
}
|
||||
},
|
||||
components: {
|
||||
'act': act,
|
||||
'work-template': workTemplate,
|
||||
'jcdt': jcdt,
|
||||
'entry': entry,
|
||||
'user': user,
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
const workTemplate = {
|
||||
template: /*language=HTML*/ `
|
||||
<div class="section-wrapper work-template-wrapper">
|
||||
<div class="work-template-header">
|
||||
<div class="work-template-title">
|
||||
<i class="fa fa-clipboard"></i>
|
||||
<span>工作模板</span>
|
||||
<em>/Templates</em>
|
||||
</div>
|
||||
</div>
|
||||
<div class="work-template-card">
|
||||
<div v-if="templateList && templateList.length > 0" class="work-template-grid">
|
||||
<div class="work-template-item"
|
||||
v-for="template in templateList"
|
||||
:key="template.id"
|
||||
@click="go(template)">
|
||||
<div class="work-template-icon">
|
||||
<img :src="template.templateIcon || template.cover || 'https://www.ncu.edu.cn/__local/8/52/2C/644986B4C9A030F7B65300178A6_8679CB08_18467.jpg'"
|
||||
alt="">
|
||||
</div>
|
||||
<div class="work-template-name">{{ template.templateName || template.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="no-activity-placeholder">
|
||||
<div class="icon"><i class="fa fa-clipboard"></i></div>
|
||||
<p>暂无工作模板</p>
|
||||
<p class="subtext">敬请关注后续更新</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
templateList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
listTemplate() {
|
||||
this.$axios.post("/platform/home/listHomeTemplate").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.templateList = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
go(template) {
|
||||
if (!template.url) {
|
||||
this.$message.warning("管理员未配置模板链接")
|
||||
return
|
||||
}
|
||||
const url = new URL(template.url, window.location.origin)
|
||||
if (!url.searchParams.get("mode")) {
|
||||
url.searchParams.set("mode", "edit")
|
||||
}
|
||||
if (!url.searchParams.get("id") && template.id) {
|
||||
url.searchParams.set("id", template.id)
|
||||
}
|
||||
window.localStorage.setItem("zhgh_home_template_edit", JSON.stringify({
|
||||
path: url.pathname,
|
||||
id: url.searchParams.get("id"),
|
||||
expiresAt: Date.now() + 60000
|
||||
}))
|
||||
window.open(url.href)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.listTemplate()
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
.work-template-wrapper {
|
||||
width: 80%;
|
||||
margin: 20px auto 28px;
|
||||
}
|
||||
|
||||
.work-template-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.work-template-title {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: 6px;
|
||||
color: #19324d;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.work-template-title i {
|
||||
color: #409eff;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.work-template-title em {
|
||||
color: #b5c0d6;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.work-template-card {
|
||||
background: #ffffff;
|
||||
border: 1px solid #edf1f7;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||
min-height: 116px;
|
||||
padding: 18px 20px;
|
||||
}
|
||||
|
||||
.work-template-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
|
||||
justify-items: center;
|
||||
justify-content: start;
|
||||
gap: 12px 18px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.work-template-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.work-template-item:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.work-template-icon {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.work-template-icon img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.work-template-name {
|
||||
min-height: 34px;
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
word-break: break-word;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.work-template-wrapper .no-activity-placeholder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 20px;
|
||||
color: #94a3b8;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.work-template-wrapper .no-activity-placeholder .icon {
|
||||
font-size: 44px;
|
||||
margin-bottom: 12px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.work-template-wrapper .no-activity-placeholder p {
|
||||
margin: 4px 0 0;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.work-template-wrapper .no-activity-placeholder .subtext {
|
||||
font-size: 13px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.work-template-grid {
|
||||
grid-template-columns: repeat(3, minmax(72px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.work-template-item {
|
||||
padding: 8px 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.work-template-grid {
|
||||
grid-template-columns: repeat(2, minmax(72px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
`
|
||||
};
|
||||
@@ -75,8 +75,9 @@ layout("/layouts/platform.html"){
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="configValue" label="参数值">
|
||||
<template v-if="formData.configKey === 'AppLogo' || formData.configKey === 'AppHomeImg'">
|
||||
<template v-if="formData.configKey === 'AppLogo'">
|
||||
<file-upload
|
||||
key="AppLogo"
|
||||
style="--upload-width: 214px;--upload-height:64px"
|
||||
:value.sync="formData.configValue"
|
||||
:upload_number="1"
|
||||
@@ -84,8 +85,43 @@ layout("/layouts/platform.html"){
|
||||
upload_result_category="interval"
|
||||
upload_result_type="url"
|
||||
></file-upload>
|
||||
<span v-if="formData.configKey === 'AppLogo'">最佳分辨率:428 x 128</span>
|
||||
<span v-else-if="formData.configKey === 'AppHomeImg'">最佳分辨率:2756 x 732</span>
|
||||
<span>最佳分辨率:428 x 128</span>
|
||||
</template>
|
||||
<template v-else-if="formData.configKey === 'AppHomeImg'">
|
||||
<file-upload
|
||||
key="AppHomeImg"
|
||||
style="--upload-width: 214px;--upload-height:64px"
|
||||
:value.sync="formData.configValue"
|
||||
:upload_number="10"
|
||||
upload_mode="image"
|
||||
upload_result_category="interval"
|
||||
upload_result_type="url"
|
||||
></file-upload>
|
||||
<span>最佳分辨率:2756 x 732,最多可上传 10 张,首页按上传顺序轮播</span>
|
||||
</template>
|
||||
<template v-else-if="formData.configKey === 'AppFeaturedActivityImg'">
|
||||
<file-upload
|
||||
key="AppFeaturedActivityImg"
|
||||
style="--upload-width: 214px;--upload-height:96px"
|
||||
:value.sync="formData.configValue"
|
||||
:upload_number="1"
|
||||
upload_mode="image"
|
||||
upload_result_category="interval"
|
||||
upload_result_type="url"
|
||||
></file-upload>
|
||||
<span>最佳分辨率:750 x 280,精彩活动页顶部图片</span>
|
||||
</template>
|
||||
<template v-else-if="formData.configKey === 'AppFestivalBenefitImg'">
|
||||
<file-upload
|
||||
key="AppFestivalBenefitImg"
|
||||
style="--upload-width: 214px;--upload-height:96px"
|
||||
:value.sync="formData.configValue"
|
||||
:upload_number="1"
|
||||
upload_mode="image"
|
||||
upload_result_category="interval"
|
||||
upload_result_type="url"
|
||||
></file-upload>
|
||||
<span>最佳分辨率:750 x 280,节日福利页顶部图片</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div v-if="'true'===formData.configValue||'false'===formData.configValue">
|
||||
@@ -179,6 +215,7 @@ layout("/layouts/platform.html"){
|
||||
doEdit: function () {
|
||||
var self = this
|
||||
var url = base + "/platform/sys/conf/editDo"
|
||||
self.normalizeConfigValue()
|
||||
self.$refs["editForm"].validate(function (valid) {
|
||||
if (valid) {
|
||||
$.post(
|
||||
@@ -204,6 +241,41 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
})
|
||||
},
|
||||
normalizeConfigValue: function () {
|
||||
if (Array.isArray(this.formData.configValue)) {
|
||||
this.formData.configValue = this.formData.configValue
|
||||
.map(function (item) {
|
||||
if (typeof item === "string") {
|
||||
return item
|
||||
}
|
||||
if (item && item.response && item.response.data) {
|
||||
return item.response.data
|
||||
}
|
||||
if (item && item.url) {
|
||||
return item.url
|
||||
}
|
||||
if (item && item.data) {
|
||||
return item.data
|
||||
}
|
||||
return ""
|
||||
})
|
||||
.filter(function (item) {
|
||||
return item
|
||||
})
|
||||
.join(",")
|
||||
}
|
||||
if (typeof this.formData.configValue === "string") {
|
||||
this.formData.configValue = this.formData.configValue
|
||||
.split(",")
|
||||
.map(function (item) {
|
||||
return item.trim()
|
||||
})
|
||||
.filter(function (item) {
|
||||
return item
|
||||
})
|
||||
.join(",")
|
||||
}
|
||||
},
|
||||
pageOrder: function (column) {
|
||||
//按字段排序
|
||||
this.pageForm.pageOrderName = column.prop
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="名称" prop="name">
|
||||
<el-input v-model="pageForm.name" clearable placeholder="请输入名称"></el-input>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
<el-card shadow="never">
|
||||
<el-table :data="tableData" header-align="center" border style="width: 100%">
|
||||
<el-table-column label="序号" type="index" width="50px" :index="indexMethod"></el-table-column>
|
||||
<el-table-column label="模板名称" prop="templateName" width="260px">
|
||||
<template slot-scope="scope">
|
||||
<el-input
|
||||
v-model="scope.row.templateName"
|
||||
size="mini"
|
||||
clearable
|
||||
placeholder="请输入模板名称"
|
||||
@change="updateTemplateName(scope.row)">
|
||||
</el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="PC端链接" prop="url" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="模板图标" prop="templateIcon" width="120px" align="center">
|
||||
<template slot-scope="scope">
|
||||
<file-upload
|
||||
class="template-icon-upload"
|
||||
:upload_number="1"
|
||||
:value="scope.row.templateIcon"
|
||||
accept=".jpg,.jpeg,.png"
|
||||
upload_result_type="url"
|
||||
upload_result_category="interval"
|
||||
upload_mode="image"
|
||||
@update:value="onTemplateIconChange(scope.row, $event)">
|
||||
</file-upload>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否置顶" prop="top" width="100px">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="mini" v-if="scope.row.top" type="success">是</el-tag>
|
||||
<el-tag size="mini" v-else type="info">否</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="关联类路径" prop="classPath" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="状态" prop="enable" width="80px">
|
||||
<template slot-scope="scope">
|
||||
<i v-if="!scope.row.enable" class="fa fa-circle text-danger ml5"></i>
|
||||
<i v-else class="fa fa-circle text-success ml5"></i>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="180px">
|
||||
<template slot-scope="scope">
|
||||
<el-link type="danger" size="mini" @click="disable(scope.row.id)" v-if="scope.row.enable">关闭</el-link>
|
||||
<el-link type="primary" size="mini" @click="enable(scope.row.id)" v-if="!scope.row.enable">开启</el-link>
|
||||
<el-link type="primary" size="mini" @click="topUp(scope.row.id)" v-if="!scope.row.top">置顶</el-link>
|
||||
<el-link type="danger" size="mini" @click="cancelTopUp(scope.row.id)" v-if="scope.row.top">取消置顶</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
disable(id) {
|
||||
this.$confirm("您确定要关闭吗?", "提示", {
|
||||
type: "warning",
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消"
|
||||
}).then(() => {
|
||||
this.$axios.post(loc() + "/disable", {id}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
enable(id) {
|
||||
this.$confirm("您确定要开启吗?", "提示", {
|
||||
type: "warning",
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消"
|
||||
}).then(() => {
|
||||
this.$axios.post(loc() + "/enable", {id}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
topUp(id) {
|
||||
this.$confirm("您确定要置顶吗?", "提示", {
|
||||
type: "warning",
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消"
|
||||
}).then(() => {
|
||||
this.$axios.post(loc() + "/topUp", {id}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
cancelTopUp(id) {
|
||||
this.$confirm("您确定要取消置顶吗?", "提示", {
|
||||
type: "warning",
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消"
|
||||
}).then(() => {
|
||||
this.$axios.post(loc() + "/cancelTopUp", {id}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
updateTemplateName(row) {
|
||||
this.$axios.post(loc() + "/updateTemplateName", {
|
||||
id: row.id,
|
||||
templateName: row.templateName
|
||||
}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
onTemplateIconChange(row, templateIcon) {
|
||||
if (templateIcon === undefined && !row.templateIcon) {
|
||||
return
|
||||
}
|
||||
row.templateIcon = templateIcon
|
||||
this.updateTemplateIcon(row)
|
||||
},
|
||||
updateTemplateIcon(row) {
|
||||
this.$nextTick(() => {
|
||||
this.$axios.post(loc() + "/updateTemplateIcon", {
|
||||
id: row.id,
|
||||
templateIcon: row.templateIcon
|
||||
}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
.template-icon-upload {
|
||||
--upload-width: 48px;
|
||||
--upload-height: 48px;
|
||||
}
|
||||
|
||||
.template-icon-upload .el-upload-list--picture-card .el-upload-list__item,
|
||||
.template-icon-upload .el-upload--picture-card {
|
||||
width: 48px !important;
|
||||
height: 48px !important;
|
||||
line-height: 48px !important;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.template-icon-upload .el-upload--picture-card i {
|
||||
font-size: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -949,39 +949,44 @@ const ACTIVITY_CULTURE_APPLY_ACTIVITY = {
|
||||
return data
|
||||
},
|
||||
async init(id) {
|
||||
if (id) {
|
||||
this.activeName = "1"
|
||||
this.findOne(id)
|
||||
} else {
|
||||
this.formData = {
|
||||
time: [],
|
||||
applyTime2: [],
|
||||
plannedDate: [],
|
||||
goods: [],
|
||||
billFiles: [],
|
||||
photoFiles: [],
|
||||
otherFiles: [],
|
||||
tissuePersonList: [],
|
||||
unionUserNumberLimit: [],
|
||||
signUpMethod: null,
|
||||
rangerMeter: 100,
|
||||
isEnrollSystem: true,
|
||||
isPushHome: 0,
|
||||
isIntegral: false
|
||||
this.formLoading = true
|
||||
try {
|
||||
if (id) {
|
||||
this.activeName = "1"
|
||||
await this.findOne(id)
|
||||
} else {
|
||||
this.formData = {
|
||||
time: [],
|
||||
applyTime2: [],
|
||||
plannedDate: [],
|
||||
goods: [],
|
||||
billFiles: [],
|
||||
photoFiles: [],
|
||||
otherFiles: [],
|
||||
tissuePersonList: [],
|
||||
unionUserNumberLimit: [],
|
||||
signUpMethod: null,
|
||||
rangerMeter: 100,
|
||||
isEnrollSystem: true,
|
||||
isPushHome: 0,
|
||||
isIntegral: false
|
||||
}
|
||||
this.generateActivityCode().then((data) => {
|
||||
this.$set(this.formData, "activityCode", data)
|
||||
})
|
||||
this.getUnionData().then((data) => {
|
||||
this.$set(this.formData, "unionUserNumberLimit", data)
|
||||
})
|
||||
}
|
||||
this.generateActivityCode().then((data) => {
|
||||
this.$set(this.formData, "activityCode", data)
|
||||
})
|
||||
this.getUnionData().then((data) => {
|
||||
this.$set(this.formData, "unionUserNumberLimit", data)
|
||||
this.clubOptions = await this.getClubsByRole()
|
||||
this.clubOptions.map((v) => {
|
||||
v.name = v.clubName
|
||||
})
|
||||
const units = await this.$businessTool.listUnit()
|
||||
this.unitOptions = this.clubOptions.concat(units)
|
||||
} finally {
|
||||
this.formLoading = false
|
||||
}
|
||||
this.clubOptions = await this.getClubsByRole()
|
||||
this.clubOptions.map((v) => {
|
||||
v.name = v.clubName
|
||||
})
|
||||
const units = await this.$businessTool.listUnit()
|
||||
this.unitOptions = this.clubOptions.concat(units)
|
||||
},
|
||||
async queryUserByIds(ids) {
|
||||
const {data} = await this.$axios.post("/platform/activity/culture/applyActivity/queryUserByIds", {ids: JSON.stringify(ids)})
|
||||
@@ -1018,6 +1023,14 @@ const ACTIVITY_CULTURE_APPLY_ACTIVITY = {
|
||||
this.bizId = row.id
|
||||
this.activeName = "1"
|
||||
this.init(row.id)
|
||||
},
|
||||
openUrlEdit() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
const mode = params.get("mode")
|
||||
const id = params.get("id")
|
||||
if (mode === "edit" && id) {
|
||||
this.openEdit({id})
|
||||
}
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
@@ -1030,5 +1043,8 @@ const ACTIVITY_CULTURE_APPLY_ACTIVITY = {
|
||||
})
|
||||
this.getActivityGroup()
|
||||
// this.init()
|
||||
},
|
||||
mounted() {
|
||||
this.openUrlEdit()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,18 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
|
||||
撤回
|
||||
</el-dropdown-item>
|
||||
|
||||
<el-dropdown-item :command="{type:'delete',row}"
|
||||
<el-dropdown-item
|
||||
v-if="activity_type === 40001 && $auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && !row.isTemplate"
|
||||
:command="{type:'setTemplate',row}">
|
||||
设为模板
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="activity_type === 40001 && $auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && row.isTemplate"
|
||||
:command="{type:'cancelTemplate',row}">
|
||||
取消模板
|
||||
</el-dropdown-item>
|
||||
|
||||
<el-dropdown-item :command="{type:'delete',row}" :disabled="!!row.isTemplate"
|
||||
v-if="(activity_type === 40001 && (row.taskKey === 'startTask' || !row.instanceId)) || (activity_type !== 40001 && $auth.hasRole('SYSADMIN'))" >
|
||||
删除
|
||||
</el-dropdown-item>
|
||||
@@ -209,6 +220,10 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
|
||||
this.onRevoke(row)
|
||||
} else if (type === "delete") {
|
||||
this.doDelete(row)
|
||||
} else if (type === "setTemplate") {
|
||||
this.setTemplate(row)
|
||||
} else if (type === "cancelTemplate") {
|
||||
this.cancelTemplate(row)
|
||||
} else if (type === "openCode") {
|
||||
this.url = location.origin + "/platform/h5/activity/culture/signUp?id=" + row.id + "&groupId=" + row.groupId
|
||||
this.codeDialogVisible = true
|
||||
@@ -231,6 +246,10 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
|
||||
})
|
||||
},
|
||||
doDelete(row) {
|
||||
if (row.isTemplate) {
|
||||
this.$message.warning("该活动已设为模板,请先取消模板后再删除")
|
||||
return
|
||||
}
|
||||
const {id} = row
|
||||
this.$confirm("确定要删除该活动吗?", "提示", {type: "warning"}).then(async () => {
|
||||
this.$set(row, "loading", true)
|
||||
@@ -244,6 +263,40 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
|
||||
this.$set(row, "loading", false)
|
||||
})
|
||||
},
|
||||
setTemplate(row) {
|
||||
this.$confirm("确定将该活动设为工作模板吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
this.$set(row, "loading", true)
|
||||
const resp = await this.$axios.post("/platform/activity/culture/infoManage/setTemplate", {id: row.id})
|
||||
if (resp.code === 0) {
|
||||
this.doSearch()
|
||||
this.$message.success(resp.msg)
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
this.$set(row, "loading", false)
|
||||
})
|
||||
},
|
||||
cancelTemplate(row) {
|
||||
this.$confirm("确定取消该活动的工作模板吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
this.$set(row, "loading", true)
|
||||
const resp = await this.$axios.post("/platform/activity/culture/infoManage/cancelTemplate", {id: row.id})
|
||||
if (resp.code === 0) {
|
||||
this.doSearch()
|
||||
this.$message.success(resp.msg)
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
this.$set(row, "loading", false)
|
||||
})
|
||||
},
|
||||
onRevoke(row) {
|
||||
this.$confirm("您确定要撤回吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
@@ -268,7 +321,8 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
|
||||
}
|
||||
})
|
||||
this.tableLoading = false
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
async created() {
|
||||
// 根据 activity_type 动态添加流程相关列
|
||||
@@ -279,5 +333,5 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
|
||||
);
|
||||
}
|
||||
this.pageData()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -656,7 +656,7 @@
|
||||
async applyUserModelInput(val) {
|
||||
if (val === 2) {
|
||||
if (!this.eventForm.unionLimit || this.eventForm.unionLimit.length === 0) {
|
||||
const resp = await $.get(loc() + "/getUnionLimit", { activityScopeId: this.eventForm.activityGroupId })
|
||||
const resp = await $.get("/platform/activity/sports/info/mange/getUnionLimit", { activityScopeId: this.eventForm.activityGroupId })
|
||||
if (resp.code === 0) {
|
||||
this.$set(this.eventForm, "unionLimit", resp.data)
|
||||
}
|
||||
@@ -736,7 +736,7 @@
|
||||
spinner: "el-icon-loading",
|
||||
background: "rgba(0,0,0,.45)"
|
||||
})
|
||||
const resp = await this.$axios.post(loc() + "/doAssignmentDate", {
|
||||
const resp = await this.$axios.post("/platform/activity/sports/info/mange/doAssignmentDate", {
|
||||
eventIds: JSON.stringify(this.checkedEventInfo.map((v) => v.id)),
|
||||
events: JSON.stringify(this.checkedEventInfo)
|
||||
})
|
||||
@@ -1043,7 +1043,7 @@
|
||||
},
|
||||
async operate() {
|
||||
const deleteEventIds = this.eventsIds.filter((v) => !this.formData.eventsIds.includes(v))
|
||||
const { data } = await $.get(loc() + "/getEventApply", {
|
||||
const { data } = await $.get("/platform/activity/sports/info/mange/getEventApply", {
|
||||
activityId: this.formData.id,
|
||||
eventId: JSON.stringify(deleteEventIds)
|
||||
})
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card shadow="never">
|
||||
<div slot="header">
|
||||
<div class="sports-new-actions">
|
||||
<el-button @click="doSave" type="primary">保 存</el-button>
|
||||
<el-button @click="doOperate" type="primary">提 交</el-button>
|
||||
<!--<el-button @click="back">返 回</el-button>-->
|
||||
</div>
|
||||
</div>
|
||||
<add-activity
|
||||
:is_a06="$auth.hasRole('SCHOOL_UNION_ADMIN')"
|
||||
:is_club="$auth.hasRole('CLUB_PRESIDENT')"
|
||||
:is_sysadmin="$auth.hasRole('SYSADMIN')"
|
||||
ref="addActivity"
|
||||
@flip="flip"
|
||||
@flush="flush">
|
||||
</add-activity>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("/platform/zhgh/activity/sports/infoManage/addActivity.js"){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
"add-activity": ACTIVITY_SPORTS_ADD_ACTIVITY
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
commonUtil.pjaxPush("/platform/activity/sports/info/mange")
|
||||
},
|
||||
flip() {
|
||||
this.back()
|
||||
},
|
||||
flush() {
|
||||
},
|
||||
async doOperate() {
|
||||
await this.$refs.addActivity.operate()
|
||||
},
|
||||
async doSave() {
|
||||
await this.$refs.addActivity.doSave()
|
||||
},
|
||||
initForm() {
|
||||
const mode = GetQueryString("mode")
|
||||
const id = GetQueryString("id")
|
||||
if (mode === "edit" && id) {
|
||||
this.$refs.addActivity.openEdit({id}, true)
|
||||
} else {
|
||||
this.$refs.addActivity.openAdd()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.initForm()
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.sports-new-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,58 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.el-drawer__body {
|
||||
padding: 20px;
|
||||
}
|
||||
.my-drawer .el-col-4 {
|
||||
text-align: right;
|
||||
}
|
||||
.my-drawer .el-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.courseTimeButton {
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card shadow="never">
|
||||
<basic-form ref="formRef" @back="back" @refresh="refresh"></basic-form>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("/platform/zhgh/activity/trainSignUp/manage/basicForm.js"){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
dicts: ["USER_CAMPUS", "TRAIN_SIGNUP_TYPE"],
|
||||
components: {
|
||||
"basic-form": basicForm
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
commonUtil.pjaxPush("/platform/trainSignUp/manage")
|
||||
},
|
||||
refresh() {
|
||||
},
|
||||
initForm() {
|
||||
const mode = GetQueryString("mode")
|
||||
const id = GetQueryString("id")
|
||||
const row = mode === "edit" && id ? {id} : undefined
|
||||
this.$refs.formRef.initData(row)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.initForm()
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#include('courseTime.js'){}#-->
|
||||
<!--#include('customForm.js'){}#-->
|
||||
<!--#include('/platform/zhgh/activity/trainSignUp/manage/courseTime.js'){}#-->
|
||||
<!--#include('/platform/zhgh/activity/trainSignUp/manage/customForm.js'){}#-->
|
||||
const basicForm = {
|
||||
template: /*language=HTML*/ `
|
||||
<div>
|
||||
|
||||
@@ -92,7 +92,13 @@ layout("/layouts/platform.html"){
|
||||
<el-dropdown-item @click.native="makeCode(row)">签到二维码</el-dropdown-item>
|
||||
<el-dropdown-item @click.native="onView(row)">查看</el-dropdown-item>
|
||||
<el-dropdown-item @click.native="openEdit(row)">编辑</el-dropdown-item>
|
||||
<el-dropdown-item @click.native="onDelete(row)">删除</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && !row.isTemplate"
|
||||
@click.native="setTemplate(row)">设为模板</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && row.isTemplate"
|
||||
@click.native="cancelTemplate(row)">取消模板</el-dropdown-item>
|
||||
<el-dropdown-item :disabled="!!row.isTemplate" @click.native="onDelete(row)">删除</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
@@ -154,9 +160,25 @@ layout("/layouts/platform.html"){
|
||||
],
|
||||
codeDialogVisible: false,
|
||||
activityUrl: '',
|
||||
urlEditInitialized: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
pageData(data = null) {
|
||||
const address = this.pageDataUrl ? this.pageDataUrl : loc() + "/pageData"
|
||||
this.tableLoading = true
|
||||
return this.$axios.post(address, data ? data : this.pageForm).then((res) => {
|
||||
this.tableLoading = false
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
this.$nextTick(() => {
|
||||
this.openUrlEdit()
|
||||
})
|
||||
}
|
||||
return res
|
||||
})
|
||||
},
|
||||
back() {
|
||||
this.$refs.guava.index()
|
||||
},
|
||||
@@ -170,6 +192,25 @@ layout("/layouts/platform.html"){
|
||||
this.$refs.formRef.initData(row)
|
||||
})
|
||||
},
|
||||
openUrlEdit() {
|
||||
if (this.urlEditInitialized) {
|
||||
return
|
||||
}
|
||||
const mode = GetQueryString("mode")
|
||||
const id = GetQueryString("id")
|
||||
if (mode !== "edit" || !id) {
|
||||
return
|
||||
}
|
||||
if (!this.$refs.guava) {
|
||||
this.$nextTick(() => {
|
||||
this.openUrlEdit()
|
||||
})
|
||||
return
|
||||
}
|
||||
this.urlEditInitialized = true
|
||||
const row = (this.tableData || []).find(item => item.id === id) || { id }
|
||||
this.openEdit(row)
|
||||
},
|
||||
onView(row) {
|
||||
this.$refs.guava.view(() => {
|
||||
this.$refs.infoRef.initData(row.id)
|
||||
@@ -191,18 +232,56 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
async onDelete(row) {
|
||||
if (row.isTemplate) {
|
||||
this.$message.warning("该活动已设为模板,请先取消模板后再删除")
|
||||
return
|
||||
}
|
||||
this.$confirm("此操作将永久删除, 是否继续?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
const resp = await this.$axios.post(loc() + "/onDelete", { id: row.id })
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
async setTemplate(row) {
|
||||
this.$confirm("确定将该活动设为工作模板吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
const resp = await this.$axios.post(loc() + "/setTemplate", { id: row.id })
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
async cancelTemplate(row) {
|
||||
this.$confirm("确定取消该活动的工作模板吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
const resp = await this.$axios.post(loc() + "/cancelTemplate", { id: row.id })
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
mounted() {
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -242,7 +242,7 @@ let ASSSET_FORM = {
|
||||
this.searchAssetUseUser(this.formData.assetUseUserId)
|
||||
},
|
||||
assetUseUnionIdChange(val) {
|
||||
const union = this.unions.find(v => v.id === val)
|
||||
const union = this.unionList.find(v => v.id === val)
|
||||
if (union) {
|
||||
this.$set(this.formData, "assetUseUnionName", union.name)
|
||||
} else {
|
||||
@@ -260,16 +260,16 @@ let ASSSET_FORM = {
|
||||
},
|
||||
// 点击责任人
|
||||
assetUseUserIdChange(val) {
|
||||
const {
|
||||
unionname,
|
||||
unionid
|
||||
} = this.assetUseUserOption.find(v => v.id === val)
|
||||
this.formData.assetUseUnionId = unionid
|
||||
const user = this.assetUseUserOption.find(v => v.id === val)
|
||||
if (!user) return
|
||||
const unionId = user.unionId || user.unionid
|
||||
const unionName = user.unionName || user.unionname
|
||||
this.formData.assetUseUnionId = unionId
|
||||
if (this.formData.assetTypeCode === 1) {
|
||||
this.formData.assetUseUnionName = "校工会"
|
||||
} else {
|
||||
|
||||
this.formData.assetUseUnionName = unionname
|
||||
this.formData.assetUseUnionName = unionName
|
||||
}
|
||||
},
|
||||
// 点击开始使用日期🧄预计报废时间
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
const form = {
|
||||
template: /*language=HTML*/ `
|
||||
<el-dialog :title="formData.id ? '编辑' : '新增'" :visible.sync="dialogVisible" :close-on-click-modal="false">
|
||||
<el-form ref="formRef" :model="formData" :rules="rules" label-width="80px">
|
||||
<el-form-item label="单位" prop="unitName">
|
||||
<el-input v-model="formData.unitName" placeholder="请输入单位" maxlength="100"
|
||||
show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-dialog :title="formData.id ? '编辑' : '新增'" :visible.sync="dialogVisible" :close-on-click-modal="false" width="60%">
|
||||
<el-form ref="formRef" :model="formData" :rules="rules" label-width="110px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="当前工会" prop="unionName">
|
||||
<el-input v-model="formData.unionName" disabled placeholder="当前登录人所在工会"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="当前单位" prop="unitName">
|
||||
<el-input v-model="formData.unitName" disabled placeholder="当前登录人所在单位"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="地点" prop="address">
|
||||
<el-input v-model="formData.address" placeholder="请输入地点" maxlength="100"
|
||||
show-word-limit></el-input>
|
||||
@@ -21,6 +29,28 @@ const form = {
|
||||
<el-form-item label="开放时间" prop="openTime">
|
||||
<el-input v-model="formData.openTime" placeholder="请输入开放时间"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="图片/视频资料" prop="mediaFiles">
|
||||
<file-upload
|
||||
:value.sync="formData.mediaFiles"
|
||||
:upload_number="10"
|
||||
upload_mode="drag"
|
||||
upload_result_category="array"
|
||||
complete_result
|
||||
:accept="mediaAccept">
|
||||
</file-upload>
|
||||
</el-form-item>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="地图X坐标" prop="mapX">
|
||||
<el-input v-model="formData.mapX" disabled placeholder="请通过坐标按钮采集"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="地图Y坐标" prop="mapY">
|
||||
<el-input v-model="formData.mapY" disabled placeholder="请通过坐标按钮采集"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
@@ -32,8 +62,11 @@ const form = {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
formData: {},
|
||||
currentUserOrg: {},
|
||||
mediaAccept: ".jpg,.jpeg,.png,.mp4,.mov",
|
||||
rules: {
|
||||
unitName: [{ required: true, message: "请输入单位", trigger: "blur" }],
|
||||
unitName: [{ required: true, message: "未获取到当前单位", trigger: "blur" }],
|
||||
unionName: [{ required: true, message: "未获取到当前工会", trigger: "blur" }],
|
||||
address: [{ required: true, message: "请输入地点", trigger: "blur" }],
|
||||
area: [{ required: true, message: "请输入面积", trigger: "blur" }],
|
||||
facility: [{ required: true, message: "请输入设施", trigger: "blur" }],
|
||||
@@ -42,18 +75,22 @@ const form = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onOpen(id) {
|
||||
async onOpen(id) {
|
||||
this.dialogVisible = true
|
||||
this.resetForm()
|
||||
await this.loadCurrentUserOrg()
|
||||
if (id) {
|
||||
this.dialogVisible = true
|
||||
this.resetForm()
|
||||
$.post("/platform/buildHome/littleHouse/detail/" + id).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.formData = resp.data
|
||||
this.formData = Object.assign({}, this.currentUserOrg, resp.data, {
|
||||
mediaFiles: this.parseFiles(resp.data.mediaFiles)
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.dialogVisible = true
|
||||
this.formData = {}
|
||||
this.formData = Object.assign({}, this.currentUserOrg, {
|
||||
mediaFiles: []
|
||||
})
|
||||
this.$nextTick(() => {
|
||||
this.$refs.formRef.clearValidate()
|
||||
})
|
||||
@@ -67,10 +104,41 @@ const form = {
|
||||
}
|
||||
})
|
||||
},
|
||||
async loadCurrentUserOrg() {
|
||||
const resp = await $.post("/platform/buildHome/littleHouse/currentUserOrg")
|
||||
if (resp.code === 0) {
|
||||
this.currentUserOrg = resp.data || {}
|
||||
}
|
||||
},
|
||||
parseFiles(value) {
|
||||
if (!value) return []
|
||||
if (Array.isArray(value)) return value
|
||||
try {
|
||||
return JSON.parse(value)
|
||||
} catch (e) {
|
||||
return []
|
||||
}
|
||||
},
|
||||
getFileExt(file) {
|
||||
const name = file.name || file.url || file.response?.data || file.data || ""
|
||||
const index = name.lastIndexOf(".")
|
||||
return index > -1 ? name.substring(index + 1).toLowerCase() : ""
|
||||
},
|
||||
validateMediaFiles(files) {
|
||||
const acceptExts = this.mediaAccept.split(",").map(v => v.replace(".", "").toLowerCase())
|
||||
return (files || []).every(file => acceptExts.includes(this.getFileExt(file)))
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.formRef.validate((valid) => {
|
||||
if (valid) {
|
||||
$.post("/platform/buildHome/littleHouse/save", this.formData).then((resp) => {
|
||||
if (!this.validateMediaFiles(this.formData.mediaFiles)) {
|
||||
this.$message.warning("仅支持上传 jpg、jpeg、png、mp4、mov 格式文件")
|
||||
return
|
||||
}
|
||||
const data = Object.assign({}, this.formData, {
|
||||
mediaFiles: JSON.stringify(this.formData.mediaFiles || [])
|
||||
})
|
||||
$.post("/platform/buildHome/littleHouse/save", data).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.$emit("refresh")
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava ref="guava">
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="单位名称">
|
||||
<el-input placeholder="单位名称" clearable v-model="pageForm.searchKeyword"></el-input>
|
||||
<search-item label="单位/工会名称">
|
||||
<el-input placeholder="单位/工会名称" clearable v-model="pageForm.searchKeyword"></el-input>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
@@ -18,6 +17,7 @@ layout("/layouts/platform.html"){
|
||||
</table-tool>
|
||||
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
|
||||
<el-table-column :index="indexMethod" align="center" header-align="center" label="序号" type="index" width="80px"></el-table-column>
|
||||
<el-table-column label="工会" prop="unionName" sortable width="220px" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="单位" prop="unitName" sortable width="200px"></el-table-column>
|
||||
<el-table-column label="活动场所基本情况">
|
||||
<el-table-column label="地点" prop="address" sortable width="200px"></el-table-column>
|
||||
@@ -25,8 +25,9 @@ layout("/layouts/platform.html"){
|
||||
<el-table-column label="设施" prop="facility" sortable></el-table-column>
|
||||
<el-table-column label="开放时间" prop="openTime" sortable width="200px"></el-table-column>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="200px">
|
||||
<el-table-column label="操作" fixed="right" width="280px">
|
||||
<template scope="{row}">
|
||||
<el-button v-if="$auth.hasRole('SYSADMIN')" size="mini" type="warning" @click="openCoordinate(row)">坐标</el-button>
|
||||
<el-button size="mini" type="primary" @click="$refs.littleHouseFormRef.onOpen(row.id)">修改</el-button>
|
||||
<el-button size="mini" type="danger" @click="onDelete(row.id)">删除</el-button>
|
||||
</template>
|
||||
@@ -37,6 +38,7 @@ layout("/layouts/platform.html"){
|
||||
</guava>
|
||||
|
||||
<little-house-form ref="littleHouseFormRef" @refresh="doSearch"></little-house-form>
|
||||
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
@@ -63,12 +65,78 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
})
|
||||
},
|
||||
openCoordinate(row) {
|
||||
if (!row || !row.id) {
|
||||
this.$message.warning("\u672a\u83b7\u53d6\u5230\u5c0f\u5bb6\u8bb0\u5f55")
|
||||
return
|
||||
}
|
||||
if (this.hasCoordinate(row)) {
|
||||
this.$confirm(
|
||||
"\u5f53\u524d\u8bb0\u5f55\u5df2\u6709\u5750\u6807\uff0c\u662f\u4fee\u6539\u8fd8\u662f\u6e05\u7a7a\uff1f",
|
||||
"\u63d0\u793a",
|
||||
{
|
||||
type: "warning",
|
||||
distinguishCancelAndClose: true,
|
||||
confirmButtonText: "\u4fee\u6539\u5750\u6807",
|
||||
cancelButtonText: "\u6e05\u7a7a\u5750\u6807"
|
||||
}
|
||||
).then(() => {
|
||||
this.doOpenCoordinate(row)
|
||||
}).catch((action) => {
|
||||
if (action === "cancel") {
|
||||
this.clearCoordinate(row)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
this.doOpenCoordinate(row)
|
||||
},
|
||||
hasCoordinate(row) {
|
||||
return row
|
||||
&& row.mapX !== null
|
||||
&& row.mapX !== undefined
|
||||
&& row.mapX !== ""
|
||||
&& row.mapY !== null
|
||||
&& row.mapY !== undefined
|
||||
&& row.mapY !== ""
|
||||
},
|
||||
doOpenCoordinate(row) {
|
||||
const params = [
|
||||
"coordinateMode=1",
|
||||
"houseId=" + encodeURIComponent(row.id),
|
||||
"t=" + Date.now()
|
||||
]
|
||||
window.open("/platform/careData/leader?" + params.join("&"), "_blank")
|
||||
},
|
||||
clearCoordinate(row) {
|
||||
$.post("/platform/buildHome/littleHouse/clearCoordinate", { id: row.id }).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success("\u5750\u6807\u5df2\u6e05\u7a7a")
|
||||
this.doSearch()
|
||||
}
|
||||
})
|
||||
},
|
||||
handleCoordinateMessage(event) {
|
||||
if (event.origin !== window.location.origin) {
|
||||
return
|
||||
}
|
||||
const data = event.data || {}
|
||||
if (data.type !== "littleHouseCoordinateSaved") {
|
||||
return
|
||||
}
|
||||
this.$message.success("\u5750\u6807\u91c7\u96c6\u6210\u529f")
|
||||
this.doSearch()
|
||||
},
|
||||
onExport() {
|
||||
this.$downLoad("/platform/buildHome/littleHouse/exportXlsx")
|
||||
}
|
||||
},
|
||||
created() {
|
||||
window.addEventListener("message", this.handleCoordinateMessage)
|
||||
this.pageData()
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener("message", this.handleCoordinateMessage)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<script src="${base!}/assets/platform/plugins/echarts/echarts.min.js?v=20260527"></script>
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.asset-data-panel {
|
||||
position: absolute;
|
||||
left: 1.35%;
|
||||
top: 69.6%;
|
||||
width: 20.82%;
|
||||
height: 28.06%;
|
||||
background: url("${base!}/assets/platform/images/careData/leader/asset-data-panel.png?v=20260527") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.asset-data-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1.3%;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.78);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.asset-data-chart {
|
||||
position: absolute;
|
||||
left: 3%;
|
||||
top: 14%;
|
||||
width: 94%;
|
||||
height: 74%;
|
||||
}
|
||||
|
||||
.asset-data-note {
|
||||
position: absolute;
|
||||
left: 8%;
|
||||
right: 8%;
|
||||
bottom: 4.5%;
|
||||
overflow: hidden;
|
||||
color: #315d86;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
|
||||
.asset-data-empty {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 48%;
|
||||
z-index: 2;
|
||||
color: rgba(36, 71, 105, 0.82);
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="asset-data-panel">
|
||||
<div class="asset-data-title">资产数据</div>
|
||||
<div ref="usageChart" class="asset-data-chart"></div>
|
||||
<div class="asset-data-empty" v-if="!chartRows.length">暂无数据</div>
|
||||
<div class="asset-data-note">不同颜色代表不同使用状况</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "\u9000\u51fa\u5168\u5c4f" : "\u5168\u5c4f\u663e\u793a" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
chart: null,
|
||||
chartRows: [],
|
||||
fullscreen: false,
|
||||
chartColors: ["#1c8df4", "#35c982", "#f3a64f", "#8a7cff", "#f05d80", "#2ec7c9", "#b6a2de"]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadAssetData()
|
||||
},
|
||||
mounted() {
|
||||
this.initChart()
|
||||
window.addEventListener("resize", this.resizeChart)
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener("resize", this.resizeChart)
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
if (this.chart) {
|
||||
this.chart.dispose()
|
||||
this.chart = null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initChart() {
|
||||
if (!window.echarts || !this.$refs.usageChart) {
|
||||
return
|
||||
}
|
||||
this.chart = echarts.init(this.$refs.usageChart)
|
||||
this.renderChart()
|
||||
},
|
||||
loadAssetData() {
|
||||
this.$axios.post("/platform/careData/leader/assetDataData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.chartRows = (data.states || [])
|
||||
.map(item => ({
|
||||
name: item.name || "\u672a\u586b\u5199",
|
||||
value: Number(item.value || 0)
|
||||
}))
|
||||
.filter(item => item.value > 0)
|
||||
this.renderChart()
|
||||
})
|
||||
},
|
||||
renderChart() {
|
||||
if (!this.chart) {
|
||||
return
|
||||
}
|
||||
const total = this.chartRows.reduce((sum, item) => sum + item.value, 0)
|
||||
this.chart.setOption({
|
||||
color: this.chartColors,
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
formatter: "{b}<br/>{c} ({d}%)"
|
||||
},
|
||||
legend: {
|
||||
orient: "vertical",
|
||||
right: "3%",
|
||||
top: "24%",
|
||||
itemWidth: 8,
|
||||
itemHeight: 8,
|
||||
itemGap: 9,
|
||||
textStyle: {
|
||||
color: "#315d86",
|
||||
fontSize: 12,
|
||||
lineHeight: 14
|
||||
},
|
||||
formatter(name) {
|
||||
return name.length > 5 ? name.slice(0, 5) + "..." : name
|
||||
}
|
||||
},
|
||||
graphic: {
|
||||
type: "text",
|
||||
left: "28%",
|
||||
top: "47%",
|
||||
style: {
|
||||
text: total ? total + "\n\u4ef6" : "",
|
||||
fill: "#1683f4",
|
||||
fontSize: 15,
|
||||
fontWeight: 700,
|
||||
textAlign: "center"
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: "\u4f7f\u7528\u72b6\u51b5",
|
||||
type: "pie",
|
||||
radius: ["32%", "56%"],
|
||||
center: ["32%", "52%"],
|
||||
avoidLabelOverlap: true,
|
||||
minAngle: 8,
|
||||
itemStyle: {
|
||||
borderColor: "rgba(255,255,255,0.9)",
|
||||
borderWidth: 2
|
||||
},
|
||||
label: {
|
||||
color: "#244769",
|
||||
fontSize: 11,
|
||||
formatter: "{d}%"
|
||||
},
|
||||
labelLine: {
|
||||
length: 8,
|
||||
length2: 4,
|
||||
lineStyle: {
|
||||
color: "rgba(36, 71, 105, 0.55)"
|
||||
}
|
||||
},
|
||||
data: this.chartRows
|
||||
}]
|
||||
}, true)
|
||||
},
|
||||
resizeChart() {
|
||||
if (this.chart) {
|
||||
this.chart.resize()
|
||||
}
|
||||
},
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,257 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.base-union-panel {
|
||||
position: absolute;
|
||||
right: calc(1.55% - 2px);
|
||||
top: calc(60.05% + 95px);
|
||||
width: calc(28.2% - 140px);
|
||||
height: 28.1%;
|
||||
background: url("${base!}/assets/platform/images/careData/leader/base-union-panel.png?v=20260526") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.base-union-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1.3%;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.78);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.base-union-list {
|
||||
position: absolute;
|
||||
left: calc(8.5% - 15px);
|
||||
top: 20.2%;
|
||||
width: calc(83% + 35px);
|
||||
height: 68.5%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.base-union-list::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.base-union-list::-webkit-scrollbar-track {
|
||||
background: rgba(110, 178, 237, 0.22);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.base-union-list::-webkit-scrollbar-thumb {
|
||||
background: rgba(49, 142, 231, 0.76);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.base-union-row {
|
||||
position: relative;
|
||||
flex: 0 0 17.2%;
|
||||
height: 17.2%;
|
||||
min-height: 31px;
|
||||
background-position: center center;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
color: #244769;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.base-union-row:nth-child(2n + 1) {
|
||||
background-image: url("${base!}/assets/platform/images/careData/leader/base-union-row-a.png?v=20260526");
|
||||
}
|
||||
|
||||
.base-union-row:nth-child(2n) {
|
||||
background-image: url("${base!}/assets/platform/images/careData/leader/base-union-row-b.png?v=20260526");
|
||||
}
|
||||
|
||||
.base-union-name {
|
||||
position: absolute;
|
||||
left: 18%;
|
||||
top: 50%;
|
||||
width: 52%;
|
||||
overflow: hidden;
|
||||
transform: translateY(-50%);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.base-union-count {
|
||||
position: absolute;
|
||||
right: 9.5%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #1d82e8;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.base-union-count span {
|
||||
margin-left: 3px;
|
||||
color: #4e6d8d;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.base-union-empty {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 48%;
|
||||
color: rgba(36, 71, 105, 0.82);
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="base-union-panel">
|
||||
<div class="base-union-title">基层工会</div>
|
||||
<div class="base-union-list" v-if="displayUnions.length">
|
||||
<div class="base-union-row" v-for="item in displayUnions" :key="item.unionCode || item.id">
|
||||
<div class="base-union-name" :title="item.unionname">{{ item.unionname || "--" }}</div>
|
||||
<div class="base-union-count">{{ item.value || 0 }}<span>人</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="base-union-empty" v-else>暂无数据</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "退出全屏" : "全屏显示" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
unions: [],
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
displayUnions() {
|
||||
return this.unions
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadBaseUnionData()
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
methods: {
|
||||
loadBaseUnionData() {
|
||||
this.$axios.post("/platform/careData/leader/baseUnionData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.unions = data.unions || []
|
||||
})
|
||||
},
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,252 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.club-panel {
|
||||
position: absolute;
|
||||
right: calc(1.55% - 3px);
|
||||
top: calc(38.2% + 3px);
|
||||
width: calc(28.2% - 145px);
|
||||
height: 28.1%;
|
||||
background: url("${base!}/assets/platform/images/careData/leader/base-union-panel.png?v=20260526") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.club-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1.3%;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.78);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.club-list {
|
||||
position: absolute;
|
||||
left: calc(8.5% - 14px);
|
||||
top: 20.2%;
|
||||
width: calc(83% + 29px);
|
||||
height: 68.5%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.club-list::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.club-list::-webkit-scrollbar-track {
|
||||
background: rgba(110, 178, 237, 0.22);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.club-list::-webkit-scrollbar-thumb {
|
||||
background: rgba(49, 142, 231, 0.76);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.club-row {
|
||||
position: relative;
|
||||
flex: 0 0 17.2%;
|
||||
height: 17.2%;
|
||||
min-height: 31px;
|
||||
background-position: center center;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
color: #244769;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.club-row:nth-child(2n + 1) {
|
||||
background-image: url("${base!}/assets/platform/images/careData/leader/base-union-row-a.png?v=20260526");
|
||||
}
|
||||
|
||||
.club-row:nth-child(2n) {
|
||||
background-image: url("${base!}/assets/platform/images/careData/leader/base-union-row-b.png?v=20260526");
|
||||
}
|
||||
|
||||
.club-name {
|
||||
position: absolute;
|
||||
left: 18%;
|
||||
top: 50%;
|
||||
width: 52%;
|
||||
overflow: hidden;
|
||||
transform: translateY(-50%);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.club-count {
|
||||
position: absolute;
|
||||
right: 9.5%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #1d82e8;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.club-count span {
|
||||
margin-left: 3px;
|
||||
color: #4e6d8d;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.club-empty {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 48%;
|
||||
color: rgba(36, 71, 105, 0.82);
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="club-panel">
|
||||
<div class="club-title">协会社团</div>
|
||||
<div class="club-list" v-if="clubs.length">
|
||||
<div class="club-row" v-for="item in clubs" :key="item.clubCode || item.id">
|
||||
<div class="club-name" :title="item.clubName">{{ item.clubName || "--" }}</div>
|
||||
<div class="club-count">{{ item.value || 0 }}<span>人</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="club-empty" v-else>暂无数据</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "退出全屏" : "全屏显示" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
clubs: [],
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadClubData()
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
methods: {
|
||||
loadClubData() {
|
||||
this.$axios.post("/platform/careData/leader/clubData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.clubs = data.clubs || []
|
||||
})
|
||||
},
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,282 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.condolence-panel {
|
||||
position: absolute;
|
||||
left: calc(1.35% - 5px);
|
||||
top: calc(38.9% - 28px);
|
||||
width: calc(20.82% - 6px);
|
||||
height: calc(27.65% + 70px);
|
||||
background: url("${base!}/assets/platform/images/careData/leader/condolence-panel.png?v=20260526") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.condolence-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1.3%;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.78);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.condolence-chart {
|
||||
position: absolute;
|
||||
left: 4%;
|
||||
top: calc(18% + 10px);
|
||||
width: 92%;
|
||||
height: 72%;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-around;
|
||||
padding: 2.5% 2.2% 7.5%;
|
||||
}
|
||||
|
||||
.condolence-bar-item {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 16%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.condolence-value {
|
||||
position: absolute;
|
||||
bottom: calc(17% + var(--bar-height) + 5px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
color: #243f5d;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
line-height: 14px;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
|
||||
.condolence-bar {
|
||||
position: absolute;
|
||||
bottom: 17%;
|
||||
left: 50%;
|
||||
width: 42%;
|
||||
height: var(--bar-height);
|
||||
min-height: 0;
|
||||
transform: translateX(-50%);
|
||||
background: linear-gradient(180deg, rgba(95, 183, 255, 0.96), rgba(35, 126, 238, 0.88));
|
||||
border: 1px solid rgba(208, 241, 255, 0.66);
|
||||
box-shadow: inset 0 0 10px rgba(215, 244, 255, 0.4), 0 0 10px rgba(58, 152, 245, 0.46);
|
||||
}
|
||||
|
||||
.condolence-bar-item:nth-child(2n) .condolence-bar {
|
||||
background: linear-gradient(180deg, rgba(90, 219, 162, 0.94), rgba(40, 177, 103, 0.86));
|
||||
box-shadow: inset 0 0 10px rgba(224, 255, 239, 0.36), 0 0 10px rgba(54, 190, 118, 0.36);
|
||||
}
|
||||
|
||||
.condolence-bar-item:nth-child(3) .condolence-bar {
|
||||
background: linear-gradient(180deg, rgba(255, 183, 109, 0.94), rgba(229, 132, 66, 0.86));
|
||||
box-shadow: inset 0 0 10px rgba(255, 236, 211, 0.34), 0 0 10px rgba(227, 142, 76, 0.36);
|
||||
}
|
||||
|
||||
.condolence-label {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
width: 56px;
|
||||
overflow: hidden;
|
||||
transform: translateX(-50%);
|
||||
color: #244769;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.68);
|
||||
}
|
||||
|
||||
.condolence-empty {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 43%;
|
||||
color: rgba(36, 71, 105, 0.82);
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="condolence-panel">
|
||||
<div class="condolence-title">慰问汇总</div>
|
||||
<div class="condolence-chart">
|
||||
<div class="condolence-empty" v-if="!hasData">暂无数据</div>
|
||||
<div class="condolence-bar-item" v-for="item in displayTypes" :key="item.index" :style="{ '--bar-height': barHeight(item) }">
|
||||
<div class="condolence-value">{{ item.rate || "0%" }}</div>
|
||||
<div class="condolence-bar"></div>
|
||||
<div class="condolence-label" :title="item.name">{{ shortName(item.name) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "退出全屏" : "全屏显示" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
types: [],
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasData() {
|
||||
return this.types.some(item => Number(item.count || 0) > 0)
|
||||
},
|
||||
maxCount() {
|
||||
return Math.max(...this.types.map(item => Number(item.count || 0)), 0)
|
||||
},
|
||||
displayTypes() {
|
||||
const rows = this.types.slice(0, 5)
|
||||
while (rows.length < 5) {
|
||||
rows.push({
|
||||
index: rows.length + 1,
|
||||
name: "",
|
||||
rate: "0%",
|
||||
rateValue: 0
|
||||
})
|
||||
}
|
||||
return rows
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadCondolenceData()
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
methods: {
|
||||
loadCondolenceData() {
|
||||
this.$axios.post("/platform/careData/leader/condolenceData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.types = data.types || []
|
||||
})
|
||||
},
|
||||
shortName(name) {
|
||||
if (!name) {
|
||||
return "--"
|
||||
}
|
||||
return name.length > 4 ? name.slice(0, 4) : name
|
||||
},
|
||||
barHeight(item) {
|
||||
const count = Number(item.count || 0)
|
||||
if (count <= 0 || this.maxCount <= 0) {
|
||||
return "0%"
|
||||
}
|
||||
return Math.min(76, Math.max(8, count / this.maxCount * 76)) + "%"
|
||||
},
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,248 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.data-metric-panel {
|
||||
position: absolute;
|
||||
right: calc(1.55% - 2px);
|
||||
top: 8.2%;
|
||||
width: calc(28.2% - 140px);
|
||||
height: 28.1%;
|
||||
background: url("${base!}/assets/platform/images/careData/leader/data-metric-panel.png?v=20260527") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.data-metric-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1.3%;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.78);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.data-metric-graph {
|
||||
position: absolute;
|
||||
left: calc(8% + 5px);
|
||||
top: 21%;
|
||||
width: calc(84% + 5px);
|
||||
height: calc(66% + 20px);
|
||||
background: url("${base!}/assets/platform/images/careData/leader/data-metric-graph.png?v=20260527") center center / contain no-repeat;
|
||||
}
|
||||
|
||||
.data-metric-point {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 28%;
|
||||
min-width: 62px;
|
||||
transform: translate(-50%, -50%);
|
||||
color: #1c79dc;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
text-align: center;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 8px rgba(255, 255, 255, 0.9), 0 0 10px rgba(72, 168, 255, 0.42);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.data-metric-point-center {
|
||||
width: 34%;
|
||||
}
|
||||
|
||||
.data-metric-label {
|
||||
margin-top: 2px;
|
||||
overflow: hidden;
|
||||
color: #315d86;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.data-metric-value {
|
||||
overflow: hidden;
|
||||
color: #1683f4;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
line-height: 17px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.data-metric-point-center .data-metric-value {
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
}
|
||||
|
||||
.data-metric-unit {
|
||||
margin-left: 2px;
|
||||
color: #4e6d8d;
|
||||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="data-metric-panel">
|
||||
<div class="data-metric-title">数据指标</div>
|
||||
<div class="data-metric-graph">
|
||||
<div
|
||||
class="data-metric-point"
|
||||
v-for="item in dataMetricPoints"
|
||||
:key="item.key"
|
||||
:class="{ 'data-metric-point-center': item.center }"
|
||||
:style="{ left: item.left, top: item.top }">
|
||||
<div class="data-metric-value">{{ item.value }}<span class="data-metric-unit">{{ item.unit }}</span></div>
|
||||
<div class="data-metric-label">{{ item.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "退出全屏" : "全屏显示" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
dataMetric: {},
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dataMetricPoints() {
|
||||
return [
|
||||
{key: "tourCount", label: "\u7597\u4f11\u517b\u4eba\u6570", value: this.displayNumber(this.dataMetric.tourCount), unit: "\u4eba", left: "12%", top: "19%"},
|
||||
{key: "honorCount", label: "\u52b3\u6a21\u5148\u8fdb", value: this.displayNumber(this.dataMetric.honorCount), unit: "\u4eba", left: "88%", top: "19%"},
|
||||
{key: "difficultCount", label: "\u56f0\u96be\u4eba\u6570", value: this.displayNumber(this.dataMetric.difficultCount), unit: "\u4eba", left: "12%", top: "74%"},
|
||||
{key: "reimburseTotal", label: "\u62a5\u9500\u603b\u6570", value: this.displayMoneyWan(this.dataMetric.reimburseTotal), unit: "\u4e07\u5143", left: "88%", top: "74%"},
|
||||
{key: "budgetTotal", label: "\u9884\u7b97\u603b\u989d", value: this.displayMoneyWan(this.dataMetric.budgetTotal), unit: "\u4e07\u5143", left: "50%", top: "50%", center: true}
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadDataMetricData()
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
methods: {
|
||||
loadDataMetricData() {
|
||||
this.$axios.post("/platform/careData/leader/dataMetricData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
this.dataMetric = res.data || {}
|
||||
})
|
||||
},
|
||||
displayNumber(value) {
|
||||
return Number(value || 0)
|
||||
},
|
||||
displayMoneyWan(value) {
|
||||
const amount = Number(value || 0) / 10000
|
||||
if (amount >= 100) {
|
||||
return Math.round(amount).toString()
|
||||
}
|
||||
if (amount >= 10) {
|
||||
return amount.toFixed(1).replace(/\.0$/, "")
|
||||
}
|
||||
return amount.toFixed(2).replace(/\.?0+$/, "")
|
||||
},
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,599 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #071b36;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.leader-screen {
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
min-width: 1280px;
|
||||
min-height: 720px;
|
||||
overflow: hidden;
|
||||
color: #eaf7ff;
|
||||
background:
|
||||
radial-gradient(circle at 50% 45%, rgba(255, 255, 255, 0.62) 0, rgba(135, 202, 255, 0.4) 26%, transparent 58%),
|
||||
linear-gradient(135deg, #74b8f2 0%, #9acbfb 48%, #6aaee9 100%);
|
||||
}
|
||||
|
||||
.leader-screen::before,
|
||||
.leader-screen::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.leader-screen::before {
|
||||
border: 2px solid rgba(219, 245, 255, 0.58);
|
||||
box-shadow: inset 0 0 34px rgba(24, 126, 220, 0.34);
|
||||
}
|
||||
|
||||
.leader-screen::after {
|
||||
background:
|
||||
linear-gradient(rgba(255, 255, 255, 0.16) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(255, 255, 255, 0.12) 1px, transparent 1px);
|
||||
background-size: 78px 78px;
|
||||
mask-image: radial-gradient(circle at 50% 50%, #000 0, transparent 76%);
|
||||
}
|
||||
|
||||
.screen-header {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
height: 82px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.screen-header::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 22%;
|
||||
right: 22%;
|
||||
height: 72px;
|
||||
border: 2px solid rgba(216, 246, 255, 0.58);
|
||||
border-top: none;
|
||||
border-radius: 0 0 88px 88px;
|
||||
background: linear-gradient(180deg, rgba(39, 144, 255, 0.42), rgba(27, 110, 205, 0.12));
|
||||
box-shadow: 0 12px 28px rgba(23, 94, 180, 0.28), inset 0 -12px 24px rgba(159, 230, 255, 0.36);
|
||||
}
|
||||
|
||||
.screen-title {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin: 0;
|
||||
color: #f8fdff;
|
||||
font-size: 36px;
|
||||
line-height: 58px;
|
||||
font-weight: 700;
|
||||
text-shadow: 0 0 10px rgba(40, 140, 232, 0.9);
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.weather-box,
|
||||
.time-box {
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
z-index: 3;
|
||||
color: rgba(255, 255, 255, 0.94);
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.weather-box {
|
||||
left: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.weather-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle at 35% 35%, #ffe599, #ff9d32 58%, #74c8ff 60%, #d9f4ff 100%);
|
||||
box-shadow: 0 0 14px rgba(255, 207, 99, 0.45);
|
||||
}
|
||||
|
||||
.time-box {
|
||||
right: 28px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.screen-body {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
height: calc(100vh - 92px);
|
||||
padding: 6px 26px 22px;
|
||||
display: grid;
|
||||
grid-template-columns: 400px minmax(520px, 1fr) 400px;
|
||||
grid-template-rows: 300px 1fr 300px;
|
||||
gap: 18px 22px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
border: 1px solid rgba(232, 249, 255, 0.62);
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.18), rgba(77, 162, 229, 0.08));
|
||||
box-shadow: inset 0 0 24px rgba(255, 255, 255, 0.18), 0 10px 28px rgba(25, 103, 183, 0.16);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.panel::before,
|
||||
.panel::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
width: 42px;
|
||||
height: 2px;
|
||||
background: #ffe078;
|
||||
opacity: 0.92;
|
||||
}
|
||||
|
||||
.panel::before {
|
||||
left: 7px;
|
||||
}
|
||||
|
||||
.panel::after {
|
||||
right: 7px;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #f8fdff;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
background: linear-gradient(90deg, rgba(31, 126, 238, 0.18), rgba(54, 159, 255, 0.62), rgba(31, 126, 238, 0.18));
|
||||
text-shadow: 0 0 8px rgba(60, 150, 240, 0.78);
|
||||
}
|
||||
|
||||
.proposal-panel {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
.metrics-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 14px 20px;
|
||||
padding: 18px 16px 14px;
|
||||
}
|
||||
|
||||
.metric-item {
|
||||
position: relative;
|
||||
height: 62px;
|
||||
padding: 10px 12px 9px 70px;
|
||||
border: 1px solid rgba(227, 248, 255, 0.42);
|
||||
background: linear-gradient(90deg, rgba(231, 248, 255, 0.34), rgba(139, 205, 255, 0.12));
|
||||
box-shadow: inset 0 -8px 12px rgba(32, 124, 218, 0.16);
|
||||
}
|
||||
|
||||
.metric-item::after {
|
||||
content: "↑";
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
bottom: 8px;
|
||||
color: rgba(47, 142, 224, 0.72);
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.metric-icon {
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
top: 12px;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, #f4fbff 0, #55c8ff 42%, rgba(34, 139, 227, 0.16) 68%);
|
||||
box-shadow: 0 0 14px rgba(77, 187, 255, 0.7);
|
||||
}
|
||||
|
||||
.metric-icon::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 11px;
|
||||
right: 11px;
|
||||
top: 9px;
|
||||
height: 14px;
|
||||
border-radius: 2px;
|
||||
background: #1d97e6;
|
||||
box-shadow: -7px 9px 0 -2px #1d97e6, 7px 9px 0 -2px #1d97e6;
|
||||
}
|
||||
|
||||
.metric-label {
|
||||
color: rgba(38, 74, 112, 0.86);
|
||||
font-size: 14px;
|
||||
line-height: 1.3;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
margin-top: 3px;
|
||||
color: #1677d8;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.metric-value small {
|
||||
margin-left: 3px;
|
||||
color: rgba(49, 93, 132, 0.76);
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.center-map {
|
||||
grid-column: 2;
|
||||
grid-row: 1 / 3;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.orbit {
|
||||
position: absolute;
|
||||
width: min(78%, 760px);
|
||||
aspect-ratio: 1;
|
||||
border: 1px dashed rgba(255, 255, 255, 0.6);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 60px rgba(255, 255, 255, 0.22);
|
||||
}
|
||||
|
||||
.map-shape {
|
||||
position: relative;
|
||||
width: min(76%, 760px);
|
||||
height: min(58%, 430px);
|
||||
border-radius: 46% 54% 47% 53% / 38% 45% 55% 62%;
|
||||
background:
|
||||
radial-gradient(circle at 74% 33%, rgba(243, 251, 255, 0.95) 0, rgba(68, 168, 255, 0.88) 22%, transparent 23%),
|
||||
radial-gradient(circle at 50% 52%, #5fb3ff 0, #2786f0 58%, #1b69cf 100%);
|
||||
box-shadow: 0 18px 38px rgba(35, 115, 210, 0.36), 0 0 38px rgba(255, 255, 255, 0.6);
|
||||
opacity: 0.88;
|
||||
}
|
||||
|
||||
.map-shape::before,
|
||||
.map-shape::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
background: rgba(37, 129, 232, 0.9);
|
||||
box-shadow: 0 0 22px rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
.map-shape::before {
|
||||
right: -62px;
|
||||
top: 92px;
|
||||
width: 120px;
|
||||
height: 132px;
|
||||
border-radius: 42% 58% 55% 45%;
|
||||
}
|
||||
|
||||
.map-shape::after {
|
||||
right: 42px;
|
||||
bottom: -42px;
|
||||
width: 55px;
|
||||
height: 82px;
|
||||
border-radius: 50%;
|
||||
transform: rotate(18deg);
|
||||
}
|
||||
|
||||
.center-session {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
color: rgba(20, 76, 134, 0.8);
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.placeholder-list {
|
||||
padding: 18px 22px;
|
||||
}
|
||||
|
||||
.placeholder-row {
|
||||
display: grid;
|
||||
grid-template-columns: 34px 1fr 48px;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
height: 40px;
|
||||
color: rgba(39, 73, 111, 0.82);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.placeholder-index {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
background: rgba(58, 151, 236, 0.72);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.placeholder-track {
|
||||
height: 5px;
|
||||
background: rgba(255, 255, 255, 0.38);
|
||||
}
|
||||
|
||||
.placeholder-bar {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #41c79f, #3a96ec);
|
||||
}
|
||||
|
||||
.right-circle {
|
||||
height: calc(100% - 40px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.circle-core {
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
background: radial-gradient(circle, #e8fbff 0, #42bbff 45%, #1f75da 100%);
|
||||
box-shadow: 0 0 30px rgba(38, 135, 230, 0.46);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.circle-core strong {
|
||||
font-size: 34px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.bottom-nav {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 14px;
|
||||
transform: translateX(-50%);
|
||||
z-index: 3;
|
||||
display: flex;
|
||||
gap: 28px;
|
||||
}
|
||||
|
||||
.nav-dot {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(238, 251, 255, 0.72);
|
||||
background: radial-gradient(circle, #ecfbff 0, #59bfff 52%, #2675d4 100%);
|
||||
box-shadow: 0 0 18px rgba(32, 126, 220, 0.42);
|
||||
}
|
||||
|
||||
@media (max-width: 1500px) {
|
||||
.screen-body {
|
||||
grid-template-columns: 360px minmax(480px, 1fr) 360px;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.metrics-grid {
|
||||
gap: 12px;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="leader-screen" v-cloak>
|
||||
<header class="screen-header">
|
||||
<div class="weather-box">
|
||||
<span class="weather-icon"></span>
|
||||
<span>智慧工会 · 领导驾驶舱</span>
|
||||
</div>
|
||||
<h1 class="screen-title">数智工会领导驾驶舱</h1>
|
||||
<div class="time-box">
|
||||
<div>{{ currentDate }}</div>
|
||||
<div>{{ currentTime }}</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="screen-body">
|
||||
<section class="panel proposal-panel">
|
||||
<div class="panel-title">提案征集与办理</div>
|
||||
<div class="metrics-grid">
|
||||
<div class="metric-item">
|
||||
<span class="metric-icon"></span>
|
||||
<div class="metric-label">提案总数</div>
|
||||
<div class="metric-value">{{ overview.total || 0 }}<small>件</small></div>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-icon"></span>
|
||||
<div class="metric-label">立案数量</div>
|
||||
<div class="metric-value">{{ overview.filedCount || 0 }}<small>件</small></div>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-icon"></span>
|
||||
<div class="metric-label">意见建议梳理</div>
|
||||
<div class="metric-value">{{ overview.suggestionCount || 0 }}<small>件</small></div>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-icon"></span>
|
||||
<div class="metric-label">不予立案</div>
|
||||
<div class="metric-value">{{ overview.rejectedCount || 0 }}<small>件</small></div>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-icon"></span>
|
||||
<div class="metric-label">办结数量</div>
|
||||
<div class="metric-value">{{ overview.doneCount || 0 }}<small>件</small></div>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-icon"></span>
|
||||
<div class="metric-label">满意率</div>
|
||||
<div class="metric-value">{{ overview.satisfiedRate || '0%' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="center-map">
|
||||
<div class="center-session">{{ session.fullName || '当前届次' }}</div>
|
||||
<div class="orbit"></div>
|
||||
<div class="map-shape"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-title">专题指标总览</div>
|
||||
<div class="right-circle">
|
||||
<div class="circle-core">
|
||||
<strong>{{ overview.total || 0 }}</strong>
|
||||
<span>提案指标</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-title">办理进度排行</div>
|
||||
<div class="placeholder-list">
|
||||
<div class="placeholder-row" v-for="(item, index) in progressRows" :key="item.name">
|
||||
<span class="placeholder-index">{{ pad(index + 1) }}</span>
|
||||
<div>
|
||||
<div>{{ item.name }}</div>
|
||||
<div class="placeholder-track"><div class="placeholder-bar" :style="{width: item.rate}"></div></div>
|
||||
</div>
|
||||
<span>{{ item.rate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-title">专题模块预留</div>
|
||||
<div class="placeholder-list">
|
||||
<div class="placeholder-row" v-for="(item, index) in reserveRows" :key="item">
|
||||
<span class="placeholder-index">{{ pad(index + 1) }}</span>
|
||||
<div>{{ item }}</div>
|
||||
<span>待接入</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-title">数据趋势预留</div>
|
||||
<div class="placeholder-list">
|
||||
<div class="placeholder-row" v-for="item in trendRows" :key="item.name">
|
||||
<span class="placeholder-index">{{ item.index }}</span>
|
||||
<div>
|
||||
<div>{{ item.name }}</div>
|
||||
<div class="placeholder-track"><div class="placeholder-bar" :style="{width: item.rate}"></div></div>
|
||||
</div>
|
||||
<span>{{ item.rate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-title">重点数据预留</div>
|
||||
<div class="placeholder-list">
|
||||
<div class="placeholder-row" v-for="item in keyRows" :key="item.name">
|
||||
<span class="placeholder-index">{{ item.index }}</span>
|
||||
<div>{{ item.name }}</div>
|
||||
<span>{{ item.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<nav class="bottom-nav">
|
||||
<span class="nav-dot"></span>
|
||||
<span class="nav-dot"></span>
|
||||
<span class="nav-dot"></span>
|
||||
<span class="nav-dot"></span>
|
||||
<span class="nav-dot"></span>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
timer: null,
|
||||
currentDate: "",
|
||||
currentTime: "",
|
||||
session: {},
|
||||
overview: {},
|
||||
progressRows: [
|
||||
{name: "提案征集", rate: "87%"},
|
||||
{name: "立案办理", rate: "82%"},
|
||||
{name: "承办答复", rate: "68%"},
|
||||
{name: "结果反馈", rate: "43%"},
|
||||
{name: "满意评价", rate: "36%"}
|
||||
],
|
||||
reserveRows: ["职工关爱专题", "工会经费专题", "活动服务专题", "荣誉建设专题"],
|
||||
trendRows: [
|
||||
{index: "01", name: "年度提案趋势", rate: "78%"},
|
||||
{index: "02", name: "办理效率趋势", rate: "64%"},
|
||||
{index: "03", name: "满意度趋势", rate: "72%"}
|
||||
],
|
||||
keyRows: [
|
||||
{index: "01", name: "专题指标标题", value: "256"},
|
||||
{index: "02", name: "专题指标标题", value: "205"},
|
||||
{index: "03", name: "专题指标标题", value: "123"}
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.updateTime()
|
||||
this.timer = setInterval(this.updateTime, 1000)
|
||||
this.loadProposalData()
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.timer)
|
||||
},
|
||||
methods: {
|
||||
loadProposalData() {
|
||||
this.$axios.post("/platform/careData/leader/proposalData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.session = data.session || {}
|
||||
this.overview = data.overview || {}
|
||||
})
|
||||
},
|
||||
updateTime() {
|
||||
const now = new Date()
|
||||
const week = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"][now.getDay()]
|
||||
this.currentDate = now.getFullYear() + "-" + this.pad(now.getMonth() + 1) + "-" + this.pad(now.getDate()) + " " + week
|
||||
this.currentTime = this.pad(now.getHours()) + ":" + this.pad(now.getMinutes()) + ":" + this.pad(now.getSeconds())
|
||||
},
|
||||
pad(value) {
|
||||
return String(value).padStart(2, "0")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,142 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
position: absolute;
|
||||
min-width: 86px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #1b83e9;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.75);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.metric-value::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: -2px -8px;
|
||||
z-index: -1;
|
||||
background: rgba(189, 224, 252, 0.54);
|
||||
filter: blur(3px);
|
||||
}
|
||||
|
||||
.metric-value small {
|
||||
margin-left: 3px;
|
||||
color: rgba(43, 105, 159, 0.82);
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.metric-total {
|
||||
left: 5.8%;
|
||||
top: 16.7%;
|
||||
}
|
||||
|
||||
.metric-filed {
|
||||
left: 15.9%;
|
||||
top: 16.7%;
|
||||
}
|
||||
|
||||
.metric-suggestion {
|
||||
left: 5.8%;
|
||||
top: 24.2%;
|
||||
}
|
||||
|
||||
.metric-rejected {
|
||||
left: 15.9%;
|
||||
top: 24.2%;
|
||||
}
|
||||
|
||||
.metric-done {
|
||||
left: 5.8%;
|
||||
top: 31.7%;
|
||||
}
|
||||
|
||||
.metric-satisfied {
|
||||
left: 15.9%;
|
||||
top: 31.7%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<div class="metric-value metric-total">{{ displayNumber(overview.total) }}<small>件</small></div>
|
||||
<div class="metric-value metric-filed">{{ displayNumber(overview.filedCount) }}<small>件</small></div>
|
||||
<div class="metric-value metric-suggestion">{{ displayNumber(overview.suggestionCount) }}<small>件</small></div>
|
||||
<div class="metric-value metric-rejected">{{ displayNumber(overview.rejectedCount) }}<small>件</small></div>
|
||||
<div class="metric-value metric-done">{{ displayNumber(overview.doneCount) }}<small>件</small></div>
|
||||
<div class="metric-value metric-satisfied">{{ overview.satisfiedRate || "0%" }}</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
overview: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadProposalData()
|
||||
},
|
||||
methods: {
|
||||
loadProposalData() {
|
||||
this.$axios.post("/platform/careData/leader/proposalData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.overview = data.overview || {}
|
||||
})
|
||||
},
|
||||
displayNumber(value) {
|
||||
return Number(value || 0)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,260 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.proposal-panel {
|
||||
position: absolute;
|
||||
left: 1.35%;
|
||||
top: 8.2%;
|
||||
width: 20.82%;
|
||||
height: 27.65%;
|
||||
background: url("${base!}/assets/platform/images/careData/leader/proposal-panel.png?v=20260526") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.proposal-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1.3%;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
|
||||
.proposal-card-grid {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
.proposal-card {
|
||||
position: absolute;
|
||||
width: 44%;
|
||||
height: 19.2%;
|
||||
background: var(--card-bg) center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.proposal-card-total {
|
||||
left: calc(4.3% - 2px);
|
||||
top: 18.5%;
|
||||
}
|
||||
|
||||
.proposal-card-filed {
|
||||
left: 51.7%;
|
||||
top: 18.5%;
|
||||
}
|
||||
|
||||
.proposal-card-total {
|
||||
height: calc(25.6% + 3px);
|
||||
}
|
||||
|
||||
.proposal-card-filed {
|
||||
height: calc(25.6% + 2px);
|
||||
}
|
||||
|
||||
.proposal-card-suggestion {
|
||||
left: calc(4.3% - 1px);
|
||||
top: calc(41.3% + 10px);
|
||||
height: calc(19.8% + 20px);
|
||||
}
|
||||
|
||||
.proposal-card-rejected {
|
||||
left: calc(51.7% + 2px);
|
||||
top: calc(41.3% + 10px);
|
||||
height: calc(19.8% + 20px);
|
||||
}
|
||||
|
||||
.proposal-card-done {
|
||||
left: calc(4.3% - 1px);
|
||||
top: calc(65.2% + 20px);
|
||||
height: calc(19.8% + 20px);
|
||||
}
|
||||
|
||||
.proposal-card-satisfied {
|
||||
left: 51.7%;
|
||||
top: calc(65.2% + 20px);
|
||||
height: calc(19.8% + 20px);
|
||||
}
|
||||
|
||||
.proposal-label {
|
||||
position: absolute;
|
||||
left: 38.5%;
|
||||
top: 20%;
|
||||
max-width: 50%;
|
||||
overflow: hidden;
|
||||
color: #304f70;
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
letter-spacing: 0;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.proposal-value {
|
||||
position: absolute;
|
||||
left: calc(38.5% + 23px);
|
||||
top: 48%;
|
||||
max-width: 50%;
|
||||
overflow: hidden;
|
||||
color: #1683f4;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
line-height: 17px;
|
||||
letter-spacing: 0;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 0 8px rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="proposal-panel">
|
||||
<div class="proposal-title">提案征集和办理</div>
|
||||
<div class="proposal-card-grid">
|
||||
<article class="proposal-card" v-for="item in proposalMetrics" :key="item.key" :class="'proposal-card-' + item.key" :style="{ '--card-bg': 'url(' + item.bg + ')' }">
|
||||
<div class="proposal-label">{{ item.label }}</div>
|
||||
<div class="proposal-value">{{ item.value }}</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "\u9000\u51fa\u5168\u5c4f" : "\u5168\u5c4f\u663e\u793a" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
overview: {},
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
proposalMetrics() {
|
||||
const imagePath = "${base!}/assets/platform/images/careData/leader/"
|
||||
return [
|
||||
{key: "total", label: "\u63d0\u6848\u603b\u6570", value: this.displayNumber(this.overview.total), bg: imagePath + "proposal-card-total.png?v=20260526"},
|
||||
{key: "filed", label: "\u7acb\u6848\u6570\u91cf", value: this.displayNumber(this.overview.filedCount), bg: imagePath + "proposal-card-filed.png?v=20260526"},
|
||||
{key: "suggestion", label: "\u610f\u89c1\u5efa\u8bae", value: this.displayNumber(this.overview.suggestionCount), bg: imagePath + "proposal-card-suggestion.png?v=20260526"},
|
||||
{key: "rejected", label: "\u4e0d\u4e88\u7acb\u6848", value: this.displayNumber(this.overview.rejectedCount), bg: imagePath + "proposal-card-rejected.png?v=20260526"},
|
||||
{key: "done", label: "\u529e\u7ed3\u6570\u91cf", value: this.displayNumber(this.overview.doneCount), bg: imagePath + "proposal-card-done.png?v=20260526"},
|
||||
{key: "satisfied", label: "\u6ee1\u610f\u7387", value: this.overview.satisfiedRate || "0%", bg: imagePath + "proposal-card-satisfied.png?v=20260526"}
|
||||
]
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.loadProposalData()
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
methods: {
|
||||
loadProposalData() {
|
||||
this.$axios.post("/platform/careData/leader/proposalData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.overview = data.overview || {}
|
||||
})
|
||||
},
|
||||
displayNumber(value) {
|
||||
return Number(value || 0)
|
||||
},
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,173 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.staff-home-panel {
|
||||
position: absolute;
|
||||
left: 24.1%;
|
||||
top: 22.5%;
|
||||
width: 53.1%;
|
||||
height: 63.5%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.staff-home-title {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
min-width: 168px;
|
||||
height: 30px;
|
||||
padding: 0 28px;
|
||||
transform: translateX(-50%);
|
||||
background: linear-gradient(90deg, rgba(78, 161, 246, 0.08), rgba(79, 169, 255, 0.88), rgba(78, 161, 246, 0.08));
|
||||
border-top: 1px solid rgba(214, 241, 255, 0.7);
|
||||
border-bottom: 1px solid rgba(83, 173, 255, 0.48);
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 28px;
|
||||
text-align: center;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 8px rgba(255, 255, 255, 0.85), 0 0 12px rgba(57, 151, 255, 0.72);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.staff-home-map-wrap {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 30px;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: radial-gradient(circle at center, rgba(181, 223, 255, 0.3), rgba(54, 145, 235, 0.08) 56%, rgba(54, 145, 235, 0));
|
||||
}
|
||||
|
||||
.staff-home-map {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -40px;
|
||||
top: -100px;
|
||||
width: calc(100% + 100px);
|
||||
height: calc(100% + 100px);
|
||||
max-width: none;
|
||||
max-height: none;
|
||||
object-fit: fill;
|
||||
filter: drop-shadow(0 0 18px rgba(91, 177, 255, 0.52));
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="staff-home-panel">
|
||||
<div class="staff-home-title">职工小家</div>
|
||||
<div class="staff-home-map-wrap">
|
||||
<img class="staff-home-map" src="${base!}/assets/platform/images/careData/leader/staff-home-campus-map.png?v=20260527" alt="">
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "\u9000\u51fa\u5168\u5c4f" : "\u5168\u5c4f\u663e\u793a" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
methods: {
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||