Compare commits
6
Commits
28d8b14bab
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6082aedf03 | ||
|
|
503072e5b1 | ||
|
|
6c0489b66c | ||
|
|
360ce71f0b | ||
|
|
f2fda8202a | ||
|
|
0a431bf86e |
+1
-8
@@ -6,7 +6,6 @@ import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.DesensitizedUtil;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.zhgh.staffmanage.member.param.pageform.MemberStatisticsPageForm;
|
||||
@@ -54,13 +53,7 @@ public class MemberComprehensiveController {
|
||||
@At
|
||||
@SaCheckPermission("member.statistics.comprehensive")
|
||||
public Result pageData(MemberStatisticsPageForm pageForm) {
|
||||
Sql sql = memberStatisticsService.getComprehensiveSql(pageForm);
|
||||
Pagination<NutMap> pagination = memberStatisticsService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
for (NutMap row : pagination.getList()) {
|
||||
row.put("mobile", DesensitizedUtil.mobilePhone(row.getString("mobile")));
|
||||
row.put("idCard", DesensitizedUtil.idCardNum(row.getString("idCard"), 3, 4));
|
||||
}
|
||||
return Result.success(pagination);
|
||||
return Result.success(memberStatisticsService.getComprehensivePage(pageForm));
|
||||
}
|
||||
|
||||
|
||||
|
||||
+8
@@ -1,6 +1,7 @@
|
||||
package com.budwk.app.zhgh.staffmanage.member.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.zhgh.staffmanage.member.param.pageform.MemberStatisticsPageForm;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
@@ -33,6 +34,13 @@ public interface MemberStatisticsService extends BaseService<Sys_user> {
|
||||
*/
|
||||
Sql getComprehensiveSql(MemberStatisticsPageForm pageForm);
|
||||
|
||||
/**
|
||||
* 查询综合查询列表,证件号码是否脱敏由当前登录人的角色决定。
|
||||
* @param pageForm 列表筛选、排序和分页条件,不接受调用方指定脱敏权限
|
||||
* @return 分页结果,list中的mobile始终脱敏;idCard仅系统管理员或校工会管理员可见原值
|
||||
*/
|
||||
Pagination<NutMap> getComprehensivePage(MemberStatisticsPageForm pageForm);
|
||||
|
||||
|
||||
/**
|
||||
* 获取工会分析数据
|
||||
|
||||
+18
@@ -7,6 +7,8 @@ import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.DesensitizedUtil;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
@@ -44,6 +46,22 @@ public class MemberStatisticsServiceImpl extends BaseServiceImpl<Sys_user> imple
|
||||
super(dao);
|
||||
}
|
||||
|
||||
/** 列表沿用原查询范围,只按登录角色调整证件号码展示,不改变手机号及导出规则。 */
|
||||
@Override
|
||||
public Pagination<NutMap> getComprehensivePage(MemberStatisticsPageForm pageForm) {
|
||||
Sql sql = getComprehensiveSql(pageForm);
|
||||
Pagination<NutMap> pagination = listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
boolean showFullIdCard = AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
|
||||
for (NutMap row : pagination.getList()) {
|
||||
row.put("mobile", DesensitizedUtil.mobilePhone(row.getString("mobile")));
|
||||
// 角色取自服务端会话;同时拥有普通角色的管理员仍按管理员展示原始证件号码。
|
||||
if (!showFullIdCard) {
|
||||
row.put("idCard", DesensitizedUtil.idCardNum(row.getString("idCard"), 3, 4));
|
||||
}
|
||||
}
|
||||
return pagination;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Cnd getCnd(MemberStatisticsPageForm pageForm) {
|
||||
|
||||
@@ -347,6 +347,19 @@ module.exports = {
|
||||
|
||||
// 预览图片
|
||||
handlePreview(file) {
|
||||
if (this.upload_mode === "image") {
|
||||
// 回显记录的名称可能是无扩展名的下载地址;图片模式直接预览缩略图地址。
|
||||
const url = file.url || (this.upload_result_type === "url" && file.response?.data)
|
||||
if (!url) {
|
||||
this.$message.warning("暂无可预览的图片")
|
||||
return
|
||||
}
|
||||
const image = new Image()
|
||||
image.src = url
|
||||
const viewer = new Viewer(image, {zIndex: 99999, title: false, hidden: () => viewer.destroy()})
|
||||
viewer.show()
|
||||
return
|
||||
}
|
||||
const suffix = file.name.substring(file.name.lastIndexOf(".") + 1).toLowerCase()
|
||||
const fileId = file.response.data.substring(file.response.data.lastIndexOf("=") + 1)
|
||||
const buildFile = {
|
||||
|
||||
@@ -75,7 +75,11 @@ const optionSelect = {
|
||||
class="option-tag" type="primary" effect="plain">已选择
|
||||
</el-tag>
|
||||
|
||||
<div class="option-image">
|
||||
<div class="option-image" role="button" :tabindex="option.imgUrl ? 0 : -1"
|
||||
aria-label="预览福利图片" :aria-disabled="option.imgUrl ? 'false' : 'true'"
|
||||
@click.stop="previewOptionImage(option.imgUrl)"
|
||||
@keydown.enter.stop.prevent="previewOptionImage(option.imgUrl)"
|
||||
@keydown.space.stop.prevent="previewOptionImage(option.imgUrl)">
|
||||
<el-image :src="option.imgUrl" fit="cover"></el-image>
|
||||
</div>
|
||||
|
||||
@@ -605,6 +609,15 @@ const optionSelect = {
|
||||
}
|
||||
},
|
||||
|
||||
previewOptionImage(url) {
|
||||
if (!url) return
|
||||
// 福利图片地址可能没有扩展名,直接预览原图,不触发福利选择。
|
||||
const image = new Image()
|
||||
image.src = url
|
||||
const viewer = new Viewer(image, {zIndex: 99999, title: false, hidden: () => viewer.destroy()})
|
||||
viewer.show()
|
||||
},
|
||||
|
||||
// 显示选项详情
|
||||
showOptionDetail(option) {
|
||||
// 阻止事件冒泡,避免触发父元素的点击事件
|
||||
@@ -886,6 +899,7 @@ const optionSelect = {
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, var(--primary-color), #66b1ff);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* 选项标签 */
|
||||
@@ -894,6 +908,7 @@ const optionSelect = {
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
@@ -918,6 +933,10 @@ const optionSelect = {
|
||||
background: linear-gradient(to top, rgba(0, 0, 0, 0.2), transparent);
|
||||
}
|
||||
|
||||
/deep/ .option-image[aria-disabled="false"] {
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
/deep/ .option-image .el-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
@@ -10,13 +10,48 @@ layout("/layouts/platform_h5.html"){
|
||||
box-shadow: 0 8px 12px #ebedf0;
|
||||
text-align: center !important;
|
||||
}
|
||||
.info-container {
|
||||
margin-bottom: 60px;
|
||||
.activity-info-sheet {
|
||||
height: 90vh;
|
||||
height: 90dvh;
|
||||
max-height: 90vh;
|
||||
max-height: 90dvh;
|
||||
}
|
||||
.button {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
.activity-info-sheet .van-action-sheet__content {
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.activity-info-sheet .info-container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
flex-direction: column;
|
||||
}
|
||||
.activity-info-sheet .info-body {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
/* PDF内部使用百分比高度,必须提供明确的预览高度;外层正文仍可滚动查看封面和全文。 */
|
||||
.activity-info-sheet .info-preview {
|
||||
height: 60vh;
|
||||
height: 60dvh;
|
||||
min-height: 260px;
|
||||
}
|
||||
.activity-info-sheet .info-preview > div {
|
||||
height: 100%;
|
||||
}
|
||||
.activity-info-sheet .info-preview .content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
.activity-info-sheet .button {
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
background: #fff;
|
||||
}
|
||||
.info-img {
|
||||
display: block;
|
||||
@@ -27,7 +62,7 @@ layout("/layouts/platform_h5.html"){
|
||||
</style>
|
||||
|
||||
<div id="app">
|
||||
<van-nav-bar title="品牌活动" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
<van-nav-bar title="品牌活动" left-text="返回" left-arrow @click-left="onNavBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<van-sticky offset-top="46px">
|
||||
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||
@@ -67,13 +102,14 @@ layout("/layouts/platform_h5.html"){
|
||||
</template>
|
||||
</table-list>
|
||||
|
||||
<van-action-sheet :close-on-click-overlay="false" title="详细信息" v-model="infoVisible">
|
||||
<van-action-sheet class="activity-info-sheet" :close-on-click-overlay="false" title="详细信息"
|
||||
:value="infoVisible" @input="visible => { if (!visible) closeInfo() }">
|
||||
|
||||
<div class="info-container">
|
||||
<div>
|
||||
<van-image class="info-img" height="186" width="100%" :src="infoRow.cover"></van-image>
|
||||
<div class="info-body">
|
||||
<van-image class="info-img" height="124" width="100%" :src="infoRow.cover"></van-image>
|
||||
<div class="info-title">{{infoRow.activityName}}</div>
|
||||
<pdf-preview :content="infoRow.introduce"></pdf-preview>
|
||||
<div class="info-preview"><pdf-preview :content="infoRow.introduce"></pdf-preview></div>
|
||||
</div>
|
||||
<div class="button">
|
||||
<van-button @click="onApply(infoRow)" type="primary" block>
|
||||
@@ -82,7 +118,7 @@ layout("/layouts/platform_h5.html"){
|
||||
</span>
|
||||
<template v-else>
|
||||
距离开始
|
||||
<van-count-down :time="Math.abs(time)" class="count-down" format="DD 天 HH 时 mm 分 ss 秒" @finish="time = 0"></van-count-down>
|
||||
<van-count-down :time="Math.abs(time)" class="count-down" format="DD 天 HH 时 mm 分 ss 秒" @finish="this.$set(this, 'time', 0)"></van-count-down>
|
||||
</template>
|
||||
</van-button>
|
||||
</div>
|
||||
@@ -100,6 +136,9 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
popupOwnerId: 'train-activity-info-' + Date.now(),
|
||||
infoClosing: false,
|
||||
pageDisposed: false,
|
||||
time: 0,
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
@@ -116,35 +155,45 @@ layout("/layouts/platform_h5.html"){
|
||||
],
|
||||
infoVisible: false,
|
||||
infoRow: {},
|
||||
|
||||
id: GetQueryString('id')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onView(row) {
|
||||
this.infoRow = row
|
||||
this.time = this.$moment().diff(this.$moment(row.activitySignUpStartTime), 'milliseconds')
|
||||
this.infoVisible = true
|
||||
if (this.pageDisposed || this.infoClosing) return
|
||||
// 详情只由列表中的“查看介绍”点击打开,不根据链接参数或报名操作自动打开。
|
||||
this.$set(this, 'infoRow', row)
|
||||
this.$set(this, 'time', this.$moment().diff(this.$moment(row.activitySignUpStartTime), 'milliseconds'))
|
||||
this.$set(this, 'infoVisible', true)
|
||||
// 重复查看仅更新内容,不重复压入历史;关闭和系统返回统一交给全局栈。
|
||||
window.mobilePopupHistory.open(this.popupOwnerId, 'info')
|
||||
},
|
||||
closeInfo() {
|
||||
if (!this.infoVisible || this.infoClosing) return
|
||||
// 回退为异步操作:立即隐藏并锁定本次关闭,防止连点产生多次历史回退。
|
||||
this.$set(this, 'infoClosing', true)
|
||||
this.$set(this, 'infoVisible', false)
|
||||
window.mobilePopupHistory.close(this.popupOwnerId, 'info')
|
||||
},
|
||||
onInfoHistoryClose() {
|
||||
// 系统返回和关闭按钮共用回调,关闭后允许用户再次主动查看。
|
||||
this.$set(this, 'infoVisible', false)
|
||||
this.$set(this, 'infoClosing', false)
|
||||
},
|
||||
onNavBack() {
|
||||
if (window.mobilePopupHistory.hasOpen(this.popupOwnerId)) this.closeInfo()
|
||||
else historyBack()
|
||||
},
|
||||
onApply(row) {
|
||||
if(this.$moment().isBefore(this.$moment(row.activitySignUpStartTime))) {
|
||||
this.onView(row)
|
||||
this.$toast('报名尚未开始')
|
||||
return
|
||||
}
|
||||
window.mobilePopupHistory.clear(this.popupOwnerId)
|
||||
this.$pjaxReplace('/platform/trainSignUp/apply/list/h5?id=' + row.id)
|
||||
},
|
||||
fetchOne() {
|
||||
this.$axios.post('/platform/trainSignUp/manage/findOne', {id: this.id}).then((res) => {
|
||||
if(res.code === 0) {
|
||||
this.onView(res.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
onReady() {
|
||||
// 首次进入和组件重新就绪都只加载列表,不触发详情弹窗。
|
||||
this.doSearch()
|
||||
if(this.id) {
|
||||
this.fetchOne()
|
||||
}
|
||||
},
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
@@ -154,8 +203,12 @@ layout("/layouts/platform_h5.html"){
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
created() {
|
||||
window.mobilePopupHistory.register(this.popupOwnerId, () => this.onInfoHistoryClose())
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$set(this, 'pageDisposed', true)
|
||||
window.mobilePopupHistory.unregister(this.popupOwnerId)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -707,9 +707,8 @@ layout("/layouts/platform_h5.html"){
|
||||
:key="option.id"
|
||||
class="welfare-option"
|
||||
:class="{ selected: projectInfo.isCheckBox === 'radio' ? selectedRadioId === option.id : option.selectNum > 0 }"
|
||||
@click="projectInfo.isCheckBox === 'radio' && !isDeadlinePassed ? selectRadioOption(option.id) : null"
|
||||
>
|
||||
<div class="welfare-option-image">
|
||||
<div class="welfare-option-image" @click.stop="previewOptionImage(option.imgUrl)">
|
||||
<van-image :src="option.imgUrl" fit="cover" width="100%" height="100%" radius="4px"></van-image>
|
||||
<div class="welfare-tag"
|
||||
v-if="projectInfo.isCheckBox === 'radio' ? selectedRadioId === option.id : option.selectNum > 0">
|
||||
@@ -717,7 +716,8 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="welfare-option-content">
|
||||
<div class="welfare-option-content"
|
||||
@click="projectInfo.isCheckBox === 'radio' && !isDeadlinePassed ? selectRadioOption(option.id) : null">
|
||||
<div class="welfare-option-title">{{ option.optionName }}</div>
|
||||
|
||||
<!-- 查看详情按钮 -->
|
||||
@@ -846,6 +846,10 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
</van-action-sheet>
|
||||
|
||||
<van-image-preview :value="showOptionImagePreview" :images="optionPreviewImages"
|
||||
closeable :show-index="false" :close-on-popstate="false"
|
||||
@input="visible => { if (!visible) closeOptionImagePreview() }"></van-image-preview>
|
||||
|
||||
<!-- 选项详情弹窗 -->
|
||||
<van-popup v-model="showOptionDetailDialog" round closeable close-icon="close" position="bottom"
|
||||
:close-on-click-overlay="false"
|
||||
@@ -932,6 +936,8 @@ layout("/layouts/platform_h5.html"){
|
||||
isSubmitting: false,
|
||||
hasSubmittedBefore: false, // 是否之前提交过
|
||||
showOptionDetailDialog: false, // 选项详情弹窗
|
||||
showOptionImagePreview: false,
|
||||
optionPreviewImages: [],
|
||||
selectedOption: null, // 当前选中的选项
|
||||
popupHistoryOwner: "welfare-select-" + Date.now(),
|
||||
detailScale: 1,
|
||||
@@ -1347,6 +1353,21 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
// 显示选项详情
|
||||
previewOptionImage(url) {
|
||||
if (!url || this.showOptionImagePreview) return
|
||||
// 图片预览不修改选项状态,返回键只关闭当前预览层。
|
||||
this.$set(this, "optionPreviewImages", [url])
|
||||
this.$set(this, "showOptionImagePreview", true)
|
||||
window.mobilePopupHistory.open(this.popupHistoryOwner, "optionImage")
|
||||
},
|
||||
|
||||
closeOptionImagePreview() {
|
||||
if (!this.showOptionImagePreview) return
|
||||
// 先隐藏,防止关闭动画期间的重复点击触发多次历史回退。
|
||||
this.$set(this, "showOptionImagePreview", false)
|
||||
window.mobilePopupHistory.close(this.popupHistoryOwner, "optionImage")
|
||||
},
|
||||
|
||||
showOptionDetail(option) {
|
||||
this.selectedOption = option
|
||||
this.showOptionDetailDialog = true
|
||||
@@ -1370,6 +1391,9 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
closePopupFromHistory(popupId) {
|
||||
if (popupId === "optionImage") {
|
||||
this.$set(this, "showOptionImagePreview", false)
|
||||
}
|
||||
if (popupId === "optionDetail") {
|
||||
this.showOptionDetailDialog = false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user