feat: 职工福利优化

This commit is contained in:
2026-11-11 17:39:15 +08:00
parent 336bea15bc
commit a7a7aa5e3a
10 changed files with 187 additions and 106 deletions
@@ -8,6 +8,7 @@ import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.zhgh.welfare.model.WelfareList;
import com.budwk.app.zhgh.welfare.model.WelfareProject;
import com.budwk.app.zhgh.welfare.model.WelfareUserSelection;
import com.budwk.app.zhgh.welfare.param.WelfareSelectionSituationPageForm;
import com.budwk.app.zhgh.welfare.service.WelfareListService;
@@ -89,6 +90,15 @@ public class WelfareSelectionSituationController {
return Result.error("此用户没有选择的权限");
}
WelfareProject project = dao.fetch(WelfareProject.class, projectId);
if (project == null) {
return Result.error("福利项目不存在");
}
String deliveryValidationMessage = project.validateDeliveryMethod(selections);
if (deliveryValidationMessage != null) {
return Result.error(deliveryValidationMessage);
}
String defaultOptionValidationMessage = welfareProjectService.validateSystemDefaultOptionSelection(projectId, selections);
if (defaultOptionValidationMessage != null) {
return Result.error(defaultOptionValidationMessage);
@@ -8,6 +8,7 @@ import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.welfare.model.WelfareList;
import com.budwk.app.zhgh.welfare.model.WelfareProject;
import com.budwk.app.zhgh.welfare.model.WelfareUserSelection;
import io.swagger.annotations.ApiOperation;
import org.nutz.aop.interceptor.ioc.TransAop;
@@ -71,7 +72,8 @@ public class WelfareUserChooseController {
sql.setParam("selectUserId", SecurityUtil.getUserId());
Cnd cnd = Cnd.NEW();
cnd.and("wp.provideMode", "in", "2,3");
cnd.and("wp.provideMode", "in", "1,2,3,5");
cnd.and(Cnd.exps("wp.provideMode", "!=", 1).or("wp.flexible", "=", true));
cnd.andEX("YEAR(wp.choiceTimeStart)", "in", year);
cnd.and("wp.isDisabled", "=", 0);
cnd.groupBy("wp.id");
@@ -87,6 +89,15 @@ public class WelfareUserChooseController {
@SLog(type = "welfare", tag = "选择福利", msg = "福利")
@SaCheckPermission("welfare.user.choose")
public Result confirmSelect(@Param("welfareUserSelections") WelfareUserSelection[] welfareUserSelections, String projectId) {
WelfareProject project = baseService.dao().fetch(WelfareProject.class, projectId);
if (project == null) {
return Result.error("福利项目不存在");
}
String deliveryValidationMessage = project.validateDeliveryMethod(welfareUserSelections);
if (deliveryValidationMessage != null) {
return Result.error(deliveryValidationMessage);
}
//删除上次选择的
baseService.dao().clear(WelfareUserSelection.class,
Cnd.where("welfareId", "=", projectId)
@@ -69,7 +69,7 @@ public class WelfareUserSelectController {
sql.setParam("selectUserId", SecurityUtil.getUserId());
Cnd cnd = Cnd.NEW();
cnd.and("wp.provideMode", "in", "2,3");
cnd.and("wp.provideMode", "in", "1,2,3,5");
cnd.and("wp.flexible", "=", true);
cnd.andEX("YEAR(wp.choiceTimeStart)", "in", year);
cnd.and("wp.isDisabled", "=", 0);
@@ -94,6 +94,14 @@ public class WelfareUserSelectController {
}
WelfareProject project = dao.fetch(WelfareProject.class, projectId);
if (project == null) {
return Result.error("福利项目不存在");
}
String deliveryValidationMessage = project.validateDeliveryMethod(selections);
if (deliveryValidationMessage != null) {
return Result.error(deliveryValidationMessage);
}
String defaultOptionValidationMessage = welfareProjectService.validateSystemDefaultOptionSelection(projectId, selections);
if (defaultOptionValidationMessage != null) {
return Result.error(defaultOptionValidationMessage);
@@ -1,5 +1,6 @@
package com.budwk.app.zhgh.welfare.model;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.model.BaseModel;
import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.sys.services.SysHomeConvert;
@@ -26,6 +27,10 @@ import java.util.List;
@Comment("福利项目")
public class WelfareProject extends BaseModel implements SysHomeConvert {
private static final int PICKUP_ONLY = 1;
private static final int PICKUP_OR_MAIL = 3;
private static final int MAIL_ONLY = 5;
@Column
@Name
@Comment("ID")
@@ -94,6 +99,30 @@ public class WelfareProject extends BaseModel implements SysHomeConvert {
@ColDefine(type = ColType.INT, width = 1)
private Integer provideMode;
public boolean allowsMailDelivery() {
return Integer.valueOf(PICKUP_OR_MAIL).equals(provideMode) || Integer.valueOf(MAIL_ONLY).equals(provideMode);
}
public String validateDeliveryMethod(WelfareUserSelection[] selections) {
if (selections == null) {
return null;
}
for (WelfareUserSelection selection : selections) {
String address = selection.getReceiveAddress();
boolean pickup = "学校自提".equals(address);
if (Integer.valueOf(PICKUP_ONLY).equals(provideMode) && !pickup && StrUtil.isNotBlank(address)) {
return "该福利仅支持实物发放";
}
if (Integer.valueOf(MAIL_ONLY).equals(provideMode) && pickup) {
return "该福利仅支持邮寄到家";
}
if (allowsMailDelivery() && StrUtil.isBlank(address)) {
return "请选择领取方式并填写所需的收货地址";
}
}
return null;
}
@Column
@Comment("签收形式")
@@ -214,7 +243,7 @@ public class WelfareProject extends BaseModel implements SysHomeConvert {
sysHomeActivity.setH5Url("/platform/h5/welfare/userSelect/index?id=" + this.getId());
sysHomeActivity.setStartDate(this.getChoiceTimeStart());
sysHomeActivity.setEndDate(this.getChoiceTimeEnd());
sysHomeActivity.setAllowUserSql("select userId from welfare_list where projectId = (select id from welfare_project where id='" + this.getId() + "' and provideMode!=1) and userId = @userId ");
sysHomeActivity.setAllowUserSql("select userId from welfare_list where projectId = (select id from welfare_project where id='" + this.getId() + "' and (provideMode!=1 or flexible=1)) and userId = @userId ");
sysHomeActivity.setEnable(true);
sysHomeActivity.setClassPath(this.getClass().getPackageName() + this.getClass().getName());
return sysHomeActivity;
@@ -194,7 +194,7 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
entities.add(new ExcelExportEntity("收货人", "userName2", 20));
entities.add(new ExcelExportEntity("联系电话", "mobile", 20));
if(project.getProvideMode() == 3){
if (project.allowsMailDelivery()) {
entities.add(new ExcelExportEntity("收货地址", "receiveAddress", 40));
}
@@ -198,10 +198,13 @@ layout("/layouts/platform.html"){
</template>
</el-row>
<el-form-item label="发放形式" prop="provideMode">
<el-radio-group size="medium" v-model="formData.provideMode">
<el-radio-button :key="item.code" :label="item.code" v-for="item in welfareProvideMode">{{item.name}}</el-radio-button>
</el-radio-group>
<el-form-item label="发放形式" prop="provideModes">
<el-checkbox-group size="medium" v-model="formData.provideModes">
<el-checkbox-button v-for="item in welfareProvideMode" :key="item.code" :label="item.code"
:disabled="isProvideModeDisabled(item.code)">
{{item.name}}
</el-checkbox-button>
</el-checkbox-group>
</el-form-item>
<el-form-item label="签收形式" prop="signMode">
@@ -265,6 +268,7 @@ layout("/layouts/platform.html"){
return {
festival: [],
welfareProvideMode: [],
formData: { provideModes: [] },
welfareSignMode: [],
pageForm: {
year: moment().format("YYYY")
@@ -284,7 +288,7 @@ layout("/layouts/platform.html"){
provideTime: [{ required: true, message: "必选", trigger: ["blur", "change"] }],
choiceTime: [{ required: true, message: "必选", trigger: ["blur", "change"] }],
provideAddress: [{ required: true, message: "必选", trigger: ["blur", "change"] }],
provideMode: [{ required: true, message: "必选", trigger: ["blur", "change"] }],
provideModes: [{ type: "array", required: true, message: "必选", trigger: ["blur", "change"] }],
signMode: [{ required: true, message: "必选", trigger: ["blur", "change"] }],
noticePushMode: [{ required: true, message: "必选", trigger: ["blur", "change"] }],
gift: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
@@ -324,6 +328,10 @@ layout("/layouts/platform.html"){
if (this.formData.flexible) {
}
const formData = clone(this.formData)
const modes = formData.provideModes
// 旧版邮寄项目使用 3,原有领取方式包括自提和邮寄。
formData.provideMode = modes.length === 2 ? 3 : modes[0] === 3 ? 5 : modes[0]
delete formData.provideModes
formData.provideAddress = "工会"
try {
@@ -391,6 +399,7 @@ layout("/layouts/platform.html"){
this.$set(this, "formData", {
isPushHome: false,
signMode: 4,
provideModes: [],
isRoutine: true,
isCheckBox: "radio",
defaultFlexibleGifts: 0,
@@ -437,6 +446,7 @@ layout("/layouts/platform.html"){
}
const projectData = clone(resp.data)
this.clearReuseProjectIdentifiers(projectData)
projectData.provideModes = this.getProvideModes(projectData.provideMode)
this.$set(projectData, "choiceTime", [projectData.choiceTimeStart, projectData.choiceTimeEnd])
this.$set(projectData, "provideTime", [projectData.provideTimeStart, projectData.provideTimeEnd])
this.$set(this, "formData", projectData)
@@ -481,12 +491,23 @@ layout("/layouts/platform.html"){
})
},
isProvideModeDisabled(mode) {
const selected = this.formData.provideModes || []
if (!selected.length || selected.includes(mode)) return false
return ![1, 3].includes(mode) || !selected.every(value => [1, 3].includes(value))
},
getProvideModes(provideMode) {
if (provideMode === 3) return [1, 3]
if (provideMode === 5) return [3]
return provideMode == null ? [] : [provideMode]
},
async openEdit(row) {
this.submitLoading = true
const resp = await this.$axios.post(loc() + "/findOne", { id: row.id })
this.submitLoading = false
if (resp.code === 0) {
const data = resp.data
data.provideModes = this.getProvideModes(data.provideMode)
data.provideTime = [data.provideTimeStart, data.provideTimeEnd]
data.choiceTime = [data.choiceTimeStart, data.choiceTimeEnd]
this.formData = data
@@ -141,19 +141,22 @@ const optionSelect = {
append-to-body
custom-class="welfare-confirm-dialog">
<div class="confirm-content">
<!-- 联系电话输入 -->
<div class="confirm-mobile-section">
<div class="confirm-section-title">联系信息</div>
<div class="confirm-section-title">{{ hasDeliveryOptions ? '领取方式' : '联系信息' }}</div>
<el-form :model="contactForm" ref="contactForm" :rules="contactRules" label-width="80px">
<el-form-item label="领取方式" v-if="projectInfo.provideMode === 3">
<el-radio-group v-model="deliveryMethod">
<el-radio-button label="pickup">学校自提</el-radio-button>
<el-radio-button label="mail">邮寄</el-radio-button>
<el-form-item v-if="hasDeliveryOptions" label-width="0px">
<el-radio-group v-if="projectInfo.provideMode === 3" v-model="deliveryMethod">
<el-radio-button label="pickup">实物发放</el-radio-button>
<el-radio-button label="mail">邮寄到家</el-radio-button>
</el-radio-group>
<div style="margin-top: 8px; padding: 8px 12px; border-radius: 6px; line-height: 1.5; background: #fff3e8; color: #9c451c">超出江浙沪不包邮,超出部分自理,具体金额联系供应商。</div>
<div v-else-if="deliveryMethod === 'mail'">邮寄到家</div>
<div v-if="deliveryMethod === 'pickup'">
{{ projectInfo.provideMode === 1 ? '实物发放 · ' : '' }}学校自提,请在学校指定地点领取
</div>
<div v-if="deliveryMethod === 'mail'" style="margin-top: 8px; padding: 8px 12px; border-radius: 6px; line-height: 1.5; background: #fff3e8; color: #9c451c">超出江浙沪不包邮,超出部分自理,具体金额联系供应商。</div>
</el-form-item>
<el-row :gutter="10">
<el-col :span="20" v-if="projectInfo.provideMode === 3 && deliveryMethod === 'mail'">
<el-col :span="20" v-if="deliveryMethod === 'mail'">
<el-form-item prop="receiveAddress"
label="收货地址"
:rules="[{ required: true, message: '请选择收货地址', trigger: 'change' }]">
@@ -167,10 +170,10 @@ const optionSelect = {
</el-select>
</el-form-item>
</el-col>
<el-col :span="4" v-if="projectInfo.provideMode === 3 && deliveryMethod === 'mail'">
<el-col :span="4" v-if="deliveryMethod === 'mail'">
<el-button @click="openAddress" type="primary" size="small">添加地址</el-button>
</el-col>
<el-col :span="24" v-if="projectInfo.provideMode === 3 && deliveryMethod === 'mail'">
<el-col :span="24" v-if="deliveryMethod === 'mail'">
<el-form-item prop="userName" label="收货人">
<el-input
v-model="contactForm.userName"
@@ -179,7 +182,7 @@ const optionSelect = {
</el-input>
</el-form-item>
</el-col>
<el-col :span="24" v-if="projectInfo.provideMode !== 3 || deliveryMethod === 'mail'">
<el-col :span="24" v-if="requiresContactInfo">
<el-form-item prop="mobile" label="联系电话">
<el-input
v-model="contactForm.mobile"
@@ -299,6 +302,14 @@ const optionSelect = {
"address-dialog": ADDRESS_DIALOG
},
computed: {
hasDeliveryOptions() {
return [1, 3, 5].includes(this.projectInfo.provideMode)
},
requiresContactInfo() {
return !this.hasDeliveryOptions || this.deliveryMethod === "mail"
},
// 系统默认福利必须被保留,管理端限制每个项目最多配置一个。
systemDefaultOption() {
if (!this.projectInfo.options) return null
@@ -437,10 +448,11 @@ const optionSelect = {
this.$axios.post("/platform/welfare/common/projectInfo", {id: this.projectId}).then((res) => {
if (res.code === 0) {
this.projectInfo = res.data
this.deliveryMethod = res.data.provideMode === 1 ? "pickup" : res.data.provideMode === 5 ? "mail" : ""
this.deadlineTime = this.projectInfo.choiceTimeEnd
// 获取收货地址
if (this.projectInfo.provideMode === 3) {
if ([3, 5].includes(this.projectInfo.provideMode)) {
this.getAddress()
}
@@ -488,17 +500,19 @@ const optionSelect = {
})
}
// 首次确认选择且没有历史记录时,尝试自动带出默认收货地址。
if (this.projectInfo.provideMode === 3) {
if ([3, 5].includes(this.projectInfo.provideMode)) {
this.applyDefaultAddressIfNeeded()
}
}
// 地址回显
if (this.projectInfo.provideMode === 3) {
if ([3, 5].includes(this.projectInfo.provideMode)) {
if (this.userSelection.length > 0 && this.userSelection[0].receiveAddress) {
const receiveAddress = this.userSelection[0].receiveAddress
this.deliveryMethod = receiveAddress === "学校自提" ? "pickup" : "mail"
this.contactForm.receiveAddress = this.deliveryMethod === "mail" ? receiveAddress : ""
if (this.projectInfo.provideMode === 3) {
this.deliveryMethod = receiveAddress === "学校自提" ? "pickup" : "mail"
}
this.contactForm.receiveAddress = receiveAddress === "学校自提" ? "" : receiveAddress
// this.contactForm.userName = this.userSelection[0].userName;
// this.contactForm.mobile = this.userSelection[0].mobile;
this.$set(this.contactForm, "userName", this.userSelection[0].userName)
@@ -543,7 +557,6 @@ const optionSelect = {
this.$message.warning("请选择领取方式")
return
}
// 验证手机号
this.$refs.contactForm.validate((valid) => {
if (!valid) {
return
@@ -561,8 +574,8 @@ const optionSelect = {
{
selectOptionId: this.selectedRadioId,
selectNum: 1,
mobile: this.contactForm.mobile,
userName: this.contactForm.userName,
mobile: this.requiresContactInfo ? this.contactForm.mobile : undefined,
userName: this.requiresContactInfo ? this.contactForm.userName : undefined,
userSign: this.contactForm.userSign,
receiveAddress: this.deliveryMethod === "pickup" ? "学校自提" : this.contactForm.receiveAddress
}
@@ -574,8 +587,8 @@ const optionSelect = {
selections = this.selectedOptions.map((option) => ({
selectOptionId: option.id,
selectNum: option.selectNum,
mobile: this.contactForm.mobile,
userName: this.contactForm.userName,
mobile: this.requiresContactInfo ? this.contactForm.mobile : undefined,
userName: this.requiresContactInfo ? this.contactForm.userName : undefined,
userSign: this.contactForm.userSign,
receiveAddress: this.deliveryMethod === "pickup" ? "学校自提" : this.contactForm.receiveAddress
}))
@@ -115,7 +115,7 @@ layout("/layouts/platform.html"){
v-for="column in tableColumns"
></el-table-column>
<el-table-column label="收货地址" prop="receiveAddress" v-if="provideMode===3"></el-table-column>
<el-table-column label="收货地址" prop="receiveAddress" v-if="[3, 5].includes(provideMode)"></el-table-column>
<el-table-column align="center" fixed="right" header-align="center" label="操作" width="100px">
<template slot-scope="{row}">
@@ -32,8 +32,7 @@ let CHOOSE_WELFARE = {
<el-col :span="8">
<el-form-item label="发放形式">
<template>
{{welfareProvideMode.find(v=>v.code==projectInfo.provideMode) &&
welfareProvideMode.find(v=>v.code==projectInfo.provideMode).name}}
{{provideModeLabel}}
</template>
</el-form-item>
</el-col>
@@ -112,15 +111,15 @@ let CHOOSE_WELFARE = {
</el-row>
</el-form-item>
<div v-if="projectInfo.provideMode === 3 && !is_view" style="padding: 8px 16px">
<div v-if="[1, 3, 5].includes(projectInfo.provideMode) && !is_view" style="padding: 8px 16px">
<div>领取方式</div>
<el-radio-group v-model="deliveryMethod">
<el-radio-button label="pickup">学校自提</el-radio-button>
<el-radio-button label="mail">邮寄</el-radio-button>
<el-radio-button v-if="projectInfo.provideMode !== 5" label="pickup">实物发放</el-radio-button>
<el-radio-button v-if="projectInfo.provideMode !== 1" label="mail">邮寄到家</el-radio-button>
</el-radio-group>
<div style="margin-top: 8px; padding: 8px; background: #fff3e8; color: #9c451c">超出江浙沪不包邮,超出部分自理,具体金额联系供应商。</div>
<div v-if="projectInfo.provideMode !== 1" style="margin-top: 8px; padding: 8px; background: #fff3e8; color: #9c451c">超出江浙沪不包邮,超出部分自理,具体金额联系供应商。</div>
</div>
<template v-if="projectInfo.provideMode === 3 && (is_view || deliveryMethod === 'mail')">
<template v-if="[3, 5].includes(projectInfo.provideMode) && (is_view || deliveryMethod === 'mail')">
<el-row :gutter="20">
<el-col :span="24" v-if="!is_view">
<el-form-item label="收货地址" prop="receiveAddress">
@@ -223,6 +222,13 @@ let CHOOSE_WELFARE = {
}
},
computed: {
provideModeLabel() {
const mode = this.projectInfo.provideMode
if (mode === 3) return "实物发放、邮寄到家"
if (mode === 5) return "邮寄到家"
const item = this.welfareProvideMode.find(item => item.code === mode)
return item ? item.name : ""
},
sumSelectNum() {
if (this.projectInfo && this.projectInfo.welfareProjectSubjects) {
return this.projectInfo.welfareProjectSubjects[0].options.map(v => v.selectNum).reduce((accumulator, currentValue) => accumulator + currentValue, 0)
@@ -322,7 +328,7 @@ let CHOOSE_WELFARE = {
return
}
}
if (this.projectInfo.provideMode === 3 && this.deliveryMethod === "mail" && !this.formData.receiveAddress) {
if (this.deliveryMethod === "mail" && !this.formData.receiveAddress) {
this.$message.warning("请填写收货地址")
return
}
@@ -374,9 +380,9 @@ let CHOOSE_WELFARE = {
this.projectInfo.welfareProjectSubjects[0].options.forEach(v => {
const option = this.userSelection.find(x => x.selectOptionId === v.id)
if (option) {
v.selectNum = option.selectNum
this.$set(v, "selectNum", option.selectNum)
} else {
v.selectNum = 0
this.$set(v, "selectNum", 0)
}
})
},
@@ -393,6 +399,9 @@ let CHOOSE_WELFARE = {
const resp = await this.$axios.post("/platform/welfare/project/mange/findOne", { id: id })
if (resp.code === 0) {
resp.data.multiSelectNum = resp.data.multiSelectNum ? resp.data.multiSelectNum : 1
if (!resp.data.welfareProjectSubjects || !resp.data.welfareProjectSubjects.length) {
resp.data.welfareProjectSubjects = [{ id, options: resp.data.options || [] }]
}
this.projectInfo = resp.data
await this.getUserSelection(id)
await this.getChoice()
@@ -410,7 +419,7 @@ let CHOOSE_WELFARE = {
},
async openChoose(row) {
await this.getProjectInfo(row.id)
this.deliveryMethod = ""
this.deliveryMethod = this.projectInfo.provideMode === 1 ? "pickup" : this.projectInfo.provideMode === 5 ? "mail" : ""
this.$set(this.formData, "receiveAddress", null)
this.$set(this.formData, "addressId", null)
this.$set(this.formData, "userName", this.$store.state.user.username)
@@ -422,7 +431,7 @@ let CHOOSE_WELFARE = {
if (this.projectInfo.provideMode === 3 && receiveAddress) {
this.deliveryMethod = receiveAddress === "学校自提" ? "pickup" : "mail"
}
this.$set(this.formData, "receiveAddress", this.deliveryMethod === "pickup" && !this.is_view ? null : receiveAddress)
this.$set(this.formData, "receiveAddress", !this.is_view && receiveAddress === "学校自提" ? null : receiveAddress)
this.$set(this.formData, "addressId", null)
this.$set(this.formData, "userSign", this.userSelection[0].userSign)
} else {
File diff suppressed because one or more lines are too long