diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/caredata/CareDataLeaderCon.java b/src/main/java/com/budwk/app/zhgh/dayofficework/caredata/CareDataLeaderCon.java index efb987d..89660d9 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/caredata/CareDataLeaderCon.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/caredata/CareDataLeaderCon.java @@ -96,6 +96,12 @@ public class CareDataLeaderCon { return Result.success(careDataLeaderService.dataMetricData(year)); } + @At + @SaCheckPermission("careData.union") + public Result memberOverviewData() { + return Result.success(careDataLeaderService.memberOverviewData()); + } + @At @SaCheckPermission("careData.union") public Result assetDataData() { diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/caredata/service/CareDataLeaderService.java b/src/main/java/com/budwk/app/zhgh/dayofficework/caredata/service/CareDataLeaderService.java index d65f43d..f4d0e73 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/caredata/service/CareDataLeaderService.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/caredata/service/CareDataLeaderService.java @@ -45,6 +45,13 @@ public interface CareDataLeaderService { */ NutMap dataMetricData(Integer year); + /** + * 查询会员总数和男女会员数。 + * + * @return 会员概览数据,包含 total、male、female、unknown。 + */ + NutMap memberOverviewData(); + /** * 查询资产使用状态分布。 * diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/caredata/service/impl/CareDataLeaderServiceImpl.java b/src/main/java/com/budwk/app/zhgh/dayofficework/caredata/service/impl/CareDataLeaderServiceImpl.java index c8b67c6..cfb5036 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/caredata/service/impl/CareDataLeaderServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/caredata/service/impl/CareDataLeaderServiceImpl.java @@ -91,13 +91,38 @@ public class CareDataLeaderServiceImpl implements CareDataLeaderService { int targetYear = year == null ? LocalDate.now().getYear() : year; return NutMap.NEW() .addv("year", targetYear) - .addv("budgetTotal", schoolBudgetTotal(targetYear)) + .addv("budgetTotal", budgetTotal(targetYear)) .addv("tourCount", tourCount(targetYear)) .addv("honorCount", honorCount(targetYear)) .addv("difficultCount", difficultCount(targetYear)) .addv("reimburseTotal", reimburseTotal(targetYear)); } + @Override + public NutMap memberOverviewData() { + Sql sql = Sqls.create(""" + SELECT + COUNT(1) AS total, + IFNULL(SUM(CASE WHEN sex = '男' THEN 1 ELSE 0 END), 0) AS male, + IFNULL(SUM(CASE WHEN sex = '女' THEN 1 ELSE 0 END), 0) AS female + FROM vw_user + WHERE member = 1 + $unionFilter + """); + setUnionFilter(sql, "unionId", null); + NutMap memberOverview = firstMap(sql); + long total = memberOverview.getLong("total", 0L); + long male = memberOverview.getLong("male", 0L); + long female = memberOverview.getLong("female", 0L); + // 部分会员性别为空或不是“男/女”,总数需要保留这部分人员。 + long unknown = Math.max(0L, total - male - female); + return NutMap.NEW() + .addv("total", total) + .addv("male", male) + .addv("female", female) + .addv("unknown", unknown); + } + @Override public NutMap assetDataData() { List states = assetUsageStateRows(); @@ -220,14 +245,41 @@ public class CareDataLeaderServiceImpl implements CareDataLeaderService { 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); + private BigDecimal budgetTotal(int year) { + Sql sql; + if (canViewAllUnionData()) { + sql = Sqls.create(""" + SELECT IFNULL(SUM(totalQuota), 0) AS total + FROM ( + SELECT totalQuota + FROM outlay_manage_school + WHERE delFlag = 0 + AND `year` = @year + UNION ALL + SELECT totalQuota + FROM outlay_manage_union + WHERE delFlag = 0 + AND `year` = @year + UNION ALL + SELECT totalQuota + FROM outlay_manage_club + WHERE delFlag = 0 + AND `year` = @year + ) budget + """); + sql.setParam("year", year); + } else { + // 普通分工会用户只能看到本分工会预算,校级和社团预算不挂具体分工会。 + sql = Sqls.create(""" + SELECT IFNULL(SUM(totalQuota), 0) AS total + FROM outlay_manage_union + WHERE delFlag = 0 + AND `year` = @year + AND unionId = @unionId + """); + sql.setParam("year", year); + sql.setParam("unionId", SecurityUtil.getUnionId()); + } return decimalValue(firstMap(sql), "total"); } diff --git a/src/main/resources/static/assets/platform/images/careData/leader/staff-home-campus-map.png b/src/main/resources/static/assets/platform/images/careData/leader/staff-home-campus-map.png index 0fb8cf9..2e07b85 100644 Binary files a/src/main/resources/static/assets/platform/images/careData/leader/staff-home-campus-map.png and b/src/main/resources/static/assets/platform/images/careData/leader/staff-home-campus-map.png differ diff --git a/src/main/resources/static/components/plugins/sysUpload/h5Index.vue b/src/main/resources/static/components/plugins/sysUpload/h5Index.vue index e818518..dfb6ed4 100644 --- a/src/main/resources/static/components/plugins/sysUpload/h5Index.vue +++ b/src/main/resources/static/components/plugins/sysUpload/h5Index.vue @@ -104,29 +104,16 @@ module.exports = { if (val) { if (Array.isArray(val)) { this.fileList = val.map((v) => { - return { - ...v, - status: null, - isImage: ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(v.name.split(".").pop().toLowerCase()) - } + return this.normalizeFile(v) }) } else if(typeof val === "string") { this.fileList = [ - { - url: val, - status: null, - isImage: true - } + this.normalizeFile(val) ] } else { val = JSON.parse(val) this.fileList = val.map((v) => { - return { - ...v, - url: v.url ? v.url : v.response?.data, - isImage: ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(v.name.split(".").pop().toLowerCase()), - status: null - } + return this.normalizeFile(v) }) } } else { @@ -142,14 +129,50 @@ module.exports = { } }, methods: { + // 统一历史数据和上传返回数据的文件名、地址字段,避免 Vant 回显时把下载路径当文件名显示。 + normalizeFile(file) { + const data = typeof file === "string" ? {url: file} : Object.assign({}, file) + const responseData = data.response && data.response.data ? data.response.data : "" + const url = data.url || responseData || data.downloadPath || data.path || "" + const name = data.name || data.fileName || data.originalName || data.originalFilename || this.getFileNameFromUrl(url) || "附件" + data.url = url + data.name = name + data.file = {name: name} + data.status = null + data.isImage = this.isImageFile(name) + delete data.content + return data + }, + // 同步父组件前移除原始 File 对象,避免表单 JSON 保存时带入不可序列化内容。 + getCleanFileList() { + return this.fileList.map((file) => { + const data = Object.assign({}, file) + delete data.file + delete data.content + return data + }) + }, + getFileNameFromUrl(url) { + if (!url || typeof url !== "string") { + return "" + } + const cleanUrl = url.split("?")[0].split("#")[0] + const splitUrl = cleanUrl.split("/") + const fileName = splitUrl[splitUrl.length - 1] + return fileName && fileName.indexOf(".") > -1 ? decodeURIComponent(fileName) : "" + }, + isImageFile(name) { + if (!name || typeof name !== "string" || name.indexOf(".") === -1) { + return false + } + const suffix = name.split(".").pop().toLowerCase() + return ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(suffix) + }, beforeDelete(file) { this.fileList = this.fileList.filter((f) => f.url !== file.url) - this.$emit("update:value", this.fileList) + this.$emit("update:value", this.getCleanFileList()) }, beforeRead(file) { - debugger - console.log(file) - console.log(this.upload_size) if (file.size > this.upload_size) { this.$toast("文件过大,请上传小于" + (this.upload_size / 1024 / 1024).toFixed(2) + "M的文件!") return false @@ -178,7 +201,7 @@ module.exports = { if (valid) { return true } - this.$toast(`文件只能是 ${this.accept} 格式!`) + this.$toast("文件只能是 " + this.accept + " 格式!") return false }, afterRead(files) { @@ -200,8 +223,8 @@ module.exports = { f.url = resp.data f.response = resp f.percentage = 100 - f.isImage = true - delete f.file + f.isImage = this.isImageFile(f.name) + f.file = {name: f.name} delete f.content } else { f.status = "fail" @@ -213,7 +236,7 @@ module.exports = { if (this.upload_result_category === "interval") { } else if (this.upload_result_category === "array") { if (this.complete_result) { - this.$emit("update:value", this.fileList) + this.$emit("update:value", this.getCleanFileList()) } else { const resultArrayValue = [] this.fileList.forEach((data) => { diff --git a/src/main/resources/views/layouts/v4/baseLayout.html b/src/main/resources/views/layouts/v4/baseLayout.html index 8cd7dfa..8f8b03a 100644 --- a/src/main/resources/views/layouts/v4/baseLayout.html +++ b/src/main/resources/views/layouts/v4/baseLayout.html @@ -494,13 +494,16 @@ padding: 0 14px; border-radius: 18px; color: #ffffff; + cursor: pointer; font-size: 12px; font-weight: 700; + font-family: inherit; line-height: 1; text-decoration: none; white-space: nowrap; background: linear-gradient(90deg, #f5a300 0%, #ff8e00 42%, #ff4b16 100%); border: 1px solid rgba(255, 247, 184, 0.9); + outline: none; box-shadow: inset 0 2px 4px rgba(255, 255, 255, 0.48), 0 2px 6px rgba(141, 53, 0, 0.25); transition: transform 0.2s ease, box-shadow 0.2s ease; } @@ -738,9 +741,9 @@
- +