This commit is contained in:
zhengziru
2025-04-02 14:26:42 +08:00
79 changed files with 6043 additions and 1829 deletions
+7 -1
View File
@@ -36,7 +36,7 @@
<jsoup.veision>1.12.1</jsoup.veision> <jsoup.veision>1.12.1</jsoup.veision>
<poitl.version>1.9.1</poitl.version> <poitl.version>1.9.1</poitl.version>
<easypoi.version>4.2.0</easypoi.version> <easypoi.version>4.2.0</easypoi.version>
<jetty.version>9.4.47.v20220610</jetty.version> <jetty.version>9.4.56.v20240826</jetty.version>
</properties> </properties>
<url>https://budwk.com</url> <url>https://budwk.com</url>
@@ -53,6 +53,12 @@
<dependencies> <dependencies>
<dependency>
<groupId>com.github.javen205</groupId>
<artifactId>IJPay-All</artifactId>
<version>2.9.10</version>
</dependency>
<dependency> <dependency>
<groupId>com.xingyuv</groupId> <groupId>com.xingyuv</groupId>
<artifactId>captcha-plus</artifactId> <artifactId>captcha-plus</artifactId>
@@ -0,0 +1,23 @@
package io.v.nutz.base.annontation;
import java.lang.annotation.*;
/**
* 自定义注解防止表单重复提交
*
* @author ruoyi
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatSubmit {
/**
* 间隔时间(ms),小于此时间视为重复提交
*/
public int interval() default 5000;
/**
* 提示消息
*/
public String message() default "请求过于频繁,请稍后再试";
}
@@ -18,8 +18,14 @@ public class RedisConstant {
//企业微信TOKEN //企业微信TOKEN
public final static String REDIS_KEY_QIYE_WECHAT_ACCESS_TOKEN = "qiyewx:token:"; public final static String REDIS_KEY_QIYE_WECHAT_ACCESS_TOKEN = "qiyewx:token:";
// 微信公众号TOKEN
public final static String REDIS_KEY_WECHAT_ACCESS_TOKEN = "wechat:token:";
//健步走小程序TOKEN //健步走小程序TOKEN
public final static String REDIS_KEY_WE_APP_ACCESS_TOKEN = "weapp:token:"; public final static String REDIS_KEY_WE_APP_ACCESS_TOKEN = "weapp:token:";
/**
* 接口重复提交前缀
*/
public static final String REPEAT_SUBMIT_PREFIX = PLATFORM_REDIS_PREFIX + "repeat_submit:";
} }
@@ -0,0 +1,16 @@
package io.v.nutz.base.exception;
import cn.hutool.core.util.StrUtil;
public class BaseException extends RuntimeException{
private static final long serialVersionUID = 7192152812384031563L;
public BaseException(String message) {
super(message);
}
public BaseException(String message, Object... arguments) {
super(StrUtil.format(message, arguments));
}
}
@@ -0,0 +1,19 @@
package io.v.nutz.base.interceptor.repeatSubmit;
import io.v.nutz.base.annontation.RepeatSubmit;
import org.nutz.aop.MethodInterceptor;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.aop.SimpleAopMaker;
import org.nutz.ioc.loader.annotation.IocBean;
import java.lang.reflect.Method;
import java.util.List;
@IocBean(name = "$aop_repeatSubmit")
public class RepeatSubmitAopConfiguration extends SimpleAopMaker<RepeatSubmit> {
@Override
public List<? extends MethodInterceptor> makeIt(RepeatSubmit repeatSubmit, Method method, Ioc ioc) {
return List.of(new RepeatSubmitAopInterceptor(ioc, repeatSubmit, method));
}
}
@@ -0,0 +1,51 @@
package io.v.nutz.base.interceptor.repeatSubmit;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import io.v.nutz.base.annontation.RepeatSubmit;
import io.v.nutz.base.constant.RedisConstant;
import io.v.nutz.base.exception.BaseException;
import io.v.nutz.web.commons.utils.ShiroUtil;
import org.nutz.aop.InterceptorChain;
import org.nutz.aop.MethodInterceptor;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.Ioc;
import org.nutz.mvc.Mvcs;
import java.lang.reflect.Method;
public class RepeatSubmitAopInterceptor implements MethodInterceptor {
protected Ioc ioc;
public RepeatSubmitAopInterceptor(Ioc ioc, RepeatSubmit repeatSubmit, Method method) {
RedisService redisService = ioc.get(RedisService.class);
}
@Override
public void filter(InterceptorChain chain) throws Throwable {
Method method = chain.getCallingMethod();
RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
int interval = annotation.interval();
RedisService redisService = Mvcs.getIoc().get(RedisService.class);
String source = method.getDeclaringClass().getName() + "#" + method.getName();
Object[] args = chain.getArgs();
String parameterJson = "";
if (ObjectUtil.isNotEmpty(args)) {
parameterJson = JSONUtil.toJsonStr(args); // 序列化实际参数
}
String key = RedisConstant.REPEAT_SUBMIT_PREFIX + ShiroUtil.getUserId() + ":" + source;
Boolean exists = redisService.exists(key);
if (exists) {
// 判断
String oldParameterJson = redisService.get(key);
if (oldParameterJson != null && oldParameterJson.equalsIgnoreCase(parameterJson)) {
throw new BaseException(annotation.message());
}
} else {
redisService.setex(key, interval / 1000, parameterJson);
}
chain.doChain();
}
}
@@ -1,6 +1,6 @@
package io.v.nutz.zhgh.memberCost.controller; package io.v.nutz.base.payment.alipay.controller;
import io.v.nutz.zhgh.memberCost.service.AlipayService; import io.v.nutz.base.payment.alipay.service.AlipayService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
@@ -1,4 +1,4 @@
package io.v.nutz.zhgh.memberCost.controller; package io.v.nutz.base.payment.alipay.service;
/** /**
* @ClassName AlipayClientConfig * @ClassName AlipayClientConfig
@@ -1,4 +1,4 @@
package io.v.nutz.zhgh.memberCost.service; package io.v.nutz.base.payment.alipay.service;
import io.v.nutz.base.service.ViService; import io.v.nutz.base.service.ViService;
@@ -1,4 +1,4 @@
package io.v.nutz.zhgh.memberCost.service.impl; package io.v.nutz.base.payment.alipay.service.impl;
import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayConstants; import com.alipay.api.AlipayConstants;
@@ -7,11 +7,11 @@ import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature; import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeWapPayRequest; import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeWapPayResponse; import com.alipay.api.response.AlipayTradeWapPayResponse;
import io.v.nutz.base.payment.alipay.service.AlipayClientConfig;
import io.v.nutz.base.payment.alipay.service.AlipayService;
import io.v.nutz.base.service.impl.ViServiceImpl; import io.v.nutz.base.service.impl.ViServiceImpl;
import io.v.nutz.web.commons.utils.ShiroUtil; import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.zhgh.memberCost.controller.AlipayClientConfig;
import io.v.nutz.zhgh.memberCost.model.MemberPaymentInfo; import io.v.nutz.zhgh.memberCost.model.MemberPaymentInfo;
import io.v.nutz.zhgh.memberCost.service.AlipayService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Chain; import org.nutz.dao.Chain;
import org.nutz.dao.Cnd; import org.nutz.dao.Cnd;
@@ -0,0 +1,24 @@
package io.v.nutz.base.payment.enums;
import io.v.nutz.base.annontation.SelectEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 退款状态枚举
*/
@Getter
@SelectEnum
@AllArgsConstructor
public enum RefundStateEnum {
INITIATE_REFUND("发起退款"),
REFUNDING("退款中"),
REFUND_SUCCESS("退款成功"),
REFUND_FAILED("退款失败");
/**
* 避免和枚举类的name冲突
*/
public final String refundStateName;
}
@@ -0,0 +1,25 @@
package io.v.nutz.base.payment.enums;
import io.v.nutz.base.annontation.SelectEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 交易渠道枚举
*/
@Getter
@SelectEnum
@AllArgsConstructor
public enum TradingChannelEnum {
QQ_PAY("QQ"),
WX_PAY("微信"),
JD_PAY("京东"),
ALI_PAY("支付宝"),
UNION_PAY("云闪付");
/**
* 避免和枚举类的name冲突
*/
public final String trdingChannelName;
}
@@ -0,0 +1,24 @@
package io.v.nutz.base.payment.enums;
import io.v.nutz.base.annontation.SelectEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 支付状态枚举
*/
@Getter
@SelectEnum
@AllArgsConstructor
public enum TradingStateEnum {
WAITING_FOR_PAYMENT("等待支付"),
PAY_SUCCESS("支付成功"),
CANCEL_PAYMENT("取消支付");
/**
* 避免和枚举类的name冲突
*/
public final String trdingStateName;
}
@@ -0,0 +1,22 @@
package io.v.nutz.base.payment.enums;
import io.v.nutz.base.annontation.SelectEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 交易类型枚举
*/
@Getter
@SelectEnum
@AllArgsConstructor
public enum TradingTypeEnum {
PAYMENT("付款"),
REFUND("退款");
/**
* 避免和枚举类的name冲突
*/
public final String trdingTypeName;
}
@@ -0,0 +1,30 @@
package io.v.nutz.base.payment.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @version 1.0
* @Author zzr
* @name:WxPayResultCode
* @Date 2025/3/10 10:27
* @注释 微信支付返回码
*/
@Getter
@AllArgsConstructor
public enum WxPayResultCode {
SUCCESS(200, "操作成功"),
APPID_MCHID_NOT_MATCH(400, "商户ID和服务号或企业微信号不匹配"),
INVALID_REQUEST(400, "无效请求"),
MCH_NOT_EXISTS(400, "商户号不存在"),
PARAM_ERROR(400, "参数错误"),
SIGN_ERROR(401, "签名错误"),
NO_AUTH(403, "商户无权限"),
OUT_TRADE_NO_USED(403, "商户订单号重复"),
FREQUENCY_LIMITED(429, "频率超限"),
SYSTEM_ERROR(500, "系统错误");
final int code;
final String msg;
}
@@ -0,0 +1,59 @@
package io.v.nutz.base.payment.model;
import io.v.nutz.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
/**
* 退款记录表
*/
@Data
@Table
@Comment("退款记录表")
@EqualsAndHashCode(callSuper = true)
public class PaymentRefundRecord extends BaseModel {
@Column
@Name
@Comment("ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@Comment("关联系统交易订单表Id")
@ColDefine(type = ColType.VARCHAR,width = 32)
private String paymentTransactionId;
@Column
@Comment("本次退款订单号")
@ColDefine(type = ColType.VARCHAR,width = 128)
private String outRefundTradeNo;
@Column
@Comment("第三方支付的退款单号")
@ColDefine(type = ColType.VARCHAR,width = 128)
private String refundNo;
@Column
@Comment("退款状态")
@ColDefine(type = ColType.VARCHAR,width = 30)
private String refundState;
@Column
@Comment("本次退款金额")
@ColDefine(type = ColType.INT)
private Integer refundAmount;
@Column
@Comment("原订单金额")
@ColDefine(type = ColType.INT)
private Integer total;
@Column
@Comment("交易返回数据")
@ColDefine(type = ColType.MYSQL_JSON)
private String resultJson;
}
@@ -0,0 +1,129 @@
package io.v.nutz.base.payment.model;
import io.v.nutz.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
/**
* 交易单表
*/
@Data
@Table
@Comment("交易订单表")
@EqualsAndHashCode(callSuper = true)
public class PaymentTransaction extends BaseModel {
@Column
@Name
@Comment("ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@Comment("商户号")
@ColDefine(type = ColType.VARCHAR,width = 128)
private String mchId;
@Column
@Comment("订单号,传递给交易系统,交易系统订单号")
@ColDefine(type = ColType.VARCHAR,width = 128)
private String outTradeNo;
@Column
@Comment("交易系统交易号")
@ColDefine(type = ColType.VARCHAR,width = 128)
private String transactionId;
@Column
@Comment("交易渠道")
@ColDefine(type = ColType.VARCHAR,width = 50)
private String tradingChannel;
@Column
@Comment("交易类型")
@ColDefine(type = ColType.VARCHAR,width = 30)
private String tradingType;
@Column
@Comment("交易状态")
@ColDefine(type = ColType.VARCHAR,width = 50)
private String tradingState;
@Column
@Comment("用户ID")
@ColDefine(type = ColType.VARCHAR,width = 32)
private String userId;
@Column
@Comment("用户工号")
@ColDefine(type = ColType.VARCHAR,width = 50)
private String loginName;
@Column
@Comment("用户姓名")
@ColDefine(type = ColType.VARCHAR,width = 50)
private String userName;
@Column
@Comment("工会id")
@ColDefine(type = ColType.VARCHAR,width = 32)
private String unionId;
@Column
@Comment("用户工会")
@ColDefine(type = ColType.VARCHAR,width = 50)
private String unionName;
@Column
@Comment("单位id")
@ColDefine(type = ColType.VARCHAR,width = 32)
private String unitId;
@Column
@Comment("用户单位")
@ColDefine(type = ColType.VARCHAR,width = 50)
private String unitName;
@Column
@Comment("交易金额")
@ColDefine(type = ColType.INT)
private Integer tradingAmount;
@Column
@Comment("是否退款")
@ColDefine(type = ColType.BOOLEAN)
private Boolean isRefund;
@Column
@Comment("退款金额")
@ColDefine(type = ColType.INT)
private Integer refundAmount;
@Column
@Comment("订单描述")
@ColDefine(type = ColType.VARCHAR,width = 128)
private String description;
@Column
@Comment("附加详细描述")
@ColDefine(type = ColType.TEXT)
private String attach;
@Column
@Comment("微信支付用户openId")
@ColDefine(type = ColType.VARCHAR,width = 50)
private String openId;
@Column
@Comment("交易返回数据")
@ColDefine(type = ColType.MYSQL_JSON)
private String resultJson;
@Column
@Comment("交易名单的主键id")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String memberPaymentInfoId;
}
@@ -0,0 +1,53 @@
package io.v.nutz.base.payment.wxpay.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @version 1.0
* @Author zzr
* @name:WxPayV3Bean
* @Date 2025/3/6 9:54
* @注释
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class WxPayV3Bean {
/**
* 服务号
* appid: wxf12fa6175ec7c75f
* app_secret: f65bbb41d3de4a93c8c93d8e2fd50369
*/
private String appId;
private String keyPath;
private String publicKeyPath;
private String certPath;
private String certP12Path;
private String platformCertPath;
private String mchId;
private String apiKey;
private String apiKey3;
private String domain;
private String publicKeyId;
@Override
public String toString() {
return "WxPayV3Bean{" +
"appId='" + appId + '\'' +
", keyPath='" + keyPath + '\'' +
", publicKeyPath='" + publicKeyPath + '\'' +
", certPath='" + certPath + '\'' +
", certP12Path='" + certP12Path + '\'' +
", platformCertPath='" + platformCertPath + '\'' +
", mchId='" + mchId + '\'' +
", apiKey='" + apiKey + '\'' +
", apiKey3='" + apiKey3 + '\'' +
", domain='" + domain + '\'' +
", publicKeyId='" + publicKeyId + '\'' +
'}';
}
}
@@ -0,0 +1,42 @@
package io.v.nutz.base.payment.wxpay.controller;
import io.v.nutz.base.payment.wxpay.service.WxPayCommonService;
import lombok.extern.slf4j.Slf4j;
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.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @version 1.0
* @Author zzr
* @name:WxPayCommonController
* @Date 2025/3/10 19:28
* @注释
*/
@Slf4j
@IocBean
@Ok("json:full")
@At("/platform/wxPay")
public class WxPayCommonController {
@Inject
private WxPayCommonService wxPayCommonService;
@At
@Ok("void")
public void payNotify(HttpServletRequest request, HttpServletResponse response){
wxPayCommonService.payNotify(request, response);
}
@At
@Ok("void")
public void refundNotify(HttpServletRequest request, HttpServletResponse response){
wxPayCommonService.refundNotify(request, response);
}
}
@@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIEKDCCAxCgAwIBAgIUONYpzvxVfV/RrWnLGPlL6/nb/AcwDQYJKoZIhvcNAQEL
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
Q0EwHhcNMjUwMzA2MTQwNDAzWhcNMzAwMzA1MTQwNDAzWjCBgTETMBEGA1UEAwwK
MTY2NjkzMDk4MDEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMS0wKwYDVQQL
DCTmrabmsYnlnLDlpKfkuInmgJ3np5HmioDmnInpmZDlhazlj7gxCzAJBgNVBAYT
AkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBALlDML+FJEW+m2hXp/qUH1cU6xlwFllLU4LjFusJkxwyzzcZO4nY0mOi
3woz8xIJipvUWj2Y413WYwMkfcJcRgghupZkfYwdQtSyPfUu7xQBUm8TLWGH88Re
kyyVABEB5T+ne6r3LesXS4IuZknm5N/iaa4z9mbbscGqF0GLvMUqZCRNyTkyfK9r
Bkvs/vspi+Jcjx9I7aU++h/vwzsGB6Bf/uB3kLMb+lj/i3xY20sdrrW8JD2sqONQ
NcRIKmNXSp4zsNy+d6kIKWE3P5609ZTta1ogkeGBNdGXMRNNy6vLIudQc7zny/9H
S4LxGsIrsYmZNhGljRng56X+PG3w1CUCAwEAAaOBuTCBtjAJBgNVHRMEAjAAMAsG
A1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2Y2Eu
aXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJDMDRC
MDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJCMjdB
OUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQBQ5e8U
1pQ40gfRoZyO0s+QF16L8pAcVLVwHffo0mmJpIRB4bu8W5IJ9kKhksJ0CzZ0YEwB
Yv7/LTC1qpi7PE73nZ4Ytm9oZeH1Kk5KIlQS+2H3IwOpoV4wucMc34y6MVQJjC7E
u5OnglBPSAopwNP4p+Us9A3ah7Ks48XCw+LCEWpA/setJwo9C13Qq2AQm8qLpogK
pNBwm/oylxb8/kZK1lLPgcXd7geLDhl/Str+aOzBXyd7YSEMxS8zWiZhWozu6rCq
dg10QFKicPGDkDzNQwBz7cDXvlJXSWRDBK5r1li1YgX+QD5WJYPchATo5SlvF4Lr
5/V/dZzI7BJTinr1
-----END CERTIFICATE-----
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5QzC/hSRFvpto
V6f6lB9XFOsZcBZZS1OC4xbrCZMcMs83GTuJ2NJjot8KM/MSCYqb1Fo9mONd1mMD
JH3CXEYIIbqWZH2MHULUsj31Lu8UAVJvEy1hh/PEXpMslQARAeU/p3uq9y3rF0uC
LmZJ5uTf4mmuM/Zm27HBqhdBi7zFKmQkTck5MnyvawZL7P77KYviXI8fSO2lPvof
78M7BgegX/7gd5CzG/pY/4t8WNtLHa61vCQ9rKjjUDXESCpjV0qeM7DcvnepCClh
Nz+etPWU7WtaIJHhgTXRlzETTcuryyLnUHO858v/R0uC8RrCK7GJmTYRpY0Z4Oel
/jxt8NQlAgMBAAECggEBAKGQqTi9Ii741Ysftsze1J4bDhS3HaZt/LyO0vPS+8qB
vRiuFrBWuNRPu/en6nl2fLz9al2Bsfep+dtJvar80c5Rq+lwZdUFx7y6XTIv5iwq
IvvfW5pM+Bfu6qbcopwybP0gUMd+nTsCq8UyNd6JUFy3lbZodqCpQ9JDRdjRxqSi
oMonve36Q9kJyDs0mS2F0w+Y9oYFtpE9WvGMBthwT7VfzWuDa+YC/Gh0RhT2V9OG
uDC8kxmfaIbk0IITDVFWVMMhScXiqmJL1II9yQWsCHH73dZS+dDxwwH0ObRD3kOx
hHptxpRzhtuNxLjCOZDGhneyvUHIftpqf4wdOgQ8iUECgYEA6TDo36s3XDFIs8SH
lpVYrhie0nmaNET50CtOc5C2M1OotrkMUrQTMoa4F263UloJfqweW9AKZX11wPp2
8h7af2sZsGawjuwv7mMthZJoi0fc5J2+z6BnVGgFo7uZbcs1Y/+B0tNrDKIHVrqb
Lywmh18iKDXrMiMDMRp8mtiNyU0CgYEAy2Im0oGb1rmAh9gPvQIENmNEgRsyIU4x
WPAFb5KO7jnseO9KrC9uiRSO5JuwZu/QNGlga2w77Gu7n+Q4HfSU2KFlNhR6pKjb
mqXzPq1quryzbtWay520VsRKz3F/Tfp1FUpIuZvj8x7FrL8z8vjbLkbW4p+Z7HE4
heYdmk2KCjkCgYBC6xU48pJtc3swk2pxjSQoucoCDoFxFIY39eWKhnGy4wQcg5gE
t8Z2jnCP0ObszAfDgTMpF9eT7l/3ZCj0LGR5gkuZ8q4iJadPmsh6d1xm89VxCc+z
F43vi/ZqWTCbcGA+9RjVXnRu6KSAgAZ+kAXyfRt5PJflCGUnFznA2fo+VQKBgG6s
n7Gno/UKBv5lPdM9mKs8A5g6A2KKWWIrYtnfJ/ZNAPiiRsFCImVoEYYnjqvFTkhn
G3f5cvZpfbU5jKwIX0MvOJNgO4kE9lPGgIKX/d9WNlJW3KB21h7tPER8X6lAZJxM
SxztzvKKyUkC1zMd5q/dDqxN64X16qs6mNtR3I9JAoGBAJbqQtg59Szi2m4jZ9Xo
0cKvP7+PSKgysdWsemTkU0ji1rcMpGRTtcUGRWlawLjRSInQS+xNdL6GVU5mHZWe
gNwXIXEpape4IJta0B1PYAhNcIvOSh5CzcUnVTeo6q0CTSVQPdsivlrObLKZ4uGQ
eewDw82Ej6YoSgczjf99ug0x
-----END PRIVATE KEY-----
@@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIIEFDCCAvygAwIBAgIUKN05Gm0Q9n9mLPPltUh8qjKKegQwDQYJKoZIhvcNAQEL
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
Q0EwHhcNMjUwMzA2MTQwNDAzWhcNMzAwMzA1MTQwNDAzWjBuMRgwFgYDVQQDDA9U
ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl
bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGEwJDTjERMA8GA1UEBwwIU2hlblpo
ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDbMenF0GNlcUYErPpj
Aj+WOuzRFz+PJcrtgkI81S0WDh8flMtq1A2nwKARNyPXx+UPd9it657nH5G8E9kL
Ea5u5rENpn+JZc4cAIvZqazteSAUg2pfQH9ewW+/CxNOWarjXPNRYa0OjZWf+5F8
ZBOT/x8sJ2+jou9lxKNe1skha+jzmiQ8m3B2vPXqR87qgL/fyQjjpLvBGpvearh/
hxTMBEfGeB4F6Fu52Fz3/VCWe38ubxwj8EMcRSPp4xsl2BTaRVMMT525Hul2N49C
vXCSVsCNt3ND8UDffXnb19Zgpir4KqpECTbfqcT7YX+U34P1Av8gcDl6rRm+7Wpj
PY4RAgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB
kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv
aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4
RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0
MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAUAvXCx55ZGmd3ATi28W4mirnUHQb2RAw
X5/0OC2SkuBdzxI5RbY4YAuugP6nQIAU8TXCANzno2oqZ6vmFZ4dBnJmLewVFMoM
qp18A4RWmnsGnmEIgMm6N1kB+RbM11oLCLdy2KK0SvmqDmTBFJyjyUGqEmRshnV/
QfKn4UUzJ4suDFAolGX4DyDIOtM0D+SCHwwxGI4yf2+nj4IB8XgmmOeschxoSvu9
T3E6BgQ271YVDwg+3r9CiFVI5JdyftvQagOEQmZJMPINEKgFn5LzrZJW7mH42+N+
i4RFz04wpGUsrSFDESh3JxYSNhq/HulpMLinntWxEBHFhpkjyyGDGg==
-----END CERTIFICATE-----
@@ -0,0 +1,70 @@
package io.v.nutz.base.payment.wxpay.service;
import io.v.nutz.base.payment.wxpay.vo.WxPayNeedParamVo;
import io.v.nutz.base.result.Result;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @version 1.0
* @Author zzr
* @name:WxPayCommonService
* @Date 2025/3/6 11:40
* @注释
*/
public interface WxPayCommonService {
/**
* 二维码统一下单,返回支付二维码链接
* @param paramVo 需要传递的信息,请自定义付款金额Amount 和 付款描述Description,其他关键信息请勿修改
* 注意Amount的总价total是int类型,会自动乘以0.01,例如传递100元,会自动转换为1元
* @return
*/
Result nativePay(WxPayNeedParamVo paramVo);
/**
* JSAPI支付,返回支付参数
* @param paramVo 需要传递的信息,请自定义付款金额Amount 和 付款描述Description,其他关键信息请勿修改
* 注意Amount的总价total是int类型,会自动乘以0.01,例如传递100元,会自动转换为1元
* JsAPI支付,需要传递openId,请自行获取
* @return
*/
Result jsApiPay(WxPayNeedParamVo paramVo);
/**
* WAP支付,返回支付参数
* @param paramVo 需要传递的信息,请自定义付款金额Amount 和 付款描述Description,其他关键信息请勿修改
* 注意Amount的总价total是int类型,会自动乘以0.01,例如传递100元,会自动转换为1元
* @return
*/
Result wapPay(WxPayNeedParamVo paramVo);
/**
* 支付回调,验证是否支付成功
* @param request 请求
* @param response 响应
*/
void payNotify(HttpServletRequest request, HttpServletResponse response);
/**
* 退款
* @param transactionId 微信订单号
* @param outTradeNo 商户订单号
* @return
*/
Result refund(String transactionId, String outTradeNo);
/**
* 退款回调
* @param request 请求
* @param response 响应
*/
void refundNotify(HttpServletRequest request, HttpServletResponse response);
}
@@ -0,0 +1,599 @@
package io.v.nutz.base.payment.wxpay.service.impl;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.AuthTypeEnum;
import com.ijpay.core.enums.RequestMethodEnum;
import com.ijpay.core.kit.AesUtil;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.PayKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxDomainEnum;
import com.ijpay.wxpay.enums.v3.BasePayApiEnum;
import com.ijpay.wxpay.model.v3.*;
import io.v.nutz.base.payment.enums.*;
import io.v.nutz.base.payment.model.PaymentRefundRecord;
import io.v.nutz.base.payment.model.PaymentTransaction;
import io.v.nutz.base.payment.wxpay.bean.WxPayV3Bean;
import io.v.nutz.base.payment.wxpay.service.WxPayCommonService;
import io.v.nutz.base.payment.wxpay.vo.WxPayNeedParamVo;
import io.v.nutz.base.result.Result;
import io.v.nutz.sys.models.Sys_user;
import io.v.nutz.sys.models.User;
import io.v.nutz.sys.services.SysUserService;
import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.zhgh.memberCost.model.MemberPaymentInfo;
import lombok.extern.slf4j.Slf4j;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.random.R;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.FileWriter;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
/**
* @version 1.0
* @Author zzr
* @name:WxPayCommonServiceImpl
* @Date 2025/3/6 11:41
* @注释
*/
@Slf4j
@IocBean
public class WxPayCommonServiceImpl implements WxPayCommonService {
// 判断下单接口成功返回码
private final static int OK = 200;
// 1666930980 商户号
// ww3eda050a1b5ad96e 企业微信
// wxf12fa6175ec7c75f 微信服务号
// 微信V3必要的支付参数,后期优化
private final static WxPayV3Bean WX_PAY_V3_BEAN = new WxPayV3Bean(
"ww3eda050a1b5ad96e",
"src/main/java/io/v/nutz/base/payment/wxpay/pem/apiclient_key.pem",
"src/main/java/io/v/nutz/base/payment/wxpay/wxpay/pem/apiclient_key.pem",
"src/main/java/io/v/nutz/base/payment/wxpay/pem/apiclient_cert.pem",
"src/main/java/io/v/nutz/base/payment/wxpay/pem/apiclient_cert.pem",
"src/main/java/io/v/nutz/base/payment/wxpay/pem/wechatpay.pem",
"1666930980",
"",
"4ebd020883285d698c44ec50939c0967",
"https://schoolhd.top/platform",
"");
// 自定义参数,内容是统一的,但会被多次调用,直接声明
private String serialNo;
private String platSerialNo;
private final String payNotifyUrl = WX_PAY_V3_BEAN.getDomain().concat("/wxPay/payNotify");
private final String refundNotifyUrl = WX_PAY_V3_BEAN.getDomain().concat("/wxPay/refundNotify");
@Inject
private Dao dao;
@Inject
private SysUserService sysUserService;
/**
* 微信扫描二维码支付
* @param paramVo 需要传递的信息,请自定义付款金额Amount 和 付款描述Description,其他关键信息请勿修改
* 注意Amount的总价total是int类型,会自动乘以0.01,例如传递100元,会自动转换为1元
* @return
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public Result nativePay(WxPayNeedParamVo paramVo) {
try {
// 商户订单号,存储当前用户的订单
String outTradeNo = PayKit.generateStr();
String timeExpire = getNowTimeExpire();
UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
.setAppid(WX_PAY_V3_BEAN.getAppId())
.setMchid(WX_PAY_V3_BEAN.getMchId())
// 描述信息
.setDescription(paramVo.getDescription())
.setOut_trade_no(outTradeNo)
.setTime_expire(timeExpire)
.setAttach(paramVo.getAttach())
.setNotify_url(payNotifyUrl)
// 订单金额
.setAmount(paramVo.getAmount());
log.info("二维码支付统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
BasePayApiEnum.NATIVE_PAY.toString(),
WX_PAY_V3_BEAN.getMchId(),
getSerialNumber(),
null,
WX_PAY_V3_BEAN.getKeyPath(),
JSONUtil.toJsonStr(unifiedOrderModel),
AuthTypeEnum.RSA.getCode()
);
log.info("统一下单响应 {}", response);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, WX_PAY_V3_BEAN.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
// 下单返回数据
String result = response.getBody();
JSONObject jsonObject = JSONUtil.parseObj(result);
if (response.getStatus() == OK) {
// 统一下单成功,向数据库插入订单记录
insertTradingOrder(paramVo, outTradeNo, result);
return Result.success("请在三分钟内完成支付,超时将自动取消订单").addData(result);
} else {
WxPayResultCode code = WxPayResultCode.valueOf(WxPayResultCode.class, jsonObject.getStr("code"));
return Result.error(code.getMsg());
}
} catch (Exception e) {
log.error("系统异常", e);
return Result.error(e.getMessage());
}
}
@Override
@Aop(TransAop.READ_COMMITTED)
public Result jsApiPay(WxPayNeedParamVo paramVo) {
try {
Sys_user user = dao.fetch(Sys_user.class, ShiroUtil.getUserId());
if (StrUtil.isBlank(user.getOpenId())) {
return Result.error("未获取到当前用户的openid,请重新登录");
}
// 商户订单号,存储当前用户的订单
String outTradeNo = PayKit.generateStr();
// 订单关闭时间
String timeExpire = getNowTimeExpire();
UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
.setAppid(WX_PAY_V3_BEAN.getAppId())
.setMchid(WX_PAY_V3_BEAN.getMchId())
.setDescription(paramVo.getDescription())
.setOut_trade_no(outTradeNo)
.setTime_expire(timeExpire)
.setAttach(paramVo.getAttach())
.setNotify_url(payNotifyUrl)
.setAmount(paramVo.getAmount())
.setPayer(new Payer().setOpenid(user.getOpenId()));
log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
BasePayApiEnum.JS_API_PAY.toString(),
WX_PAY_V3_BEAN.getMchId(),
getSerialNumber(),
null,
WX_PAY_V3_BEAN.getKeyPath(),
JSONUtil.toJsonStr(unifiedOrderModel)
);
log.info("统一下单响应 {}", response);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, WX_PAY_V3_BEAN.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
if (response.getStatus() == OK && verifySignature) {
String body = response.getBody();
JSONObject jsonObject = JSONUtil.parseObj(body);
String prepayId = jsonObject.getStr("prepay_id");
Map<String, String> map = WxPayKit.jsApiCreateSign(WX_PAY_V3_BEAN.getAppId(), prepayId, WX_PAY_V3_BEAN.getKeyPath());
log.info("唤起支付参数:{}", map);
// 唤起支付成功,向数据库插入订单参数
insertTradingOrder(paramVo, outTradeNo, body);
return Result.success();
}
// return JSONUtil.toJsonStr(response);
return null;
} catch (Exception e) {
log.error("系统异常", e);
return Result.error(e.getMessage());
}
}
@Override
@Aop(TransAop.READ_COMMITTED)
public Result wapPay(WxPayNeedParamVo paramVo) {
try {
// 商户订单号,存储当前用户的订单
String outTradeNo = PayKit.generateStr();
// 订单关闭时间
String timeExpire = getNowTimeExpire();
UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
.setAppid(WX_PAY_V3_BEAN.getAppId())
.setMchid(WX_PAY_V3_BEAN.getMchId())
.setDescription(paramVo.getDescription())
.setOut_trade_no(outTradeNo)
.setTime_expire(timeExpire)
.setAttach(paramVo.getAttach())
.setNotify_url(payNotifyUrl)
.setAmount(paramVo.getAmount())
.setScene_info(
new SceneInfo()
.setPayer_client_ip("").
setH5_info(new H5Info()
.setType("Wap")));
log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
BasePayApiEnum.H5_PAY.toString(),
WX_PAY_V3_BEAN.getMchId(),
getSerialNumber(),
null,
WX_PAY_V3_BEAN.getKeyPath(),
JSONUtil.toJsonStr(unifiedOrderModel)
);
log.info("统一下单响应 {}", response);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, WX_PAY_V3_BEAN.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
if (response.getStatus() == OK && verifySignature) {
String body = response.getBody();
insertTradingOrder(paramVo, outTradeNo, body);
return Result.success(JSONUtil.toJsonStr(body));
}
// return JSONUtil.toJsonStr(response);
return Result.error();
} catch (Exception e) {
log.error("系统异常", e);
return Result.error(e.getMessage());
}
}
/**
* 支付回调
* @param request
* @param response
*/
@Override
public void payNotify(HttpServletRequest request, HttpServletResponse response) {
Map<String, String> map = new HashMap<>(12);
try {
String timestamp = request.getHeader("Wechatpay-Timestamp");
String nonce = request.getHeader("Wechatpay-Nonce");
String serialNo = request.getHeader("Wechatpay-Serial");
String signature = request.getHeader("Wechatpay-Signature");
log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
String result = HttpKit.readData(request);
log.info("支付通知密文 {}", result);
// String plainText = null;
// 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
WX_PAY_V3_BEAN.getApiKey3(), WX_PAY_V3_BEAN.getPlatformCertPath());
// 微信公钥验证签名并解密
// if (ObjectUtil.equals(serialNo, WX_PAY_V3_BEAN.getPublicKeyId())) {
// plainText = WxPayKit.verifyPublicKeyNotify(result, signature, nonce, timestamp,
// WX_PAY_V3_BEAN.getApiKey3(), WX_PAY_V3_BEAN.getPlatformCertPath());
// }
log.info("支付通知明文 {}", plainText);
if (StrUtil.isNotEmpty(plainText)) {
// 支付结果
JSONObject jsonResult = JSONUtil.parseObj(plainText);
// 获取缴费记录,并修改缴费结果
PaymentTransaction transaction = sysUserService.dao().fetch(PaymentTransaction.class, Cnd.where("outTradeNo", "=", jsonResult.getStr("out_trade_no")));
transaction.setTradingState(TradingStateEnum.PAY_SUCCESS.getTrdingStateName());
transaction.setTransactionId(jsonResult.getStr("transaction_id"));
sysUserService.dao().update(transaction);
sysUserService.dao().update(MemberPaymentInfo.class,
Chain.make("isPayment", true).add("paymentTime", DateUtil.date(jsonResult.getLong("success_time")))
.add("paymentMoney", String.valueOf(transaction.getTransactionId())),
Cnd.where("payId", "=", transaction.getId())
);
response.setStatus(200);
map.put("code", "SUCCESS");
map.put("message", "SUCCESS");
} else {
response.setStatus(500);
map.put("code", "ERROR");
map.put("message", "签名错误");
log.error("签名错误");
}
// 支付回调,返回给微信,自己也接收不到结果,这里的返回没用
response.setHeader("Content-type", ContentType.JSON.toString());
response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
response.flushBuffer();
} catch (Exception e) {
log.error("系统异常", e);
}
}
/**
* 退款
* @param transactionId 微信订单号
* @param outTradeNo 商户订单号
* @return
*/
@Override
public Result refund(String transactionId, String outTradeNo) {
try {
// 查询商户订单
PaymentTransaction transaction = sysUserService.dao().fetch(PaymentTransaction.class, Cnd.where("outTradeNo", "=", outTradeNo));
Integer tradingAmount = transaction.getTradingAmount();
String outRefundNo = PayKit.generateStr();
log.info("商户退款单号: {}", outRefundNo);
// 没用
// List<RefundGoodsDetail> list = new ArrayList<>();
// RefundGoodsDetail refundGoodsDetail = new RefundGoodsDetail()
// .setMerchant_goods_id("123")
// .setGoods_name("测试")
// .setUnit_price(1)
// .setRefund_amount(1)
// .setRefund_quantity(1);
// list.add(refundGoodsDetail);
RefundModel refundModel = new RefundModel()
.setOut_refund_no(outRefundNo)
.setReason(transaction.getDescription() + "退款")
.setNotify_url(refundNotifyUrl)
.setAmount(new RefundAmount().setRefund(tradingAmount).setTotal(tradingAmount).setCurrency("CNY"));
// .setGoods_detail(list);
if (StrUtil.isNotEmpty(transactionId)) {
refundModel.setTransaction_id(transactionId);
}
if (StrUtil.isNotEmpty(outTradeNo)) {
refundModel.setOut_trade_no(outTradeNo);
}
log.info("退款参数 {}", JSONUtil.toJsonStr(refundModel));
IJPayHttpResponse response = WxPayApi.v3(
RequestMethodEnum.POST,
WxDomainEnum.CHINA.toString(),
BasePayApiEnum.REFUND.toString(),
WX_PAY_V3_BEAN.getMchId(),
getSerialNumber(),
null,
WX_PAY_V3_BEAN.getKeyPath(),
JSONUtil.toJsonStr(refundModel)
);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, WX_PAY_V3_BEAN.getPlatformCertPath());
// 微信支付公钥验证签名
// boolean verifySignature = WxPayKit.verifyPublicKeySignature(response, WX_PAY_V3_BEAN.getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
log.info("退款响应 {}", response);
if (verifySignature) {
// 用户发起退款,存一个退款记录
PaymentRefundRecord record = new PaymentRefundRecord();
record.setId(R.UU32());
record.setPaymentTransactionId(transaction.getId());
record.setOutRefundTradeNo(outRefundNo);
record.setRefundNo(null);
record.setRefundState(RefundStateEnum.REFUNDING.name());
record.setRefundAmount(tradingAmount);
record.setTotal(tradingAmount);
record.setResultJson(response.getBody());
sysUserService.dao().insert(record);
// 返回退款下单结果
return Result.success().addData(response.getBody());
}
} catch (Exception e) {
log.error("系统异常", e);
return Result.error(e.getMessage());
}
return null;
}
/**
* 退款回调
* @param request
* @param response
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public void refundNotify(HttpServletRequest request, HttpServletResponse response) {
Map<String, String> map = new HashMap<>(12);
try {
String timestamp = request.getHeader("Wechatpay-Timestamp");
String nonce = request.getHeader("Wechatpay-Nonce");
String serialNo = request.getHeader("Wechatpay-Serial");
String signature = request.getHeader("Wechatpay-Signature");
log.info("退款通知 timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
String result = HttpKit.readData(request);
log.info("退款通知密文 {}", result);
// String plainText = null;
// 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
WX_PAY_V3_BEAN.getApiKey3(), WX_PAY_V3_BEAN.getPlatformCertPath());
// 微信公钥验证签名并解密
// if (ObjectUtil.equals(serialNo, WX_PAY_V3_BEAN.getPublicKeyId())) {
// plainText = WxPayKit.verifyPublicKeyNotify(result, signature, nonce, timestamp,
// WX_PAY_V3_BEAN.getApiKey3(), WX_PAY_V3_BEAN.getPlatformCertPath());
// }
log.info("退款通知明文 {}", plainText);
if (StrUtil.isNotEmpty(plainText)) {
// 取出明文,修改退款的结果
JSONObject jsonObject = JSONUtil.parseObj(plainText);
// 查询出退款记录,存储关键信息并修改
PaymentRefundRecord record = dao.fetch(PaymentRefundRecord.class, Cnd.where("outRefundTradeNo", "=", jsonObject.getStr("out_refund_no")));
record.setRefundNo(jsonObject.getStr("refund_id"));
record.setRefundState(RefundStateEnum.REFUND_SUCCESS.name());
// 到此是退款成功了,还要去修改订单表的数据
dao.update(PaymentTransaction.class, Chain.make("isRefund", true)
.add("refundAmount", record.getRefundAmount()),
Cnd.where("id", "=", record.getPaymentTransactionId()));
response.setStatus(200);
map.put("code", "SUCCESS");
map.put("message", "SUCCESS");
} else {
response.setStatus(500);
map.put("code", "ERROR");
map.put("message", "签名错误");
}
// 没用
response.setHeader("Content-type", ContentType.JSON.toString());
response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
response.flushBuffer();
} catch (Exception e) {
log.error("系统异常", e);
}
}
/**
* 公共方法,获取证书序列号
* @return
*/
private String getSerialNumber() {
if (StrUtil.isEmpty(serialNo)) {
// 获取证书序列号
X509Certificate certificate = PayKit.getCertificate(WX_PAY_V3_BEAN.getCertPath());
if (null != certificate) {
serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
// 提前两天检查证书是否有效
boolean isValid = PayKit.checkCertificateIsValid(certificate, WX_PAY_V3_BEAN.getMchId(), -2);
log.info("证书是否可用 {} 证书有效期为 {}", isValid, DateUtil.format(certificate.getNotAfter(), DatePattern.NORM_DATETIME_PATTERN));
}
// System.out.println("输出证书信息:\n" + certificate.toString());
// // 输出关键信息,截取部分并进行标记
// System.out.println("证书序列号:" + certificate.getSerialNumber().toString(16));
// System.out.println("版本号:" + certificate.getVersion());
// System.out.println("签发者:" + certificate.getIssuerDN());
// System.out.println("有效起始日期:" + certificate.getNotBefore());
// System.out.println("有效终止日期:" + certificate.getNotAfter());
// System.out.println("主体名:" + certificate.getSubjectDN());
// System.out.println("签名算法:" + certificate.getSigAlgName());
// System.out.println("签名:" + certificate.getSignature().toString());
}
System.out.println("serialNo:" + serialNo);
return serialNo;
}
/**
* 公共方法,获取平台证书序列号
* @return
*/
private String getPlatSerialNumber() {
if (StrUtil.isEmpty(platSerialNo)) {
// 获取平台证书序列号
X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(WX_PAY_V3_BEAN.getPlatformCertPath()));
platSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
}
System.out.println("platSerialNo:" + platSerialNo);
return platSerialNo;
}
/**
* 公共方法,保存平台证书
* @param associatedData
* @param nonce
* @param cipherText
* @param algorithm
* @param certPath
* @return
*/
private String savePlatformCert(String associatedData, String nonce, String cipherText, String algorithm, String certPath) {
try {
String key3 = WX_PAY_V3_BEAN.getApiKey3();
String publicKey;
if (StrUtil.equals(algorithm, AuthTypeEnum.SM2.getPlatformCertAlgorithm())) {
publicKey = PayKit.sm4DecryptToString(key3, cipherText, nonce, associatedData);
} else {
AesUtil aesUtil = new AesUtil(WX_PAY_V3_BEAN.getApiKey3().getBytes(StandardCharsets.UTF_8));
// 平台证书密文解密
// encrypt_certificate 中的 associated_data nonce ciphertext
publicKey = aesUtil.decryptToString(
associatedData.getBytes(StandardCharsets.UTF_8),
nonce.getBytes(StandardCharsets.UTF_8),
cipherText
);
}
if (StrUtil.isNotEmpty(publicKey)) {
// 保存证书
FileWriter writer = new FileWriter(certPath);
writer.write(publicKey);
// 获取平台证书序列号
X509Certificate certificate = PayKit.getCertificate(new ByteArrayInputStream(publicKey.getBytes()));
return certificate.getSerialNumber().toString(16).toUpperCase();
}
return "";
} catch (Exception e) {
log.error("保存平台证书异常", e);
return e.getMessage();
}
}
/**
* 公共方法,构建订单关闭时间,默认3分钟
* @return
*/
private String getNowTimeExpire() {
long currentTimeMillis = System.currentTimeMillis() + 1000 * 60 * 3;
// 将时间戳转换为 DateTime 对象
DateTime dateTime = DateUtil.date(currentTimeMillis);
return DateUtil.format(dateTime, "yyyy-MM-dd'T'HH:mm:ssXXX");
}
/**
* 公共方法,插入交易订单
* @param paramVo 交易必填参数Vo
* @param outTradeNo 商户交易号
* @param result 下单返回结构
*/
private void insertTradingOrder(WxPayNeedParamVo paramVo, String outTradeNo, String result){
User user = sysUserService.dao().fetch(User.class, Cnd.where("id", "=", ShiroUtil.getUserId()));
PaymentTransaction transaction = new PaymentTransaction();
transaction.setId(R.UU32());
transaction.setMchId(WX_PAY_V3_BEAN.getMchId());
transaction.setOutTradeNo(outTradeNo);
transaction.setTransactionId(null);
transaction.setTradingChannel(TradingChannelEnum.WX_PAY.name());
transaction.setTradingType(TradingTypeEnum.PAYMENT.name());
transaction.setUserId(user.getId());
transaction.setLoginName(user.getLoginname());
transaction.setUserName(user.getUsername());
transaction.setUnitId(user.getUnitid());
transaction.setUnitName(user.getUnitname());
transaction.setUnionId(user.getUnionid());
transaction.setUnionName(user.getUnionname());
transaction.setTradingState(TradingStateEnum.WAITING_FOR_PAYMENT.name());
// 获取订单金额
transaction.setTradingAmount(paramVo.getAmount().getTotal());
transaction.setIsRefund(false);
transaction.setRefundAmount(null);
transaction.setDescription(paramVo.getDescription());
transaction.setAttach(paramVo.getAttach());
transaction.setOpenId(null);
transaction.setResultJson(result);
transaction.setMemberPaymentInfoId(paramVo.getMemberPaymentInfoId());
sysUserService.dao().insert(transaction);
}
}
@@ -0,0 +1,109 @@
package io.v.nutz.base.payment.wxpay.util;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import io.v.nutz.base.constant.RedisConstant;
import lombok.extern.slf4j.Slf4j;
import org.nutz.http.Http;
import org.nutz.integration.jedis.RedisService;
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 java.net.URLEncoder;
/**
* @version 1.0
* @Author zzr
* @name:WeChatUtils
* @Date 2025/3/10 14:13
* @注释
*/
@Slf4j
@IocBean
public class WeChatUtils {
@Inject
private RedisService redisService;
public static final String APPID = "wxf12fa6175ec7c75f";
public static final String SECRET = "f65bbb41d3de4a93c8c93d8e2fd50369";
// 获取code
public final static String CODE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
//获取网页access_token的接口地址
public final static String WEB_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=APPSECRET&code=CODE&grant_type=authorization_code";
//获取用户信息地址
public final static String USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
// 获取access_token的接口地址(GET) 限2000(次/天)
public final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
// 发送模板消息
public static final String SEND_MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
/**
* 生成获取code的url
*
* @param redirectUrl
* @return
*/
public String getCodeUrl(String redirectUrl, String state) {
String requestUrl = null;
state = state == null ? "" : state;
try {
requestUrl = CODE_URL.replace("APPID", APPID).replace("REDIRECT_URI", URLEncoder.encode(redirectUrl, "UTF-8")).replace("STATE", state);
} catch (Exception e) {
e.printStackTrace();
}
return requestUrl;
}
/**
* 获取微信网页access_token 和 openid
*
* @param code
* @return
*/
public JSONObject getWebAccessTokenAndOpenid(String code) {
String requestUrl = WEB_ACCESS_TOKEN_URL.replace("APPID", APPID).replace("APPSECRET", SECRET).replace("CODE", code);
return JSONUtil.parseObj(HttpUtil.post(requestUrl, new JSONObject()));
}
/**
* 网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了
* <a href="https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html">...</a>
*
* @param webAccessToken
* @param openid
* @return
*/
public JSONObject getUserInfo(String webAccessToken, String openid) {
String requestUrl = USERINFO_URL.replace("ACCESS_TOKEN", webAccessToken).replace("OPENID", openid);
return JSONUtil.parseObj(HttpUtil.post(requestUrl, new JSONObject()));
}
/**
* 获取access_token 先从Redis获取,如果没有再调微信获取并存Redis
*
* @return
*/
public String getAccessToken() {
String token = redisService.get(RedisConstant.REDIS_KEY_WECHAT_ACCESS_TOKEN);
if (StrUtil.isNotBlank(token)) {
return token;
}
String accessTokenUrl = ACCESS_TOKEN_URL.formatted(APPID, SECRET);
String accessToken = Json.fromJson(NutMap.class, Http.get(accessTokenUrl).getContent()).getString("access_token");
redisService.setex(RedisConstant.REDIS_KEY_WECHAT_ACCESS_TOKEN, 60 * 60 * 2, accessToken);
return accessToken;
}
}
@@ -0,0 +1,36 @@
package io.v.nutz.base.payment.wxpay.vo;
import com.ijpay.wxpay.model.v3.Amount;
import lombok.Data;
/**
* @version 1.0
* @Author zzr
* @name:WxPayNeedParamVo
* @Date 2025/3/7 18:43
* @注释
*/
@Data
public class WxPayNeedParamVo {
/**
* 订单描述,会显示在支付界面的标题,最大长度127,必填
*/
private String description;
/**
* 附加数据,订单的详细描述信息,不必填
*/
private String attach;
/**
* 金额对象,对象中的 total 是金额,必填;
* 其余参数可不传递也可不填
*/
private Amount amount;
/**
* 会员支付信息ID,必填
*/
private String memberPaymentInfoId;
}
@@ -0,0 +1,33 @@
package io.v.nutz.base.utils;
import org.nutz.json.JsonFormat;
import org.nutz.lang.Encoding;
import org.nutz.mvc.view.UTF8JsonView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author wizzer@qq.com
*/
public class WebUtil {
public static String AjaxEncode = Encoding.UTF8;
public static boolean isAjax(HttpServletRequest req) {
String value = req.getHeader("X-Requested-With");
return value != null && "XMLHttpRequest".equalsIgnoreCase(value.trim());
}
public static void rendAjaxResp(HttpServletRequest req, HttpServletResponse resp, Object re) {
try {
if (AjaxEncode != null) {
resp.setCharacterEncoding(AjaxEncode);
}
(new UTF8JsonView(JsonFormat.compact())).render(req, resp, re);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@@ -1,6 +1,37 @@
package io.v.nutz.sys.controllers.platform.sys; package io.v.nutz.sys.controllers.platform.sys;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.socket.SocketUtil;
import io.v.nutz.base.payment.wxpay.util.WeChatUtils;
import io.v.nutz.base.utils.LoginUtil;
import io.v.nutz.sys.models.Sys_user;
import io.v.nutz.sys.services.SysUserService;
import io.v.nutz.web.commons.base.Globals;
import io.v.nutz.web.commons.slog.SLogService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; 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.Attr;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
/** /**
* 微信公众号 * 微信公众号
@@ -9,5 +40,167 @@ import org.nutz.ioc.loader.annotation.IocBean;
* @date 2023/07/06 * @date 2023/07/06
*/ */
@IocBean @IocBean
@At("/platform/wechat")
public class SysWechatController { public class SysWechatController {
private static String ACCESS_TOKEN_URL = "https://%s/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
private static final String APPID = "wxf12fa6175ec7c75f";
private static final String SECRET = "f65bbb41d3de4a93c8c93d8e2fd50369";
@Inject
private Dao dao;
@Inject
private WeChatUtils weChatUtils;
@Inject
private SysUserService sysUserService;
@Inject
private RedisService redisService;
@Inject
private SLogService sLogService;
@Inject
private LoginUtil loginUtil;
/**
* oauth
*
* @return {@link String}
*/
@At
@Ok("re")
public String oauth(@Param("redirectUrl") String redirectUrl) {
String redirect = Globals.AppDomain + "/platform/wechat/getCode";
if (StrUtil.isNotBlank(redirect)) {
redirect += "?redirect=" + redirect;
}
String codeUrl = weChatUtils.getCodeUrl(redirect, "");
return "redirect:" + codeUrl;
}
/**
* 获取code 登录用户
*
* @param code 代码
* @return {@link String}
*/
@At
@Ok("re")
public String getCode(@Param("code") String code, @Param("redirect") String redirect, HttpSession session, HttpServletRequest request) {
String host;
try {
Socket socket = SocketUtil.connect("api.weixin.qq.com", 443, 1000);
if (socket.isConnected()) {
host = "api.weixin.qq.com";
} else {
InetAddress inetAddress = InetAddress.getLocalHost();
host = inetAddress.getHostAddress();
}
} catch (Exception e) {
host = "api.weixin.qq.com";
}
String tokenUrl = ACCESS_TOKEN_URL.formatted(host, APPID, SECRET, code);
NutMap resMap = Json.fromJson(NutMap.class, HttpUtil.get(tokenUrl));
String openid = resMap.getString("openid");
Sys_user sysUser = dao.fetch(Sys_user.class, Cnd.where("openId", "=", openid));
if (sysUser == null) {
String s = Globals.AppDomain + "/platform/wechat/doLogin?openid=" + openid;
if (StrUtil.isNotBlank(redirect)) {
s += "&redirect=" + URLEncoder.encode(redirect, StandardCharsets.UTF_8);
}
// return ">>:" + Globals.CasAddress + "/login?service=" + URLEncoder.encode(s, StandardCharsets.UTF_8);
return ">>:" + s;
}
String loginName = Optional.ofNullable(sysUser).map(x -> x.getLoginname()).orElse(null);
try {
loginUtil.doLogin(loginName, request, session, LoginUtil.LoginOrigin.WEI_XIN);
if (StrUtil.isNotBlank(redirect)) {
return ">>:" + redirect;
}
return ">>:" + Globals.AppDomain + "/platform/home";
} catch (LockedAccountException e) {
request.setAttribute("errMsg", "帐号被锁定,请5分钟后再试");
return ">>:" + Globals.AppDomain + "/platform/home/LockedAccountError";
} catch (UnknownAccountException e) {
request.setAttribute("errMsg", "系统中没有此用户");
return ">>:" + Globals.AppDomain + "/error/UnknownAccountError.html";
} catch (AuthenticationException e) {
request.setAttribute("errMsg", "系统中没有此用户");
return ">>:" + Globals.AppDomain + "/error/UnknownAccountError.html";
} catch (Exception e) {
request.setAttribute("errMsg", "用户名或密码错误");
return ">>:" + Globals.AppDomain + "/error/500.html";
}
}
@At
@Ok("re")
public Object doLogin(@Attr("platformLoginToken") AuthenticationToken token,
HttpServletRequest request, HttpSession session,
@Param("redirect") String redirect, @Param("openid") String openid) {
// int errCount = NumberUtils.toInt(Strings.sNull(SecurityUtils.getSubject().getSession(true).getAttribute("platformErrCount")));
// try {
// loginUtil.doLogin(token, request, session, LoginUtil.LoginOrigin.WEI_XIN);
//
// return Result.success("login.success");
// } catch (CaptchaIncorrectException e) {
// return Result.error(1, "login.error.captcha");
// } catch (CaptchaEmptyException e) {
// return Result.error(2, "login.error.captcha");
// } catch (LockedAccountException e) {
// return Result.error(3, "login.error.locked");
// } catch (UnknownAccountException e) {
// errCount++;
// SecurityUtils.getSubject().getSession(true).setAttribute("platformErrCount", errCount);
// return Result.error(4, "login.error.user");
// } catch (AuthenticationException e) {
// errCount++;
// SecurityUtils.getSubject().getSession(true).setAttribute("platformErrCount", errCount);
// return Result.error(5, "login.error.user");
// } catch (Exception e) {
// errCount++;
// SecurityUtils.getSubject().getSession(true).setAttribute("platformErrCount", errCount);
// return Result.error(6, "login.error.system");
// }
// Assertion assertion = (Assertion) request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
// if (assertion == null) {
// return ">>:" + Globals.AppDomain + "/platform/home/UnknownAccountError";
// }
//
// String principal = assertion.getPrincipal().toString();
// //工号 手机号 身份证
// Sys_user user = dao.fetch(Sys_user.class, Cnd.NEW().and("loginname", "=", principal).or("mobile", "=", principal).or("idcard", "=", principal));
// String loginName = Optional.ofNullable(user).map(v -> v.getLoginname()).orElse(null);
//
// try {
// loginUtil.doLogin(loginName, request, session, LoginUtil.LoginOrigin.WEI_XIN);
// //绑定openId
// if (StrUtil.isNotBlank(openid)) {
// dao.update(Sys_user.class, Chain.make("openId", openid), Cnd.where("loginName", "=", loginName));
// }
// if (StrUtil.isNotBlank(redirect)) {
// return ">>:" + redirect;
// }
// return ">>:" + Globals.AppDomain + "/mobile/index";
// } catch (LockedAccountException e) {
// request.setAttribute("errMsg", "帐号被锁定,请5分钟后再试");
// return ">>:" + Globals.AppDomain + "/platform/home/LockedAccountError";
// } catch (UnknownAccountException e) {
// request.setAttribute("errMsg", "系统中没有此用户");
// return ">>:" + Globals.AppDomain + "/platform/home/UnknownAccountError";
// } catch (Exception e) {
// request.setAttribute("errMsg", "用户名或密码错误");
// return ">>:" + Globals.AppDomain + "/platform/home/500";
// }
return null;
}
} }
@@ -626,6 +626,11 @@ public class Sys_user extends BaseModel implements Serializable {
@ColDefine(type = ColType.VARCHAR, width = 300) @ColDefine(type = ColType.VARCHAR, width = 300)
private String weAppOpenid; private String weAppOpenid;
@Column
@Comment("微信openId")
@ColDefine(type = ColType.VARCHAR, width = 300)
private String openId;
/** /**
* 2021-05-18 end * 2021-05-18 end
*/ */
@@ -1,6 +1,8 @@
package io.v.nutz.web.commons.proc; package io.v.nutz.web.commons.proc;
import io.v.nutz.base.exception.BaseException;
import io.v.nutz.base.result.Result; import io.v.nutz.base.result.Result;
import io.v.nutz.base.utils.WebUtil;
import org.nutz.integration.shiro.NutShiro; import org.nutz.integration.shiro.NutShiro;
import org.nutz.ioc.IocException; import org.nutz.ioc.IocException;
import org.nutz.log.Log; import org.nutz.log.Log;
@@ -27,13 +29,24 @@ public class WkFailProcessor extends ViewProcessor {
String uri = Mvcs.getRequestPath(ac.getRequest()); String uri = Mvcs.getRequestPath(ac.getRequest());
log.warn(String.format("Error@%s :", uri), ac.getError()); log.warn(String.format("Error@%s :", uri), ac.getError());
} }
if (ac.getError() instanceof IocException) { Throwable e = ac.getError();
if (e instanceof IocException) {
if (NutShiro.isAjax(ac.getRequest())) { if (NutShiro.isAjax(ac.getRequest())) {
NutShiro.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(Mvcs.getMessage(ac.getRequest(), "system.exception"))); NutShiro.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(Mvcs.getMessage(ac.getRequest(), "system.exception")));
} else { } else {
ac.getRequest().setAttribute("original_request_uri",ac.getRequest().getRequestURI()); ac.getRequest().setAttribute("original_request_uri",ac.getRequest().getRequestURI());
new ForwardView(errorUri).render(ac.getRequest(), ac.getResponse(), Mvcs.getMessage(ac.getRequest(), "system.exception")); new ForwardView(errorUri).render(ac.getRequest(), ac.getResponse(), Mvcs.getMessage(ac.getRequest(), "system.exception"));
} }
} else if (e instanceof BaseException) {
if (WebUtil.isAjax(ac.getRequest())) {
// WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(ResultCode.FAILURE.getCode(), !log.isDebugEnabled() ? ResultCode.FAILURE.getMsg() : e.getMessage()));
WebUtil.rendAjaxResp(ac.getRequest(), ac.getResponse(), Result.error(400, e.getMessage()));
} else {
ac.getRequest().setAttribute("original_request_uri", ac.getRequest().getRequestURI());
ac.getRequest().setAttribute("error_message", Mvcs.getMessage(ac.getRequest(), "业务异常"));
// new ForwardView(errorUri).render(ac.getRequest(), ac.getResponse(), null);
}
return;
} }
super.process(ac); super.process(ac);
} }
@@ -7,6 +7,7 @@ import io.v.nutz.web.commons.shiro.token.PlatformCaptchaToken;
import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import java.util.Arrays; import java.util.Arrays;
public class EasyCredentialsMatch extends HashedCredentialsMatcher { public class EasyCredentialsMatch extends HashedCredentialsMatcher {
@@ -25,7 +26,7 @@ public class EasyCredentialsMatch extends HashedCredentialsMatcher {
LoginUtil.LoginOrigin loginOrigin = platformCaptchaToken.getLoginOrigin(); LoginUtil.LoginOrigin loginOrigin = platformCaptchaToken.getLoginOrigin();
//cas和企业微信实现免密登录 //cas和企业微信实现免密登录
if (loginOrigin.equals(LoginUtil.LoginOrigin.CAS) || loginOrigin.equals(LoginUtil.LoginOrigin.QI_YE_WEI_XIN)) { if (loginOrigin.equals(LoginUtil.LoginOrigin.CAS) || loginOrigin.equals(LoginUtil.LoginOrigin.QI_YE_WEI_XIN) || !loginOrigin.equals(LoginUtil.LoginOrigin.WEI_XIN)) {
return true; return true;
} }
@@ -94,7 +94,7 @@ public class PlatformAuthorizingRealm extends AuthorizingRealm {
throw Lang.makeThrow(AuthenticationException.class, "验证码失效,请重新获取"); throw Lang.makeThrow(AuthenticationException.class, "验证码失效,请重新获取");
} }
user = sysUserService.fetch(Cnd.NEW().and("mobile", "=", mobile)); user = sysUserService.fetch(Cnd.NEW().and("mobile", "=", mobile));
}else if (!loginOrigin.equals(LoginUtil.LoginOrigin.CAS) && !loginOrigin.equals(LoginUtil.LoginOrigin.QI_YE_WEI_XIN)) { }else if (!loginOrigin.equals(LoginUtil.LoginOrigin.CAS) && !loginOrigin.equals(LoginUtil.LoginOrigin.QI_YE_WEI_XIN) && !loginOrigin.equals(LoginUtil.LoginOrigin.WEI_XIN)) {
validateService.checkCode(key, captcha); validateService.checkCode(key, captcha);
if (Strings.isBlank(loginname)) { if (Strings.isBlank(loginname)) {
throw Lang.makeThrow(AuthenticationException.class, "登录账号不可为空"); throw Lang.makeThrow(AuthenticationException.class, "登录账号不可为空");
@@ -116,7 +116,7 @@ public class PlatformAuthorizingRealm extends AuthorizingRealm {
throw Lang.makeThrow(LockedAccountException.class, "账号被禁用", loginname); throw Lang.makeThrow(LockedAccountException.class, "账号被禁用", loginname);
} }
if (!loginOrigin.equals(LoginUtil.LoginOrigin.CAS) && !loginOrigin.equals(LoginUtil.LoginOrigin.QI_YE_WEI_XIN)) { if (!loginOrigin.equals(LoginUtil.LoginOrigin.CAS) && !loginOrigin.equals(LoginUtil.LoginOrigin.QI_YE_WEI_XIN) && !loginOrigin.equals(LoginUtil.LoginOrigin.WEI_XIN)) {
int errCount = NumberUtils.toInt(Strings.sNull(session.getAttribute("platformErrCount"))); int errCount = NumberUtils.toInt(Strings.sNull(session.getAttribute("platformErrCount")));
if (errCount >= 4) { if (errCount >= 4) {
//输错5次禁用账户10分钟 //输错5次禁用账户10分钟
@@ -0,0 +1,180 @@
package io.v.nutz.zhgh.memberCost.controller;
import cn.wizzer.framework.base.Result;
import io.v.nutz.zhgh.memberCost.model.MemberPaymentProject;
import io.v.nutz.zhgh.memberCost.service.MemberPaymentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import java.util.List;
import java.util.stream.Collectors;
/**
* @ClassName MemberPaymentChartSummaryController
* @Description 图表汇总
* @Author zhf
* @Date 2025/3/11 下午3:20
*/
@IocBean
@Slf4j
@Ok("json:full")
@At("/platform/member/payment/chartSummary")
public class MemberPaymentChartSummaryController {
@Inject
private MemberPaymentService memberPaymentService;
@At("")
@Ok("beetl:/platform/membercost/chartSummary/index.html")
@RequiresPermissions("member.payment.chartSummary")
public void index() {
}
@At
@RequiresPermissions("member.payment.chartSummary")
public Object getPayProjectChart(@Param(value = "startYear", required = false) Integer startYear,
@Param(value = "endYear", required = false) Integer endYear) {
Sql sql = Sqls.create("""
SELECT
mpp.projectName,
COUNT( mpi.id ) AS num
FROM
member_payment_project mpp
LEFT JOIN member_payment_info mpi ON mpi.paymentProjectId = mpp.id
AND mpi.isPayment = 1
WHERE
YEAR ( mpp.createTime ) BETWEEN @startYear
AND @endYear
GROUP BY
mpp.id
""").setParam("startYear", startYear).setParam("endYear", endYear);
return Result.success(memberPaymentService.listMap(sql));
}
@At
@RequiresPermissions("member.payment.chartSummary")
public Object getRefundProjectChart(@Param(value = "startYear", required = false) Integer startYear,
@Param(value = "endYear", required = false) Integer endYear) {
Sql sql = Sqls.create("""
SELECT
mpp.projectName,
COUNT( pt.id ) AS num
FROM
member_payment_project mpp
LEFT JOIN member_payment_info mpi ON mpi.paymentProjectId = mpp.id
LEFT JOIN payment_transaction pt ON pt.memberPaymentInfoId = mpi.id
AND pt.isRefund = 1
WHERE
YEAR ( mpp.createTime ) BETWEEN @startYear
AND @endYear
GROUP BY
mpp.id
""").setParam("startYear", startYear).setParam("endYear", endYear);
return Result.success(memberPaymentService.listMap(sql));
}
@At
@RequiresPermissions("member.payment.chartSummary")
public Object getPayMoneyChart(@Param(value = "startYear", required = false) Integer startYear,
@Param(value = "endYear", required = false) Integer endYear) {
Sql sql = Sqls.create("""
SELECT
mpp.projectName,
SUM( pt.tradingAmount * 0.01 ) AS money
FROM
member_payment_project mpp
LEFT JOIN member_payment_info mpi ON mpi.paymentProjectId = mpp.id
AND mpi.isPayment = 1
LEFT JOIN payment_transaction pt ON pt.memberPaymentInfoId = mpi.id
AND pt.isRefund = 0
AND pt.tradingState = 'PAY_SUCCESS'
WHERE
YEAR ( mpp.createTime ) BETWEEN @startYear
AND @endYear
GROUP BY
mpp.id
""").setParam("startYear", startYear).setParam("endYear", endYear);
return Result.success(memberPaymentService.listMap(sql));
}
@At
@RequiresPermissions("member.payment.chartSummary")
public Object getNumData(@Param(value = "startYear", required = false) Integer startYear,
@Param(value = "endYear", required = false) Integer endYear) {
Sql sql = Sqls.create("""
SELECT
pt.tradingAmount * 0.01 AS money,
pt.isRefund
FROM
member_payment_project mpp
LEFT JOIN member_payment_info mpi ON mpi.paymentProjectId = mpp.id
AND mpi.isPayment = 1
LEFT JOIN payment_transaction pt ON pt.memberPaymentInfoId = mpi.id
AND pt.tradingState = 'PAY_SUCCESS'
WHERE
YEAR ( mpp.createTime ) BETWEEN @startYear
AND @endYear
""").setParam("startYear", startYear).setParam("endYear", endYear);
List<NutMap> map = memberPaymentService.listMap(sql);
double payMoney = map.stream().filter(v -> !v.getBoolean("isRefund")).mapToDouble(v -> v.getDouble("money")).sum();
double refundMoney = map.stream().filter(v -> v.getBoolean("isRefund")).mapToDouble(v -> v.getDouble("money")).sum();
int refundSize = map.stream().filter(v -> v.getBoolean("isRefund")).collect(Collectors.toList()).size();
int paySize = map.stream().filter(v -> !v.getBoolean("isRefund")).collect(Collectors.toList()).size();
NutMap data = new NutMap();
data.put("payMoney", payMoney);
data.put("refundMoney", refundMoney);
data.put("paySize", paySize);
data.put("refundSize", refundSize);
return Result.success(data);
}
@At
@RequiresPermissions("member.payment.chartSummary")
public Object allUnionMoney(String paymentProjectId) {
Sql sql = Sqls.create("""
SELECT
un.unionname,
COALESCE ( SUM( subquery.money ), 0 ) AS money
FROM
sys_union un
LEFT JOIN (
SELECT
pt.unionId,
SUM( pt.tradingAmount * 0.01 ) AS money
FROM
payment_transaction pt
INNER JOIN member_payment_info mpi ON mpi.id = pt.memberPaymentInfoId
AND mpi.paymentProjectId = @paymentProjectId
WHERE
pt.tradingState = 'PAY_SUCCESS'
AND pt.isRefund = 0
GROUP BY
pt.unionId
) subquery ON subquery.unionId = un.id
GROUP BY
un.id,
un.unionname,
un.unioncode
ORDER BY
un.unioncode;
""").setParam("paymentProjectId", paymentProjectId);
return Result.success(memberPaymentService.listMap(sql));
}
}
@@ -0,0 +1,92 @@
package io.v.nutz.zhgh.memberCost.controller;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.dao.CndPlus;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.zhgh.memberCost.model.MemberPaymentConfig;
import io.v.nutz.zhgh.memberCost.service.MemberPaymentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
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.lang.Strings;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
@IocBean
@Slf4j
@Ok("json:full")
@At("/platform/member/payment/config")
public class MemberPaymentConfigController {
@Inject
private MemberPaymentService memberPaymentService;
@At("")
@Ok("beetl:/platform/membercost/config.html")
@RequiresPermissions("member.payment.config")
public void index() {}
@At
@ViReturn
@RequiresPermissions("member.payment.config")
public Object pageData(PageForm pageForm,
@Param(value = "name", required = false) String name) {
Sql sql = Sqls.create("select * from member_payment_config $condition");
CndPlus cnd = CndPlus.create();
if (Strings.isNotBlank(name)) {
cnd.and(Cnd.likeEX("name", name));
}
// cnd.desc("project.`year`");
cnd.desc("createdAt");
sql.setCondition(cnd);
return memberPaymentService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
}
@At
@ViReturn
public Object getPaymentConfig(){
return memberPaymentService.getConfig();
}
@At
@ViReturn
public Object getPaymentConfigList(){
return memberPaymentService.getPaymentConfigList();
}
@At
@ViReturn
public Object doRemove(String id){
memberPaymentService.dao().clear(MemberPaymentConfig.class, Cnd.where("id", "=", id));
return null;
}
@At
@ViReturn
public Object openClosedConfig(String id){
//位运算 取反
memberPaymentService.dao().update(MemberPaymentConfig.class,
Chain.makeSpecial("isDisabled", "isDisabled ^ 1"),
Cnd.where("id", "=", id));
return null;
}
@At
@ViReturn
@RequiresPermissions("member.payment.config")
public Object doAddOrModify(MemberPaymentConfig memberPaymentConfig){
System.out.println(memberPaymentConfig);
memberPaymentService.dao().insertOrUpdate(memberPaymentConfig);
return null;
}
}
@@ -0,0 +1,106 @@
package io.v.nutz.zhgh.memberCost.controller;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.wizzer.framework.base.Result;
import com.ijpay.wxpay.model.v3.Amount;
import io.v.nutz.base.annontation.RepeatSubmit;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.payment.wxpay.service.WxPayCommonService;
import io.v.nutz.base.payment.wxpay.vo.WxPayNeedParamVo;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.zhgh.memberCost.model.MemberPaymentInfo;
import io.v.nutz.zhgh.memberCost.service.MemberPaymentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.dao.Cnd;
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.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
/**
* @version 1.0
* @Author zzr
* @name:MemberPaymentMineController
* @Date 2025/3/10 8:44
* @注释 我的缴费列表
*/
@Slf4j
@IocBean
@Ok("json:full")
@At("/platform/member/payment/mine")
public class MemberPaymentMineController {
@Inject
private WxPayCommonService wxPayCommonService;
@Inject
private MemberPaymentService memberPaymentService;
@At("")
@Ok("beetl:/platform/membercost/mine/index.html")
@RequiresPermissions("member.payment.mine")
public void index() {
}
@At
@ViReturn
@RequiresPermissions("member.payment.mine")
public Object pageData(PageForm pageForm, Integer year, Integer isPay) {
Sql sql = Sqls.create("""
SELECT
mpp.`year`,
mpp.projectName,
mpp.startTime,
mpp.endTime,
mpi.id,
mpi.isPayment,
mpi.payPersonnel,
mpi.personType,
mpi.paymentMonth,
mpc.paymentStartMonth,
mpc.paymentEndMonth,
mpc.payStandards
FROM
`member_payment_info` mpi
LEFT JOIN member_payment_project mpp ON mpi.paymentProjectId = mpp.id
LEFT JOIN member_payment_config mpc ON mpc.id = mpp.configId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.andEX("YEAR(mpp.createTime)", "=", year);
cnd.andEX("mpi.userId", "=", ShiroUtil.getUserId());
cnd.andEX("mpp.isDisabled", "=", 0);
if (ObjectUtil.isNotNull(isPay)) {
cnd.and("mpi.isPayment", "=", isPay);
}
sql.setCondition(cnd);
return memberPaymentService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
}
@At
@RepeatSubmit
@RequiresPermissions("member.payment.mine")
public Object pcOrderPay(Integer paymentMoney, String paymentInfoId) {
WxPayNeedParamVo paramVo = new WxPayNeedParamVo();
paramVo.setDescription(ShiroUtil.getPlatformUsername() + "会费缴纳支付");
paramVo.setAttach("");
paramVo.setMemberPaymentInfoId(paymentInfoId);
paramVo.setAmount(new Amount().setTotal(paymentMoney));
return wxPayCommonService.nativePay(paramVo);
}
@At
@RequiresPermissions("member.payment.mine")
public Object getIsPay(String paymentInfoId) {
int count = memberPaymentService.dao().count(MemberPaymentInfo.class,
Cnd.where("id", "=", paymentInfoId).and("isPayment", "=", 1));
return Result.success().addData(count);
}
}
@@ -1,4 +1,4 @@
package io.v.nutz.zhgh.memberCost.controller.payment; package io.v.nutz.zhgh.memberCost.controller;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateTime;
@@ -23,9 +23,7 @@ import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop; import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Strings; import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param; import org.nutz.mvc.annotation.Param;
@@ -37,28 +35,29 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@IocBean @IocBean
@Slf4j @Slf4j
@Ok("json:full") @Ok("json:full")
@At("/platform/member/payment/manage") @At("/platform/member/payment/project")
public class MemberPaymentManageController { public class MemberPaymentProjectController {
@Inject @Inject
private MemberPaymentService memberPaymentService; private MemberPaymentService memberPaymentService;
@At("") @At("")
@Ok("beetl:/platform/memberCost/payment/manage.html") @Ok("beetl:/platform/membercost/project.html")
@RequiresPermissions("member.payment.manage") @RequiresPermissions("member.payment.project")
public void index() { public void index() {
} }
@At @At
@ViReturn @ViReturn
@RequiresPermissions("member.payment.manage") @RequiresPermissions("member.payment.project")
public Object pageData(PageForm pageForm, public Object pageData(PageForm pageForm,
@Param(value = "year", required = false) String year, @Param(value = "year", required = false) String year,
@Param(value = "projectName", required = false) String projectName) { @Param(value = "projectName", required = false) String projectName) {
@@ -83,7 +82,7 @@ public class MemberPaymentManageController {
*/ */
@At @At
@ViReturn @ViReturn
@RequiresPermissions("member.payment.manage") @RequiresPermissions("member.payment.project")
public Object openClosedProject(String id) { public Object openClosedProject(String id) {
//位运算 取反 //位运算 取反
memberPaymentService.dao().update(MemberPaymentProject.class, memberPaymentService.dao().update(MemberPaymentProject.class,
@@ -101,7 +100,7 @@ public class MemberPaymentManageController {
*/ */
@At @At
@ViReturn @ViReturn
@RequiresPermissions("member.payment.manage") @RequiresPermissions("member.payment.project")
public Object doSave(MemberPaymentProject paymentProject) { public Object doSave(MemberPaymentProject paymentProject) {
memberPaymentService.insertOrUpdate(paymentProject); memberPaymentService.insertOrUpdate(paymentProject);
return null; return null;
@@ -117,20 +116,22 @@ public class MemberPaymentManageController {
*/ */
@At @At
@ViReturn @ViReturn
@RequiresPermissions("member.payment.manage") @RequiresPermissions("member.payment.project")
public Object doSetPayment(String id, Boolean isRenew) { public Object doSetPayment(String id, Boolean isRenew) {
//如果不是更新缴费人员,就删除该项目下的所有待缴费信息,再重新设置 //如果不是更新缴费人员,就删除该项目下的所有待缴费信息,再重新设置
if (!isRenew) { if (!isRenew) {
memberPaymentService.clear(Cnd.where("paymentProjectId", "=", id)); memberPaymentService.clear(Cnd.where("paymentProjectId", "=", id));
} }
//获取缴费项目
MemberPaymentProject project = memberPaymentService.dao().fetch(MemberPaymentProject.class, id);
//获取缴费配置 //获取缴费配置
MemberPaymentConfig config = memberPaymentService.getConfig(); MemberPaymentConfig config = memberPaymentService.getConfigById(project.getConfigId());
List<MemberPaymentConfig.PayStandards> payStandards = config.getPayStandards(); List<MemberPaymentConfig.PayStandards> payStandards = config.getPayStandards();
//缴费人员类型 //缴费人员类型
List<String> personTypeList = new ArrayList<>(); List<String> personTypeList = new ArrayList<>();
payStandards.forEach(v->{ payStandards.forEach(v->{
personTypeList.addAll(v.getPersonTypes()); personTypeList.add(v.getPersonType());
}); });
//获取所有有入会时间的会员 //获取所有有入会时间的会员
@@ -140,23 +141,37 @@ public class MemberPaymentManageController {
//过滤出需要新增到记录表中的人员 //过滤出需要新增到记录表中的人员
List<Sys_user> needInsertUserIds = memberList.stream().filter(v -> !paymentUserIdList.contains(v.getId())).collect(Collectors.toList()); List<Sys_user> needInsertUserIds = memberList.stream().filter(v -> !paymentUserIdList.contains(v.getId())).collect(Collectors.toList());
//获取缴费项目
MemberPaymentProject project = memberPaymentService.dao().fetch(MemberPaymentProject.class, id); //该缴费配置的缴费月份是几月到几月,转为数组
//该项目的缴费月份是几月到几月,转为数组,判断新入职教工应缴费几个月 String[] strings = {config.getPaymentStartMonth(),config.getPaymentEndMonth()};
String[] strings = project.getPaymentMonth().substring(0, project.getPaymentMonth().length() - 1).split("-"); DateTime beginDate = DateUtil.parse(strings[0] + "-01");
DateTime beginDate = DateUtil.parse(project.getYear() + "-" + strings[0] + "-01");
//获取月份的最后一天 //获取月份的最后一天
DateTime endDate = DateUtil.endOfMonth(DateUtil.parse(project.getYear() + "-" + strings[1] + "-01")); DateTime endDate = DateUtil.endOfMonth(DateUtil.parse(strings[1] + "-01"));
List<MemberPaymentInfo> memberPaymentInfos = new ArrayList<>(); List<MemberPaymentInfo> memberPaymentInfos = new ArrayList<>();
needInsertUserIds.forEach(v -> { needInsertUserIds.forEach(v -> {
MemberPaymentInfo paymentInfo = new MemberPaymentInfo(); MemberPaymentInfo paymentInfo = new MemberPaymentInfo();
paymentInfo.setPersonType(v.getPersonType());
long differMonth = 0;
//如果是新入职教工,计算需要缴纳的月数 //如果是新入职教工,计算需要缴纳的月数
if (v.getMemberJoinTime().after(beginDate) && v.getMemberJoinTime().before(endDate)){ if (v.getMemberJoinTime().after(beginDate) && v.getMemberJoinTime().before(endDate)){
long differMonth = DateUtil.betweenMonth(v.getMemberJoinTime(), endDate, false); differMonth = DateUtil.betweenMonth(v.getMemberJoinTime(), endDate, false)+1;
paymentInfo.setPaymentMonth(String.valueOf(differMonth)); paymentInfo.setPaymentMonth(String.valueOf(differMonth));
} else { paymentInfo.setPayPersonnel("新进会员");
paymentInfo.setPaymentMonth(config.getPaidDuration()); //getPayment(v, payStandards, paymentInfo, differMonth,"新进会员");
}else if(v.getRetireDate()!=null&&v.getRetireDate().after(beginDate)&&v.getRetireDate().before(endDate)){
//如果是退休会员
differMonth = DateUtil.betweenMonth(beginDate, v.getRetireDate(), false)+1;
paymentInfo.setPaymentMonth(String.valueOf(differMonth));
paymentInfo.setPayPersonnel("退休会员");
//getPayment(v, payStandards, paymentInfo, differMonth,"退休会员");
}else {
//如果是普通会员
differMonth = DateUtil.betweenMonth(beginDate, endDate, false)+1;
paymentInfo.setPaymentMonth(String.valueOf(differMonth));
paymentInfo.setPayPersonnel("普通会员");
//getPayment(v, payStandards, paymentInfo, differMonth,"普通会员");
} }
paymentInfo.setUserId(v.getId()); paymentInfo.setUserId(v.getId());
paymentInfo.setLoginname(v.getLoginname()); paymentInfo.setLoginname(v.getLoginname());
@@ -197,6 +212,24 @@ public class MemberPaymentManageController {
return null; return null;
} }
private static void getPayment(Sys_user v, List<MemberPaymentConfig.PayStandards> payStandards, MemberPaymentInfo paymentInfo, long differMonth,String payPersonnel) {
List<MemberPaymentConfig.PayStandards> list = payStandards.stream().filter(v1 -> v1.getPersonType().equals(v.getPersonType()) && payPersonnel.equals(v1.getPayPersonnel())).collect(Collectors.toList());
MemberPaymentConfig.PayStandards standards = null;
if (list!=null&&list.size()>0){
standards = list.get(0);
}
if ("在编".equals(v.getPersonType())&&standards!=null){
AtomicReference<Integer> value= new AtomicReference<>(0);
standards.getPayModeValueList().forEach(v1->{
value.set(value.get()+v1.getInt("value"));
});
paymentInfo.setPaymentMoney(String.valueOf(value.get()*0.05* differMonth));
}
if ("非编".equals(v.getPersonType())&&standards!=null){
paymentInfo.setPaymentMoney(String.valueOf(Integer.valueOf(standards.getPayModeValue())* differMonth));
}
}
/** /**
* 删除 * 删除
@@ -205,7 +238,7 @@ public class MemberPaymentManageController {
* @return * @return
*/ */
@At @At
@RequiresPermissions("member.payment.manage") @RequiresPermissions("member.payment.project")
@Aop(TransAop.READ_COMMITTED) @Aop(TransAop.READ_COMMITTED)
public Object doRemove(String id) { public Object doRemove(String id) {
int paymentCount = memberPaymentService.count(Cnd.where("paymentProjectId", "=", id).and("isPayment", "=", 1)); int paymentCount = memberPaymentService.count(Cnd.where("paymentProjectId", "=", id).and("isPayment", "=", 1));
@@ -226,7 +259,7 @@ public class MemberPaymentManageController {
*/ */
@At @At
@ViReturn @ViReturn
@RequiresPermissions("member.payment.manage") @RequiresPermissions("member.payment.project")
public Object getAllProject(String year) { public Object getAllProject(String year) {
CndPlus cnd = CndPlus.create(); CndPlus cnd = CndPlus.create();
cnd.and("isDisabled", "=", 0); cnd.and("isDisabled", "=", 0);
@@ -246,16 +279,5 @@ public class MemberPaymentManageController {
} }
@At
@ViReturn
@RequiresPermissions("member.payment.manage")
public Object isMonthCreatedByYear(@Param("year") String year, @Param("monthSelect") String monthSelect, @Param("id") String projectId) {
List<NutMap> nutMapList = Json.fromJsonAsList(NutMap.class, monthSelect);
for (NutMap nutMap : nutMapList) {
int count = memberPaymentService.dao().count(MemberPaymentProject.class, Cnd.where("`year`", "=", year).and("paymentMonth", "=", nutMap.getString("label")));
nutMap.setv("code", count > 0 ? 1 : 0);
}
return nutMapList;
}
} }
@@ -0,0 +1,114 @@
package io.v.nutz.zhgh.memberCost.controller;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import io.v.nutz.base.annontation.RepeatSubmit;
import io.v.nutz.base.annontation.Valid;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.payment.enums.TradingStateEnum;
import io.v.nutz.base.payment.enums.WxPayResultCode;
import io.v.nutz.base.payment.model.PaymentTransaction;
import io.v.nutz.base.payment.wxpay.service.WxPayCommonService;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.base.result.Result;
import io.v.nutz.zhgh.memberCost.service.MemberPaymentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.dao.Cnd;
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.json.Json;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import java.io.Reader;
/**
* @ClassName MemberPaymentRefundController
* @Description 退款
* @Author zhf
* @Date 2025/3/11 上午8:51
*/
@Slf4j
@IocBean
@Ok("json:full")
@At("/platform/member/payment/refund")
public class MemberPaymentRefundController {
@Inject
private WxPayCommonService wxPayCommonService;
@Inject
private MemberPaymentService memberPaymentService;
@At("")
@Ok("beetl:/platform/membercost/refund/index.html")
@RequiresPermissions("member.payment.refund")
public void index() {
}
@At
@ViReturn
@RequiresPermissions("member.payment.refund")
public Object pageData(PageForm pageForm, String paymentProjectId, String transactionId, Integer isRefund) {
Sql sql = Sqls.create("""
SELECT
mpp.`year`,
mpp.projectName,
mpp.startTime,
mpp.endTime,
mpi.isPayment,
mpi.payPersonnel,
mpi.personType,
mpi.paymentMonth,
mpi.paymentTime,
pt.id,
pt.outTradeNo,
pt.transactionId,
pt.userName,
pt.loginName,
pt.unitName,
pt.unionName,
pt.tradingAmount,
pt.isRefund,
prr.createdAt AS refundTime
FROM
payment_transaction pt
LEFT JOIN `member_payment_info` mpi ON pt.memberPaymentInfoId = mpi.id
LEFT JOIN `payment_refund_record` prr ON pt.memberPaymentInfoId = mpi.id
LEFT JOIN member_payment_project mpp ON mpi.paymentProjectId = mpp.id
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.andEX("mpi.paymentProjectId", "=", paymentProjectId);
cnd.andEX("pt.tradingState", "=", TradingStateEnum.PAY_SUCCESS);
cnd.and(Cnd.likeEX("pt.transactionId", transactionId));
if (isRefund != 3) {
cnd.andEX("pt.isRefund", "=", isRefund);
}
if (ObjectUtil.isNotEmpty(pageForm.getSearchKeyword())) {
SqlExpressionGroup group = new SqlExpressionGroup();
group.orLike("pt.userName", pageForm.getSearchKeyword());
group.orLike("pt.loginName", pageForm.getSearchKeyword());
cnd.and(group);
}
cnd.groupBy("pt.id");
sql.setCondition(cnd);
return memberPaymentService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
}
@At
@RepeatSubmit
@RequiresPermissions("member.payment.refund")
public Object doRefund(@Valid String id) {
PaymentTransaction transaction = memberPaymentService.dao().fetch(PaymentTransaction.class, id);
Result refund = wxPayCommonService.refund(transaction.getTransactionId(), transaction.getOutTradeNo());
return refund;
}
}
@@ -1,4 +1,4 @@
package io.v.nutz.zhgh.memberCost.controller.payment; package io.v.nutz.zhgh.memberCost.controller;
import cn.afterturn.easypoi.excel.ExcelExportUtil; import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil; import cn.afterturn.easypoi.excel.ExcelImportUtil;
@@ -66,7 +66,7 @@ public class MemberPaymentSummaryController {
private MsgApi msgApi; private MsgApi msgApi;
@At("") @At("")
@Ok("beetl:/platform/memberCost/payment/summary.html") @Ok("beetl:/platform/membercost/summary.html")
@RequiresPermissions("member.payment.summary") @RequiresPermissions("member.payment.summary")
public void index() { public void index() {
} }
@@ -75,7 +75,7 @@ public class MemberPaymentSummaryController {
public Sql dataSql(String pageOrderName, String pageOrderBy, String searchName, String searchKeyword, public Sql dataSql(String pageOrderName, String pageOrderBy, String searchName, String searchKeyword,
String unionId, String unitId, String threeUnitId, String unionGroupId, String unionId, String unitId, String threeUnitId, String unionGroupId,
String personType, String userState, String paymentProjectId, String year, String personType, String userState, String paymentProjectId, String year,
String isPay) { String isPay,String schoolTime,String retireDate,String search) {
Sql sql = Sqls.create(""" Sql sql = Sqls.create("""
SELECT SELECT
mpi.*, mpi.*,
@@ -85,7 +85,6 @@ public class MemberPaymentSummaryController {
u.sex, u.sex,
u.member, u.member,
u.welfareMember, u.welfareMember,
u.personType,
u.userState, u.userState,
u.unionname, u.unionname,
u.unionid, u.unionid,
@@ -95,7 +94,12 @@ public class MemberPaymentSummaryController {
u.threeUnitCode, u.threeUnitCode,
u.unionGroupName, u.unionGroupName,
u.mobile, u.mobile,
u.birthday u.birthday,
u.schoolTime,
u.retireDate,
u.workDate,
startSalaryDate,
renewTime
FROM FROM
`member_payment_info` mpi `member_payment_info` mpi
LEFT JOIN `user` u ON u.id = mpi.userId LEFT JOIN `user` u ON u.id = mpi.userId
@@ -106,13 +110,16 @@ public class MemberPaymentSummaryController {
if (StrUtil.isNotBlank(searchName) && StrUtil.isNotBlank(searchKeyword)) { if (StrUtil.isNotBlank(searchName) && StrUtil.isNotBlank(searchKeyword)) {
cnd.and(Cnd.likeEX(searchName, searchKeyword)); cnd.and(Cnd.likeEX(searchName, searchKeyword));
} }
if (!ShiroUtil.hasAnyRoles("sysadmin,A06,H03")) { if (!ShiroUtil.hasAnyRoles("sysadmin,A06,H04")) {
if (ShiroUtil.hasRole("H04")) { if (ShiroUtil.hasRole("H04")) {
cnd.and("u.unionid", "=", Vi.getUnionId()); cnd.and("u.unionid", "=", Vi.getUnionId());
} else { } else {
cnd.and("u.unionGroupId", "in", io.v.nutz.web.commons.utils.ShiroUtil.getUnionGroupIds()); cnd.and("u.unionGroupId", "in", io.v.nutz.web.commons.utils.ShiroUtil.getUnionGroupIds());
} }
} }
if (Strings.isNotBlank(search)){
cnd.orEX("u.username", "like","%" + search + "%");
}
cnd.andEX("mpp.`year`", "=", year); cnd.andEX("mpp.`year`", "=", year);
cnd.andEX("mpi.paymentProjectId", "=", paymentProjectId); cnd.andEX("mpi.paymentProjectId", "=", paymentProjectId);
if (Strings.isNotBlank(isPay) && !"null".equals(isPay)) { if (Strings.isNotBlank(isPay) && !"null".equals(isPay)) {
@@ -124,6 +131,8 @@ public class MemberPaymentSummaryController {
cnd.andEX("u.unionGroupId", "=", unionGroupId); cnd.andEX("u.unionGroupId", "=", unionGroupId);
cnd.andEX("u.personType", "=", personType); cnd.andEX("u.personType", "=", personType);
cnd.andEX("u.userState", "=", userState); cnd.andEX("u.userState", "=", userState);
cnd.andEX("u.schoolTime", "=", schoolTime);
cnd.andEX("u.retireDate", "=", retireDate);
cnd.groupBy("u.id"); cnd.groupBy("u.id");
if (StrUtil.isNotBlank(pageOrderName) && StrUtil.isNotBlank(pageOrderBy)) { if (StrUtil.isNotBlank(pageOrderName) && StrUtil.isNotBlank(pageOrderBy)) {
@@ -150,10 +159,13 @@ public class MemberPaymentSummaryController {
@Param(value = "userState", required = false) String userState, @Param(value = "userState", required = false) String userState,
@Param(value = "paymentProjectId", required = false) String paymentProjectId, @Param(value = "paymentProjectId", required = false) String paymentProjectId,
@Param(value = "year", required = false) String year, @Param(value = "year", required = false) String year,
@Param(value = "isPay", required = false) String isPay) { @Param(value = "isPay", required = false) String isPay,
@Param(value = "schoolTime", required = false) String schoolTime,
@Param(value = "retireDate", required = false) String retireDate,
@Param(value = "search", required = false) String search) {
Sql sql = this.dataSql(pageForm.getPageOrderName(), pageForm.getPageOrderBy(), pageForm.getSearchName(), Sql sql = this.dataSql(pageForm.getPageOrderName(), pageForm.getPageOrderBy(), pageForm.getSearchName(),
pageForm.getSearchKeyword(), unionId, unitId, threeUnitId, unionGroupId, pageForm.getSearchKeyword(), unionId, unitId, threeUnitId, unionGroupId,
personType, userState, paymentProjectId, year, isPay); personType, userState, paymentProjectId, year, isPay,schoolTime,retireDate,search);
return memberPaymentService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); return memberPaymentService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
} }
@@ -164,7 +176,7 @@ public class MemberPaymentSummaryController {
public Object modify(@Param("ids") String[] ids, String paymentMoney, boolean isPay, String remark) { public Object modify(@Param("ids") String[] ids, String paymentMoney, boolean isPay, String remark) {
List<String> idList = Arrays.asList(ids); List<String> idList = Arrays.asList(ids);
if (Lang.isNotEmpty(idList)) { if (Lang.isNotEmpty(idList)) {
if (isPay) { if (!isPay) {
//未缴费设为已缴费 //未缴费设为已缴费
memberPaymentService.update(Chain.make("paymentMoney", paymentMoney) memberPaymentService.update(Chain.make("paymentMoney", paymentMoney)
.add("remark", remark).add("isPayment", 1) .add("remark", remark).add("isPayment", 1)
@@ -285,9 +297,11 @@ public class MemberPaymentSummaryController {
@Param(value = "paymentProjectId", required = false) String paymentProjectId, @Param(value = "paymentProjectId", required = false) String paymentProjectId,
@Param(value = "year", required = false) String year, @Param(value = "year", required = false) String year,
@Param(value = "isPay", required = false) String isPay, @Param(value = "isPay", required = false) String isPay,
@Param(value = "isPay", required = false) String schoolTime,
@Param(value = "isPay", required = false) String retireDate,
boolean isZip, HttpServletResponse response) { boolean isZip, HttpServletResponse response) {
Sql sql = this.dataSql(null, null, searchName, searchKeyword, unionId, unitId, threeUnitId, Sql sql = this.dataSql(null, null, searchName, searchKeyword, unionId, unitId, threeUnitId,
unionGroupId, personType, userState, paymentProjectId, year, isPay); unionGroupId, personType, userState, paymentProjectId, year, isPay,schoolTime,retireDate,"");
List<NutMap> list = memberPaymentService.listMap(sql); List<NutMap> list = memberPaymentService.listMap(sql);
NutMap nutMap = list.stream().findFirst().orElse(null); NutMap nutMap = list.stream().findFirst().orElse(null);
@@ -0,0 +1,82 @@
package io.v.nutz.zhgh.memberCost.controller;
import io.v.nutz.base.payment.wxpay.service.WxPayCommonService;
import io.v.nutz.base.payment.wxpay.util.WeChatUtils;
import io.v.nutz.zhgh.memberCost.service.MemberPaymentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.dao.Dao;
import org.nutz.integration.jedis.RedisService;
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 org.nutz.mvc.annotation.Param;
/**
* @version 1.0
* @Author zzr
* @name:MemberPaymentTestController
* @Date 2025/3/10 14:55
* @注释
*/
@Slf4j
@IocBean
@Ok("json:full")
@At("/platform/member/payment/test")
public class MemberPaymentTestController {
@Inject
private Dao dao;
@Inject
private WeChatUtils weChatUtils;
@Inject
private RedisService redisService;
@Inject
private WxPayCommonService wxPayCommonService;
@Inject
private MemberPaymentService memberPaymentService;
@At("")
@Ok("beetl:/platform/membercost/test/index.html")
@RequiresPermissions("member.payment.test")
public void index() {
}
/**
* 微信jsapi支付需要网页授权认证
* @param redirect
* @param userId
* @return
*/
@At
@Ok("re")
public String oauth(String redirect, String userId){
String url = weChatUtils.getCodeUrl("https://schoolhd.top/platform/wxPay/getCode", userId);
redisService.setex("wx_pay_redirect_url", 60 * 60, "https://schoolhd.top/" + redirect);
return "redirect:" + url;
}
/**
* 上面授权后会转到这个地址,然后去改数据库的openId,
* 后续对微信做一个免登录
* @param code
* @param state
* @return
*/
@At
@Ok("re")
public String getCode(@Param("code") String code, @Param("state") String state){
// String openId = wxPayCommonService.getOpenId(code);
// WxPayNeedParamVo paramVo = new WxPayNeedParamVo();
// paramVo.setDescription("支付");
// paramVo.setAttach("");
// paramVo.setAmount(new Amount().setTotal(1));
// paramVo.setPayer(new Payer().setOpenid(openId));
// Result result = wxPayCommonService.jsApiPay(paramVo);
return null;
// return "redirect:" + redisService.get("wx_pay_redirect_url");
}
}
@@ -0,0 +1,83 @@
package io.v.nutz.zhgh.memberCost.controller;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.dao.CndPlus;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.zhgh.memberCost.model.MemberPaymentInfo;
import io.v.nutz.zhgh.memberCost.service.MemberPaymentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.dao.Cnd;
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.lang.Strings;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
/**
* 个人缴费管理
* @author hpf
*/
@IocBean
@Slf4j
@Ok("json:full")
@At("/platform/member/payment/user")
public class MemberPaymentUserController {
@Inject
private MemberPaymentService memberPaymentService;
@At("")
@Ok("beetl:/platform/membercost/user.html")
@RequiresPermissions("member.payment.user")
public void index() {
}
@At
@ViReturn
@RequiresPermissions("member.payment.user")
public Object pageData(PageForm pageForm,@Param(value = "year", required = false) String year,@Param(value = "projectName", required = false) String projectName){
Sql sql = Sqls.create("""
SELECT
mpi.*,
mpp.`year`,
mpp.projectName,
mpp.startTime,
mpp.endTime,
mpp.configId,
mpc.payStandards,
mpc.paymentStartMonth,
mpc.paymentEndMonth
FROM
member_payment_info mpi
LEFT JOIN member_payment_project mpp ON mpi.paymentProjectId = mpp.id
LEFT JOIN member_payment_config mpc ON mpc.id = mpp.configId
$condition
""");
CndPlus cnd = CndPlus.create();
cnd.andEX("mpp.isDisabled", "=", false);
cnd.andEX("mpp.year", "=", year);
cnd.and("mpi.userId", "=", ShiroUtil.getUserId());
if (Strings.isNotBlank(projectName)) {
cnd.and(Cnd.likeEX("mpp.projectName", projectName));
}
cnd.desc("mpp.createTime");
sql.setCondition(cnd);
return memberPaymentService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
}
@At
@ViReturn
@RequiresPermissions("member.payment.user")
public Object doSave(MemberPaymentInfo memberPaymentInfo) {
memberPaymentService.insertOrUpdate(memberPaymentInfo);
return null;
}
}
@@ -1,44 +0,0 @@
package io.v.nutz.zhgh.memberCost.controller.payment;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.zhgh.memberCost.model.MemberPaymentConfig;
import io.v.nutz.zhgh.memberCost.service.MemberPaymentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
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;
@IocBean
@Slf4j
@Ok("json:full")
@At("/platform/member/payment/config")
public class MemberPaymentConfigController {
@Inject
private MemberPaymentService memberPaymentService;
@At("")
@Ok("beetl:/platform/memberCost/payment/config.html")
@RequiresPermissions("member.payment.config")
public void index() {}
@At
@ViReturn
public Object getPaymentConfig(){
return memberPaymentService.getConfig();
}
@At
@ViReturn
@RequiresPermissions("member.payment.config")
public Object doAddOrModify(MemberPaymentConfig memberPaymentConfig){
System.out.println(memberPaymentConfig);
memberPaymentService.dao().insertOrUpdate(memberPaymentConfig);
return null;
}
}
@@ -1,6 +1,10 @@
package io.v.nutz.zhgh.memberCost.controller.mobile; package io.v.nutz.zhgh.memberCost.h5controller;
import com.ijpay.wxpay.model.v3.Amount;
import io.v.nutz.base.annontation.ViReturn; import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.payment.wxpay.service.WxPayCommonService;
import io.v.nutz.base.payment.wxpay.vo.WxPayNeedParamVo;
import io.v.nutz.base.result.Result;
import io.v.nutz.web.commons.utils.ShiroUtil; import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.zhgh.memberCost.service.MemberPaymentService; import io.v.nutz.zhgh.memberCost.service.MemberPaymentService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -25,6 +29,8 @@ public class MobileMemberCostListController {
@Inject @Inject
private MemberPaymentService memberPaymentService; private MemberPaymentService memberPaymentService;
@Inject
private WxPayCommonService wxPayCommonService;
@At("") @At("")
@Ok("beetl:/mobile/memberCost/memberCostList.html") @Ok("beetl:/mobile/memberCost/memberCostList.html")
@@ -36,6 +42,10 @@ public class MobileMemberCostListController {
public void paySuccess() { public void paySuccess() {
} }
@At("/summary")
@Ok("beetl:/mobile/memberCost/summary.html")
public void summary() {
}
@At @At
@ViReturn @ViReturn
@@ -62,5 +72,12 @@ public class MobileMemberCostListController {
return memberPaymentService.fetch(id); return memberPaymentService.fetch(id);
} }
@At
public Object pullWeChatPay(Integer money, String busId) {
WxPayNeedParamVo wxPayNeedParamVo = new WxPayNeedParamVo();
wxPayNeedParamVo.setDescription("会费缴纳");
wxPayNeedParamVo.setMemberPaymentInfoId(busId);
wxPayNeedParamVo.setAmount(new Amount().setTotal(money));
return wxPayCommonService.jsApiPay(wxPayNeedParamVo);
}
} }
@@ -1,5 +1,6 @@
package io.v.nutz.zhgh.memberCost.model; package io.v.nutz.zhgh.memberCost.model;
import io.v.nutz.base.model.BaseModel;
import lombok.Data; import lombok.Data;
import org.nutz.dao.entity.annotation.*; import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert; import org.nutz.dao.interceptor.annotation.PrevInsert;
@@ -10,7 +11,7 @@ import java.util.List;
@Data @Data
@Table @Table
public class MemberPaymentConfig { public class MemberPaymentConfig extends BaseModel {
@Column @Column
@Name @Name
@@ -19,6 +20,11 @@ public class MemberPaymentConfig {
@PrevInsert(uu32 = true) @PrevInsert(uu32 = true)
private String id; private String id;
@Column
@Comment("缴费配置名称")
@ColDefine(type = ColType.VARCHAR,width = 50)
private String name;
@Column @Column
@Comment("缴费标准") @Comment("缴费标准")
@ColDefine(type = ColType.MYSQL_JSON) @ColDefine(type = ColType.MYSQL_JSON)
@@ -39,12 +45,26 @@ public class MemberPaymentConfig {
@ColDefine(type = ColType.VARCHAR,width = 10) @ColDefine(type = ColType.VARCHAR,width = 10)
private String paidDuration; private String paidDuration;
@Column
@Comment("是否开启")
@ColDefine(type = ColType.BOOLEAN)
private boolean isDisabled;
@Column
@Comment("开始缴费月份")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String paymentStartMonth;
@Column
@Comment("结束缴费月份")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String paymentEndMonth;
@Data @Data
public static class PayStandards implements Serializable { public static class PayStandards implements Serializable {
private String payPersonnel; private String payPersonnel;
private String payMode; private String payMode;
private List<String> personTypes; private String personType;
private String payModeValue; private String payModeValue;
private List<NutMap> payModeValueList; private List<NutMap> payModeValueList;
} }
@@ -87,4 +87,15 @@ public class MemberPaymentInfo {
@Comment("缴费月份") @Comment("缴费月份")
@ColDefine(type = ColType.VARCHAR, width = 10) @ColDefine(type = ColType.VARCHAR, width = 10)
private String paymentMonth; private String paymentMonth;
@Column
@Comment("人员类型")
@ColDefine(type = ColType.VARCHAR, width = 10)
private String personType;
@Column
@Comment("会员类型")
@ColDefine(type = ColType.VARCHAR, width = 10)
private String payPersonnel;
} }
@@ -1,5 +1,6 @@
package io.v.nutz.zhgh.memberCost.model; package io.v.nutz.zhgh.memberCost.model;
import io.v.nutz.base.model.BaseModel;
import lombok.Data; import lombok.Data;
import org.nutz.dao.entity.annotation.*; import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert; import org.nutz.dao.interceptor.annotation.PrevInsert;
@@ -8,7 +9,7 @@ import java.util.Date;
@Data @Data
@Table @Table
public class MemberPaymentProject { public class MemberPaymentProject extends BaseModel {
@Column @Column
@Name @Name
@@ -39,7 +40,27 @@ public class MemberPaymentProject {
@Column @Column
@Comment("缴费月份") @Comment("开始缴费月份")
@ColDefine(type = ColType.VARCHAR, width = 10) @ColDefine(type = ColType.VARCHAR, width = 32)
private String paymentMonth; private String paymentStartMonth;
@Column
@Comment("结束缴费月份")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String paymentEndMonth;
@Column
@Comment("开始缴费时间")
@ColDefine(type = ColType.VARCHAR,width = 32)
private String startTime;
@Column
@Comment("结束缴费时间")
@ColDefine(type = ColType.VARCHAR,width = 32)
private String endTime;
@Column
@Comment("缴费配置id")
@ColDefine(type = ColType.VARCHAR,width = 32)
private String configId;
} }
@@ -17,4 +17,8 @@ public interface MemberPaymentService extends ViService<MemberPaymentInfo> {
Workbook exportOrZip(List<NutMap> list, OutputStream outputStream)throws Exception; Workbook exportOrZip(List<NutMap> list, OutputStream outputStream)throws Exception;
MemberPaymentConfig getConfig(); MemberPaymentConfig getConfig();
List<MemberPaymentConfig> getPaymentConfigList();
MemberPaymentConfig getConfigById(String configId);
} }
@@ -11,6 +11,7 @@ import io.v.nutz.zhgh.memberCost.model.MemberPaymentProject;
import io.v.nutz.zhgh.memberCost.service.MemberPaymentService; import io.v.nutz.zhgh.memberCost.service.MemberPaymentService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap; import org.nutz.lang.util.NutMap;
@@ -61,4 +62,14 @@ public class MemberPaymentServiceImpl extends ViServiceImpl<MemberPaymentInfo> i
public MemberPaymentConfig getConfig() { public MemberPaymentConfig getConfig() {
return dao().fetch(MemberPaymentConfig.class); return dao().fetch(MemberPaymentConfig.class);
} }
@Override
public List<MemberPaymentConfig> getPaymentConfigList() {
return dao().query(MemberPaymentConfig.class, Cnd.NEW().and("isDisabled","=","0"));
}
@Override
public MemberPaymentConfig getConfigById(String configId) {
return dao().fetch(MemberPaymentConfig.class,configId);
}
} }
@@ -1,5 +1,7 @@
package io.v.nutz.zhgh.welfare.controller; package io.v.nutz.zhgh.welfare.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import io.v.nutz.base.annontation.ViReturn; import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.dao.CndPlus; import io.v.nutz.base.dao.CndPlus;
@@ -32,7 +34,6 @@ import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang; import org.nutz.lang.Lang;
import org.nutz.lang.Strings; import org.nutz.lang.Strings;
import org.nutz.lang.random.R; import org.nutz.lang.random.R;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param; import org.nutz.mvc.annotation.Param;
@@ -94,7 +95,7 @@ public class WelfareProjectMangeController {
Sql sql = Sqls.create("SELECT project.*,IF((SELECT count(1) FROM welfare_list WHERE projectId = project.id)>0,TRUE,FALSE) created FROM `welfare_project` project $condition"); Sql sql = Sqls.create("SELECT project.*,IF((SELECT count(1) FROM welfare_list WHERE projectId = project.id)>0,TRUE,FALSE) created FROM `welfare_project` project $condition");
CndPlus cnd = CndPlus.create(); CndPlus cnd = CndPlus.create();
pageForm.defaultSortDesc("createdAt"); pageForm.defaultSortDesc("opAt");
cnd.andEx("year", "=", year); cnd.andEx("year", "=", year);
if (Strings.isNotBlank(name)) { if (Strings.isNotBlank(name)) {
@@ -117,13 +118,14 @@ public class WelfareProjectMangeController {
Trans.exec(() -> { Trans.exec(() -> {
project.setYear(DateUtil.thisYear());
project.setIsDisabled(false);
if (project.getConditionStructure() != null) { if (project.getConditionStructure() != null) {
project.setConditionStructureId(matchConditionStructureService.save(project.getConditionStructure()).getId()); project.setConditionStructureId(matchConditionStructureService.save(project.getConditionStructure()).getId());
} }
if (StrUtil.isBlank(project.getId())) { if (StrUtil.isBlank(project.getId())) {
WelfareProject insertProject = dao.insertWith(project, "welfareProjectSubjects"); WelfareProject insertProject = dao.insertWith(project, "welfareProjectSubjects");
if (Lang.isNotEmpty(insertProject.getWelfareProjectSubjects())) { if (Lang.isNotEmpty(insertProject.getWelfareProjectSubjects())) {
insertProject.getWelfareProjectSubjects().forEach(v -> { insertProject.getWelfareProjectSubjects().forEach(v -> {
dao.insertLinks(v, "options"); dao.insertLinks(v, "options");
@@ -235,10 +237,8 @@ public class WelfareProjectMangeController {
dao.update(project); dao.update(project);
} }
// if (project.getIsPushHome() != 0) {
// mobileHomeService.handle(project, "welfare", "/mobile/welfare/list/receive?projectId=" + project.getId(), project.getIsPushHome());
// }
Sys_home_activity sysHomeActivity = project.covertToSysHomeActivity(); Sys_home_activity sysHomeActivity = project.covertToSysHomeActivity();
sysHomeActivity.setEnable(true);
dao.insertOrUpdate(sysHomeActivity); dao.insertOrUpdate(sysHomeActivity);
}); });
return null; return null;
@@ -256,7 +256,9 @@ public class WelfareProjectMangeController {
projectService.dao().delete(MatchConditionStructure.class, project.getConditionStructureId()); projectService.dao().delete(MatchConditionStructure.class, project.getConditionStructureId());
} }
projectService.dao().clear(WelfareProjectSubject.class, Cnd.where("projectId", "=", id)); projectService.dao().clear(WelfareProjectSubject.class, Cnd.where("projectId", "=", id));
if (ObjectUtil.isNotEmpty(welfareProjectSubject)) {
projectService.dao().clear(WelfareProjectSubjectOption.class, Cnd.where("subjectId", "=", welfareProjectSubject.getId())); projectService.dao().clear(WelfareProjectSubjectOption.class, Cnd.where("subjectId", "=", welfareProjectSubject.getId()));
}
projectService.dao().clear(WelfareUserSelection.class, Cnd.where("welfareId", "=", id)); projectService.dao().clear(WelfareUserSelection.class, Cnd.where("welfareId", "=", id));
projectService.delete(id); projectService.delete(id);
mobileHomeService.delete(id); mobileHomeService.delete(id);
@@ -292,7 +294,7 @@ public class WelfareProjectMangeController {
public Object sendMsgToNotWelfareUsers(String projectId, String sendMsgValue) { public Object sendMsgToNotWelfareUsers(String projectId, String sendMsgValue) {
Sql sql = Sqls.create(""" Sql sql = Sqls.create("""
SELECT SELECT
u.loginname as userId u.loginname
FROM FROM
welfare_list wl welfare_list wl
left join sys_user u on u.id = wl.userId left join sys_user u on u.id = wl.userId
@@ -308,8 +310,13 @@ public class WelfareProjectMangeController {
) )
"""); """);
sql.setParam("projectId", projectId); sql.setParam("projectId", projectId);
List<NutMap> userList = listService.listMap(sql); // List<NutMap> userList = listService.listMap(sql);
// msgApi.sendMsg(sendMsgValue, "福利选择链接", "", "https://zhgh.jiangnan.edu.cn/mobile/welfare/list/receive?projectId=4fa233704ddb41bc8e34e966efeda0a4", "4", userList); // Set<String> loginNameList = userList.stream().map(user -> user.getString("loginname")).collect(Collectors.toSet());
// String loginNames = loginNameList.stream().collect(Collectors.joining(","));
// WelfareProject project = dao.fetch(WelfareProject.class, projectId);
// String link = Globals.AppDomain + "/mobile/welfare/list/receive?projectId=%s".formatted(projectId);
// String imageUrl = Globals.AppDomain + "/file_server/fileStreamPreview?id=" + project.getCover();
// msgApi.sendMsg(List.of("DingTalk"), loginNames, 2, "职工福利", sendMsgValue, "", link);
return null; return null;
} }
@@ -321,9 +328,11 @@ public class WelfareProjectMangeController {
*/ */
@At @At
@ViReturn @ViReturn
@Aop(TransAop.READ_COMMITTED)
@RequiresPermissions("welfare.list.mange") @RequiresPermissions("welfare.list.mange")
public Object projectStatusChange(String id, boolean val) { public Object projectStatusChange(String id, boolean val) {
dao.update(WelfareProject.class, Chain.make("isDisabled", !val), Cnd.where("id", "=", id)); dao.update(WelfareProject.class, Chain.make("isDisabled", !val), Cnd.where("id", "=", id));
dao.update(Sys_home_activity.class, Chain.make("enable", val), Cnd.where("id", "=", id));
return null; return null;
} }
@@ -55,6 +55,7 @@ public class WelfareUserChooseController {
@ViReturn @ViReturn
@RequiresPermissions("welfare.user.choose") @RequiresPermissions("welfare.user.choose")
public Object pageData(PageForm pageForm, Integer year) { public Object pageData(PageForm pageForm, Integer year) {
Sql sql = Sqls.create(""" Sql sql = Sqls.create("""
SELECT SELECT
wp.*, wp.*,
@@ -68,7 +69,7 @@ public class WelfareUserChooseController {
FROM FROM
welfare_project wp welfare_project wp
LEFT JOIN welfare_project_user_selection wus ON wp.id = wus.welfareId AND wus.selectUserId = @selectUserId LEFT JOIN welfare_project_user_selection wus ON wp.id = wus.welfareId AND wus.selectUserId = @selectUserId
INNER JOIN welfare_list wl ON wp.id = wl.projectId AND wl.userId = @selectUserId LEFT JOIN welfare_list wl ON wp.id = wl.projectId AND wl.userId = @selectUserId
LEFT JOIN welfare_project_subject_option wuso ON wus.selectOptionId = wuso.id LEFT JOIN welfare_project_subject_option wuso ON wus.selectOptionId = wuso.id
$condition $condition
"""); """);
@@ -76,6 +77,7 @@ public class WelfareUserChooseController {
Cnd cnd = Cnd.NEW(); Cnd cnd = Cnd.NEW();
cnd.and("wp.provideMode", "in", "2,3"); cnd.and("wp.provideMode", "in", "2,3");
cnd.and("wl.userId", "=", ShiroUtil.getUserId());
cnd.andEX("YEAR(wp.choiceTimeStart)", "in", year); cnd.andEX("YEAR(wp.choiceTimeStart)", "in", year);
cnd.and("wp.isDisabled", "=", 0); cnd.and("wp.isDisabled", "=", 0);
cnd.groupBy("wp.id"); cnd.groupBy("wp.id");
@@ -1,6 +1,6 @@
package io.v.nutz.zhgh.welfare.model; package io.v.nutz.zhgh.welfare.model;
import io.v.nutz.base.model.ViBaseModel; import cn.wizzer.framework.base.model.BaseModel;
import io.v.nutz.sys.models.Sys_home_activity; import io.v.nutz.sys.models.Sys_home_activity;
import io.v.nutz.sys.services.SysHomeConvert; import io.v.nutz.sys.services.SysHomeConvert;
import io.v.nutz.zhgh.data.model.MatchConditionStructure; import io.v.nutz.zhgh.data.model.MatchConditionStructure;
@@ -29,7 +29,7 @@ import java.util.List;
@Accessors(chain = true) @Accessors(chain = true)
@Table("welfare_project") @Table("welfare_project")
@Comment("福利项目") @Comment("福利项目")
public class WelfareProject extends ViBaseModel implements Serializable, SysHomeConvert { public class WelfareProject extends BaseModel implements Serializable, SysHomeConvert {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -43,9 +43,6 @@ public class WelfareProject extends ViBaseModel implements Serializable, SysHome
@Column @Column
@Comment("年度") @Comment("年度")
@ColDefine(type = ColType.INT, width = 4) @ColDefine(type = ColType.INT, width = 4)
@PrevInsert(
els = {@EL("$me.nowYear()")}
)
private Integer year; private Integer year;
@Column @Column
@@ -1,10 +1,10 @@
package io.v.nutz.zhgh.welfare.service.impl; package io.v.nutz.zhgh.welfare.service.impl;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.annotation.Excel; import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.entity.ExportParams; import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.excel.export.ExcelExportService;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
@@ -21,6 +21,7 @@ import io.v.nutz.zhgh.welfare.model.WelfareProject;
import io.v.nutz.zhgh.welfare.model.template.WelfareExportEntityTc; import io.v.nutz.zhgh.welfare.model.template.WelfareExportEntityTc;
import io.v.nutz.zhgh.welfare.service.WelfareSingleService; import io.v.nutz.zhgh.welfare.service.WelfareSingleService;
import lombok.Data; import lombok.Data;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
@@ -46,9 +47,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -671,23 +670,25 @@ public class WelfareSingleServiceImpl extends ViServiceImpl<WelfareProject> impl
SELECT SELECT
u.loginname, u.loginname,
u.username, u.username,
vwl.welfareUnitId as unionid, IF(staffUnion.id IS NOT NULL, staffUnion.id, vwl.welfareUnitId) AS unionid,
gh.unionname as unionname, IF(staffUnion.id IS NOT NULL, staffUnion.unionname, gh.unionname) AS unionname,
vwl.welfareSecondLevelUnitId as unitid, vwl.welfareSecondLevelUnitId as unitid,
dw.`name` as unitname, dw.`name` as unitname,
wpus.userSign, wpus.userSign,
wpus.selectOptionId, wpus.selectOptionId,
wpus.selectNum\s wpus.selectNum
FROM FROM
welfare_list vwl welfare_list vwl
LEFT join sys_user u on u.id = vwl.userId LEFT JOIN special_staff staff ON staff.userId = vwl.userId
left join sys_union gh on gh.id = vwl.welfareUnitId LEFT JOIN sys_union staffUnion ON staff.unionRelationUnionId = staffUnion.id
left join sys_unit dw on dw.id = vwl.welfareSecondLevelUnitId LEFT JOIN sys_user u ON u.id = vwl.userId
LEFT JOIN welfare_project_user_selection wpus ON wpus.selectUserId = vwl.userId\s LEFT JOIN sys_union gh ON gh.id = vwl.welfareUnitId
AND wpus.welfareId = @projectId\s LEFT JOIN sys_unit dw ON dw.id = vwl.welfareSecondLevelUnitId
LEFT JOIN welfare_project_user_selection wpus ON wpus.selectUserId = vwl.userId
AND wpus.welfareId = @projectId
WHERE WHERE
projectId = @projectId projectId = @projectId
AND vwl.welfareUnitId = @unionId AND (vwl.welfareUnitId = @unionId OR staffUnion.id = @unionId)
order by vwl.welfareUnitId,vwl.welfareSecondLevelUnitId order by vwl.welfareUnitId,vwl.welfareSecondLevelUnitId
"""); """);
@@ -712,18 +713,21 @@ public class WelfareSingleServiceImpl extends ViServiceImpl<WelfareProject> impl
}); });
List<ExcelExportEntity> exportEntities = new ArrayList<>(); List<ExcelExportEntity> exportEntities = new ArrayList<>();
exportEntities.add(new ExcelExportEntity("序号", "no", 20)); exportEntities.add(new ExcelExportEntity("序号", "no", 10));
exportEntities.add(new ExcelExportEntity("姓名", "username", 20)); exportEntities.add(new ExcelExportEntity("姓名", "username", 10));
exportEntities.add(new ExcelExportEntity("工号", "loginname", 20)); exportEntities.add(new ExcelExportEntity("工号", "loginname", 15));
exportEntities.add(new ExcelExportEntity("所在基层工会", "unionname", 20)); // exportEntities.add(new ExcelExportEntity("所在分工会", "unionname", 20));
exportEntities.add(new ExcelExportEntity("所在单位", "unitname", 20)); ExcelExportEntity excelExportEntity1 = new ExcelExportEntity("所在单位", "unitname", 20);
excelExportEntity1.setWrap(true);
exportEntities.add(excelExportEntity1);
for (NutMap option : options) { for (NutMap option : options) {
exportEntities.add(new ExcelExportEntity(option.getString("optionName"), option.getString("id"), 20)); exportEntities.add(new ExcelExportEntity(option.getString("optionName"), option.getString("id"), 10));
} }
ExcelExportEntity excelExportEntity = new ExcelExportEntity(); ExcelExportEntity excelExportEntity = new ExcelExportEntity();
excelExportEntity.setName("签字"); excelExportEntity.setName("签字");
excelExportEntity.setKey("qzBytes"); excelExportEntity.setKey("qzBytes");
excelExportEntity.setHeight(12);
excelExportEntity.setWidth(20); excelExportEntity.setWidth(20);
excelExportEntity.setType(2); excelExportEntity.setType(2);
excelExportEntity.setExportImageType(2); excelExportEntity.setExportImageType(2);
@@ -764,9 +768,16 @@ public class WelfareSingleServiceImpl extends ViServiceImpl<WelfareProject> impl
totalMap.put(option.getString("id"), selectNum); totalMap.put(option.getString("id"), selectNum);
} }
dataList.add(totalMap); dataList.add(totalMap);
ExportParams exportParams = new ExportParams(); /*ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF); exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, dataList); Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, dataList);
workbook.write(outputStream);*/
Workbook workbook = new HSSFWorkbook();
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.HSSF);
ExcelExportService service = new ExcelExportService();
service.createSheetForMap(workbook, exportParams, exportEntities, dataList);
workbook.write(outputStream); workbook.write(outputStream);
// List<NutMap> result = new ArrayList<>(); // List<NutMap> result = new ArrayList<>();
@@ -1023,7 +1034,6 @@ public class WelfareSingleServiceImpl extends ViServiceImpl<WelfareProject> impl
sheet.setColumnWidth(0, 1000 * 2); sheet.setColumnWidth(0, 1000 * 2);
sheet.setColumnWidth(1, 1500 * 2); sheet.setColumnWidth(1, 1500 * 2);
sheet.setColumnWidth(2, 3000 * 2); sheet.setColumnWidth(2, 3000 * 2);
sheet.setColumnWidth(2, 3000 * 2);
sheet.setColumnWidth(3, 2000 * 2); sheet.setColumnWidth(3, 2000 * 2);
sheet.setColumnWidth(4, 2000 * 2); sheet.setColumnWidth(4, 2000 * 2);
sheet.setColumnWidth(5, 1500 * 2); sheet.setColumnWidth(5, 1500 * 2);
@@ -1180,18 +1190,43 @@ public class WelfareSingleServiceImpl extends ViServiceImpl<WelfareProject> impl
} else { } else {
v.setQzBytes(null); v.setQzBytes(null);
} }
} }
Map<String, String> addressMap = new HashMap<>();
String receiveAddress = v.getReceiveAddress();
if (StrUtil.isNotBlank(receiveAddress)) {
List<String> addressList = Arrays.stream(receiveAddress.split("[,,]")).collect(Collectors.toList());
for (String pair : addressList) {
// 2. 根据冒号分割键和值
String[] keyValue = pair.split("[::]", 2);
if (keyValue.length == 2) {
String key = keyValue[0].trim();
String value = keyValue[1].trim();
addressMap.put(key, value);
}
}
// v.setRecipient(addressMap.get("收件人"));
// v.setPhone(addressMap.get("联系方式"));
// v.setAddress(addressMap.get("收货地址"));
}
}); });
ExportParams exportParams = new ExportParams(); ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF); exportParams.setType(ExcelType.HSSF);
exportParams.setSheetName(project.getName()); exportParams.setSheetName(project.getName());
try { try {
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, WelfareExportEntityTc.class, welfareExportEntityTcList); ViTool.excelResponse(response, (project.getName() + (flag ? "已选名单" : "未选名单")) + ".xls");
ViTool.excelResponse(response, (project.getName() + (flag ? "已选名单" : "未选名单")) + ".xlsx"); Workbook workbook = new HSSFWorkbook();
ExcelExportService service = new ExcelExportService();
service.createSheet(workbook, exportParams, WelfareExportEntityTc.class, welfareExportEntityTcList);
ServletOutputStream outputStream = response.getOutputStream(); ServletOutputStream outputStream = response.getOutputStream();
workbook.write(outputStream); workbook.write(outputStream);
outputStream.close();
// Workbook workbook = ExcelExportUtil.exportExcel(exportParams, WelfareExportEntityTc.class, welfareExportEntityTcList);
// ServletOutputStream outputStream = response.getOutputStream();
// workbook.write(outputStream);
// outputStream.close();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
+12 -2
View File
@@ -47,7 +47,7 @@ jdbc.defaultAutoCommit=true
xsssql.ignore.urls=/platform/cms/content/article/addDo,/platform/sys/app/conf/addDo,/platform/sys/app/conf/editDo,\ xsssql.ignore.urls=/platform/cms/content/article/addDo,/platform/sys/app/conf/addDo,/platform/sys/app/conf/editDo,\
/platform/member/change/mange/userPageData,/platform/welfare/member/mange/userPageData,/platform/sys/task/cronExp,\ /platform/member/change/mange/userPageData,/platform/welfare/member/mange/userPageData,/platform/sys/task/cronExp,\
/platform/sys/task/editDo,/platform/sys/task/addDo,/platform/fellowship/manage/activity/doHandle,/platform/sys/menu/editMenuDo,\ /platform/sys/task/editDo,/platform/sys/task/addDo,/platform/fellowship/manage/activity/doHandle,/platform/sys/menu/editMenuDo,\
/platform/trainSingUp/manage/activity/doHandle /platform/trainSingUp/manage/activity/doHandle,/platform/activity/school/info/mange/doAdd,/platform/activity/school/info/mange/doEdit
#环境 dev/prod #环境 dev/prod
v.environment=dev v.environment=dev
v.loginUrl=/sso/login v.loginUrl=/sso/login
@@ -78,7 +78,7 @@ shiro.url.login=/platform
shiro.url.logout_redirect=/platform shiro.url.logout_redirect=/platform
shiro.url.unauth=/platform shiro.url.unauth=/platform
#开发时设置本地路径,便于调试 #开发时设置本地路径,便于调试
beetl.RESOURCE.rootLocal=G:/zhgh/zhgh_hrbnu/src/main/resources/views/ beetl.RESOURCE.rootLocal=G:/zhgh/ /src/main/resources/views/
beetl.RESOURCE.root=views/ beetl.RESOURCE.root=views/
beetl.DELIMITER_STATEMENT_START=<!--# beetl.DELIMITER_STATEMENT_START=<!--#
beetl.DELIMITER_STATEMENT_END=#--> beetl.DELIMITER_STATEMENT_END=#-->
@@ -143,5 +143,15 @@ logback.exts.loglevel.enabled=true
#心跳间隔(单位:秒) #心跳间隔(单位:秒)
logback.exts.loglevel.heartbeat=15 logback.exts.loglevel.heartbeat=15
wxpay.appId=\u5E94\u7528\u7F16\u53F7
wxpay.keyPath=key.pem
wxpay.certPath=cert.pem
wxpay.certP12Path=cert.p12
wxpay.platformCertPath=wx_cert.pem
wxpay.mchId=\u5FAE\u4FE1\u5546\u6237\u53F7
wxpay.apiKey3=Api-v3 \u5BC6\u94A5
wxpay.apiKey=Api \u5BC6\u94A5
wxpay.domain=https://ijpay.javen.com
+1 -1
View File
@@ -32,7 +32,7 @@
<logger name="org.quartz" level="INFO"/> <logger name="org.quartz" level="INFO"/>
<logger name="org.nutz" level="DEBUG"/> <logger name="org.nutz" level="DEBUG"/>
<root level="DEBUG"> <root level="INFO">
<appender-ref ref="STDOUT" /> <appender-ref ref="STDOUT" />
<appender-ref ref="ASYNC" /> <appender-ref ref="ASYNC" />
</root> </root>
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1741597488639" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3556" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M1007.00026 280.122039c-19.967068-135.446124-127.709596-243.188651-263.127276-263.15572A1592.10348 1592.10348 0 0 0 291.371434 15.373505a323.11381 323.11381 0 0 0-276.040452 276.040451 1594.549588 1594.549588 0 0 0 1.621258 452.444664c19.910182 135.446124 127.709596 243.217094 263.127276 263.155719a1591.705276 1591.705276 0 0 0 463.793468 0c135.389237-19.910182 243.188651-127.709596 263.098833-263.155719a1591.591504 1591.591504 0 0 0 0-463.736581" fill="#FFB123" p-id="3557"></path><path d="M668.413394 540.433446a156.437144 156.437144 0 1 1 0 312.874289 156.437144 156.437144 0 0 1 0-312.874289z m-56.089827 85.386238l-0.654192 0.398204-13.937127 15.131738c-0.369761 0.398204-0.511976 0.967066-0.36976 1.479042l0.36976 0.711078 37.061382 40.247011a1.621258 1.621258 0 0 1-0.170659 2.332335l-0.82485 0.284431h-24.517967c-0.568862 0-1.080838 1.877246-1.308384 3.157186l-0.113772 1.023953v21.389224c0 0.568862 0.284431 1.052395 0.711078 1.308383l0.711078 0.227545h46.44761a2.844312 2.844312 0 0 1 2.616767 1.848803l0.199101 1.194611v19.853295c0 0.568862-0.284431 1.052395-0.682634 1.336827l-0.711078 0.199102H609.25171a1.393713 1.393713 0 0 0-1.223054 0.767964l-0.199101 0.767964v21.389224c0 0.568862 0.284431 1.052395 0.711078 1.308383l0.711077 0.227545h47.869767c0.511976 0 0.967066 0.284431 1.223054 0.739521l0.170658 0.796408v30.946111c0 0.568862 0.284431 1.052395 0.711078 1.336827l0.711078 0.199101h19.71108c0.511976 0 0.967066-0.284431 1.223054-0.767964l0.170659-0.767964v-30.946111c0-0.568862 0.284431-1.052395 0.711078-1.336827l0.711078-0.199102h47.869766c0.511976 0 0.967066-0.312874 1.223054-0.767964l0.170659-0.767964v-21.389224c0-0.568862-0.284431-1.052395-0.682635-1.308383l-0.711078-0.227545h-47.869766a1.393713 1.393713 0 0 1-1.223054-0.767965l-0.199102-0.767964v-19.853295c0-1.251497 0.711078-2.360779 1.706587-2.815869l1.137725-0.227545h46.44761c0.511976 0 0.967066-0.312874 1.223054-0.767964l0.170659-0.767964v-21.389224a11.377247 11.377247 0 0 0-0.853294-3.669163l-0.568862-0.511976h-27.305393c-0.938623 0-1.535928-0.938623-1.393712-1.791916l0.398203-0.82485 37.061382-40.247011a1.649701 1.649701 0 0 0 0.398204-1.479042l-0.341318-0.711078-13.937127-15.131738a1.336827 1.336827 0 0 0-1.36527-0.398204l-0.625748 0.398204-50.799408 55.122761a5.318863 5.318863 0 0 1-6.513473 1.137724l-1.422156-1.137724-50.82785-55.122761c-0.369761-0.398204-0.853294-0.540419-1.336827-0.398204zM682.634953 256.002275a56.886234 56.886234 0 0 1 56.886234 56.886235v213.266492A184.880261 184.880261 0 0 0 497.726248 767.978383H312.87443a56.886234 56.886234 0 0 1-56.886234-56.886234V312.88851a56.886234 56.886234 0 0 1 56.886234-56.886235h369.760523z m-170.658703 199.10182h-142.215585a28.443117 28.443117 0 0 0-3.327845 56.687133L369.760665 511.990329h142.215585a28.443117 28.443117 0 0 0 0-56.886234z m113.772468-113.772468h-255.988053a28.443117 28.443117 0 0 0-3.327845 56.687132L369.760665 398.217861h255.988053a28.443117 28.443117 0 0 0 0-56.886234z" fill="#FFFFFF" p-id="3558"></path></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

@@ -0,0 +1 @@
<svg t="1741604634908" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5087" width="32" height="32"><path d="M501.009067 0C224.50176 0 0.395947 229.198507 0.395947 512s224.105813 512 500.626773 512c276.514133 0 500.619947-229.198507 500.619947-512S777.434453 0 501.015893 0z m-39.103147 732.99968L257.938773 514.300587l52.210347-44.305067L428.168533 567.405227c48.011947-60.299947 155.56608-180.599467 303.506774-276.39808l12.417706 30.399146c-135.816533 131.50208-247.186773 316.798293-282.187093 411.600214z" fill="#06B464" p-id="5088"></path></svg>

After

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

@@ -84,8 +84,17 @@ module.exports = {
clearInterval(signatureInterval) clearInterval(signatureInterval)
const ts = new Date().getTime() + (Math.floor(Math.random() * (1000 - 1 + 1)) + 1).toString() const ts = new Date().getTime() + (Math.floor(Math.random() * (1000 - 1 + 1)) + 1).toString()
console.log(ts) console.log(ts)
// this.postAddress = location.protocol + '//' + location.host + '/signature?prefix=' + this.prefix + '&id=' + ts + "&is_value_base64=" + this.is_value_base64 this.postAddress =
this.postAddress = "https://zhgh.hrbnu.edu.cn/signature?prefix=" + this.prefix + "&id=" + ts + "&is_value_base64=" + this.is_value_base64 location.protocol +
"//" +
location.host +
"/signature?prefix=" +
this.prefix +
"&id=" +
ts +
"&is_value_base64=" +
this.is_value_base64
// this.postAddress = "https://zhgh.hrbnu.edu.cn/signature?prefix=" + this.prefix + "&id=" + ts + "&is_value_base64=" + this.is_value_base64
this.showQrCode = true this.showQrCode = true
@@ -101,7 +101,6 @@
<script src="${base!}/assets/platform/js/offscreen.js"></script> <script src="${base!}/assets/platform/js/offscreen.js"></script>
<!-- <script src="https://cdn.jsdelivr.net/npm/vue-echarts@4.0.2"></script>--> <!-- <script src="https://cdn.jsdelivr.net/npm/vue-echarts@4.0.2"></script>-->
<script src="${base!}/assets/platform/plugins/vue-charts/echartTheme.js"></script> <script src="${base!}/assets/platform/plugins/vue-charts/echartTheme.js"></script>
<script src="${base!}/assets/platform/js/chengSh.js"></script>
<!--拖拽js--> <!--拖拽js-->
<script src="${base!}/assets/platform/js/directive/v-sticky.js"></script> <script src="${base!}/assets/platform/js/directive/v-sticky.js"></script>
@@ -109,6 +108,7 @@
<script src="${base!}/assets/platform/js/jr-qrcode.js"></script> <script src="${base!}/assets/platform/js/jr-qrcode.js"></script>
<!--字典混入--> <!--字典混入-->
<script src="${base!}/assets/platform/js/chengSh.js"></script>
<script src="${base!}/components/plugins/sysDict/DictData.js"></script> <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/commonUtil.js"></script>
@@ -3,45 +3,70 @@ layout("/mobile/platform.html"){
#--> #-->
<style> <style>
.module {
margin: 10px 10px 14px 10px; .parent-card {
box-shadow: 0 8px 12px #ebedf0; margin: 14px;
padding: 12px 12px;
background-color: #fff;
border-radius: 10px; border-radius: 10px;
box-shadow: 0 8px 12px #ebedf0;
line-height: 22px;
font-size: 13px;
position: relative;
} }
.content-card {
.menu {
display: flex;
flex-wrap: wrap;
row-gap: 10px;
background-color: white;
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
padding: 6px 0px;
}
.menu_img {
position: absolute;
right: 10px;
bottom: 0px;
}
.menu_img_yjf {
position: absolute;
right: 10px;
bottom: 10px;
width: 100px;
height: 60px;
}
.pay_img {
margin-right: 5px;
display: flex;
}
.member_cost .van-cell__title {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.left-child-card {
display: table;
margin-right: 8px;
}
.left-child-card img {
display: table-cell;
width: 40px;
}
.footer-card {
text-align: right;
}
.footer-card .van-button {
border-radius: 6px;
height: 28px;
}
.pay-content {
}
.pay-content .van-cell {
align-items: center;
justify-content: space-between;
}
.pay-content .van-cell__title {
color: #646566;
}
.pay_img {
display: table;
}
.pay_img img {
display: table-cell;
}
.costFormula {
}
.costFormula .van-cell__title {
max-width: 100px;
}
.van-action-sheet__content {
padding-bottom: 50px;
}
.van-dropdown-menu__bar {
box-shadow: none;
}
.van-empty {
position: relative;
transform: none;
left: 0;
}
</style> </style>
<div id="app" v-cloak> <div id="app" v-cloak>
@@ -49,70 +74,93 @@ layout("/mobile/platform.html"){
<van-nav-bar @click-left="pjaxReplace('/mobile/index')" left-arrow title="会费支付"></van-nav-bar> <van-nav-bar @click-left="pjaxReplace('/mobile/index')" left-arrow title="会费支付"></van-nav-bar>
</van-sticky> </van-sticky>
<div> <van-dropdown-menu active-color="#1989fa">
<van-tabs @change="pageData" v-model="memberActive"> <van-dropdown-item v-model="pageForm.year" @change="doSearch" :options="yearList"></van-dropdown-item>
<van-tab title="未缴费"></van-tab> <van-dropdown-item v-model="pageForm.isPay" @change="doSearch" :options="payList"></van-dropdown-item>
<van-tab title="已缴费"></van-tab> </van-dropdown-menu>
</van-tabs>
<van-row class="module" v-for="p in payList"> <div class="parent-card">
<div class="menu"> <div v-for="item in tableData">
<van-col :span="8" style="padding: 10px"> <div class="content-card">
<van-image height="6rem" round src="/assets/mobile/svg/memberPay/hf.svg" width="6rem"></van-image> <div class="left-child-card">
</van-col> <img src="/assets/mobile/svg/memberPay/icon_xsgj.svg"/>
<van-col :span="16" style="position: relative">
<div style="text-align: left">
会费项目:
<div style="font-weight: bold; font-size: 14px">{{p.projectName}}</div>
</div> </div>
<div style="text-align: left"> <div class="right-child-card">
会费标准: <div>
<div v-if="p.selectMode==='1'" style="font-weight: bold; font-size: 14px">{{p.modeValue}}</div> <span>项目名称:</span>
<div v-if="p.selectMode==='2'" style="font-weight: bold; font-size: 14px">{{p.modeValueName}}</div> <span>{{item.projectName}}</span>
</div> </div>
<div style="text-align: left" v-if="p.paymentMoney&&p.isPayment">已缴费金额:{{p.paymentMoney}}</div> <div>
<div class="menu_img" v-if="!p.isPayment"> <span>所属时间:</span>
<van-button @click.stop="openAlipay(p)" color="#1867b0" round size="mini" style="width: 75px; height: 30px" type="primary"> <span>{{item.paymentStartMonth}} 至 {{item.paymentEndMonth}}</span>
</div>
<div>
<span>缴费时间:</span>
<span>{{moment(item.startTime).format('MM-DD') + ' 至 ' + moment(item.endTime).format('MM-DD')}}</span>
</div>
</div>
</div>
<div class="footer-card">
<van-button v-if="!item.isPayment" @click.stop="openPay(item)" color="#1867b0" size="small" type="primary">
我要缴费 我要缴费
</van-button> </van-button>
<van-button v-if="item.isPayment" size="small" type="primary" :disabled="true">
您已缴费
</van-button>
</div> </div>
<div class="menu_img_yjf" v-if="p.isPayment">
<van-image src="/assets/mobile/svg/memberPay/yjf.svg"></van-image>
</div> </div>
</van-col> <van-empty
<el-col span="2"></el-col> class="custom-image"
description="暂无缴费记录"
image="https://img01.yzcdn.cn/vant/custom-empty-image.png"
v-if="tableData && tableData.length===0"
></van-empty>
</div> </div>
</van-row>
<van-action-sheet :close-on-click-overlay="false" :title="viewData.projectName" style="height: 60%" v-model="payShow"> <van-action-sheet :close-on-click-overlay="false" :title="payInfo.projectName" style="height: 60%" v-model="payVisible" @close="payVisibleClose">
<div class="member_cost"> <div class="pay-content">
<div v-if="viewData.selectMode==='2'"> <template>
<van-cell :value="costFormula" title="会费计算公式"></van-cell> <van-cell class="costFormula" title="缴费所属时间">
<van-cell-group> <template #right-icon>
{{formData.paymentStartMonth}} 至 {{formData.paymentEndMonth}}
</template>
</van-cell>
<van-cell class="costFormula" title="缴费标准">
<template #right-icon>
<div style="color: red"
v-if="formData.payModeValueList&&formData.payModeValueList.length>0">
(
<template v-for="(o,i) in formData.payModeValueList">
{{o.name}}
<template v-if="i != formData.payModeValueList.length - 1">+</template>
</template>
) * 0.5% * {{formData.paymentMonth}}个月
</div>
<div v-else>固定金额缴费</div>
</template>
</van-cell>
<van-field <van-field
:label="o.name" :label="o.name"
:placeholder="'请输入'+o.name" :placeholder="'请输入' + o.name"
@input="moneyInput" @input="moneyInput"
input-align="right" input-align="right"
type="number" type="number"
v-for="(o,index) in viewData.modeValueList" v-for="(o,index) in formData.payModeValueList"
v-model="o.value" v-model="o.value"
> >
<template #left-icon> <template #left-icon>
<div class="pay_img"> <div class="pay_img">
<van-image src="/assets/mobile/svg/memberPay/money.svg"></van-image> <img src="/assets/mobile/svg/memberPay/money.svg"/>
</div> </div>
</template> </template>
</van-field> </van-field>
</van-cell-group> </template>
</div>
<div>
<van-radio-group checked-color="#1867b0" v-model="moneyModel"> <van-radio-group checked-color="#1867b0" v-model="moneyModel">
<van-cell-group>
<van-cell @click="moneyModel = 1" clickable title="支付宝"> <van-cell @click="moneyModel = 1" clickable title="支付宝">
<template #icon> <template #icon>
<div class="pay_img"> <div class="pay_img" style="margin-right: 4px">
<van-image src="/assets/mobile/svg/memberPay/zfb.svg"></van-image> <img src="/assets/mobile/svg/memberPay/zfb.svg"/>
</div> </div>
</template> </template>
<template #right-icon> <template #right-icon>
@@ -121,110 +169,109 @@ layout("/mobile/platform.html"){
</van-cell> </van-cell>
<van-cell @click="moneyModel = 2" clickable title="微信"> <van-cell @click="moneyModel = 2" clickable title="微信">
<template #icon> <template #icon>
<div class="pay_img"> <div class="pay_img" style="margin-right: 4px">
<van-image src="/assets/mobile/svg/memberPay/wx.svg"></van-image> <img src="/assets/mobile/svg/memberPay/wx.svg"/>
</div> </div>
</template> </template>
<template #right-icon> <template #right-icon>
<van-radio :name="2"></van-radio> <van-radio :name="2"></van-radio>
</template> </template>
</van-cell> </van-cell>
</van-cell-group>
</van-radio-group> </van-radio-group>
<van-submit-bar :loading="loading" :price="formData.paymentMoney" @submit="doPay" button-color="#1867b0" button-text="支付"></van-submit-bar>
</div> </div>
</div>
<van-submit-bar :loading="loading" :price="money" @submit="doAlipay" button-color="#1867b0" button-text="支付"></van-submit-bar>
</van-action-sheet> </van-action-sheet>
<van-popup :style="{ height: '100%', width: '100%'}" @close="imgClose" closeable position="right" v-model="zfImg"> <van-popup :style="{ height: '100%', width: '100%'}" @close="imgClose" closeable position="right" v-model="payToOtherPage">
<van-image src="/assets/mobile/svg/memberPay/zf_img.png" style="margin-top: 40px; height: 95%; width: 100%"></van-image> <van-image src="/assets/mobile/svg/memberPay/zf_img.png" style="margin-top: 40px; height: 95%; width: 100%"></van-image>
</van-popup> </van-popup>
<van-empty
class="custom-image"
description="暂无缴费记录"
image="https://img01.yzcdn.cn/vant/custom-empty-image.png"
v-if="payList&&payList.length===0"
></van-empty>
</div>
</div> </div>
<script src="https://res2.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<script> <script>
function onBridgeReady(json) {
// const data = JSON.parse(json)
WeixinJSBridge.invoke("getBrandWCPayRequest", JSON.parse(json), function (res) {
if (res.err_msg === "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}
})
}
const vue = new Vue({ const vue = new Vue({
el: "#app", el: "#app",
mixins: [mobileMixins], mixins: [mobileMixins],
data() { data() {
return { return {
zfImg: false, payToOtherPage: false,
costFormula: "", costFormula: "",
formData: {}, payVisible: false,
payShow: false,
loading: false, loading: false,
moneyModel: "",
money: 0,
viewData: {}, viewData: {},
configData: {}, tableData: [],
payList: [], payList: [
memberActive: 0, {text: '全部', value: null},
intervalTimer: null {text: '已缴费', value: true},
{text: '未缴费', value: false},
],
pageForm: {
year: new Date().getFullYear(),
isPay: false
},
payInfo: {},
formData: {},
moneyModel: 2,
intervalTimer: null,
hasPayed: false,
} }
}, },
methods: { methods: {
imgClose() { async payVisibleClose() {
clearInterval(this.intervalTimer) clearInterval(this.intervalTimer)
},
doSearch() {
this.pageForm.pageNumber = 1
this.tableData = []
this.finished = false
this.pageData()
},
imgClose() {
this.loading = false this.loading = false
this.zfImg = false this.payToOtherPage = false
}, },
moneyInput() { moneyInput() {
const moneys = this.viewData.modeValueList.map((m) => Number(m.value)) let paymentMoney = this.formData.payModeValueList.reduce((a, b) => {
let money = 0 return a + b.value
moneys.forEach((m) => { }, 0)
money += m const pr = parseFloat((paymentMoney * 0.005 * this.formData.paymentMonth).toFixed(2))
}) this.$set(this.formData, "paymentMoney", pr * 100)
if (money <= 10) {
this.money = 1
} else {
money = money.toFixed(2)
this.money = (Number(money.replace(".", "")) * 0.5) / 100
}
}, },
async doAlipay() { async doPay() {
this.doIsPaySuccess() if (!this.formData.paymentMoney) {
if (!this.money) { this.$toast('请计算会费金额')
vant.Toast("请计算会费金额")
return return
} }
if (!this.moneyModel) { if (!this.moneyModel) {
vant.Toast("请选择支付方式") this.$toast('请选择支付方式')
return return
} }
this.loading = true if(this.moneyModel === 1) {
var u = navigator.userAgent this.$toast('暂未开通,敬请期待')
var isAndroid = u.indexOf("Android") > -1 || u.indexOf("Adr") > -1 //android终端 return
var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) //ios终端
let money = 0
if (this.viewData.selectMode === "1") {
money = this.viewData.modeValue
} else if (this.viewData.selectMode === "2") {
const moneys = this.viewData.modeValueList.map((m) => Number(m.value))
moneys.forEach((m) => {
money += m
})
money = (money * 0.5) / 100
money = money.toFixed(2)
} }
const u = navigator.userAgent
const isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) //ios终端
let userAgent = window.navigator.userAgent.toLowerCase()
if (this.moneyModel === 1) { if (this.moneyModel === 1) {
let use = window.navigator.userAgent.toLowerCase()
//是否微信浏览器 //是否微信浏览器
if (use.match(/MicroMessenger/i) && use.match(/MicroMessenger/i)[0] === "micromessenger") { if (userAgent.match(/MicroMessenger/i) && userAgent.match(/MicroMessenger/i)[0] === "micromessenger") {
this.zfImg = true this.payToOtherPage = true
return
} else { } else {
if (this.moneyModel === 1) {
const resp = await $.get("/mobile/memberCost/AlipayClient/tradePagePay", { const resp = await $.get("/mobile/memberCost/AlipayClient/tradePagePay", {
money: money, money: paymentMoney,
paymentProjectId: this.viewData.paymentProjectId paymentProjectId: this.payInfo.id
}) })
const div = document.createElement("div") const div = document.createElement("div")
div.innerHTML = resp // data就是接口返回的form 表单字符串 div.innerHTML = resp // data就是接口返回的form 表单字符串
@@ -237,67 +284,101 @@ layout("/mobile/platform.html"){
document.forms[0].submit() document.forms[0].submit()
} }
} }
} else if(this.moneyModel === 2) {
if (userAgent.match(/MicroMessenger/i) && userAgent.match(/MicroMessenger/i)[0] === "micromessenger") {
const confirm = await this.$dialog.confirm({
title: '温馨提示',
message: '您确定要支付吗?',
})
if (confirm === 'confirm') {
const loading = this.$toast.loading({
message: '支付中...',
forbidClick: true,
})
this.hasPayed = false
await this.pullWeChatPay()
await this.getIsPay(loading)
} }
} else { } else {
this.$toast('微信支付只能在微信APP中使用,请切换支付方式')
}
} }
}, },
async getConfig() { //拉起微信支付
const { data } = await $.get("/platform/member/payment/config/getPaymentConfig") async pullWeChatPay() {
this.configData = data const resp = await $.post("/mobile/memberCost/list/pullWeChatPay", {
money: this.formData.paymentMoney,
busId: this.payInfo.id
})
if (resp.code === 0) {
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener("WeixinJSBridgeReady", onBridgeReady(resp.data))
} else if (document.attachEvent) {
document.attachEvent("WeixinJSBridgeReady", onBridgeReady(resp.data))
document.attachEvent("onWeixinJSBridgeReady", onBridgeReady(resp.data))
}
} else {
onBridgeReady(resp.data)
}
}
}, },
async openAlipay(p) { async getIsPay(loading) {
const data = clone(p) this.intervalTimer = setInterval(async () => {
this.money = 0 const resp = await $.get("/platform/member/payment/mine/getIsPay", { paymentInfoId: this.payInfo.id })
this.moneyModel = "" if (resp.code === 0) {
this.viewData = data loading.close()
if(resp.data > 0) {
if (this.viewData.selectMode === "1") { this.hasPayed = true
this.money = Number(data.modeValue + "00")
} }
if (this.viewData.selectMode === "2") {
const names = this.viewData.modeValueList.map((m) => m.name)
this.costFormula = "(" + names.join("+") + ")" + "×0.5%"
} }
this.payShow = true }, 2000)
},
async openPay(row) {
this.payInfo = row
const payStandards = JSON.parse(row.payStandards)
const payStandard = payStandards.find(p => p.payPersonnel === row.payPersonnel && p.personType === row.personType)
this.$set(this.formData, "paymentMonth", row.paymentMonth)
this.$set(this.formData, "paymentStartMonth", row.paymentStartMonth)
this.$set(this.formData, "paymentEndMonth", row.paymentEndMonth)
this.$set(this.formData, "paymentInfoId", row.id)
if (payStandard.payModeValue) {
this.$set(this.formData, "payModeValueList", [])
this.$set(this.formData, "paymentMoney", payStandard.payModeValue)
} else {
this.$set(this.formData, "payModeValueList", payStandard.payModeValueList)
this.$set(this.formData, "paymentMoney", 0)
}
this.payVisible = true
}, },
async pageData() { async pageData() {
const resp = await $.post("/mobile/memberCost/list/pageData", { memberActive: this.memberActive }) const res = await $.post("/platform/member/payment/mine/pageData", this.pageForm)
if (resp.code === 0) { if (res.code === 0) {
const personType = "${@shiro.getPrincipalProperty('personType')}" this.tableData = this.tableData.concat(res.data.list)
const payStandards = this.configData.payStandards if (this.tableData.length === res.data.totalCount) {
resp.data.forEach((r) => { this.finished = true
payStandards.map((p) => {
if (p.personTypes.includes(personType)) {
r.selectMode = p.payMode
if (p.c === "1") {
r.modeValue = p.payModeValue
} else { } else {
r.modeValueList = p.payModeValueList this.pageForm.pageNumber++
const names = r.modeValueList.map((m) => m.name)
r.modeValueName = "(" + names.join("+") + ")" + "×0.5%"
} }
} }
})
})
this.payList = resp.data
}
}, },
doIsPaySuccess() {
this.intervalTimer = setInterval(async () => {
const resp = await $.get("/mobile/memberCost/list/getPayInfo", { id: this.viewData.id })
if (resp.data.isPayment === true) {
clearInterval(this.intervalTimer)
this.doSearch()
this.payShow = false
this.loading = false
this.zfImg = false
}
}, 4000)
}
}, },
async created() { async created() {
await this.getConfig() let nowYear = new Date().getFullYear()
for (let i = nowYear; i >= nowYear - 9; i--) {
this.yearList.push({ text: i, value: i })
}
await this.pageData() await this.pageData()
},
watch: {
"hasPayed"(val) {
if(val === true) {
clearInterval(this.intervalTimer)
this.$dialog.alert({title: '温馨提示', message: '支付成功'})
this.doSearch()
this.payVisible = false
}
}
} }
}) })
</script> </script>
@@ -0,0 +1,198 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<van-sticky>
<van-nav-bar @click-left="pjaxReplace('/mobile/index')" left-arrow title="缴费汇总"></van-nav-bar>
</van-sticky>
<div>
<van-search v-model="pageForm.search" placeholder="请输入搜索关键词" @search="doSearch">
</van-search>
</div>
<div>
<van-tabs @change="doSearch" v-model="pageForm.isPay">
<van-tab title="未缴费" :name="false"></van-tab>
<van-tab title="已缴费" :name="true"></van-tab>
</van-tabs>
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="pageData"
>
<van-cell-group>
<van-swipe-cell v-for="item in tableData">
<template #left>
<van-button @click="sendPaymentMsg(item)" style="height: 100%" square type="info" text="催缴" />
</template>
<van-cell >
<template #title>
<span class="custom-title">{{item.username}}</span>({{item.loginname}})
<van-tag :type="item.isPayment?'primary':'danger'">{{item.isPayment?'已缴':'未缴'}}</van-tag>
</template>
<template #label>
<div class="custom-title">人员类型:{{item.personType}}</div>
<div class="custom-title">在职状态:{{item.userState}}</div>
<div class="custom-title">所属工会:{{item.unionname}}</div>
<div class="custom-title">所属单位:{{item.unitname}}</div>
<div class="custom-title">缴费金额:{{item.paymentMoney}}</div>
</template>
<template #right-icon>
<van-button @click="openPay(item)" v-if="!item.isPayment" size="mini" plain type="info">设为已缴</van-button>
</template>
</van-cell>
<template #right>
<van-button style="height: 100%" @click="doDelete(item.id)" square type="danger" text="删除" />
</template>
</van-swipe-cell>
</van-cell-group>
</van-list>
<van-empty
class="custom-image"
description="暂无缴费记录"
image="https://img01.yzcdn.cn/vant/custom-empty-image.png"
v-if="tableData&&tableData.length===0"
></van-empty>
<van-action-sheet v-model="show" title="标题">
<div class="content">
<van-form @submit="onSubmit">
<van-field
v-model="formData.paymentMoney"
name="缴费金额"
label="缴费金额"
type="digit"
placeholder="缴费金额"
:rules="[{ required: true, message: '请填写缴费金额' }]"
></van-field>
<van-field
v-model="formData.remark"
name="备注"
label="备注"
placeholder="备注"
></van-field>
<div style="margin: 16px;">
<van-button round block type="info" native-type="submit">提交</van-button>
</div>
</van-form>
</div>
</van-action-sheet>
</div>
</div>
<script>
const vue = new Vue({
el: "#app",
data() {
return {
tableData: [],
memberActive: 0,
loading: false,
finished: false,
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
username: "",
isPay:false,
search:''
},
option1: [
{ text: '姓名', value: 'u.username' },
{ text: '工号', value: 'u.loginname' },
],
show:false,
formData: {}
}
},
methods: {
async pageData() {
const resp = await $.post("/platform/member/payment/summary/pageData", this.pageForm)
if (resp.code === 0) {
this.tableData = this.tableData.concat(resp.data.list)
this.pageForm.totalCount = resp.data.totalCount
if (this.tableData.length >= this.pageForm.totalCount) {
this.finished = true
} else {
this.pageForm.pageNumber++
}
this.loading = false
}
},
doSearch(){
this.pageForm.pageNumber = 1
if(this.tableData.length==this.pageForm.totalCount){
this.finished = true
}else{
this.finished = false
}
this.tableData = []
this.pageData()
},
async doDelete(id) {
const loading = this.$toast.loading({
message: "加载中...",
forbidClick: true,
overlay: true,
duration: 0
})
const resp = await $.get("/platform/member/payment/summary/doRemoveById", { id: id })
if (resp.code === 0) {
this.$toast.success(resp.msg)
await this.doSearch()
loading.close()
} else {
this.$toast.fail(resp.msg)
}
},
async sendPaymentMsg(row) {
this.$dialog.confirm({
title: '提示',
message: "您确定对【" + row.username + "】会员进行催缴吗?",
}).then(async () => {
const resp = await $.get("/platform/member/payment/summary/sendPaymentMsg", { id: row.id })
if (resp.code === 0) {
this.$toast.success(resp.msg)
await this.doSearch()
} else {
this.$toast.fail(resp.msg)
}
})
},
openPay(item){
this.show=true
this.formData=item
},
onSubmit(){
this.$dialog.confirm({
title: '提示',
message: "您确定要更改缴费信息吗?",
}).then(async () => {
const data={
ids:JSON.stringify([this.formData.id]),
paymentMoney:this.formData.paymentMoney,
remark:this.formData.remark,
isPay:this.formData.isPayment
}
const resp = await $.get("/platform/member/payment/summary/modify", data)
if (resp.code === 0) {
this.$toast.success(resp.msg)
await this.doSearch()
this.show=false
} else {
this.$toast.fail(resp.msg)
}
})
}
},
async created() {
await this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -16,11 +16,13 @@ layout("/mobile/platform.html"){
border-bottom: 1px dashed lightgrey; border-bottom: 1px dashed lightgrey;
} }
.selection .van-checkbox-group .van-cell, .selection .van-radio-group .van-cell { .selection .van-checkbox-group .van-cell,
.selection .van-radio-group .van-cell {
flex-direction: row-reverse; flex-direction: row-reverse;
} }
.selection .van-checkbox-group .van-cell .van-cell__title, .selection .van-radio-group .van-cell .van-cell__title { .selection .van-checkbox-group .van-cell .van-cell__title,
.selection .van-radio-group .van-cell .van-cell__title {
padding-left: 20px; padding-left: 20px;
} }
@@ -41,7 +43,6 @@ layout("/mobile/platform.html"){
} }
.van-collapse-item .van-collapse-item__title { .van-collapse-item .van-collapse-item__title {
} }
.selection .van-radio { .selection .van-radio {
@@ -59,7 +60,9 @@ layout("/mobile/platform.html"){
height: 80px; height: 80px;
} }
.welfare_img .van-image__error, .welfare_img .van-image__img, .welfare_img .van-image__loading { .welfare_img .van-image__error,
.welfare_img .van-image__img,
.welfare_img .van-image__loading {
border-radius: 10px; border-radius: 10px;
margin-left: -35px; margin-left: -35px;
} }
@@ -115,7 +118,7 @@ layout("/mobile/platform.html"){
padding-left: 20px; padding-left: 20px;
padding-right: 10px; padding-right: 10px;
position: relative; position: relative;
height: 100px height: 100px;
} }
.optionDesc { .optionDesc {
@@ -132,39 +135,52 @@ layout("/mobile/platform.html"){
border: 1pt solid #000000 !important; border: 1pt solid #000000 !important;
} }
.van-submit-bar__button {
width: 150px;
}
.custom-cell {
font-size: 18px;
font-weight: bold;
}
</style> </style>
<div id="app" v-cloak> <div id="app" v-cloak>
<van-sticky> <van-sticky>
<van-nav-bar @click-left="history.go(-1)" left-arrow <van-nav-bar @click-left="history.go(-1)" left-arrow title="福利详情"></van-nav-bar>
title="福利详情"></van-nav-bar>
</van-sticky> </van-sticky>
<template v-show="vLoading && !vLoading.value"> <template v-show="vLoading && !vLoading.value">
<div> <div>
<van-image :src="CREATE_PREVIEW_URL(projectInfo.cover)" <van-image :src="CREATE_PREVIEW_URL(projectInfo.cover)" fit="cover" style="width: 100%; height: 150px"></van-image>
fit="cover"
style="width: 100%;height: 150px"></van-image>
</div> </div>
<!--基本信息--> <!--基本信息-->
<van-cell-group class="van-cell-group--inset"> <van-cell-group class="van-cell-group--inset">
<van-cell> <van-cell>
<div style="font-weight: bold;font-size: 15px;display: flex;align-items: center"> <div style="font-weight: bold; font-size: 15px; display: flex; align-items: center; justify-content: space-between">
福利信息 <div>
<span>福利信息</span>
</div>
<div @click="clickUpOrDown=!clickUpOrDown">
<span>{{clickUpOrDown ? '点击收起' : '点击展开'}}</span>
<van-icon :name="clickUpOrDown?'arrow-up':'arrow-down'"></van-icon>
</div>
</div> </div>
</van-cell> </van-cell>
<template v-if="clickUpOrDown">
<van-cell :border="false" :value="projectInfo.name" title="福利名称"></van-cell> <van-cell :border="false" :value="projectInfo.name" title="福利名称"></van-cell>
<van-cell :border="false" :value="projectInfo.festival" title="发放节日"></van-cell> <van-cell :border="false" :value="projectInfo.festival" title="发放节日"></van-cell>
<van-cell :border="false" :value="projectInfo.gift" title="福利礼品" <van-cell :border="false" :value="projectInfo.gift" title="福利礼品" v-if="!projectInfo.flexible"></van-cell>
v-if="!projectInfo.flexible"></van-cell>
<!--<van-cell :border="false" :value="projectInfo.provideAddress" <!--<van-cell :border="false" :value="projectInfo.provideAddress"
title="发放地点"></van-cell>--> title="发放地点"></van-cell>-->
<van-cell :border="false" title="选择形式"> <van-cell :border="false" title="选择形式">{{projectInfo.isCheckBox==='checkBox'?'多选':'单选'}}</van-cell>
{{projectInfo.isCheckBox==='checkBox'?'多选':'单选'}} <van-cell
</van-cell> :border="false"
<van-cell :border="false" :value="projectInfo.multiSelectNum" title="最多选几个" :value="projectInfo.multiSelectNum"
v-if="projectInfo.isCheckBox==='checkBox'"></van-cell> title="最多选几个"
v-if="projectInfo.isCheckBox==='checkBox'"
></van-cell>
<van-cell :border="false" title="发放形式"> <van-cell :border="false" title="发放形式">
<template> <template>
{{welfareProvideMode.find(v=>v.code==projectInfo.provideMode) && {{welfareProvideMode.find(v=>v.code==projectInfo.provideMode) &&
@@ -173,58 +189,52 @@ layout("/mobile/platform.html"){
</van-cell> </van-cell>
<van-cell :border="false" title="签收形式"> <van-cell :border="false" title="签收形式">
<template> <template>
{{welfareSignMode.find(v=>v.code==projectInfo.signMode) && {{welfareSignMode.find(v=>v.code==projectInfo.signMode) && welfareSignMode.find(v=>v.code==projectInfo.signMode).description}}
welfareSignMode.find(v=>v.code==projectInfo.signMode).description}}
</template> </template>
</van-cell> </van-cell>
<van-cell :border="false" title="选择时间"> <van-cell :border="false" title="选择时间">
<template #label> <template #label>{{projectInfo.choiceTimeStart + ' 至 ' + projectInfo.choiceTimeEnd}}</template>
{{projectInfo.choiceTimeStart + ' 至 ' + projectInfo.choiceTimeEnd}}
</template>
</van-cell> </van-cell>
</template>
</van-cell-group> </van-cell-group>
<!--礼品套餐--> <!--礼品套餐-->
<div class="van-cell-group--inset" <div
style="margin:10px auto" class="van-cell-group--inset"
style="margin: 10px auto"
v-if="projectInfo.flexible && [2,3].includes(projectInfo.provideMode) v-if="projectInfo.flexible && [2,3].includes(projectInfo.provideMode)
&& projectInfo.welfareProjectSubjects && projectInfo.welfareProjectSubjects
&& projectInfo.welfareProjectSubjects.length>0"> && projectInfo.welfareProjectSubjects.length>0"
>
<van-cell> <van-cell>
<div style="font-weight: bold;font-size: 15px;display: flex;align-items: center"> <div style="font-weight: bold; font-size: 15px; display: flex; align-items: center">选择套餐</div>
选择套餐
</div>
</van-cell> </van-cell>
<div class="selection" style="background: #FFF" <div class="selection" style="background: #fff" v-for="(subject,sidx) in projectInfo.welfareProjectSubjects">
v-for="(subject,sidx) in projectInfo.welfareProjectSubjects"> <div style="display: flex; width: 100%; padding: 10px 0" v-for="(option, oidx) in subject.options">
<div style="display: flex;width: 100%;padding: 10px 0" <div style="width: 120px; height: 100px; display: flex; justify-content: center; align-items: center">
v-for="(option, oidx) in subject.options"> <van-image
<div style="width: 120px;height: 100px;display: flex;justify-content: center;align-items: center"> :src="FILE_STREAM_PREVIEW_ADDRESS+'?id='+option.imgUrl"
<van-image :src="FILE_STREAM_PREVIEW_ADDRESS+'?id='+option.imgUrl"
fit="contain" fit="contain"
style="width: 100px;height: 100px;border-radius: 10px"></van-image> style="width: 100px; height: 100px; border-radius: 10px"
></van-image>
<!-- @click="vant.ImagePreview([CREATE_PREVIEW_URL(option.imgUrl)])"--> <!-- @click="vant.ImagePreview([CREATE_PREVIEW_URL(option.imgUrl)])"-->
</div> </div>
<div class="right_content"> <div class="right_content">
<div style="display: flex;justify-content: space-between;align-items: center;font-size: 14px"> <div style="display: flex; justify-content: space-between; align-items: center; font-size: 14px">
<div style="width: 100%">{{option.optionName}}</div> <div style="width: 100%">{{option.optionName}}</div>
</div> </div>
<div class="optionDesc"> <div class="optionDesc">
<template v-if="option.supplier"> <template v-if="option.supplier">服务专线:{{option.supplier}}</template>
服务专线:{{option.supplier}}
</template>
</div> </div>
<div class="optionDesc" v-if="option.simpleDesc"> <div class="optionDesc" v-if="option.simpleDesc">备注:{{option.simpleDesc}}</div>
备注:{{option.simpleDesc}} <div style="position: absolute; right: 10px; bottom: 0; left: 0; display: flex; justify-content: space-between">
</div> <div @click="openViewDesc(option.description)" style="width: 70px; font-size: 13px; color: #918a8a; text-align: right">
<div style="position: absolute;right: 10px;bottom: 0;left: 0;display: flex;justify-content: space-between">
<div @click="openViewDesc(option.description)"
style="width: 70px;font-size: 13px;color: #918a8a;text-align: right">
套餐详情 套餐详情
</div> </div>
<van-stepper :default-value="0" <van-stepper
:default-value="0"
:disabled="confirmButtonInfo.disabled" :disabled="confirmButtonInfo.disabled"
:min="0" :min="0"
@change="(value)=>{numChange(value,option,oidx)}" @change="(value)=>{numChange(value,option,oidx)}"
@@ -233,41 +243,35 @@ layout("/mobile/platform.html"){
disable-input disable-input
integer integer
theme="round" theme="round"
v-model="option.selectNum"></van-stepper> v-model="option.selectNum"
></van-stepper>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<van-submit-bar :button-text="confirmButtonInfo.text" <van-submit-bar
:button-text="confirmButtonInfo.text"
@submit="confirmSelect" @submit="confirmSelect"
tip="您可以在福利选择截至时间之前修改福利套餐" tip="您可以在福利选择截至时间之前修改福利套餐"
tip-icon="info-o"> tip-icon="info-o"
<div style="width: calc(100% - 110px);"> >
<div style="width: 25px;height: 25px;position: relative"> <div style="width: calc(100% - 110px)">
<div style="width: 25px; height: 25px; position: relative">
<van-icon name="shopping-cart-o" size="25"></van-icon> <van-icon name="shopping-cart-o" size="25"></van-icon>
<div class="van-info"> <div class="van-info">{{sumSelectNum}}</div>
{{sumSelectNum}}
</div>
</div> </div>
</div> </div>
</van-submit-bar> </van-submit-bar>
</template> </template>
<van-popup :style="{ height: '70%' }" closeable position="bottom" safe-area-inset-bottom <van-popup :style="{ height: '70%' }" closeable position="bottom" safe-area-inset-bottom v-model="selectAddressPopup">
v-model="selectAddressPopup">
<div style="height: 100%"> <div style="height: 100%">
<div style="font-size: 15px;font-weight: bold;text-align: center;padding-top: 16px;"> <div style="font-size: 15px; font-weight: bold; text-align: center; padding-top: 16px">配送至</div>
配送至
</div>
<template v-if="addressList && addressList.length>0"> <template v-if="addressList && addressList.length>0">
<van-cell @click="addressClick(item);selectAddressPopup=false" clickable <van-cell @click="addressClick(item);selectAddressPopup=false" clickable icon="location-o" v-for="item in addressList">
icon="location-o" <template #title>{{item.address}}</template>
v-for="item in addressList">
<template #title>
{{item.address}}
</template>
<template #label> <template #label>
<div>{{"地区:" + item.province + item.city + item.county}}</div> <div>{{"地区:" + item.province + item.city + item.county}}</div>
<div>{{"收件人:" + item.name}}</div> <div>{{"收件人:" + item.name}}</div>
@@ -278,42 +282,35 @@ layout("/mobile/platform.html"){
<van-empty description="暂无地址" v-else></van-empty> <van-empty description="暂无地址" v-else></van-empty>
<div style="position: absolute;bottom: 0;left: 0;box-sizing: border-box;width: 100%;padding: 0 16px;background: #fff"> <div style="position: absolute; bottom: 0; left: 0; box-sizing: border-box; width: 100%; padding: 0 16px; background: #fff">
<van-button @click="openAddressManage" block round <van-button @click="openAddressManage" block round style="height: 40px; margin: 5px 0" type="danger">地址管理</van-button>
style="height: 40px;margin: 5px 0"
type="danger">
地址管理
</van-button>
</div> </div>
</div> </div>
</van-popup> </van-popup>
<van-popup :style="{ height: '100%',width: '100%'}" position="right" safe-area-inset-bottom <van-popup :style="{ height: '100%',width: '100%'}" position="right" safe-area-inset-bottom v-model="descPopup">
v-model="descPopup">
<van-sticky> <van-sticky>
<van-nav-bar @click-left="descPopup=false" left-arrow <van-nav-bar @click-left="descPopup=false" left-arrow title="详情"></van-nav-bar>
title="详情"></van-nav-bar>
</van-sticky> </van-sticky>
<div @click="descImgClick" class="desc" style="padding: 20px;" v-html="desc"></div> <div @click="descImgClick" class="desc" style="padding: 20px" v-html="desc"></div>
</van-popup> </van-popup>
<van-popup :close-on-click-overlay="false" <van-popup
:close-on-click-overlay="false"
:style="{ height: '90vh', 'overflow-y':'auto', background:'#f9f9f9'}" :style="{ height: '90vh', 'overflow-y':'auto', background:'#f9f9f9'}"
closeable closeable
position="bottom" position="bottom"
round round
safe-area-inset-bottom safe-area-inset-bottom
v-model="confirmPopup"> v-model="confirmPopup"
>
<div> <div>
<!--选择的信息--> <!--选择的信息-->
<div class="van-cell-group--inset"> <div class="van-cell-group--inset">
<van-cell> <van-cell>
<van-icon class="van-cell__left-icon" color="red" name="location" <van-icon class="van-cell__left-icon" color="red" name="location" slot="icon"></van-icon>
slot="icon"></van-icon> <div slot="title" style="font-weight: bold; font-size: 15px">已选福利</div>
<div slot="title" style="font-weight: bold;font-size: 15px">已选福利</div>
</van-cell> </van-cell>
<van-cell style="padding: 0" v-for="(item,index) in selectedOptions"> <van-cell style="padding: 0" v-for="(item,index) in selectedOptions">
<van-card <van-card
@@ -322,15 +319,11 @@ layout("/mobile/platform.html"){
:thumb="FILE_STREAM_PREVIEW_ADDRESS+'?id='+item.imgUrl" :thumb="FILE_STREAM_PREVIEW_ADDRESS+'?id='+item.imgUrl"
:title="item.optionName" :title="item.optionName"
desc="" desc=""
style="border-radius: 8px;background: #FFFFFF" style="border-radius: 8px; background: #ffffff"
></van-card> ></van-card>
<div class="van-hairline--top"></div> <div class="van-hairline--top"></div>
<van-cell @click="openShoppingPopup(item,index)" is-link title="收货门店" <van-cell @click="openShoppingPopup(item,index)" is-link title="收货门店" v-if="item.shoppingId">
v-if="item.shoppingId"> <template #label>{{item.receiveAddress?item.receiveAddress:'暂未选择'}}</template>
<template #label>
{{item.receiveAddress?item.receiveAddress:'暂未选择'}}
</template>
</van-cell> </van-cell>
</van-cell> </van-cell>
</div> </div>
@@ -338,17 +331,13 @@ layout("/mobile/platform.html"){
<!--邮寄到家 填写收货地址--> <!--邮寄到家 填写收货地址-->
<div class="van-cell-group--inset" v-if="projectInfo.provideMode===3"> <div class="van-cell-group--inset" v-if="projectInfo.provideMode===3">
<van-cell> <van-cell>
<van-icon class="van-cell__left-icon" color="red" name="location" <van-icon class="van-cell__left-icon" color="red" name="location" slot="icon"></van-icon>
slot="icon"></van-icon> <div slot="title" style="font-weight: bold; font-size: 15px">收货地址</div>
<div slot="title" style="font-weight: bold;font-size: 15px">收货地址</div>
</van-cell> </van-cell>
<van-cell @click="clickSelectAddressPopup" class="address-cell" is-link <van-cell @click="clickSelectAddressPopup" class="address-cell" is-link title="">
title="">
<template> <template>
<span v-if="$.isEmptyObject(selectAddress)">请选择地址</span> <span v-if="$.isEmptyObject(selectAddress)">请选择地址</span>
<span v-else> <span v-else>{{selectAddress}}</span>
{{selectAddress}}
</span>
</template> </template>
</van-cell> </van-cell>
</div> </div>
@@ -357,69 +346,58 @@ layout("/mobile/platform.html"){
<div class="van-cell-group--inset" v-if="projectInfo.signMode===2"> <div class="van-cell-group--inset" v-if="projectInfo.signMode===2">
<van-cell> <van-cell>
<template #title> <template #title>
<div style="font-weight: bold;font-size: 15px">电子签名</div> <div style="font-weight: bold; font-size: 15px">电子签名</div>
</template> </template>
</van-cell> </van-cell>
<van-cell title=""> <van-cell title="">
<template #label> <template #label>
<mobile-sign :is_value_base64="false" prefix="welfare" ref="signature" <mobile-sign :is_value_base64="false" prefix="welfare" ref="signature" v-model="signData"></mobile-sign>
v-model="signData"></mobile-sign>
</template> </template>
</van-cell> </van-cell>
</div> </div>
<div style="padding: 10px 16px;left: 0;right: 0;bottom: 0;background: #FFFFFF"> <div style="padding: 10px 16px; left: 0; right: 0; bottom: 0; background: #ffffff">
<van-button @click="submitSelect" round style="width: 100%" type="danger">提交 <van-button @click="submitSelect" round style="width: 100%" type="danger">提交</van-button>
</van-button>
</div> </div>
</div> </div>
</van-popup> </van-popup>
<van-popup :style="{ height: '90vh', 'overflow-y':'auto', background:'#f9f9f9'}" <van-popup
:style="{ height: '90vh', 'overflow-y':'auto', background:'#f9f9f9'}"
closeable closeable
position="bottom" position="bottom"
round round
safe-area-inset-bottom safe-area-inset-bottom
v-model="shoppingPopup"> v-model="shoppingPopup"
>
<div> <div>
<div style="margin-top: 45px"> <div style="margin-top: 45px">
<van-search <van-search @search="onSearchShoppingAddress" placeholder="请输入门店关键词" show-action v-model="shoppingAddress">
@search="onSearchShoppingAddress"
placeholder="请输入门店关键词"
show-action
v-model="shoppingAddress">
<template #action> <template #action>
<div @click="onSearchShoppingAddress">搜索</div> <div @click="onSearchShoppingAddress">搜索</div>
</template> </template>
</van-search> </van-search>
<div class="van-cell-group--inset" <div class="van-cell-group--inset" v-if="offlineStoresOption && offlineStoresOption.length>0">
v-if="offlineStoresOption&&offlineStoresOption.length>0"> <van-cell icon="location-o" class="custom-cell" @click="addShopping(item.address)" v-for="item in offlineStoresOption">
<van-cell @click="addShopping(item.address)" is-link
v-for="item in offlineStoresOption"
>
{{item.address}} {{item.address}}
</van-cell> </van-cell>
</div> </div>
<div v-else> <div v-else>
<van-empty description="描述文字" style="height: calc(100% - 180px);"></van-empty> <van-empty description="描述文字" style="height: calc(100% - 180px)"></van-empty>
</div> </div>
</div> </div>
</div> </div>
</van-popup> </van-popup>
</div> </div>
<script> <script>
<!--#include("/mobile/welfare/include/mixins.js"){}#--> <!--#include("/mobile/welfare/include/mixins.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: '#app', el: "#app",
mixins: [mobileMixins, welfareMixins], mixins: [mobileMixins, welfareMixins],
components: { components: {
'mobile-sign': httpVueLoader('/components/sign/mobileSign.vue'), "mobile-sign": httpVueLoader("/components/sign/mobileSign.vue")
}, },
data() { data() {
return { return {
@@ -441,13 +419,16 @@ layout("/mobile/platform.html"){
shoppingAddress: "", shoppingAddress: "",
optionIndex: null, optionIndex: null,
optionData: {}, optionData: {},
clickUpOrDown: false
} }
}, },
computed: { computed: {
sumSelectNum() { sumSelectNum() {
if (this.projectInfo && this.projectInfo.welfareProjectSubjects) { if (this.projectInfo && this.projectInfo.welfareProjectSubjects) {
return this.projectInfo.welfareProjectSubjects[0].options.map(v => v.selectNum).reduce((accumulator, currentValue) => accumulator + currentValue, 0) return this.projectInfo.welfareProjectSubjects[0].options
.map((v) => v.selectNum)
.reduce((accumulator, currentValue) => accumulator + currentValue, 0)
} }
return 0 return 0
}, },
@@ -465,92 +446,129 @@ layout("/mobile/platform.html"){
}, },
confirmButtonInfo() { confirmButtonInfo() {
if (this.projectInfo) { if (this.projectInfo) {
const {choiceTimeEnd, choiceTimeStart, overdueChoiceTimeEnd} = this.projectInfo const { choiceTimeEnd, choiceTimeStart, overdueChoiceTimeEnd } = this.projectInfo
const now = moment().valueOf() const now = moment().valueOf()
if (overdueChoiceTimeEnd == null || overdueChoiceTimeEnd === '') { if (overdueChoiceTimeEnd == null || overdueChoiceTimeEnd === "") {
if (now > moment(choiceTimeStart).valueOf() && now < moment(choiceTimeEnd).valueOf()) { if (now > moment(choiceTimeStart).valueOf() && now < moment(choiceTimeEnd).valueOf()) {
return {text: this.isSelect ? '确定修改' : '确定选择', disabled: false} return { text: this.isSelect ? "选好了,下一步" : "选好了,下一步", disabled: false }
} else if (now > moment(choiceTimeEnd).valueOf()) { } else if (now > moment(choiceTimeEnd).valueOf()) {
return {text: '选择已结束', disabled: true} return { text: "选择已结束", disabled: true }
} else if (now < moment(choiceTimeStart).valueOf()) { } else if (now < moment(choiceTimeStart).valueOf()) {
return {text: '选择未开始', disabled: true} return { text: "选择未开始", disabled: true }
} }
} else { } else {
//已选择了不能再动了 //已选择了不能再动了
if (this.isSelect) { if (this.isSelect) {
if (moment(this.selectTime).valueOf() > moment(choiceTimeEnd).valueOf() && now < moment(overdueChoiceTimeEnd).valueOf()) { if (moment(this.selectTime).valueOf() > moment(choiceTimeEnd).valueOf() && now < moment(overdueChoiceTimeEnd).valueOf()) {
return {text: '确定修改', disabled: false} return { text: "下一步", disabled: false }
} }
return {text: '选择已结束', disabled: true} return { text: "选择已结束", disabled: true }
} else { } else {
if (now > moment(choiceTimeStart).valueOf() && now < moment(overdueChoiceTimeEnd).valueOf()) { if (now > moment(choiceTimeStart).valueOf() && now < moment(overdueChoiceTimeEnd).valueOf()) {
return {text: this.isSelect ? '确定修改' : '确定选择', disabled: false} return { text: this.isSelect ? "选好了,下一步" : "选好了,下一步", disabled: false }
} else if (now > moment(overdueChoiceTimeEnd).valueOf()) { } else if (now > moment(overdueChoiceTimeEnd).valueOf()) {
return {text: '选择已结束', disabled: true} return { text: "选择已结束", disabled: true }
} else if (now < moment(choiceTimeStart).valueOf()) { } else if (now < moment(choiceTimeStart).valueOf()) {
return {text: '选择未开始', disabled: true} return { text: "选择未开始", disabled: true }
} }
} }
} }
} }
return {text: '', disabled: true} return { text: "", disabled: true }
}, },
selectedOptions() { selectedOptions() {
if (this.projectInfo && this.projectInfo.welfareProjectSubjects) { if (this.projectInfo && this.projectInfo.welfareProjectSubjects) {
return this.projectInfo.welfareProjectSubjects[0].options.filter(v => v.selectNum >= 1) return this.projectInfo.welfareProjectSubjects[0].options.filter((v) => v.selectNum >= 1)
} }
return [] return []
} }
}, },
methods: { methods: {
addShopping(address) { addShopping(address) {
this.$set(this.projectInfo.welfareProjectSubjects[0].options[this.optionIndex], 'receiveAddress', address) this.$set(this.projectInfo.welfareProjectSubjects[0].options[this.optionIndex], "receiveAddress", address)
this.projectInfo.welfareProjectSubjects[0].options[this.optionIndex].receiveAddress = address
this.shoppingPopup = false this.shoppingPopup = false
}, },
async onSearchShoppingAddress() { async onSearchShoppingAddress() {
const data = await this.getShoppingType() const data = await this.getShoppingType()
const shopping = data.find(d => d.id === this.optionData.shoppingId) const shopping = data.find((d) => d.id === this.optionData.shoppingId)
if (this.shoppingAddress) { if (this.shoppingAddress) {
this.offlineStoresOption = shopping.offlineStores.filter(s => s.address.includes(this.shoppingAddress)) this.offlineStoresOption = shopping.offlineStores.filter((s) => s.address.includes(this.shoppingAddress))
} else { } else {
this.offlineStoresOption = shopping.offlineStores this.offlineStoresOption = shopping.offlineStores
} }
}, },
openShoppingPopup(item, optionIndex) { openShoppingPopup(item, optionIndex) {
this.optionData = item this.optionData = item
const shopping = this.shoppingTypeOptions.find(v => v.id === item.shoppingId) const shopping = this.shoppingTypeOptions.find((v) => v.id === item.shoppingId)
this.offlineStoresOption = shopping.offlineStores this.offlineStoresOption = shopping.offlineStores
this.optionIndex = optionIndex this.optionIndex = optionIndex
this.shoppingAddress = "" this.shoppingAddress = ""
this.shoppingPopup = true this.shoppingPopup = true
}, },
editAddress(item) {
location.replace("/mobile/welfare/mine/addressEdit?projectId=" + this.projectId + "&id=" + item.id)
window.sessionStorage.setItem("welfareProjectId", this.projectId)
const formData = {
projectInfo: this.projectInfo,
signData: this.signData || null
}
window.sessionStorage.setItem("welfareProjectSelectInfo" + "${@shiro.getPrincipalProperty('loginname')}", JSON.stringify(formData))
},
deleteAddress(item) {
this.selectAddressPopup = true
// 确认要删除该地址吗
this.$dialog
.confirm({
title: "提示",
message: "确认要删除该地址吗"
})
.then(async () => {
const loading = this.$toast.loading({
message: "删除中...",
forbidClick: true,
overlay: true,
duration: 0
})
const resp = await $.post("/mobile/welfare/mine/deleteAddress", { id: item.id })
loading.close()
if (resp.code === 0) {
this.$toast.success(resp.msg)
}
await this.selectAddressList()
if (this.addressList && this.addressList.length > 0) {
const resp = this.addressList.find((v) => v.isDefault)
this.addressClick(resp)
} else {
this.selectAddress = ""
}
this.selectAddressPopup = true
})
.catch(() => {
this.selectAddressPopup = true
})
},
//数量更改 //数量更改
numChange(value, option, optionIndex) { numChange(value, option, optionIndex) {
const { const { isCheckBox, multiSelectNum, singleOptionSupportMultipleSelection } = this.projectInfo
isCheckBox, if (isCheckBox === "checkBox") {
multiSelectNum,
singleOptionSupportMultipleSelection
} = this.projectInfo
if (isCheckBox === 'checkBox') {
//判断是否支持单个多选 //判断是否支持单个多选
if (!singleOptionSupportMultipleSelection && value > 1) { if (!singleOptionSupportMultipleSelection && value > 1) {
this.$set(this.projectInfo.welfareProjectSubjects[0].options[optionIndex], 'selectNum', 1) this.$set(this.projectInfo.welfareProjectSubjects[0].options[optionIndex], "selectNum", 1)
this.$toast('此套餐最多只能选择1份') this.$toast("此套餐最多只能选择1份")
return; return
} }
} }
//获取用户当前选择的数量 //获取用户当前选择的数量
const selectNums = this.projectInfo.welfareProjectSubjects[0].options.map(v => v.selectNum) const selectNums = this.projectInfo.welfareProjectSubjects[0].options.map((v) => v.selectNum)
const sum = selectNums.reduce((accumulator, currentValue) => accumulator + currentValue, 0) const sum = selectNums.reduce((accumulator, currentValue) => accumulator + currentValue, 0)
if (sum > multiSelectNum) { if (sum > multiSelectNum) {
this.$set(this.projectInfo.welfareProjectSubjects[0].options[optionIndex], 'selectNum', value - 1) this.$set(this.projectInfo.welfareProjectSubjects[0].options[optionIndex], "selectNum", value - 1)
this.$toast('此次福利最多只能选择' + multiSelectNum + '份') this.$toast("此次福利最多只能选择" + multiSelectNum + "份")
} }
}, },
//确定选择 //确定选择
@@ -560,15 +578,11 @@ layout("/mobile/platform.html"){
return return
} }
const { const { isCheckBox, multiSelectNum, singleOptionSupportMultipleSelection } = this.projectInfo
isCheckBox,
multiSelectNum,
singleOptionSupportMultipleSelection
} = this.projectInfo
if (isCheckBox === "checkBox") { if (isCheckBox === "checkBox") {
if (this.sumSelectNum < multiSelectNum) { if (this.sumSelectNum < multiSelectNum) {
//用户没有选择完 //用户没有选择完
this.$toast('一共可以选择' + multiSelectNum + '份,您目前只选择了' + this.sumSelectNum + '份,快去选择吧!') this.$toast("一共可以选择" + multiSelectNum + "份,您目前只选择了" + this.sumSelectNum + "份,快去选择吧!")
return return
} }
} }
@@ -583,25 +597,26 @@ layout("/mobile/platform.html"){
if (this.projectInfo.signMode === 2 && this.isSelect && this.userSelection) { if (this.projectInfo.signMode === 2 && this.isSelect && this.userSelection) {
this.signData = this.userSelection[0].userSign this.signData = this.userSelection[0].userSign
} }
}, },
//提交选择 //提交选择
async submitSelect() { async submitSelect() {
if (this.projectInfo.provideMode === 3) { if (this.projectInfo.provideMode === 3) {
if (this.selectAddress == null || this.selectAddress === '') { if (this.selectAddress == null || this.selectAddress === "") {
this.$modal.msg("请填写您的收货地址") this.$modal.msg("请填写您的收货地址")
return return
} }
} }
if (this.projectInfo.signMode === 2) { if (this.projectInfo.signMode === 2) {
if (this.signData == null || this.signData === '') { if (this.signData == null || this.signData === "") {
this.$modal.msg("请签名") this.$modal.msg("请签名")
return return
} }
} }
const notReceiveAddress = [] const notReceiveAddress = []
const formData = this.projectInfo.welfareProjectSubjects[0].options.filter(v => v.selectNum >= 1).map(v => { const formData = this.projectInfo.welfareProjectSubjects[0].options
.filter((v) => v.selectNum >= 1)
.map((v) => {
if (v.shoppingId && !v.receiveAddress) { if (v.shoppingId && !v.receiveAddress) {
notReceiveAddress.push(v.optionName) notReceiveAddress.push(v.optionName)
} }
@@ -618,11 +633,7 @@ layout("/mobile/platform.html"){
this.$modal.msg("请填写收货门店:" + notReceiveAddress.join(",")) this.$modal.msg("请填写收货门店:" + notReceiveAddress.join(","))
return return
} }
const { const { code, msg, data } = await $.post("/platform/welfare/userChoose/confirmSelect", {
code,
msg,
data
} = await $.post('/platform/welfare/userChoose/confirmSelect', {
welfareUserSelections: JSON.stringify(formData), welfareUserSelections: JSON.stringify(formData),
projectId: this.projectId projectId: this.projectId
}) })
@@ -638,24 +649,29 @@ layout("/mobile/platform.html"){
//查看详情 //查看详情
openViewDesc(desc) { openViewDesc(desc) {
if (desc == null || desc.length === 0) { if (desc == null || desc.length === 0) {
this.$toast('没有更多了') this.$toast("没有更多了")
return return
} }
this.desc = desc this.desc = desc
this.descPopup = true this.descPopup = true
}, },
descImgClick(e) { descImgClick(e) {
if (e.target.tagName === 'IMG') { if (e.target.tagName === "IMG") {
vant.ImagePreview([e.target.src]) vant.ImagePreview([e.target.src])
} }
}, },
//地址管理 //地址管理
openAddressManage() { openAddressManage() {
location.replace('/mobile/welfare/mine/address') location.replace("/mobile/welfare/mine/addressEdit?projectId=" + this.projectId)
window.sessionStorage.setItem('welfareProjectId', this.projectId) window.sessionStorage.setItem("welfareProjectId", this.projectId)
const formData = {
projectInfo: this.projectInfo,
signData: this.signData || null
}
window.sessionStorage.setItem("welfareProjectSelectInfo" + "${@shiro.getPrincipalProperty('loginname')}", JSON.stringify(formData))
}, },
clickSelectAddressPopup() { clickSelectAddressPopup() {
@@ -665,12 +681,12 @@ layout("/mobile/platform.html"){
//地址列表点击 //地址列表点击
addressClick(item) { addressClick(item) {
const {province, city, county, address, name, tel} = item const { province, city, county, address, name, tel } = item
this.selectAddress = "收货地址:" + province + city + county + address + "," + "收件人:" + name + "," + "联系方式:" + tel this.selectAddress = "收货地址:" + province + city + county + address + "," + "收件人:" + name + "," + "联系方式:" + tel
}, },
async getProjectInfo() { async getProjectInfo() {
const resp = await $.get('/platform/welfare/common/findOne', {projectId: this.projectId}) const resp = await $.get("/platform/welfare/common/findOne", { projectId: this.projectId })
if (resp.code === 0) { if (resp.code === 0) {
resp.data.multiSelectNum = resp.data.multiSelectNum ? resp.data.multiSelectNum : 1 resp.data.multiSelectNum = resp.data.multiSelectNum ? resp.data.multiSelectNum : 1
this.projectInfo = resp.data this.projectInfo = resp.data
@@ -680,15 +696,15 @@ layout("/mobile/platform.html"){
//获取用户选择的数据 //获取用户选择的数据
async getUserSelection(projectId) { async getUserSelection(projectId) {
const resp = await $.get('/platform/welfare/mine/getUserSelection', {projectId: projectId}) const resp = await $.get("/platform/welfare/mine/getUserSelection", { projectId: projectId })
this.userSelection = resp.data this.userSelection = resp.data
this.echoUserSelection() this.echoUserSelection()
}, },
//回显用户选择的数据 //回显用户选择的数据
echoUserSelection() { echoUserSelection() {
this.projectInfo.welfareProjectSubjects[0].options.forEach(v => { this.projectInfo.welfareProjectSubjects[0].options.forEach((v) => {
const option = this.userSelection.find(x => x.selectOptionId === v.id) const option = this.userSelection.find((x) => x.selectOptionId === v.id)
if (option) { if (option) {
v.selectNum = option.selectNum v.selectNum = option.selectNum
v.receiveAddress = option.receiveAddress v.receiveAddress = option.receiveAddress
@@ -698,25 +714,36 @@ layout("/mobile/platform.html"){
async getShoppingType() { async getShoppingType() {
const resp = await $.get("/platform/shoppingType/apply/getShoppingType") const resp = await $.get("/platform/shoppingType/apply/getShoppingType")
return resp.data return resp.data
}
},
}, },
async created() { async created() {
const id = GetQueryString("projectId") const id = GetQueryString("projectId")
if (!id) return if (!id) return
this.projectId = id this.projectId = id
this.getProjectInfo()
this.shoppingTypeOptions = await this.getShoppingType() this.shoppingTypeOptions = await this.getShoppingType()
// this.getChoice() // this.getChoice()
getEnumOptions("WelfareProvideMode").then(res => { getEnumOptions("WelfareProvideMode").then((res) => {
this.welfareProvideMode = res this.welfareProvideMode = res
}) })
getEnumOptions("WelfareSignMode").then(res => { getEnumOptions("WelfareSignMode").then((res) => {
this.welfareSignMode = res this.welfareSignMode = res
}) })
},
const loginname = "${@shiro.getPrincipalProperty('loginname')}"
const formData = window.sessionStorage.getItem("welfareProjectSelectInfo" + loginname)
if (formData) {
const resp = JSON.parse(formData)
this.projectInfo = resp.projectInfo
this.signData = resp.signData
this.confirmSelect()
window.sessionStorage.removeItem("welfareProjectSelectInfo" + loginname)
// this.selectAddressPopup = true
} else {
this.getProjectInfo()
}
}
}) })
window.addEventListener('pageshow', e => { window.addEventListener("pageshow", (e) => {
if (e.persisted || (window.performance && window.performance.navigation.type === 2)) { if (e.persisted || (window.performance && window.performance.navigation.type === 2)) {
vue.init() vue.init()
} }
@@ -12,8 +12,7 @@ layout("/mobile/platform.html"){
<div id="app" v-cloak> <div id="app" v-cloak>
<van-sticky> <van-sticky>
<van-nav-bar title="地址管理" left-arrow placeholder fixed <van-nav-bar title="地址管理" left-arrow placeholder fixed @click-left="back()"></van-nav-bar>
@click-left="location.replace('/mobile/welfare/mine/address')"></van-nav-bar>
</van-sticky> </van-sticky>
<div v-if="vLoading && !vLoading.value"> <div v-if="vLoading && !vLoading.value">
@@ -30,80 +29,80 @@ layout("/mobile/platform.html"){
@delete="onDelete" @delete="onDelete"
></van-address-edit> ></van-address-edit>
</div> </div>
</div> </div>
<script> <script>
<!--#include("/mobile/welfare/include/areaList.js"){};include("/mobile/welfare/include/mixins.js"){}#--> <!--#include("/mobile/welfare/include/areaList.js"){};include("/mobile/welfare/include/mixins.js"){}#-->
const vue = new Vue({ const vue = new Vue({
el: '#app', el: "#app",
mixins: [mobileMixins, welfareMixins], mixins: [mobileMixins, welfareMixins],
data() { data() {
return { return {
projectId: GetQueryString("projectId"),
areaList: areaList, areaList: areaList,
addressInfo: {}, addressInfo: {},
addressId: null addressId: null
}; }
}, },
methods: { methods: {
back() {
if (this.projectId) {
// pjaxReplace("/mobile/welfare/mine/address?projectId=" + this.projectId)
pjaxReplace("/mobile/welfare/list/receive?projectId=" + this.projectId)
} else {
pjaxReplace("/mobile/welfare/mine/address")
}
},
async onSave(content) { async onSave(content) {
const loading = this.$toast.loading({ const loading = this.$toast.loading({
message: '保存中...', message: "保存中...",
forbidClick: true, forbidClick: true,
overlay: true, overlay: true,
duration: 0 duration: 0
}) })
content.userName = content.name content.userName = content.name
const resp = await $.post('/mobile/welfare/mine/doSaveUserAddress', content) const resp = await $.post("/mobile/welfare/mine/doSaveUserAddress", content)
loading.close() loading.close()
if (resp.code === 0) { if (resp.code === 0) {
this.$toast.success(resp.msg) this.$toast.success(resp.msg)
setTimeout(() => { this.$nextTick(() => {
let welfareProjectId = window.sessionStorage.getItem("welfareProjectId"); this.back()
if (welfareProjectId) { })
location.replace('/mobile/welfare/list/receive?projectId=' + welfareProjectId)
window.sessionStorage.removeItem("welfareProjectId");
} else {
location.replace('/mobile/welfare/mine/address')
}
}, 1000)
} }
}, },
async onDelete(content) { async onDelete(content) {
const loading = this.$toast.loading({ const loading = this.$toast.loading({
message: '删除中...', message: "删除中...",
forbidClick: true, forbidClick: true,
overlay: true, overlay: true,
duration: 0 duration: 0
}) })
const resp = await $.post('/mobile/welfare/mine/deleteAddress', {id: content.id}) const resp = await $.post("/mobile/welfare/mine/deleteAddress", { id: content.id })
loading.close() loading.close()
if (resp.code === 0) { if (resp.code === 0) {
this.$toast.success(resp.msg) this.$toast.success(resp.msg)
setTimeout(() => { this.$nextTick(() => {
location.replace('/mobile/welfare/mine/address') this.back()
}, 1000) })
} }
} }
}, },
async created() { async created() {
this.startLoading() this.startLoading()
this.addressId = GetQueryString("id") === '' ? null : GetQueryString("id") this.addressId = GetQueryString("id") === "" ? null : GetQueryString("id")
if (this.addressId) { if (this.addressId) {
const resp = await $.get('/mobile/welfare/mine/findOneUserAddress', {id: this.addressId}) const resp = await $.get("/mobile/welfare/mine/findOneUserAddress", { id: this.addressId })
if (resp.code === 0) { if (resp.code === 0) {
this.addressInfo = resp.data this.addressInfo = resp.data
} }
this.closeLoading() this.closeLoading()
} else { } else {
this.addressInfo.name = "${@shiro.getPrincipalProperty('username')}"; this.addressInfo.name = "${@shiro.getPrincipalProperty('username')}"
this.closeLoading() this.closeLoading()
} }
/*this.areaList.province_list = {320000: "江苏省"} /*this.areaList.province_list = {320000: "江苏省"}
this.areaList.city_list = {320200: "无锡市"}*/ this.areaList.city_list = {320200: "无锡市"}*/
} }
}) })
</script> </script>
@@ -44,8 +44,8 @@ layout("/layouts/platform.html"){
style="width: 100%" v-model="pageForm.searchKeyword"> style="width: 100%" v-model="pageForm.searchKeyword">
<el-select slot="prepend" style="width: 80px;" <el-select slot="prepend" style="width: 80px;"
v-model="pageForm.searchName"> v-model="pageForm.searchName">
<el-option label="姓名" value="u.username"></el-option> <el-option label="姓名" value="hcu.username"></el-option>
<el-option label="工号" value="u.loginname"></el-option> <el-option label="工号" value="hcu.loginname"></el-option>
</el-select> </el-select>
</el-input> </el-input>
</div> </div>
@@ -217,7 +217,7 @@ layout("/layouts/platform.html"){
return { return {
pageForm: { pageForm: {
year: moment().format('YYYY'), year: moment().format('YYYY'),
searchName: "u.username", searchName: "hcu.username",
}, },
threeUnits: [], threeUnits: [],
unionGroups: [], unionGroups: [],
@@ -84,10 +84,10 @@ layout("/layouts/platform.html"){
<el-col :span="12"> <el-col :span="12">
<el-form-item label="申报基层工会" prop="fundsUnitName" v-if="formData.activity_type!=40003"> <el-form-item label="申报基层工会" prop="fundsUnitName" v-if="formData.activity_type!=40003">
<el-input placeholder="请输入基层工会名称" type="text" v-model="formData.fundsUnitName"></el-input> <el-input placeholder="请输入基层工会名称" readonly type="text" v-model="formData.fundsUnitName"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="申请协会" prop="clubId" v-else-if="formData.activity_type==40003"> <el-form-item label="申报文体协会" prop="clubId" v-else-if="formData.activity_type==40003">
<el-select @change="fundsUnitChange" placeholder="请选择申请协会" style="width: 100%" v-model="formData.clubId"> <el-select @change="fundsUnitChange" placeholder="请选择申报文体协会" style="width: 100%" v-model="formData.clubId">
<el-option <el-option
:key="item.id" :key="item.id"
:label="item.name+' ('+item.code+')'" :label="item.name+' ('+item.code+')'"
@@ -106,29 +106,6 @@ layout("/layouts/platform.html"){
v-model="formData.joinActivityNum" v-model="formData.joinActivityNum"
></el-input-number> ></el-input-number>
</el-form-item> </el-form-item>
<!-- <el-form-item prop="projectTypeCode" label="活动项目类型">
<el-select v-model="formData.projectTypeCode" placeholder="请选择活动类型"
style="width: 100%;">
<el-option
v-for="item in projectType"
:key="item.id"
:label="item.name+' ('+item.code+')'"
:value="item.code">
</el-option>
</el-select>
</el-form-item>-->
<!--<el-form-item label="活动经费类型" prop="projectJfCode">
<el-select placeholder="选择活动主体类型自动选择" style="width: 100%" v-model="formData.projectJfCode">
<el-option
:key="item.id"
:label="item.name+' ('+item.code+')'"
:value="item.code"
disabled
v-for="item in projectJfType"
></el-option>
</el-select>
</el-form-item>-->
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -155,7 +132,7 @@ layout("/layouts/platform.html"){
<el-form-item label="预算总费用" prop="funds_money"> <el-form-item label="预算总费用" prop="funds_money">
<el-input-number <el-input-number
disabled disabled
placeholder="输入物品单价自动计算" placeholder="输入预算费用自动计算"
:precision="2" :precision="2"
style="width: 100%" style="width: 100%"
v-model="formData.funds_money" v-model="formData.funds_money"
@@ -366,19 +343,10 @@ layout("/layouts/platform.html"){
} }
}, },
async getProjectCodeChange(val) { async getProjectCodeChange(val) {
this.$set(this.formData, "fundsUnitName", null)
await this.generateProjectCode(this.formData.activity_type) await this.generateProjectCode(this.formData.activity_type)
if (this.formData.activity_type == "40001") { if (this.formData.activity_type == "40002") {
const jfType = this.projectJfType.find((p) => p.code == "70001")
this.$set(this.formData, "projectJfCode", jfType ? jfType.code : null)
this.$set(this.formData, "fundsUnitName", "校工会")
} else if (this.formData.activity_type == "40002") {
const jfType = this.projectJfType.find((p) => p.code == "70002")
this.$set(this.formData, "projectJfCode", jfType ? jfType.code : null)
this.$set(this.formData, "fundsUnitName", '${@shiro.getPrincipalProperty("union").getUnionname()}') this.$set(this.formData, "fundsUnitName", '${@shiro.getPrincipalProperty("union").getUnionname()}')
} else if (this.formData.activity_type == "40003") { } else if (this.formData.activity_type == "40003") {
const jfType = this.projectJfType.find((p) => p.code == "70003")
this.$set(this.formData, "projectJfCode", jfType ? jfType.code : null)
const { data } = await $.get("/platform/jf/Funds/apply/getUserClub") const { data } = await $.get("/platform/jf/Funds/apply/getUserClub")
const clubList = await getClubs() const clubList = await getClubs()
const aa = clubList.filter((v) => { const aa = clubList.filter((v) => {
@@ -0,0 +1,376 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.top_block {
width: 100%;
padding: 20px 80px;
border-bottom: 10px solid rgb(240, 240, 240);
}
.top_title {
font-size: 14px;
color: #808492;
height: 30px;
line-height: 30px;
margin-bottom: 5px;
}
.top_num {
font-size: 26px;
}
.cut-off-line {
width: 1px;
height: 70%;
position: absolute;
right: 0;
top: 0;
bottom: 0;
margin: auto;
background-color: rgb(230, 230, 230);
}
.chartTitle {
font-size: 14px;
color: #808492;
margin-bottom: 20px;
}
</style>
<div id="app" v-cloak>
<div class="p10">
<el-card shadow="never">
<div class="top_block" v-loading="top_block_loading">
<el-row gutter="60">
<div style="position: absolute; top: -35px; right: -8px">
<el-date-picker
class="year"
style="width: 120px"
size="mini"
v-model="numForm.startYear"
type="year"
:clearable="false"
value-format="yyyy"
@change="if(numForm.endYear){getNumData();}"
placeholder="选择年"
></el-date-picker>
-
<el-date-picker
class="year"
style="width: 120px"
size="mini"
v-model="numForm.endYear"
type="year"
:clearable="false"
value-format="yyyy"
@change="if(numForm.startYear){getNumData();}"
placeholder="选择年"
></el-date-picker>
</div>
<el-col :span="6" style="position: relative">
<div class="top_title">总缴费金额</div>
<div class="top_num">{{numData.payMoney?numData.payMoney:'0'}}</div>
<div class="cut-off-line"></div>
</el-col>
<el-col :span="6" style="position: relative">
<div class="top_title">退款金额</div>
<div class="top_num">{{numData.refundMoney?numData.refundMoney:'0'}}</div>
<div class="cut-off-line"></div>
</el-col>
<el-col :span="6" style="position: relative">
<div class="top_title">退款订单数</div>
<div class="top_num">{{numData.refundSize?numData.refundSize:'0'}}</div>
<div class="cut-off-line"></div>
</el-col>
<el-col :span="6" style="position: relative">
<div class="top_title">总缴费人数</div>
<div class="top_num">{{numData.paySize?numData.paySize:'0'}}</div>
</el-col>
</el-row>
</div>
<el-row style="padding: 30px 0; border-bottom: 10px solid rgb(240, 240, 240)">
<div style="position: absolute; top: 25px; right: 40px; z-index: 200">
<el-date-picker
class="year"
style="width: 120px"
size="mini"
v-model="oneForm.startYear"
type="year"
:clearable="false"
value-format="yyyy"
@change="if(oneForm.endYear){getPayProjectChart();getPayMoneyChart();}"
placeholder="选择年"
></el-date-picker>
-
<el-date-picker
class="year"
style="width: 120px"
size="mini"
v-model="oneForm.endYear"
type="year"
:clearable="false"
value-format="yyyy"
@change="if(oneForm.startYear){getPayProjectChart();getPayMoneyChart();}"
placeholder="选择年"
></el-date-picker>
</div>
<el-col :span="12" style="padding: 0 20px" v-loading="payProjectLoading">
<div class="chartTitle">已缴人数</div>
<div id="payProjectChart" style="width: 100%; height: 330px"></div>
</el-col>
<el-col :span="12" style="padding: 0 20px" v-loading="payMoneyLoading">
<div class="chartTitle">已缴金额</div>
<div id="payMoneyChart" style="width: 100%; height: 330px"></div>
</el-col>
</el-row>
<el-row style="padding: 30px 0; border-bottom: 10px solid rgb(240, 240, 240)">
<div style="position: absolute; top: 25px; right: 250px; z-index: 999">
<el-date-picker
class="year"
style="width: 120px"
size="mini"
v-model="unionForm.year"
type="year"
:clearable="false"
value-format="yyyy"
@change="getProjectList"
placeholder="选择年"
></el-date-picker>
</div>
<div style="position: absolute; top: 25px; right: 40px; z-index: 999">
<el-select
placeholder="请选择项目"
v-model="unionForm.paymentProjectId"
style="width: 100%"
size="mini"
:clearable="false"
@change="doSearch"
@clear="doSearch"
filterable="true"
>
<el-option v-for="item in paymentProjectList"
:label="item.projectName" :value="item.id"></el-option>
</el-select>
</div>
<el-col :span="24" style="padding: 0 20px" v-loading="all_union_loading">
<div class="chartTitle" style="margin-bottom: 50px">
</div>
<div id="allUnionChart" style="width: 100%; height: 300px"></div>
</el-col>
</el-row>
</el-card>
</div>
</div>
<script>
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
oneForm: {
startYear: new Date().getFullYear() - 2 + "",
endYear: new Date().getFullYear() + ""
},
twoForm: {
startYear: new Date().getFullYear() - 2 + "",
endYear: new Date().getFullYear() + ""
},
numForm: {
startYear: new Date().getFullYear() - 2 + "",
endYear: new Date().getFullYear() + ""
},
payProjectLoading: false,
refundProjectLoading: false,
payMoneyLoading: false,
top_block_loading: false,
numData: {},
all_union_loading: false,
unionForm: {
year: new Date().getFullYear() + ""
},
paymentProjectList: []
}
},
methods: {
async getNumData() {
this.top_block_loading = true
const resp = await $.post("/platform/member/payment/chartSummary/getNumData", this.numForm)
if (resp.code === 0) {
this.numData = resp.data
}
this.top_block_loading = false
},
async getPayProjectChart() {
this.payProjectLoading = true
const resp = await $.post("/platform/member/payment/chartSummary/getPayProjectChart", this.oneForm)
if (resp.code === 0) {
let { data } = resp
document.getElementById("payProjectChart").innerHTML = ""
const config = {
xField: "projectName",
yField: "num",
label: {
position: "middle", // 'top', 'bottom', 'middle',
style: {
fill: "#FFFFFF",
opacity: 0.6
}
},
xAxis: {
label: {
autoHide: true,
autoRotate: false
}
},
meta: {
projectName: {
alias: "项目"
},
num: {
alias: "缴费人数"
}
}
}
const plot = new G2Plot.Column(document.getElementById("payProjectChart"), {
data,
...config
})
plot.render()
}
this.payProjectLoading = false
},
async getPayMoneyChart() {
this.payMoneyLoading = true
const resp = await $.post("/platform/member/payment/chartSummary/getPayMoneyChart", this.oneForm)
if (resp.code === 0) {
let { data } = resp
document.getElementById("payMoneyChart").innerHTML = ""
const config = {
xField: "projectName",
yField: "money",
label: {
position: "middle", // 'top', 'bottom', 'middle',
style: {
fill: "#FFFFFF",
opacity: 0.6
}
},
xAxis: {
label: {
autoHide: true,
autoRotate: false
}
},
meta: {
projectName: {
alias: "项目"
},
money: {
alias: "金额(元)"
}
}
}
const plot = new G2Plot.Column(document.getElementById("payMoneyChart"), {
data,
...config
})
plot.render()
}
this.payMoneyLoading = false
},
async allUnionMoney() {
this.all_union_loading = true
const resp = await $.get("/platform/member/payment/chartSummary/allUnionMoney", {
paymentProjectId: this.unionForm.paymentProjectId
})
if (resp.code === 0) {
let { data } = resp
document.getElementById("allUnionChart").innerHTML = ""
const config = {
isStack: true,
legend: {
position: "top-right",
flipPage: false
},
autoFit: true,
title: {
visible: true,
text: ""
},
description: {
visible: true,
text: "单位(元)"
},
xField: "unionname",
yField: "money",
stackField: "type",
color: ["#5B8FF9", "#5AD8A6"],
xAxis: {
label: {
formatter: (v) => {
if (data.length > 30 && v.length > 3) {
return v.substr(0, 2) + "..."
} else if (data.length > 20 && v.length > 4) {
return v.substr(0, 3) + "..."
} else if (data.length > 10 && v.length > 6) {
return v.substr(0, 5) + "..."
}
return v
}
}
},
yAxis: {},
meta: {
unionname: {
alias: "工会"
},
money: {
alias: "金额"
}
},
connectedArea: {
visible: true,
triggerOn: false
}
}
const plot = new G2Plot.Column(document.getElementById("allUnionChart"), {
data,
...config
})
plot.render()
}
this.all_union_loading = false
},
async getProjectList() {
const resp = await $.get("/platform/member/payment/project/getAllProject", { year: this.unionForm.year })
if (resp.code === 0) {
this.paymentProjectList = resp.data
this.$set(this.unionForm, "paymentProjectId", (this.paymentProjectList && this.paymentProjectList.length > 0) ? this.paymentProjectList[0].id : null)
await this.allUnionMoney()
}
}
},
async created() {
await this.getPayProjectChart()
await this.getPayMoneyChart()
await this.getNumData()
await this.getProjectList()
}
})
</script>
<!--#
}
#-->
@@ -10,14 +10,116 @@ layout("/layouts/platform.html"){
</style> </style>
<div id="app" v-cloak> <div id="app" v-cloak>
<guava ref="guava"> <guava ref="guava">
<template>
<el-card shadow="never"> <el-card shadow="never">
<div slot="header" class="clearfix"> <div class="search">
<h3 style="color: rgb(24, 103, 176);font-family: Microsoft YaHei;">缴费配置</h3> <div class="search-item">
<div class="search-item-label">缴费配置:</div>
<div class="search-item-option">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
style="width: 100%"
v-model="pageForm.name">
</el-input>
</div> </div>
</div>
<div class="search-query">
<el-button type="primary" icon="el-icon-search" @click="doSearch">搜索
</el-button>
</div>
</div>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool :app="this" label="缴费配置列表">
<template #func>
<el-button @click="openAdd" size="small" type="primary">
新增缴费配置
</el-button>
</template>
</table-tool>
<el-table :data="tableData" :size="tableSize"
@sort-change="pageOrder"
class="vi-table"
ref="table" row-key="id" style="width: 100%"
v-loading="tableLoading">
<el-table-column :index="indexMethod" align="center" header-align="center"
label="序号" type="index"
width="80px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop==='isDisabled'">
<el-switch
:active-value="false"
:inactive-value="true"
@change="(val)=>{configStatusChange(row.id)}"
active-color="#13ce66"
inactive-color="#ff4949"
v-model="row.isDisabled">
</el-switch>
</template>
</el-table-column>
<el-table-column prop="userOnline" align="center" header-align="center"
label="操作"
width="100px">
<template scope="scope">
<el-dropdown @command="dropdownCommand">
<el-button :loading="submitLoading" plain size="mini">
<i class="ti-settings"></i>
<span class="ti-angle-down"></span>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{type:'edit',data:scope.row}">
编辑
</el-dropdown-item>
<el-dropdown-item :command="{type:'remove',data:scope.row}">
删除
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #view>
<el-form :model="formData" ref="addForm" :rules="rules" <el-form :model="formData" ref="addForm" :rules="rules"
label-width="120px" label-width="120px"
style="margin: 10px 0 0 0"> style="margin: 10px 0 0 0">
<vi-title title="缴费配置"></vi-title>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="配置名称" prop="name">
<el-input v-model="formData.name"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="缴费月份" prop="paymentMonth" size="medium">
<el-date-picker
v-model="formData.paymentMonth"
type="monthrange"
range-separator="至"
style="width: 100%"
value-format="yyyy-MM"
start-placeholder="开始月份"
end-placeholder="结束月份">
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<vi-title title="缴纳标准"></vi-title> <vi-title title="缴纳标准"></vi-title>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="24"> <el-col :span="24">
@@ -39,32 +141,47 @@ layout("/layouts/platform.html"){
<el-form-item :prop="'payStandards.'+$index+'.payPersonnel'" <el-form-item :prop="'payStandards.'+$index+'.payPersonnel'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]" :rules="[{required:true,message:'必填',trigger:['change','blur']}]"
label-width="0"> label-width="0">
<el-input clearable maxlength="100" placeholder="请输入缴费人员" <!-- <el-input clearable maxlength="100" placeholder="请输入缴费人员"
v-model="row.payPersonnel"></el-input> v-model="row.payPersonnel"></el-input>-->
<el-select placeholder="请选择人员类型" v-model="row.payPersonnel"
style="width: 100%" clearable>
<el-option v-for="item in memberTypeList" :label="item.name" :value="item.code"></el-option>
</el-select>
</el-form-item> </el-form-item>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="缴费模式" prop="payMode" width="200"> <el-table-column label="人员类型" prop="personType" >
<template slot-scope="{row,$index}">
<el-select @change="row.payMode=null" placeholder="请选择人员类型" v-model="row.personType"
style="width: 100%" clearable>
<el-option v-for="item in personTypeList" :label="item.name" :value="item.code"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column label="缴费模式" prop="payMode" >
<template scope="{row,$index}"> <template scope="{row,$index}">
<el-form-item :prop="'payStandards.'+$index+'.payMode'" <el-form-item :prop="'payStandards.'+$index+'.payMode'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]" :rules="[{required:true,message:'必填',trigger:['change','blur']}]"
label-width="0"> label-width="0">
<el-select placeholder="请选择缴费模式" v-model="row.payMode" <el-select placeholder="请选择缴费模式" v-model="row.payMode"
style="width: 100%"> style="width: 100%">
<el-option v-for="item in payModeList" :label="item.value" :value="item.code"></el-option> <el-option :disabled="row.personType!='非编'" label="固定金额缴纳" value="1"></el-option>
<el-option :disabled="row.personType!='在编'" label="按比例缴纳" value="2"></el-option>
<el-option label="导入" value="3"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="人员类型" prop="personTypes" width="300">
<!-- <el-table-column label="在职状态" prop="userState" >
<template slot-scope="{row,$index}"> <template slot-scope="{row,$index}">
<el-select multiple placeholder="请选择人员类型" v-model="row.personTypes" <el-select placeholder="请选择在职状态" v-model="row.userState"
style="width: 100%" clearable> style="width: 100%" clearable>
<el-option v-for="item in personTypeList" :label="item.name" :value="item.code"></el-option> <el-option v-for="item in userStateList" :label="item.name" :value="item.code"></el-option>
</el-select> </el-select>
</template> </template>
</el-table-column> </el-table-column>-->
<el-table-column label="缴费标准" prop="payModeValue"> <el-table-column label="缴费标准" prop="payModeValue" width="650">
<template scope="{row,$index}"> <template scope="{row,$index}">
<div v-if="row.payMode=='2'"> <div v-if="row.payMode=='2'">
@@ -73,8 +190,8 @@ layout("/layouts/platform.html"){
label-width="0"> label-width="0">
<div style="display:flex;justify-content: space-between;margin-left: 30px"> <div style="display:flex;justify-content: space-between;margin-left: 30px">
( (
<template v-for="(o,i) in row.payModeValueList"> <template v-for="(o,i) in row.payModeValueList" >
<el-input placeholder="请输入" style="width: 120px;" <el-input placeholder="" style="width: 100px;"
v-model="o.name"> v-model="o.name">
<el-button @click="row.payModeValueList.splice(i, 1)" slot="append" style="padding: 0 7px;" <el-button @click="row.payModeValueList.splice(i, 1)" slot="append" style="padding: 0 7px;"
icon="el-icon-circle-close"></el-button> icon="el-icon-circle-close"></el-button>
@@ -96,7 +213,7 @@ layout("/layouts/platform.html"){
label-width="0"> label-width="0">
<div v-if="row.payMode == '1'"> <div v-if="row.payMode == '1'">
<el-input clearable maxlength="100" type="number" placeholder="请输入缴费金额" <el-input clearable maxlength="5" type="number" placeholder="请输入缴费金额"
v-model="row.payModeValue"></el-input> v-model="row.payModeValue"></el-input>
</div> </div>
<div v-if="row.payMode == '3'" style="text-align: center"> <div v-if="row.payMode == '3'" style="text-align: center">
@@ -125,7 +242,7 @@ layout("/layouts/platform.html"){
</el-col> </el-col>
</el-row> </el-row>
<vi-title title="退会标准"></vi-title> <!-- <vi-title title="退会标准"></vi-title>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="未缴费退会时间" prop="unPaidExitDuration"> <el-form-item label="未缴费退会时间" prop="unPaidExitDuration">
@@ -161,17 +278,17 @@ layout("/layouts/platform.html"){
<div style="margin-top: 10px"> <div style="margin-top: 10px">
<span style="color: red">说明:多长时间缴费一次。</span> <span style="color: red">说明:多长时间缴费一次。</span>
</div> </div>
</el-row> </el-row>-->
</el-form> </el-form>
<el-row class="mt10" justify="center" type="flex"> <div>
<el-button @click="doSubmit" style="width: 300px" type="primary">保存 <el-button @click="doSubmit" v-if="isSubmit" v-loading="submitLoading" style="float: right"
type="primary">
提交
</el-button> </el-button>
<el-button @click="doSubmit" style="width: 300px" type="primary">提交 </div>
</el-button>
</el-row>
</el-card> </template>
</guava> </guava>
</div> </div>
@@ -183,20 +300,84 @@ layout("/layouts/platform.html"){
return { return {
payModeList:[{code:'1',value:'固定金额缴纳'},{code:'2',value:'按比例缴纳'},{code:'3',value:'导入'}], payModeList:[{code:'1',value:'固定金额缴纳'},{code:'2',value:'按比例缴纳'},{code:'3',value:'导入'}],
formData: { formData: {
payStandards: [{payPersonnel: null, payMode: '1', personTypes: null, payModeValue: null,payModeValueList:[{name:'',value:''}]}] payStandards: [{payPersonnel: null, payMode: null, personTypes: null, payModeValue: null,payModeValueList:[{name:'',value:''}]}]
}, },
rules: { rules: {
name: [{required: true, message: '必填', trigger: ['blur', 'change']}],
paymentMonth: [{required: true, message: '必填', trigger: ['blur', 'change']}],
exit: [{required: true, message: '必填', trigger: ['blur', 'change']}], exit: [{required: true, message: '必填', trigger: ['blur', 'change']}],
}, },
personTypeList:[], personTypeList:[],
userStateList:[],
memberTypeList:[],
pageForm:{},
tableData:[],
tableColumns:[
{prop: 'name', label: '配置名称'},
{prop: 'paymentStartMonth', label: '缴费起始月份'},
{prop: 'paymentEndMonth', label: '缴费截止月份'},
{prop: 'isDisabled', label: '开启状态'},
],
isSubmit: true,
} }
}, },
methods: { methods: {
dropdownCommand(command) {
const {type, data} = command
if (type === 'view') {
this.openView(data)
} else if (type === 'edit') {
this.openEdit(data)
} else if (type === 'remove') {
this.doRemove(data.id)
}
},
openAdd(){
this.$refs.guava.view()
},
async doRemove(id) {
const confirm = await this.$confirm('您确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
if (confirm === 'confirm') {
const resp = await $.get(loc() + '/doRemove', {id: id})
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.pageData()
} else {
this.notifyWarning(resp.msg)
}
}
},
async configStatusChange(id) {
const resp = await $.post(loc() + '/openClosedConfig', { id: id })
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.pageData()
} else {
this.notifyWarning(resp.msg)
}
},
openEdit(data) {
this.formData = {}
this.formData = {
...data,
paymentMonth:[data.paymentStartMonth, data.paymentEndMonth],
}
this.formData.payStandards= JSON.parse(this.formData.payStandards)
this.isSubmit = true
this.$refs.guava.view()
},
async doSubmit(){ async doSubmit(){
this.formData.paymentStartMonth = this.formData.paymentMonth[0]
this.formData.paymentEndMonth = this.formData.paymentMonth[1]
const formData = clone(this.formData) const formData = clone(this.formData)
formData.payStandards = JSON.stringify(this.formData.payStandards) formData.payStandards = JSON.stringify(this.formData.payStandards)
const resp = await $.post(loc() + '/doAddOrModify',formData) const resp = await $.post(loc() + '/doAddOrModify',formData)
if (resp.code === 0){ if (resp.code === 0){
this.$refs.guava.index()
await this.getPaymentConfig() await this.getPaymentConfig()
this.notifySuccess(resp.msg) this.notifySuccess(resp.msg)
} else { } else {
@@ -216,8 +397,13 @@ layout("/layouts/platform.html"){
} }
}, },
async created() { async created() {
this.pageData()
this.personTypeList = await getDictOptions('UserType') this.personTypeList = await getDictOptions('UserType')
await this.getPaymentConfig() //在职状态
this.userStateList = await getDictOptions('UserState')
//会员类型
this.memberTypeList = await getDictOptions('memberType')
} }
}) })
</script> </script>
@@ -0,0 +1,317 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.payForm .el-form-item__label {
font-weight: bold;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">年度:</div>
<div class="search-item-option">
<el-date-picker
:clearable="false"
@change="doSearch"
placeholder="选择年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</div>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="缴费列表" :app="this">
<template #func>
<el-radio-group @change="doSearch" class="mr10" size="small"
v-model="pageForm.isPay">
<el-radio-button :label="null">全部</el-radio-button>
<el-radio-button :label="true">已缴</el-radio-button>
<el-radio-button :label="false">未缴</el-radio-button>
</el-radio-group>
</template>
</table-tool>
<el-table
:data="tableData"
:size="tableSize"
@sort-change="pageOrder"
class="vi-table"
ref="table"
row-key="id"
style="width: 100%"
v-loading="tableLoading"
>
<el-table-column
:index="indexMethod"
align="center"
header-align="center"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop==='isPayment'">
<span style="color: #00aa3a" v-if="row.isPayment">已缴</span>
<span style="color: red" v-else>未缴</span>
</template>
<template scope="{row}" v-else-if="column.prop==='paymentStartMonth'">
{{row.paymentStartMonth}}至{{row.paymentEndMonth}}
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="操作"
prop="userOnline" width="200px">
<template scope="{row}">
<el-button :disabled="row.isPayment" @click="openPay(row)"
size="mini" type="primary">缴费
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
</guava>
<el-diaLog :close-on-click-modal="false" :visible.sync="payVisible" title="缴费" width="50%"
:before-close="clickClose">
<el-form ref="form" :model="formData" :rules="formRules" label-width="170px"
label-suffix=":" class="payForm">
<el-steps :active="payActive" finish-status="success">
<el-step title="计算缴费金额"></el-step>
<el-step title="生成缴费二维码"></el-step>
<el-step title="完成"></el-step>
</el-steps>
<div v-if="payActive===0" class="mt25">
<el-form-item label="缴费所属时间">
<div>{{formData.paymentStartMonth}}至{{formData.paymentEndMonth}}</div>
</el-form-item>
<el-form-item label="缴费标准">
<div style="color: red"
v-if="formData.payModeValueList&&formData.payModeValueList.length>0">
(
<template v-for="(o,i) in formData.payModeValueList">
{{o.name}}
<template v-if="i !=formData.payModeValueList.length-1">+</template>
</template>
) * 0.5% * {{formData.paymentMonth}}个月
</div>
<div v-else>固定金额缴费</div>
</el-form-item>
<!--如果是根据比例算的-->
<div v-if="formData.payModeValueList&&formData.payModeValueList.length>0">
<template v-for="(o,i) in formData.payModeValueList" :key="i">
<el-form-item :label="o.name">
<el-input-number v-model="o.value" :min="0" :max="1000000"
:precision="2"
placeholder="请输入缴费金额"
@change="changePayModeValue(o)"></el-input-number>
</el-form-item>
</template>
</div>
<el-form-item label="支付金额">
<div style="color: #2cd000;font-size: 25px">¥ {{formData.paymentMoney}}</div>
</el-form-item>
</div>
<div v-if="payActive===1" class="mt25">
<el-form-item label="商品订单">
{{formData.transactionId}}
</el-form-item>
<el-form-item label="支付金额">
<div style="color: #2cd000;font-size: 25px">¥ {{formData.paymentMoney}}</div>
</el-form-item>
<div style="width: 100%;">
<el-row :gutter="20">
<el-col :span="12" v-loading="qrcodeLoading">
<div id="qrcode" style="width: 60%;left: 0;right: 0;margin: auto"></div>
<div style="display: flex;justify-content: center">
<span
style="font-weight: bold;
font-size: 15px;
color: #fbfbfb;
background-color: rgb(44, 208, 0);
height: 30px;
width: 60%;
display: flex;
justify-content: center;
align-items: center;">
请打开手机微信,扫一扫完成支付</span>
</div>
</el-col>
<el-col :span="12">
<div>
<el-image src="/assets/mobile/svg/memberPay/wx_img.png"></el-image>
</div>
</el-col>
</el-row>
</div>
</div>
<div v-if="payActive===3">
<div v-loading="submitLoading">
<div style="margin-top: 35px;background-color: RGB(245, 254, 243);">
<div
style="display: flex;align-items: center;height: 100px;margin-left: 10%">
<div>
<el-image
src="/assets/mobile/svg/memberPay/pcPaySuccess.svg"></el-image>
</div>
<div style="font-weight: bold;font-size: 25px;margin-left: 10px;">
支付成功!
</div>
</div>
</div>
<el-form-item label="商品订单">
{{formData.transactionId}}
</el-form-item>
<el-form-item label="支付金额">
<div style="color: #2cd000;font-size: 25px">¥ {{formData.paymentMoney}}
</div>
</el-form-item>
</div>
</div>
</el-form>
<div style="text-align: right">
<span>
<el-button @click="clickClose">关 闭</el-button>
<el-button @click="next" v-if="payActive===0&&formData.paymentMoney>0"
type="primary">下一步</el-button>
</span>
</div>
</el-diaLog>
</div>
<script>
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
tableColumns: [
{ prop: "year", label: "年度", sortable: true },
{ prop: "projectName", label: "项目名称", sortable: true },
{ prop: "startTime", label: "缴费开始时间", sortable: true },
{ prop: "endTime", label: "缴费截止时间", sortable: true },
{ prop: "paymentStartMonth", label: "缴费所属时间", sortable: true },
{ prop: "isPayment", label: "是否缴费", sortable: true }
],
pageForm: {
isPay: false,
year: moment().format("YYYY")
},
payVisible: false,
payActive: 0,
intervalTimer: null,
qrcodeLoading: false,
payInfo: {}
}
},
methods: {
clickClose() {
if (this.payActive === 3) {
this.payVisible = false
} else {
this.$confirm("您确定要关闭当前缴费吗?关闭后将不会保存当前数据", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.payVisible = false
})
}
clearInterval(this.intervalTimer)
},
next() {
this.$confirm("您确定要生成缴费二维码吗?当前需缴费【" + this.formData.paymentMoney + "】元", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
this.qrcodeLoading = true
const paymentMoney = Math.floor(this.formData.paymentMoney * 100)
this.payActive = this.payActive + 1
const resp = await $.post("/platform/member/payment/mine/pcOrderPay", {
paymentMoney: paymentMoney,
paymentInfoId: this.formData.paymentInfoId
})
if (resp.code === 0) {
const data = JSON.parse(resp.data)
this.$nextTick(() => {
$("#qrcode").html("")
$("#qrcode").qrcode({
render: "canvas",
width: $("#qrcode").width(),
height: $("#qrcode").width(),
text: data.code_url,
correctLevel: 3
})
})
this.formData.transactionId = data.transactionId
await this.getIsPay()
}
this.qrcodeLoading = false
})
},
async getIsPay() {
this.intervalTimer = setInterval(async () => {
const resp = await $.get(loc() + "/getIsPay", { paymentInfoId: this.formData.paymentInfoId })
if (resp.code === 0) {
if (resp.data) {
this.payActive = 3
this.submitLoading = true
clearInterval(this.intervalTimer)
setTimeout(() => {
this.submitLoading = false
}, 1500)
}
}
}, 4000)
},
changePayModeValue() {
let paymentMoney = this.formData.payModeValueList.reduce((a, b) => {
return a + b.value
}, 0)
this.$set(this.formData, "paymentMoney", parseFloat((paymentMoney * 0.005 * this.formData.paymentMonth).toFixed(2)))
},
openPay(row) {
this.payActive = 0
const payStandards = JSON.parse(row.payStandards)
const payStandard = payStandards.find(p => p.payPersonnel === row.payPersonnel && p.personType === row.personType)
this.$set(this.formData, "paymentMonth", row.paymentMonth)
this.$set(this.formData, "paymentStartMonth", row.paymentStartMonth)
this.$set(this.formData, "paymentEndMonth", row.paymentEndMonth)
this.$set(this.formData, "paymentInfoId", row.id)
if (payStandard.payModeValue) {
this.$set(this.formData, "payModeValueList", [])
this.$set(this.formData, "paymentMoney", payStandard.payModeValue)
} else {
this.$set(this.formData, "payModeValueList", payStandard.payModeValueList)
this.$set(this.formData, "paymentMoney", 0)
}
this.payVisible = true
},
},
created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -132,20 +132,19 @@ layout("/layouts/platform.html"){
<el-input maxlength="100" placeholder="项目名称" v-model="formData.projectName"></el-input> <el-input maxlength="100" placeholder="项目名称" v-model="formData.projectName"></el-input>
</el-form-item> </el-form-item>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col span="12"> <el-col :span="12">
<el-form-item label="缴费年度" prop="year"> <el-form-item label="缴费年度" prop="year">
<el-date-picker <el-date-picker
:clearable="false" :clearable="false"
placeholder="选择年度" placeholder="选择年度"
type="year" style="width: 100%" type="year" style="width: 100%"
v-model="formData.year" v-model="formData.year"
@change="isMonthCreatedByYear"
value-format="yyyy"> value-format="yyyy">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col span="12"> <el-col :span="12">
<el-form-item label="创建日期" prop="createTime"> <el-form-item label="创建日期" prop="createTime">
<el-date-picker <el-date-picker
placeholder="创建日期" placeholder="创建日期"
@@ -160,12 +159,30 @@ layout("/layouts/platform.html"){
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="24"> <el-col :span="12">
<el-form-item label="缴费月份" prop="paymentMonth" size="medium"> <el-form-item label="缴费配置" prop="configId" size="medium">
<el-radio-group v-model="formData.paymentMonth"> <el-select placeholder="请选择缴费配置" v-model="formData.configId"
<el-radio-button v-for="item in monthSelect" :label="item.label" style="width: 100%" clearable>
:disabled="item.code===1"></el-radio-button> <el-option
</el-radio-group> v-for="item in configList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="缴费时间" prop="paymentTime" size="medium">
<el-date-picker
v-model="formData.paymentTime"
type="daterange"
value-format="yyyy-MM-dd"
range-separator="至"
style="width: 100%"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -196,6 +213,8 @@ layout("/layouts/platform.html"){
tableColumns: [ tableColumns: [
{prop: 'year', label: '年度', sortable: true}, {prop: 'year', label: '年度', sortable: true},
{prop: 'projectName', label: '项目名称', sortable: true}, {prop: 'projectName', label: '项目名称', sortable: true},
{prop: 'startTime', label: '缴费开始时间', sortable: true},
{prop: 'endTime', label: '缴费截止时间', sortable: true},
{prop: 'createTime', label: '创建时间', sortable: true}, {prop: 'createTime', label: '创建时间', sortable: true},
{prop: 'isDisabled', label: '开启状态'}, {prop: 'isDisabled', label: '开启状态'},
], ],
@@ -206,9 +225,12 @@ layout("/layouts/platform.html"){
projectName: [{required: true, message: '必填', trigger: ['blur', 'change']}], projectName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
year: [{required: true, message: '必填', trigger: ['blur', 'change']}], year: [{required: true, message: '必填', trigger: ['blur', 'change']}],
paymentMonth: [{required: true, message: '必填', trigger: ['blur', 'change']}], paymentMonth: [{required: true, message: '必填', trigger: ['blur', 'change']}],
paymentTime: [{required: true, message: '必填', trigger: ['blur', 'change']}],
configId: [{required: true, message: '必填', trigger: ['blur', 'change']}],
}, },
paymentConfig: {}, paymentConfig: {},
monthSelect: [] monthSelect: [],
configList:[]
} }
}, },
components: { components: {
@@ -237,13 +259,19 @@ layout("/layouts/platform.html"){
}, },
openView(data) { openView(data) {
this.formData = {} this.formData = {}
this.formData = {...data} this.formData = {
...data,
paymentTime:[data.startTime, data.endTime],
}
this.isSubmit = false this.isSubmit = false
this.$refs.guava.view() this.$refs.guava.view()
}, },
openEdit(data) { openEdit(data) {
this.formData = {} this.formData = {}
this.formData = {...data} this.formData = {
...data,
paymentTime:[data.startTime, data.endTime],
}
this.isSubmit = true this.isSubmit = true
this.$refs.guava.view() this.$refs.guava.view()
}, },
@@ -324,7 +352,6 @@ layout("/layouts/platform.html"){
year: moment().format('YYYY'), year: moment().format('YYYY'),
} }
this.$refs.guava.view() this.$refs.guava.view()
this.isMonthCreatedByYear()
}, },
async doSave() { async doSave() {
const formValid = await this.$refs["form"].validate() const formValid = await this.$refs["form"].validate()
@@ -336,15 +363,9 @@ layout("/layouts/platform.html"){
spinner: 'el-icon-loading', spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)' background: 'rgba(0, 0, 0, 0.7)'
}); });
this.formData.startTime=this.formData.paymentTime[0]
this.formData.endTime=this.formData.paymentTime[1]
const formData = clone(this.formData) const formData = clone(this.formData)
const o = this.monthSelect.find(v => v.label === formData.paymentMonth)
if (o.code === 1) {
this.notifyWarning("该年份下的此月份已创建了项目,请选择其他月份!")
loading.close()
this.submitLoading = false
return
}
const resp = await $.post(loc() + '/doSave', formData) const resp = await $.post(loc() + '/doSave', formData)
loading.close() loading.close()
this.submitLoading = false this.submitLoading = false
@@ -366,40 +387,16 @@ layout("/layouts/platform.html"){
this.notifyWarning(resp.msg) this.notifyWarning(resp.msg)
} }
}, },
async getPaymentConfig() { async getPaymentConfigList(id) {
const resp = await $.get('/platform/member/payment/config/getPaymentConfig') const resp = await $.post('/platform/member/payment/config/getPaymentConfigList')
if (resp.code === 0) { if (resp.code === 0) {
this.paymentConfig = resp.data this.configList = resp.data
const arr = []
let monthHalve = this.paymentConfig.paidDuration
let halve = 12 / monthHalve
for (let i = 1; i <= halve; i++) {
let value = (Number(i) - 1) * monthHalve + 1;
let followValue = i * monthHalve
if (i === 1) {
arr.push({label: i + '-' + monthHalve + '月', code: 0})
} else {
arr.push({label: value + '-' + followValue + '月', code: 0})
}
}
this.monthSelect = arr
} }
}, },
async isMonthCreatedByYear() {
console.log(this.formData.year)
const resp = await $.post(loc() + '/isMonthCreatedByYear', {
year: this.formData.year,
monthSelect: JSON.stringify(this.monthSelect)
})
if (resp.code === 0) {
this.monthSelect = resp.data
}
}
}, },
async created() { async created() {
this.getPaymentConfigList()
this.pageData() this.pageData()
await this.getPaymentConfig();
} }
}) })
</script> </script>
@@ -0,0 +1,210 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">年度:</div>
<div class="search-item-option">
<el-date-picker
:clearable="false"
@change="doSearch();getProjectList()"
placeholder="选择年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</div>
</div>
<div class="search-item">
<div class="search-item-label">缴费项目:</div>
<div class="search-item-option">
<el-select
placeholder="请选择项目"
v-model="pageForm.paymentProjectId"
style="width: 100%"
:clearable="false"
@change="doSearch"
@clear="doSearch"
filterable="true"
>
<el-option v-for="item in paymentProjectList"
:label="item.projectName" :value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">工号/姓名:</div>
<div class="search-item-option">
<el-input placeholder="请输入工号/姓名"
v-model="pageForm.searchKeyword" clearable>
<template slot="prepend">姓名/工号</template>
</el-input>
</div>
</div>
<div class="search-item">
<div class="search-item-label">交易单号:</div>
<div class="search-item-option">
<el-input placeholder="请输入交易单号"
v-model="pageForm.transactionId" clearable>
</el-input>
</div>
</div>
<div class="search-item">
<div class="search-item-label">
<el-button @click="doSearch" type="primary">查询</el-button>
</div>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="缴费列表" :app="this">
<template #func>
<el-radio-group @change="doSearch" class="mr10" size="small"
v-model="pageForm.isRefund">
<el-radio-button :label="3">全部</el-radio-button>
<el-radio-button :label="0">未退款</el-radio-button>
<el-radio-button :label="1">已退款</el-radio-button>
</el-radio-group>
</template>
</table-tool>
<el-table
:data="tableData"
:size="tableSize"
@sort-change="pageOrder"
class="vi-table"
ref="table"
row-key="id"
style="width: 100%"
v-loading="tableLoading"
>
<el-table-column
:index="indexMethod"
align="center"
header-align="center"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop==='isRefund'">
<span v-if="row.isRefund" style="color: red">已全额退款</span>
<span v-else style="color: #2cd000">支付成功</span>
</template>
<template scope="{row}" v-else-if="column.prop==='tradingAmount'">
{{row.tradingAmount*0.01}}
</template>
<template scope="{row}" v-else-if="column.prop==='refundTime'">
<span v-if="!row.refundTime"></span>
<span
v-else>{{moment(row.refundTime).format("YYYY-MM-DD HH:mm:ss")}}</span>
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="操作"
prop="userOnline" width="200px">
<template scope="{row}">
<el-button :disabled="row.isRefund" @click="doRefund(row)"
size="mini" type="danger" :loading="submitLoading">退款
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
</guava>
</div>
<script>
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
paymentProjectList: [],
pageForm: {
isRefund: 3,
year: moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "工号", sortable: true },
{ prop: "userName", label: "姓名", sortable: true },
{ prop: "unitName", label: "单位", sortable: true },
{ prop: "unionName", label: "工会", sortable: true },
{ prop: "projectName", label: "项目名称", sortable: true },
{ prop: "tradingAmount", label: "缴费金额(元)", sortable: true },
{ prop: "paymentTime", label: "支付时间", sortable: true },
{ prop: "transactionId", label: "交易单号", sortable: true },
{ prop: "isRefund", label: "是否退款", sortable: true },
{ prop: "refundTime", label: "退款到账时间", sortable: true }
]
}
},
methods: {
doRefund(row) {
this.$confirm("您确定要退款吗?退款金额将原路退还,退款后将不能撤回!", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
this.submitLoading = true
const resp = await $.post("/platform/member/payment/refund/doRefund", {
id: row.id
})
this.submitLoading = false
if (resp.code === 0) {
this.doSearch()
this.$message({
type: "success",
message: resp.data
})
} else {
this.$message({
type: "error",
message: resp.data
})
}
})
},
async getProjectList() {
const resp = await $.get("/platform/member/payment/project/getAllProject", { year: this.pageForm.year })
if (resp.code === 0) {
this.paymentProjectList = resp.data
this.$set(this.pageForm, "paymentProjectId", this.paymentProjectList ? this.paymentProjectList[0].id : null)
}
}
},
async created() {
await this.getProjectList()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -143,6 +143,32 @@ layout("/layouts/platform.html"){
></dict-select> ></dict-select>
</div> </div>
</div> </div>
<div class="search-item">
<div class="search-item-label">入职时间:</div>
<div class="search-item-option">
<el-date-picker
value-format="yyyy-MM-dd"
v-model="pageForm.schoolTime"
type="date"
style="width: 100%"
placeholder="选择日期">
</el-date-picker>
</div>
</div>
<div class="search-item">
<div class="search-item-label">退休时间:</div>
<div class="search-item-option">
<el-date-picker
value-format="yyyy-MM-dd"
v-model="pageForm.retireDate"
type="date"
style="width: 100%"
placeholder="选择日期">
</el-date-picker>
</div>
</div>
</template> </template>
<div class="search-query"> <div class="search-query">
<el-button type="primary" icon="el-icon-search" @click="doSearch">搜索</el-button> <el-button type="primary" icon="el-icon-search" @click="doSearch">搜索</el-button>
@@ -267,8 +293,9 @@ layout("/layouts/platform.html"){
tableColumns: [ tableColumns: [
{ prop: "loginname", label: "工号", sortable: true }, { prop: "loginname", label: "工号", sortable: true },
{ prop: "username", label: "姓名" }, { prop: "username", label: "姓名" },
{ prop: "sex", label: "性别" },
{ prop: "mobile", label: "联系电话" }, { prop: "mobile", label: "联系电话" },
{ prop: "schoolTime", label: "入职时间" },
{ prop: "retireDate", label: "退休时间" },
{ prop: "personType", label: "人员类型", sortable: true }, { prop: "personType", label: "人员类型", sortable: true },
{ prop: "userState", label: "在职状态", sortable: true }, { prop: "userState", label: "在职状态", sortable: true },
{ prop: "unionname", label: "所属工会", sortable: true }, { prop: "unionname", label: "所属工会", sortable: true },
@@ -491,7 +518,7 @@ layout("/layouts/platform.html"){
this.checkUsers = val this.checkUsers = val
}, },
async getProjectList() { async getProjectList() {
const resp = await $.get("/platform/member/payment/manage/getAllProject", { year: this.pageForm.year }) const resp = await $.get("/platform/member/payment/project/getAllProject", { year: this.pageForm.year })
if (resp.code === 0) { if (resp.code === 0) {
this.paymentProjectList = resp.data this.paymentProjectList = resp.data
this.$set(this.pageForm, "paymentProjectId", this.paymentProjectList ? this.paymentProjectList[0].id : null) this.$set(this.pageForm, "paymentProjectId", this.paymentProjectList ? this.paymentProjectList[0].id : null)
@@ -0,0 +1,48 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<!-- 微信唤起jsapi支付的HTML方法 -->
</div>
<script src="https://res2.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<script>
function onBridgeReady(json) {
// const data = JSON.parse(json)
WeixinJSBridge.invoke("getBrandWCPayRequest", JSON.parse(json), function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}
})
}
new Vue({
el: "#app",
data() {
return {}
},
methods: {
async initData() {
const resp = await $.post("/platform/member/payment/test/getCode")
debugger
if (resp.code === 0) {
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener("WeixinJSBridgeReady", onBridgeReady(resp.data))
} else if (document.attachEvent) {
document.attachEvent("WeixinJSBridgeReady", onBridgeReady(resp.data))
document.attachEvent("onWeixinJSBridgeReady", onBridgeReady(resp.data))
}
} else {
onBridgeReady(resp.data)
}
}
}
},
created() {
// this.initData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,352 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">年度:</div>
<div class="search-item-option">
<el-date-picker
:clearable="false"
clearable
@change="doSearch"
placeholder="选择年度"
type="year" style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</div>
</div>
<div class="search-item">
<div class="search-item-label">缴费项目:</div>
<div class="search-item-option">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
style="width: 100%"
v-model="pageForm.projectName">
</el-input>
</div>
</div>
<div class="search-query">
<el-button type="primary" icon="el-icon-search" @click="doSearch">搜索
</el-button>
</div>
</div>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool :app="this" label="个人缴费列表">
</table-tool>
<el-table :data="tableData" :size="tableSize"
@sort-change="pageOrder"
class="vi-table"
ref="table" row-key="id" style="width: 100%"
v-loading="tableLoading">
<el-table-column :index="indexMethod" align="center" header-align="center"
label="序号" type="index"
width="80px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop==='isPayment'">
<span style="color: #00aa3a" v-if="row.isPayment">已缴</span>
<span style="color: red" v-else>未缴</span>
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="是否确认金额">
<template scope="{row}">
<span style="color: #00aa3a" v-if="row.paymentMoney!=null">已确定</span>
<span style="color: red" v-else>未确定</span>
</template>
</el-table-column>
<el-table-column prop="userOnline" align="center" header-align="center"
label="操作"
width="100px">
<template scope="scope">
<el-dropdown @command="dropdownCommand">
<el-button :loading="submitLoading" plain size="mini">
<i class="ti-settings"></i>
<span class="ti-angle-down"></span>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{type:'view',data:scope.row}">
查看
</el-dropdown-item>
<el-dropdown-item v-if="!scope.row.isPayment" :command="{type:'edit',data:scope.row}">
设为已缴
</el-dropdown-item>
<el-dropdown-item v-if="scope.row.paymentMoney==null" :command="{type:'pay',data:scope.row}">
确定缴费金额
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #pay>
<el-form :model="formData" :rules="formRules" label-width="100px" ref="form">
<vi-title title="缴费信息"></vi-title>
<el-form-item label="缴费项目" prop="projectName">
<span>{{formData.projectName}}</span>
</el-form-item>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="人员类型" size="medium">
<span>{{formData.personType}}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="会员类型" size="medium">
<span>{{formData.payPersonnel}}</span>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="需缴费用" size="medium">
<div v-for="item in payStandard" style="display:flex;justify-content: space-between;margin-left: 30px">
<template v-if="item.payModeValueList.length>0" >
(
<template v-for="(o,i) in item.payModeValueList">
<el-input @change="getMoney(item)" placeholder="" style="width: 200px;" v-model="o.value">
<template slot="prepend">{{o.name}}</template>
</el-input>
<span v-if="(i+1)!=item.payModeValueList.length">+</span>
</template>
) * 0.5% *{{formData.paymentMonth}}个月
</template>
<template v-else>
<span>{{item.payModeValue}}</span>*{{formData.paymentMonth}}个月
</template>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="缴费金额" prop="paymentMoney" size="medium">
<el-input disabled="true" placeholder="" style="width: 200px;" v-model="formData.paymentMoney">
</el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div>
<el-button @click="doSave" v-loading="submitLoading" style="float: right"
type="primary">
提交
</el-button>
</div>
</template>
<template #view>
<el-form :model="formData" label-width="100px" ref="form">
<vi-title title="缴费信息"></vi-title>
<el-form-item label="缴费项目" prop="projectName">
<span>{{formData.projectName}}</span>
</el-form-item>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="人员类型" size="medium">
<span>{{formData.personType}}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="会员类型" size="medium">
<span>{{formData.payPersonnel}}</span>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="缴纳标准" size="medium">
<div v-for="item in payStandard" style="display:flex;justify-content: space-between;margin-left: 30px">
<span v-if="item.payModeValueList.length>0" >
(
<span v-for="(o,i) in item.payModeValueList">
<span>{{o.name}}</span>
<span v-if="(i+1)!=item.payModeValueList.length">+</span>
</span>
) * 0.5% *{{formData.paymentMonth}}个月
</span>
<template v-else>
<span>{{item.payModeValue}}</span>*{{formData.paymentMonth}}个月
</template>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="缴费金额" size="medium">
<span>{{formData.paymentMoney}}</span>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="缴费月份" size="medium">
<span>{{formData.paymentStartMonth}} - {{formData.paymentEndMonth}}</span>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="缴费开始时间" size="medium">
<span>{{formData.startTime}} - {{formData.endTime}}</span>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
</guava>
</div>
<script>
const vue = new Vue({
el: '#app',
mixins: [initTableMixins],
data() {
return {
pageForm: {
year: moment().format('YYYY'),
},
tableColumns: [
{prop: 'year', label: '年度'},
{prop: 'projectName', label: '缴费项目名称'},
{prop: 'paymentStartMonth', label: '缴费开始月份'},
{prop: 'paymentEndMonth', label: '缴费截止月份'},
{prop: 'paymentMonth', label: '需要缴费月数'},
{prop: 'startTime', label: '缴费开始时间'},
{prop: 'endTime', label: '缴费截止时间'},
{prop: 'paymentMoney', label: '缴费金额'},
{prop: "isPayment", label: "是否缴费", sortable: true},
],
payStandard:{},
formRules: {
paymentMoney: [{required: true, message: '必填', trigger: ['blur', 'change']}],
},
}
},
components: {
'guava': httpVueLoader('/components/plugins/Guava.vue'),
},
methods: {
dropdownCommand(command) {
const {type, data} = command
if (type === 'edit') {
this.doPay(data)
}
if (type === 'pay'){
this.openPay(data)
}
if (type === 'view'){
this.openView(data)
}
},
openPay(data){
const payStandards=JSON.parse(data.payStandards)
this.payStandard=payStandards.filter(item => item.personType===data.personType&&item.payPersonnel===data.payPersonnel)
if (this.payStandard.length>0&&this.payStandard[0].payModeValueList===null){
this.formData.paymentMoney=+this.payStandard[0].payModeValue*+this.formData.paymentMonth
}
this.formData=data
this.$refs.guava.pay()
},
async doPay(data) {
const confirm = await this.$confirm("您确定要更改缴费信息吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
if (confirm === "confirm") {
const formData={
ids:JSON.stringify([data.id]),
paymentMoney:data.paymentMoney,
isPay:data.isPay,
remark:"缴费"
}
const resp = await $.post("/platform/member/payment/summary/modify", formData)
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.pageData()
} else {
this.notifyWarning(resp.msg)
}
}
},
openView(data) {
const payStandards=JSON.parse(data.payStandards)
this.payStandard=payStandards.filter(item => item.personType===data.personType&&item.payPersonnel===data.payPersonnel)
if (this.payStandard.length>0&&this.payStandard[0].payModeValueList===null){
this.formData.paymentMoney=+this.payStandard[0].payModeValue*+this.formData.paymentMonth
}
this.formData=data
this.$refs.guava.view()
},
async doSave() {
const formValid = await this.$refs["form"].validate()
if (formValid) {
this.submitLoading = true
const loading = this.$loading({
lock: true,
text: '数据保存中请稍后',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
const formData = clone(this.formData)
const resp = await $.post(loc() + '/doSave', formData)
loading.close()
this.submitLoading = false
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.$refs.guava.index()
this.pageData()
} else {
this.notifyWarning(resp.msg)
}
}
},
getMoney(item){
this.formData.paymentMoney=0
let money=0
item.payModeValueList.forEach(o=>{
money=+o.value+money
})
this.formData.paymentMoney=money*0.005*+this.formData.paymentMonth
}
},
async created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -11,68 +11,53 @@ layout("/layouts/platform.html"){
</template> </template>
</table-tool> </table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" <el-table
:data="tableData"
:size="tableSize"
@sort-change="pageOrder"
ref="table" ref="table"
row-key="id" style="width: 100%" v-loading="tableLoading"> row-key="id"
style="width: 100%"
<el-table-column v-loading="tableLoading"
label="序号" type="index" >
width="80px"></el-table-column> <el-table-column label="序号" type="index" width="80px"></el-table-column>
<el-table-column <el-table-column
:key="column.prop" :key="column.prop"
:label="column.label" :label="column.label"
:prop="column.prop" :prop="column.prop"
:sortable="column.sortable" :sortable="column.sortable"
:width="column.width" show-overflow-tooltip :width="column.width"
v-for="column in tableColumns"> show-overflow-tooltip
<template scope="{row}" v-if="column.prop=='address'"> v-for="column in tableColumns"
{{row.province}} {{row.city}} {{row.county}} >
</template> <template scope="{row}" v-if="column.prop=='address'">{{row.province}} {{row.city}} {{row.county}}</template>
</el-table-column> </el-table-column>
<el-table-column align="center" fixed="right" header-align="center" <el-table-column align="center" fixed="right" header-align="center" label="操作" prop="userOnline" width="170px">
label="操作" prop="userOnline"
width="170px">
<template scope="{row}"> <template scope="{row}">
<el-button @click="openEdit(row)" size="mini" type="primary"> <el-button @click="openEdit(row)" size="mini" type="primary">修改</el-button>
修改 <el-button @click="doDelete(row.id)" size="mini" type="danger">删除</el-button>
</el-button>
<el-button @click="doDelete(row.id)" size="mini" type="danger">
删除
</el-button>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" fixed="right" header-align="center" label="" <el-table-column align="center" fixed="right" header-align="center" label="" prop="userOnline" width="170px">
prop="userOnline"
width="170px">
<template scope="{row}"> <template scope="{row}">
<span v-if="row.isDefault"> <span v-if="row.isDefault">
<el-tag type="danger">默认地址</el-tag></span> <el-tag type="danger">默认地址</el-tag>
</span>
<span v-else> <span v-else>
<el-button @click="doDefault(row)" size="mini" <el-button @click="doDefault(row)" size="mini" type="primary">设为默认</el-button>
type="primary">设为默认</el-button>
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</el-card> </el-card>
</template> </template>
</guava> </guava>
<el-dialog <el-dialog title="收货地址" :close-on-click-modal="false" :visible.sync="dialogVisible" width="40%">
title="收货地址" <el-form :model="formData" label-position="right" :rules="formRules" label-suffix=":" label-width="120px" ref="addForm">
:close-on-click-modal="false"
:visible.sync="dialogVisible"
width="30%">
<el-form :model="formData" label-position="right"
label-suffix=":" label-width="120px" ref="addForm">
<el-row :gutter="60"> <el-row :gutter="60">
<el-col :span="24"> <el-col :span="24">
<el-form-item :rules="{required:true,message: '请选择地址信息', trigger: 'blur'}" <el-form-item label="地址信息" prop="addressList">
label="地址信息"
prop="addressList">
<el-cascader <el-cascader
:options="dzOptions" :options="dzOptions"
:props="{ expandTrigger: 'hover' }" :props="{ expandTrigger: 'hover' }"
@@ -80,40 +65,44 @@ layout("/layouts/platform.html"){
clearable clearable
placeholder="请选择地址信息" placeholder="请选择地址信息"
style="width: 100%" style="width: 100%"
v-model="formData.addressList"></el-cascader> v-model="formData.addressList"
></el-cascader>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item <el-form-item label="详细地址" prop="addressDetail">
:rules="{required:true,message: '请填写您的详细地址', trigger: 'blur'}" <el-input
label="详细地址" maxlength="100"
prop="addressDetail">
<el-input maxlength="100"
placeholder="请输入详细地址信息,如道路、门牌号、小区、楼栋号、单元等信息" placeholder="请输入详细地址信息,如道路、门牌号、小区、楼栋号、单元等信息"
rows="3" rows="3"
show-word-limit show-word-limit
type="textarea" type="textarea"
v-model="formData.addressDetail"></el-input> v-model="formData.addressDetail"
></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item <el-form-item label="收货人姓名" prop="userName">
:rules="{required:true,message: '请填写收货人姓名', trigger: 'blur'}" <el-input maxlength="11" placeholder="请填写收货人姓名" v-model="formData.userName"></el-input>
label="收货人姓名"
prop="userName">
<el-input maxlength="11"
placeholder="请填写收货人姓名"
v-model="formData.userName"></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item <el-form-item label="手机号码" prop="tel">
:rules="{required:true,message: '请填写手机号码', trigger: 'blur'}" <el-input maxlength="11" placeholder="请填写手机号码" clearable v-model="formData.tel"></el-input>
label="手机号码" </el-form-item>
prop="tel"> </el-col>
<el-input maxlength="11" placeholder="请填写手机号码"
type="tel" <el-col :span="24">
v-model="formData.tel"></el-input> <el-form-item label="是否默认" prop="isDefault">
<el-switch
v-model="formData.isDefault"
active-color="#13ce66"
inactive-color="#ff4949"
active-value="1"
inactive-value="0"
active-text="是"
inactive-text="否"
></el-switch>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -124,67 +113,79 @@ layout("/layouts/platform.html"){
<el-button @click="doSaveUserAddress" type="primary">保存</el-button> <el-button @click="doSaveUserAddress" type="primary">保存</el-button>
</span> </span>
</el-dialog> </el-dialog>
</div> </div>
<script src="${base!}/assets/platform/js/chengSh.js"></script>
<script> <script>
const vue = new Vue({ const vue = new Vue({
el: '#app', el: "#app",
mixins: [initTableMixins], mixins: [initTableMixins],
data() { data() {
return { return {
dzOptions: chengShiList, dzOptions: chengShiList,
dialogVisible: false, dialogVisible: false,
tableColumns: [ tableColumns: [
{prop: 'userName', label: '收货人'}, { prop: "userName", label: "收货人" },
{prop: 'address', label: '所在地区'}, { prop: "address", label: "所在地区" },
{prop: 'addressDetail', label: '详细地址'}, { prop: "addressDetail", label: "详细地址" },
{prop: 'tel', label: '电话'}, { prop: "tel", label: "电话" }
],
formRules: {
addressList: [{ required: true, message: "请选择地址信息", trigger: ["blur", "change"] }],
addressDetail: [{ required: true, message: "请填写您的详细地址", trigger: ["blur", "change"] }],
userName: [{ required: true, message: "请填写收货人姓名", trigger: ["blur", "change"] }],
tel: [
{ required: true, message: "必填", trigger: ["blur", "change"] },
{ pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号" }
] ]
} }
}
}, },
methods: { methods: {
pageData() { pageData() {
sublime.showLoadingbar(); sublime.showLoadingbar()
this.tableLoading = true this.tableLoading = true
$.post(loc() + "/selectUserAddress", this.pageForm, (data) => { $.post(
sublime.closeLoadingbar(); loc() + "/selectUserAddress",
this.pageForm,
(data) => {
sublime.closeLoadingbar()
this.tableLoading = false this.tableLoading = false
if (data.code === 0) { if (data.code === 0) {
this.tableData = data.data; this.tableData = data.data
} else { } else {
this.$message.error(data.msg); this.$message.error(data.msg)
} }
}, "json"); },
"json"
)
}, },
handleChange(val) { handleChange(val) {
if (val) { if (val) {
let provinceName = "" let provinceName = ""
let cityName = "" let cityName = ""
let countyName = "" let countyName = ""
const province = this.dzOptions.find(c => c.value === val[0]) const province = this.dzOptions.find((c) => c.value === val[0])
provinceName = province.label provinceName = province.label
const city = province.children.find(p => p.value === val[1]) const city = province.children.find((p) => p.value === val[1])
cityName = city.label cityName = city.label
if (val.length === 3) { if (val.length === 3) {
const county = city.children.find(p => p.value === val[2]) const county = city.children.find((p) => p.value === val[2])
countyName = county.label countyName = county.label
this.$set(this.formData, "areaCode", county.value) this.$set(this.formData, "areaCode", county.value)
}else{ } else {
this.$set(this.formData, "areaCode", city.value) this.$set(this.formData, "areaCode", city.value)
} }
this.$set(this.formData, "province", provinceName) this.$set(this.formData, "province", provinceName)
this.$set(this.formData, "city", cityName) this.$set(this.formData, "city", cityName)
this.$set(this.formData, "county", countyName) this.$set(this.formData, "county", countyName)
} }
}, },
openAddress() { openAddress() {
this.formData = {} this.formData = {
userName: "${@shiro.getPrincipalProperty('username')}",
tel: "${@shiro.getPrincipalProperty('mobile')}"
}
this.dialogVisible = true this.dialogVisible = true
if (this.$refs["addForm"]) if (this.$refs["addForm"]) this.$refs["addForm"].resetFields()
this.$refs["addForm"].resetFields();
}, },
doSaveUserAddress() { doSaveUserAddress() {
this.$refs["addForm"].validate(async (valid) => { this.$refs["addForm"].validate(async (valid) => {
@@ -194,72 +195,69 @@ layout("/layouts/platform.html"){
this.doSearch() this.doSearch()
this.$message({ this.$message({
message: resp.msg, message: resp.msg,
type: 'success' type: "success"
}); })
this.dialogVisible = false this.dialogVisible = false
} else { } else {
this.$message.error(resp.msg); this.$message.error(resp.msg)
} }
} }
}) })
}, },
doDelete(id) { doDelete(id) {
this.$confirm('此操作将永久删除该地址, 是否继续?', '提示', { this.$confirm("此操作将永久删除该地址, 是否继续?", "提示", {
confirmButtonText: '确定', confirmButtonText: "确定",
cancelButtonText: '取消', cancelButtonText: "取消",
type: 'warning' type: "warning"
}).then(async () => { }).then(async () => {
const resp = await $.post("/mobile/welfare/mine/deleteAddress", {id: id}) const resp = await $.post("/mobile/welfare/mine/deleteAddress", { id: id })
if (resp.code === 0) { if (resp.code === 0) {
this.doSearch() this.doSearch()
this.$message({ this.$message({
type: 'success', type: "success",
message: resp.msg message: resp.msg
}); })
} else { } else {
this.$message.error(resp.msg); this.$message.error(resp.msg)
} }
}) })
}, },
openEdit(row) { openEdit(row) {
row.addressList = [] row.addressList = []
const province = chengShiList.find(c => c.label === row.province) const province = chengShiList.find((c) => c.label === row.province)
row.addressList.push(province.value) row.addressList.push(province.value)
const city = province.children.find(p => p.label === row.city) const city = province.children.find((p) => p.label === row.city)
row.addressList.push(city.value) row.addressList.push(city.value)
const county = city.children.find(p => p.label === row.county) if (row.county) {
const county = city.children.find((p) => p.label === row.county)
if (county) { if (county) {
row.addressList.push(county.value) row.addressList.push(county.value)
} }
this.formData = row }
this.formData = { ...row }
this.formData.isDefault = this.formData.isDefault ? "1" : "0"
this.dialogVisible = true this.dialogVisible = true
}, },
async doDefault(row) { async doDefault(row) {
const resp = await $.post(loc()+"/doDefault", {id: row.id}) const resp = await $.post(loc() + "/doDefault", { id: row.id })
if (resp.code === 0) { if (resp.code === 0) {
this.doSearch() this.doSearch()
this.$message({ this.$message({
type: 'success', type: "success",
message: resp.msg message: resp.msg
}); })
} else { } else {
this.$message.error(resp.msg); this.$message.error(resp.msg)
}
} }
},
}, },
async created() { async created() {
this.pageData() this.pageData()
/* if ("${@shiro.hasRole('sysadmin')}" === 'false') {
this.dzOptions = this.dzOptions.filter(d => d.label === "江苏省")
this.dzOptions[0].children = this.dzOptions[0].children.filter(d => d.label === "无锡市")
}*/
} }
}) })
</script> </script>
<!--# <!--#
} }
#--> #-->
@@ -25,16 +25,13 @@ layout("/layouts/platform.html"){
font-size: 13px; font-size: 13px;
color: #868282; color: #868282;
} }
</style> </style>
<div id="app" v-cloak> <div id="app" v-cloak>
<guava :edit_scroll="false" ref="guava"> <guava :edit_scroll="false" ref="guava">
<template> <template>
<el-card shadow="never"> <el-card shadow="never">
<div class="search"> <div class="search">
<div class="search-item"> <div class="search-item">
<div class="search-item-label">年度:</div> <div class="search-item-label">年度:</div>
<div class="search-item-option"> <div class="search-item-option">
@@ -42,9 +39,10 @@ layout("/layouts/platform.html"){
:clearable="true" :clearable="true"
placeholder="选择年" placeholder="选择年"
type="year" type="year"
style="width: 100%"
v-model="pageForm.year" v-model="pageForm.year"
value-format="yyyy"> value-format="yyyy"
</el-date-picker> ></el-date-picker>
</div> </div>
</div> </div>
@@ -59,26 +57,33 @@ layout("/layouts/platform.html"){
</div>--> </div>-->
<div class="search-query"> <div class="search-query">
<el-button @click="doSearch" icon="el-icon-search" type="primary">搜索 <el-button @click="doSearch" icon="el-icon-search" type="primary">搜索</el-button>
</el-button>
</div> </div>
</div> </div>
</el-card> </el-card>
<el-card class="mt10" shadow="never"> <el-card class="mt10" shadow="never">
<table-tool :app="this" label="我的福利"> <table-tool :app="this" label="我的福利">
<template #func> <template #func></template>
</template>
</table-tool> </table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" <el-table
class="vi-table" ref="table" :data="tableData"
row-key="id" style="width: 100%" v-loading="tableLoading"> :size="tableSize"
@sort-change="pageOrder"
class="vi-table"
<el-table-column :index="indexMethod" align="center" header-align="center" ref="table"
label="序号" type="index" row-key="id"
width="80px"></el-table-column> style="width: 100%"
v-loading="tableLoading"
>
<el-table-column
:index="indexMethod"
align="center"
header-align="center"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column <el-table-column
:label="column.label" :label="column.label"
@@ -87,10 +92,13 @@ layout("/layouts/platform.html"){
:width="column.width" :width="column.width"
align="center" align="center"
header-align="center" header-align="center"
min-width="100px" show-overflow-tooltip v-for="column in tableColumns"> min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='choiceTime'"> <template scope="{row}" v-if="column.prop=='choiceTime'">
<i class="el-icon-time"></i>&ensp; <i class="el-icon-time"></i>
{{moment(row.choiceTimeStart).format('YYYY/MM/DD HH:mm')}} &ensp; {{moment(row.choiceTimeStart).format('YYYY/MM/DD HH:mm')}}
<span>- {{moment(row.choiceTimeEnd).format('YYYY/MM/DD HH:mm')}}</span> <span>- {{moment(row.choiceTimeEnd).format('YYYY/MM/DD HH:mm')}}</span>
</template> </template>
@@ -101,9 +109,7 @@ layout("/layouts/platform.html"){
<template scope="{row}" v-else-if="column.prop=='gist_list'"> <template scope="{row}" v-else-if="column.prop=='gist_list'">
<template v-if="!projectInfo.flexible">{{projectInfo.gift}}</template> <template v-if="!projectInfo.flexible">{{projectInfo.gift}}</template>
<template v-if="row.gist_list"> <template v-if="row.gist_list">{{row.gifts.map(v=>v.name + '('+v.num+'份)').join(',')}}</template>
{{row.gifts.map(v=>v.name + '('+v.num+'份)').join(',')}}
</template>
</template> </template>
<template scope="{row}" v-else-if="column.prop=='receiveAddress'"> <template scope="{row}" v-else-if="column.prop=='receiveAddress'">
@@ -112,33 +118,21 @@ layout("/layouts/platform.html"){
</template> </template>
<template scope="{row}" v-else-if="column.prop=='courierNumber'"> <template scope="{row}" v-else-if="column.prop=='courierNumber'">
<span @click="viewCourierNumber(row)" class="text-primary" <span @click="viewCourierNumber(row)" class="text-primary" style="cursor: pointer">点击查看</span>
style="cursor: pointer">点击查看</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" fixed="right" header-align="center" <el-table-column align="center" fixed="right" header-align="center" label="操作" prop="userOnline" width="200px">
label="操作" prop="userOnline"
width="200px">
<template scope="{row}"> <template scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary"> <el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
查看
</el-button>
<!-- <el-button :disabled="!row.courierNumber" @click="openExpress(row)"--> <!-- <el-button :disabled="!row.courierNumber" @click="openExpress(row)"-->
<!-- size="mini"--> <!-- size="mini"-->
<!-- type="primary">--> <!-- type="primary">-->
<!-- 查看物流--> <!-- 查看物流-->
<!-- </el-button>--> <!-- </el-button>-->
<el-button :disabled="!row.courierNumber" @click="openEvaluate(row)" <el-button :disabled="!row.courierNumber" @click="openEvaluate(row)" size="mini" type="primary">评价</el-button>
size="mini"
type="primary">
评价
</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!--#include("/layouts/pagination.html"){}#--> <!--#include("/layouts/pagination.html"){}#-->
</el-card> </el-card>
@@ -148,29 +142,20 @@ layout("/layouts/platform.html"){
<el-card shadow="never"> <el-card shadow="never">
<el-form :model="formData" label-width="120px" ref="addForm"> <el-form :model="formData" label-width="120px" ref="addForm">
<el-form-item label="福利名称"> <el-form-item label="福利名称">
<span style="font-weight: bold;font-size: 20px">{{projectInfo.name}}</span> <span style="font-weight: bold; font-size: 20px">{{projectInfo.name}}</span>
</el-form-item> </el-form-item>
<el-row :gutter="10"> <el-row :gutter="10">
<el-col span="8"> <el-col span="8">
<el-form-item label="福利节日"> <el-form-item label="福利节日">{{projectInfo.festival}}</el-form-item>
{{projectInfo.festival}}
</el-form-item>
</el-col> </el-col>
<el-col span="8" v-if="!projectInfo.flexible"> <el-col span="8" v-if="!projectInfo.flexible">
<el-form-item label="福利礼品"> <el-form-item label="福利礼品">{{projectInfo.gift}}</el-form-item>
{{projectInfo.gift}}
</el-form-item>
</el-col> </el-col>
<el-col span="8"> <el-col span="8">
<el-form-item label="选择形式">{{projectInfo.isCheckBox==='checkBox'?'多选':'单选'}}</el-form-item>
<el-form-item label="选择形式">
{{projectInfo.isCheckBox==='checkBox'?'多选':'单选'}}
</el-form-item>
</el-col> </el-col>
<el-col span="8" v-if="projectInfo.isCheckBox==='checkBox'"> <el-col span="8" v-if="projectInfo.isCheckBox==='checkBox'">
<el-form-item label="最多选几个"> <el-form-item label="最多选几个">{{projectInfo.multiSelectNum}}个</el-form-item>
{{projectInfo.multiSelectNum}}个
</el-form-item>
</el-col> </el-col>
<el-col span="8"> <el-col span="8">
<el-form-item label="发放形式"> <el-form-item label="发放形式">
@@ -189,75 +174,52 @@ layout("/layouts/platform.html"){
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col span="8"> <el-col span="8">
<el-form-item label="选择时间"> <el-form-item label="选择时间">{{projectInfo.choiceTimeStart}}至{{projectInfo.choiceTimeEnd}}</el-form-item>
{{projectInfo.choiceTimeStart}}至{{projectInfo.choiceTimeEnd}}
</el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item label="福利套餐"> <el-form-item label="福利套餐">
<el-row :gutter="0"> <el-row :gutter="0">
<div :key="subject.id" <div :key="subject.id" v-for="subject in projectInfo.welfareProjectSubjects">
v-for="subject in projectInfo.welfareProjectSubjects"> <el-col :key="oidx" :span="6" v-for="(option, oidx) in subject.options">
<el-col :key="oidx" :span="6" <el-card shadow="never" style="margin: 5px">
v-for="(option, oidx) in subject.options"> <div slot="header" style="display: flex; justify-content: space-between">
<el-card shadow="never" <div>{{option.optionName}}</div>
style="margin: 5px;">
<div slot="header"
style="display: flex;justify-content: space-between">
<div> <div>
{{option.optionName}} <el-button @click.stop="viewDesc(option)" type="text">套餐详情</el-button>
</div>
<div>
<el-button @click.stop="viewDesc(option)"
type="text">套餐详情
</el-button>
</div> </div>
</div> </div>
<el-row :gutter="10"> <el-row :gutter="10">
<el-col :span="24"> <el-col :span="24">
<div class="optionImg"> <div class="optionImg">
<el-image <el-image :src="CREATE_PREVIEW_URL(option.imgUrl)" fit="contain"></el-image>
:src="CREATE_PREVIEW_URL(option.imgUrl)"
fit="contain"
></el-image>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="10" v-if="option.supplier"> <el-row :gutter="10" v-if="option.supplier">
<el-col :span="24"> <el-col :span="24">
<div class="descriptionClass"> <div class="descriptionClass">{{removeHTMLTag(option.supplier)}}</div>
{{removeHTMLTag(option.supplier)}}
</div>
</el-col> </el-col>
</el-row> </el-row>
<el-row style=""> <el-row style="">
<el-input-number disabled <el-input-number disabled style="width: 100%" v-model="option.selectNum"></el-input-number>
style="width: 100%"
v-model="option.selectNum"></el-input-number>
</el-row> </el-row>
</el-card> </el-card>
</el-col> </el-col>
</div> </div>
</el-row> </el-row>
</el-form-item> </el-form-item>
<el-form-item <el-form-item label="收货地址" prop="receiveAddress" v-if="projectInfo.provideMode===3">{{formData.receiveAddress}}</el-form-item>
label="收货地址"
prop="receiveAddress" v-if="projectInfo.provideMode===3">
{{formData.receiveAddress}}
</el-form-item>
<el-form-item label="签字" prop="sign" v-if="projectInfo.signMode===2"> <el-form-item label="签字" prop="sign" v-if="projectInfo.signMode===2">
<el-image :src="'/signature/getSignData?path=' +formData.imageUrl" <el-image
:src="'/signature/getSignData?path=' +formData.imageUrl"
fit="contain" fit="contain"
style="height: 100px;width: 100%" v-if="formData.imageUrl"> style="height: 100px; width: 100%"
</el-image> v-if="formData.imageUrl"
></el-image>
<span v-else>暂无</span> <span v-else>暂无</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
@@ -265,71 +227,53 @@ layout("/layouts/platform.html"){
</template> </template>
</guava> </guava>
<el-dialog :close-on-click-modal="false" :visible.sync="evaluateDialogVisible" title="福利评价" width="40%">
<el-dialog
:close-on-click-modal="false"
:visible.sync="evaluateDialogVisible"
title="福利评价"
width="40%">
<el-form :model="formData" label-width="80px" ref="form"> <el-form :model="formData" label-width="80px" ref="form">
<el-form-item :rules="[{ required: true, message: ''}]" label="评价套餐"> <el-form-item :rules="[{ required: true, message: ''}]" label="评价套餐">
<el-radio-group <el-radio-group @change="finOneWelfareEvaluate(formData.projectId,formData.optionId)" v-model="formData.optionId">
@change="finOneWelfareEvaluate(formData.projectId,formData.optionId)"
v-model="formData.optionId">
<el-row gutter="10"> <el-row gutter="10">
<el-col :key="item.selectOptionId" class="mt10" span="24" <el-col :key="item.selectOptionId" class="mt10" span="24" v-for="item in userSelection">
v-for="item in userSelection"> <el-radio :label="item.selectOptionId" border style="width: 100%; position: relative">
<el-radio :label="item.selectOptionId" border style="width: 100%;position: relative">
{{item.optionName}} {{item.optionName}}
<span style="color: red;position: absolute;right: 10px;" v-if="!item.isPj">未评价</span> <span style="color: red; position: absolute; right: 10px" v-if="!item.isPj">未评价</span>
</el-radio> </el-radio>
</el-col> </el-col>
</el-row> </el-row>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item :rules="[{ required: true, message: ''}]" label="评分"> <el-form-item :rules="[{ required: true, message: ''}]" label="评分">
<div style="position: absolute; top: 20%;"> <div style="position: absolute; top: 20%">
<el-rate :disabled="formData.id" <el-rate :disabled="formData.id" show-score text-color="#ff9900" v-model="formData.evaluateScore"></el-rate>
show-score text-color="#ff9900"
v-model="formData.evaluateScore"></el-rate>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="评价"> <el-form-item label="评价">
<el-input :disabled="formData.id" <el-input
:disabled="formData.id"
maxlength="500" maxlength="500"
placeholder="请输入评价" placeholder="请输入评价"
rows="5" rows="5"
show-word-limit show-word-limit
type="textarea" type="textarea"
v-model="formData.evaluateText" v-model="formData.evaluateText"
> ></el-input>
</el-input>
</el-form-item> </el-form-item>
</el-form> </el-form>
<span class="dialog-footer" slot="footer"> <span class="dialog-footer" slot="footer">
<el-button @click="evaluateDialogVisible = false" type="primary">关 闭</el-button> <el-button @click="evaluateDialogVisible = false" type="primary">关 闭</el-button>
<el-button :loading="evaluateLoading" @click="doEvaluate" type="primary" <el-button :loading="evaluateLoading" @click="doEvaluate" type="primary" v-if="!formData.id">提 交</el-button>
v-if="!formData.id">提 交</el-button>
</span> </span>
</el-dialog> </el-dialog>
<el-drawer <el-drawer :visible.sync="descDialogVisible" direction="rtl" size="50%" title="福利详情">
:visible.sync="descDialogVisible"
direction="rtl"
size="50%"
title="福利详情">
<el-card style="margin: 20px"> <el-card style="margin: 20px">
<div v-html="descData"></div> <div v-html="descData"></div>
</el-card> </el-card>
</el-drawer> </el-drawer>
<el-drawer <el-drawer :visible.sync="expressDrawer" direction="rtl" size="50%">
:visible.sync="expressDrawer"
direction="rtl"
size="50%">
<template #title> <template #title>
<div style="font-size: 20px">物流详情 <div style="font-size: 20px">
物流详情
<span style="color: red">&nbsp;&nbsp;温馨提示:物流信息一小时更新一次</span> <span style="color: red">&nbsp;&nbsp;温馨提示:物流信息一小时更新一次</span>
</div> </div>
</template> </template>
@@ -339,12 +283,11 @@ layout("/layouts/platform.html"){
:color="item.color" :color="item.color"
:key="index" :key="index"
:timestamp="moment().format('YYYY-MM-DD HH:mm:ss')" :timestamp="moment().format('YYYY-MM-DD HH:mm:ss')"
v-for="(item, index) in logisticsTrace.logisticsTraceDetailList"> v-for="(item, index) in logisticsTrace.logisticsTraceDetailList"
>
{{item.desc}} {{item.desc}}
</el-timeline-item> </el-timeline-item>
</el-timeline> </el-timeline>
</el-card> </el-card>
</el-drawer> </el-drawer>
@@ -353,7 +296,7 @@ layout("/layouts/platform.html"){
</div> </div>
<script> <script>
const vue = new Vue({ const vue = new Vue({
el: '#app', el: "#app",
mixins: [initTableMixins], mixins: [initTableMixins],
data() { data() {
return { return {
@@ -361,7 +304,7 @@ layout("/layouts/platform.html"){
descDialogVisible: false, descDialogVisible: false,
projectInfo: {}, projectInfo: {},
userSelection: [], userSelection: [],
userId: '', userId: "",
projectOptions: [], projectOptions: [],
units: [], units: [],
welfareUnits: [], welfareUnits: [],
@@ -370,18 +313,17 @@ layout("/layouts/platform.html"){
welfareSignMode: [], welfareSignMode: [],
welfareNoticePushMode: [], welfareNoticePushMode: [],
pageForm: { pageForm: {
year: moment().format('YYYY'), year: moment().format("YYYY"),
searchName: 'username' searchName: "username"
}, },
tableColumns: [ tableColumns: [
{prop: 'year', label: '年度'}, { prop: "year", label: "年度" },
{prop: 'name', label: '项目名称'}, { prop: "name", label: "项目名称" },
{prop: 'choiceTime', label: '选择时间'}, { prop: "choiceTime", label: "选择时间" },
{prop: 'isChoose', label: '是否选择'}, { prop: "isChoose", label: "是否选择" },
{prop: 'gist_list', label: '所选福利'}, { prop: "gist_list", label: "所选福利" },
{prop: 'receiveAddress', label: '收货地址'}, { prop: "receiveAddress", label: "收货地址" },
{prop: 'courierNumber', label: '快递单号', sortable: true}, { prop: "courierNumber", label: "快递单号", sortable: true }
], ],
formRules: {}, formRules: {},
selPersonType: [], selPersonType: [],
@@ -392,12 +334,11 @@ layout("/layouts/platform.html"){
evaluateLoading: false, evaluateLoading: false,
expressDrawer: false, expressDrawer: false,
logisticsTrace: {}, logisticsTrace: {}
} }
}, },
components: { components: {
'courier-number-info': httpVueLoader('/components/welfare/CourierNumberInfo.vue?v=' + new Date().getTime()) "courier-number-info": httpVueLoader("/components/welfare/CourierNumberInfo.vue?v=" + new Date().getTime())
}, },
methods: { methods: {
//查看快递单号 //查看快递单号
@@ -411,15 +352,15 @@ layout("/layouts/platform.html"){
async doEvaluate() { async doEvaluate() {
if (!this.formData.evaluateScore || !this.formData.optionId) { if (!this.formData.evaluateScore || !this.formData.optionId) {
this.$message({ this.$message({
message: '请打分后再提交', message: "请打分后再提交",
type: 'warning' type: "warning"
}); })
return return
} }
const confirm = await this.$confirm('提交后将不能修改,确定要提交评价吗?', '提示', { const confirm = await this.$confirm("提交后将不能修改,确定要提交评价吗?", "提示", {
confirmButtonText: '确定', confirmButtonText: "确定",
cancelButtonText: '取消', cancelButtonText: "取消",
type: 'warning' type: "warning"
}) })
if (confirm === "confirm") { if (confirm === "confirm") {
this.evaluateLoading = true this.evaluateLoading = true
@@ -427,24 +368,18 @@ layout("/layouts/platform.html"){
if (resp.code === 0) { if (resp.code === 0) {
this.$message({ this.$message({
message: resp.msg, message: resp.msg,
type: 'success' type: "success"
}); })
this.doSearch() this.doSearch()
this.evaluateDialogVisible = false this.evaluateDialogVisible = false
} else { } else {
this.$message.error(resp.msg); this.$message.error(resp.msg)
} }
this.evaluateLoading = false this.evaluateLoading = false
} }
}, },
async finOneWelfareEvaluate(projectId, optionId) { async finOneWelfareEvaluate(projectId, optionId) {
const { data, code, msg } = await $.post(loc() + "/finOneWelfareEvaluate", {
const {
data,
code,
msg
} = await $.post(loc() + "/finOneWelfareEvaluate", {
projectId: projectId, projectId: projectId,
optionId: optionId optionId: optionId
}) })
@@ -470,7 +405,7 @@ layout("/layouts/platform.html"){
this.evaluateDialogVisible = true this.evaluateDialogVisible = true
}, },
async getProjectInfo(id) { async getProjectInfo(id) {
const resp = await $.get('/platform/welfare/common/findOne', {projectId: id}) const resp = await $.get("/platform/welfare/common/findOne", { projectId: id })
if (resp.code === 0) { if (resp.code === 0) {
this.projectInfo = resp.data this.projectInfo = resp.data
await this.getUserSelection(id) await this.getUserSelection(id)
@@ -479,14 +414,14 @@ layout("/layouts/platform.html"){
}, },
//获取用户选择的数据 //获取用户选择的数据
async getUserSelection(projectId) { async getUserSelection(projectId) {
const resp = await $.get('/platform/welfare/mine/getUserSelection', {projectId: projectId}) const resp = await $.get("/platform/welfare/mine/getUserSelection", { projectId: projectId })
this.userSelection = resp.data this.userSelection = resp.data
}, },
//回显用户选择的数据 //回显用户选择的数据
echoUserSelection() { echoUserSelection() {
//获取用户当前选择的数量 //获取用户当前选择的数量
this.projectInfo.welfareProjectSubjects[0].options.forEach(v => { this.projectInfo.welfareProjectSubjects[0].options.forEach((v) => {
const option = this.userSelection.find(x => x.selectOptionId === v.id) const option = this.userSelection.find((x) => x.selectOptionId === v.id)
if (option) { if (option) {
v.selectNum = option.selectNum v.selectNum = option.selectNum
} else { } else {
@@ -508,7 +443,7 @@ layout("/layouts/platform.html"){
this.$refs.guava.edit() this.$refs.guava.edit()
}, },
async getExpressInfo(row) { async getExpressInfo(row) {
const resp = await $.get(loc() + '/getExpressInfo', {courierNumber: row.courierNumber}) const resp = await $.get(loc() + "/getExpressInfo", { courierNumber: row.courierNumber })
if (resp.code === 0) { if (resp.code === 0) {
for (let i = 0; i < resp.data.logisticsTraceDetailList.length; i++) { for (let i = 0; i < resp.data.logisticsTraceDetailList.length; i++) {
if (i === resp.data.logisticsTraceDetailList.length - 1) { if (i === resp.data.logisticsTraceDetailList.length - 1) {
@@ -518,17 +453,16 @@ layout("/layouts/platform.html"){
} }
this.logisticsTrace = resp.data this.logisticsTrace = resp.data
} else { } else {
this.$message.error(resp.msg); this.$message.error(resp.msg)
}
} }
},
}, },
async created() { async created() {
this.pageData() this.pageData()
getEnumOptions("WelfareProvideMode").then(res => { getEnumOptions("WelfareProvideMode").then((res) => {
this.welfareProvideMode = res this.welfareProvideMode = res
}) })
getEnumOptions("WelfareSignMode").then(res => { getEnumOptions("WelfareSignMode").then((res) => {
this.welfareSignMode = res this.welfareSignMode = res
}) })
} }
File diff suppressed because it is too large Load Diff
@@ -65,6 +65,20 @@ layout("/layouts/platform.html"){
</div> </div>
</div> </div>
<div class="search-item">
<div class="search-item-label">人员类型:</div>
<div class="search-item-option">
<dict-select
@change="doSearch"
clearable
code="PERSON_TYPE"
placeholder="人员类型"
style="width: 100%"
v-model="pageForm.personType"
></dict-select>
</div>
</div>
<div class="search-query"> <div class="search-query">
<el-button @click="doSearch();unionGroupChange()" icon="el-icon-search" type="primary">搜索</el-button> <el-button @click="doSearch();unionGroupChange()" icon="el-icon-search" type="primary">搜索</el-button>
</div> </div>
@@ -86,7 +100,7 @@ layout("/layouts/platform.html"){
type="primary" type="primary"
v-if="judgmentAuthority" v-if="judgmentAuthority"
> >
导出各基层工会福利签领表 导出各分工会福利签领表
</el-button> </el-button>
<el-button <el-button
@@ -105,7 +119,7 @@ layout("/layouts/platform.html"){
type="primary">按品牌导出全部(蛋糕券) type="primary">按品牌导出全部(蛋糕券)
</el-button>--> </el-button>-->
<template v-if="judgmentAuthority || ${@shiro.hasRole('H04') || @shiro.hasRole('gh12')}"> <template v-if="judgmentAuthority || ${@shiro.hasRole('H04') || @shiro.hasRole('gh01') || @shiro.hasRole('gh12')}">
<el-button <el-button
:disabled="!pageForm.projectId" :disabled="!pageForm.projectId"
@click="exportReceiveDetail(true)" @click="exportReceiveDetail(true)"
@@ -138,12 +152,19 @@ layout("/layouts/platform.html"){
<!-- @click="exportByUnionGroup">按工会小组导出汇总表--> <!-- @click="exportByUnionGroup">按工会小组导出汇总表-->
<!-- </el-button>--> <!-- </el-button>-->
</template> </template>
<template v-if="judgmentAuthority"> <!--<template
<el-button :disabled="!pageForm.projectId" @click="exportByUnion" icon="el-icon-printer" size="small" type="primary"> v-if="judgmentAuthority">
导出基层工会/福利套餐汇总表 <el-button :disabled="!pageForm.projectId" @click="reimbursementDialog = true"
icon="el-icon-printer"
size="small"
type="primary">导出发放清单
</el-button> </el-button>
<el-button @click="selectOptionByAdmin" icon="el-icon-printer" size="small" type="primary">管理员代选择</el-button> <el-button @click="selectOptionByAdmin"
</template> icon="el-icon-printer"
size="small"
type="primary">管理员代选择
</el-button>
</template>-->
</template> </template>
</table-tool> </table-tool>
<el-table <el-table
@@ -309,6 +330,19 @@ layout("/layouts/platform.html"){
<el-button @click="doSelectByAdmin" type="primary">提交</el-button> <el-button @click="doSelectByAdmin" type="primary">提交</el-button>
</el-row> </el-row>
</el-dialog> </el-dialog>
<el-dialog :visible.sync="reimbursementDialog" title="导出发放清单" width="40%">
<el-radio-group v-model="reimbursementPersonType" size="small">
<el-radio label="在职人员" border>在职人员</el-radio>
<el-radio label="劳务派遣人员" border>劳务派遣人员</el-radio>
<el-radio label="空状态" border>空状态</el-radio>
<el-radio label="全部" border>全部</el-radio>
</el-radio-group>
<span class="dialog-footer" slot="footer">
<el-button @click="reimbursementDialog = false">取消</el-button>
<el-button @click="exportByUnion" type="primary">导出</el-button>
</span>
</el-dialog>
</div> </div>
<script> <script>
@@ -328,7 +362,8 @@ layout("/layouts/platform.html"){
month: "", month: "",
unionGroupId: "", unionGroupId: "",
year: "", year: "",
welfareUnitCode: "" welfareUnitCode: "",
personType: ""
}, },
unions: [], unions: [],
tableColumns: [], tableColumns: [],
@@ -383,7 +418,10 @@ layout("/layouts/platform.html"){
projectInfo: {}, projectInfo: {},
viewTableWrapHeight: 500, viewTableWrapHeight: 500,
judgmentAuthority judgmentAuthority,
reimbursementDialog: false,
reimbursementPersonType: null
} }
}, },
computed: { computed: {
@@ -614,6 +652,10 @@ layout("/layouts/platform.html"){
this.unclaimedPageData() this.unclaimedPageData()
}, },
exportByUnion() { exportByUnion() {
if (!this.reimbursementPersonType) {
this.$message.warning("请先选择需要导出的人员类型")
return
}
const { projectId, welfareUnitCode } = this.pageForm const { projectId, welfareUnitCode } = this.pageForm
window.open( window.open(
loc() + loc() +
@@ -622,8 +664,11 @@ layout("/layouts/platform.html"){
"&welfareUnitCode=" + "&welfareUnitCode=" +
(welfareUnitCode ? welfareUnitCode : "") + (welfareUnitCode ? welfareUnitCode : "") +
"&month=" + "&month=" +
this.pageForm.month this.pageForm.month +
"&personType=" +
this.reimbursementPersonType
) )
this.reimbursementDialog = false
}, },
exportByUnit() { exportByUnit() {
const { projectId, welfareUnitCode } = this.pageForm const { projectId, welfareUnitCode } = this.pageForm
@@ -3,8 +3,6 @@ layout("/layouts/platform.html"){
#--> #-->
<style> <style>
.optionImg { .optionImg {
display: grid; display: grid;
place-items: center; place-items: center;
@@ -49,7 +47,6 @@ layout("/layouts/platform.html"){
} }
</style> </style>
<div id="app" v-cloak> <div id="app" v-cloak>
<guava :edit_scroll="false" ref="guava"> <guava :edit_scroll="false" ref="guava">
<template> <template>
@@ -64,31 +61,38 @@ layout("/layouts/platform.html"){
style="width: 100%" style="width: 100%"
type="year" type="year"
v-model="pageForm.year" v-model="pageForm.year"
value-format="yyyy"> value-format="yyyy"
</el-date-picker> ></el-date-picker>
</div> </div>
</div> </div>
<div class="search-query"> <div class="search-query">
<el-button @click="doSearch" icon="el-icon-search" type="primary">搜索 <el-button @click="doSearch" icon="el-icon-search" type="primary">搜索</el-button>
</el-button>
</div> </div>
</div> </div>
</el-card> </el-card>
<el-card class="mt10" shadow="never"> <el-card class="mt10" shadow="never">
<table-tool :app="this" label="福利项目"> <table-tool :app="this" label="福利项目">
<template #func> <template #func></template>
</template>
</table-tool> </table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" <el-table
:data="tableData"
:size="tableSize"
@sort-change="pageOrder"
ref="table" ref="table"
row-key="id" style="width: 100%" v-loading="tableLoading"> row-key="id"
style="width: 100%"
<el-table-column :index="indexMethod" align="center" header-align="center" v-loading="tableLoading"
label="序号" type="index" >
width="80px"></el-table-column> <el-table-column
:index="indexMethod"
align="center"
header-align="center"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column <el-table-column
:key="column.prop" :key="column.prop"
@@ -98,11 +102,13 @@ layout("/layouts/platform.html"){
:width="column.width" :width="column.width"
align="center" align="center"
header-align="center" header-align="center"
min-width="100px" show-overflow-tooltip min-width="100px"
v-for="column in tableColumns"> show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='choiceTime'"> <template scope="{row}" v-if="column.prop=='choiceTime'">
<i class="el-icon-time"></i>&ensp; <i class="el-icon-time"></i>
{{moment(row.choiceTimeStart).format('YYYY/MM/DD HH:mm')}} &ensp; {{moment(row.choiceTimeStart).format('YYYY/MM/DD HH:mm')}}
<span>- {{moment(row.choiceTimeEnd).format('YYYY/MM/DD HH:mm')}}</span> <span>- {{moment(row.choiceTimeEnd).format('YYYY/MM/DD HH:mm')}}</span>
</template> </template>
@@ -122,12 +128,9 @@ layout("/layouts/platform.html"){
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" header-align="center" label="操作" <el-table-column align="center" header-align="center" label="操作" prop="userOnline" width="150px">
prop="userOnline" width="150px">
<template scope="{row}"> <template scope="{row}">
<el-button type="primary" size="mini" @click="openChoose(row)"> <el-button type="primary" size="mini" @click="openChoose(row)">{{confirmButtonInfo(row).text}}</el-button>
{{confirmButtonInfo(row).text}}
</el-button>
<!-- <el-button @click="openChoose(row)" size="mini" type="primary"--> <!-- <el-button @click="openChoose(row)" size="mini" type="primary"-->
<!-- v-if="new Date().getTime()>moment(row.choiceTimeStart).valueOf()--> <!-- v-if="new Date().getTime()>moment(row.choiceTimeStart).valueOf()-->
@@ -143,7 +146,6 @@ layout("/layouts/platform.html"){
<!-- </template>--> <!-- </template>-->
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!--#include("/layouts/pagination.html"){}#--> <!--#include("/layouts/pagination.html"){}#-->
</el-card> </el-card>
@@ -153,29 +155,20 @@ layout("/layouts/platform.html"){
<el-card shadow="never"> <el-card shadow="never">
<el-form :model="formData" label-width="120px" ref="addForm"> <el-form :model="formData" label-width="120px" ref="addForm">
<el-form-item label="福利名称"> <el-form-item label="福利名称">
<span style="font-weight: bold;font-size: 20px">{{projectInfo.name}}</span> <span style="font-weight: bold; font-size: 20px">{{projectInfo.name}}</span>
</el-form-item> </el-form-item>
<el-row :gutter="10"> <el-row :gutter="10">
<el-col span="8"> <el-col span="8">
<el-form-item label="福利节日"> <el-form-item label="福利节日">{{projectInfo.festival}}</el-form-item>
{{projectInfo.festival}}
</el-form-item>
</el-col> </el-col>
<el-col span="8" v-if="!projectInfo.flexible"> <el-col span="8" v-if="!projectInfo.flexible">
<el-form-item label="福利礼品"> <el-form-item label="福利礼品">{{projectInfo.gift}}</el-form-item>
{{projectInfo.gift}}
</el-form-item>
</el-col> </el-col>
<el-col span="8"> <el-col span="8">
<el-form-item label="选择形式">{{projectInfo.isCheckBox==='checkBox'?'多选':'单选'}}</el-form-item>
<el-form-item label="选择形式">
{{projectInfo.isCheckBox==='checkBox'?'多选':'单选'}}
</el-form-item>
</el-col> </el-col>
<el-col span="8" v-if="projectInfo.isCheckBox==='checkBox'"> <el-col span="8" v-if="projectInfo.isCheckBox==='checkBox'">
<el-form-item label="最多选几个"> <el-form-item label="最多选几个">{{projectInfo.multiSelectNum}}个</el-form-item>
{{projectInfo.multiSelectNum}}个
</el-form-item>
</el-col> </el-col>
<el-col span="8"> <el-col span="8">
<el-form-item label="发放形式"> <el-form-item label="发放形式">
@@ -194,91 +187,76 @@ layout("/layouts/platform.html"){
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col span="8"> <el-col span="8">
<el-form-item label="选择时间"> <el-form-item label="选择时间">{{projectInfo.choiceTimeStart}}至{{projectInfo.choiceTimeEnd}}</el-form-item>
{{projectInfo.choiceTimeStart}}至{{projectInfo.choiceTimeEnd}}
</el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item label="福利套餐"> <el-form-item label="福利套餐">
<el-row :gutter="0"> <el-row :gutter="0">
<div :key="subject.id" <div :key="subject.id" v-for="subject in projectInfo.welfareProjectSubjects">
v-for="subject in projectInfo.welfareProjectSubjects"> <el-col :key="oidx" :span="8" v-for="(option, oidx) in subject.options">
<el-col :key="oidx" :span="8" <el-card shadow="never" style="margin: 5px">
v-for="(option, oidx) in subject.options"> <div slot="header" style="display: flex; justify-content: space-between">
<el-card shadow="never" <div style="color: #000; font-size: 18px">{{option.optionName}}</div>
style="margin: 5px;">
<div slot="header" style="display: flex;justify-content: space-between">
<div style="color:#000;font-size: 18px">
{{option.optionName}}
</div>
<div> <div>
<el-button @click.stop="viewDesc(option)" <el-button @click.stop="viewDesc(option)" type="text">套餐详情</el-button>
type="text">套餐详情
</el-button>
</div> </div>
</div> </div>
<div style="display: grid; grid-template-rows: auto 1fr auto; height: 200px">
<div style="display: flex"> <div style="display: flex">
<el-image <el-image
style="width: 150px;height: 150px;" style="width: 150px; height: 150px"
:src="CREATE_PREVIEW_URL(option.imgUrl)" :src="CREATE_PREVIEW_URL(option.imgUrl)"
fit="contain" fit="contain"
></el-image> ></el-image>
<div style="width:calc(100% - 150px);padding-left: 20px;position: relative">
<div style="white-space: nowrap;display: flex"> <div style="width: calc(100% - 150px); padding-left: 20px; position: relative">
<span class="desc_label">服务专线</span> <div style="white-space: nowrap; display: flex">
<span class="desc_label"></span>
<el-tooltip placement="top" :content="option.supplier"> <el-tooltip placement="top" :content="option.supplier">
<span class="desc_value" <span
style="width: calc(100% - 80px);text-overflow: ellipsis;overflow: hidden"> class="desc_value"
{{option.supplier}} style="width: calc(100% - 80px); text-overflow: ellipsis; overflow: hidden"
>
{{ option.supplier }}
</span> </span>
</el-tooltip> </el-tooltip>
</div> </div>
<div v-if="option.simpleDesc"> <div v-if="option.simpleDesc">
<span class="desc_label">备&emsp;&emsp;注</span> <span class="desc_label"></span>
<span class="desc_value"> <span class="desc_value">{{ option.simpleDesc }}</span>
{{option.simpleDesc}}
</span>
</div> </div>
<div> <div>
<el-input-number :disabled="isView" <el-input-number
:disabled="isView"
:max="option.maxNum" :max="option.maxNum"
:min="0" :min="0"
@change="numChange(option.selectNum,option,oidx)" @keydown.native="onKeydown"
style="width: 150px;position: absolute;right: 0;bottom: 0;" @change="numChange(option.selectNum, option, oidx)"
v-model="option.selectNum"></el-input-number> style="width: 150px; position: absolute; right: 0; bottom: 0"
v-model="option.selectNum"
></el-input-number>
</div> </div>
</div> </div>
</div> </div>
<div style="margin-top: 17px">
<el-select
<!-- <el-row :gutter="10">--> style="width: 100%"
<!-- <el-col :span="24">--> clearable
<!-- <div class="optionImg">--> :disabled="option.selectNum == 0"
<!-- <el-image--> placeholder="请选择取货门店"
<!-- :src="CREATE_PREVIEW_URL(option.imgUrl)"--> v-model="option.receiveAddress"
<!-- fit="contain"--> >
<!-- ></el-image>--> <el-option
<!-- </div>--> v-for="item in option.receiveAddressList"
:key="item.address"
<!-- </el-col>--> :label="item.address"
<!-- </el-row>--> :value="item.address"
></el-option>
<!-- <div class="descriptionClass" style="white-space: pre-line">--> </el-select>
<!-- {{option.supplier}}--> </div>
<!-- </div>--> </div>
<!-- <el-row style="text-align: right">-->
<!-- <el-input-number :disabled="isView"-->
<!-- :max="option.maxNum"-->
<!-- :min="0"-->
<!-- @change="numChange(option.selectNum,option,oidx)"-->
<!-- style="width: 50%"-->
<!-- v-model="option.selectNum"></el-input-number>-->
<!-- </el-row>-->
</el-card> </el-card>
</el-col> </el-col>
</div> </div>
@@ -291,58 +269,68 @@ layout("/layouts/platform.html"){
<el-form-item label="收货地址" prop="receiveAddress"> <el-form-item label="收货地址" prop="receiveAddress">
<div style="display: flex; column-gap: 10px"> <div style="display: flex; column-gap: 10px">
<div style="flex: 1"> <div style="flex: 1">
<el-select @change="addressChange" <el-select
filterable placeholder="请选择收货地址" @change="addressChange"
filterable
placeholder="请选择收货地址"
style="width: 100%" style="width: 100%"
v-model="formData.addressId"> v-model="formData.addressId"
>
<el-option <el-option
:key="item.id" :key="item.id"
:label="item.name+' '+item.defaultName" :label="item.name+' '+item.defaultName"
:value="item.id" :value="item.id"
v-for="item in addressOptions"> v-for="item in addressOptions"
</el-option> ></el-option>
</el-select> </el-select>
</div> </div>
<div> <div>
<el-button <el-button @click="openAddress" type="primary">添加收货地址</el-button>
@click="openAddress"
type="primary">添加收货地址
</el-button>
</div> </div>
</div> </div>
<span style="color: #ac3111">
温馨提示:填写默认收货地址后,系统会自动选择默认地址;如未设置默认,请您在添加收货地址后在此下拉框进行选择
</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col span="24"> <el-col span="24">
<el-form-item <el-form-item
:rules="{required:true,message: '请确认收货地址', trigger: 'blur'}" :rules="{required:true,message: '请确认收货地址', trigger: 'blur'}"
label="请确认收货地址" label="请确认收货地址"
prop="receiveAddress"> prop="receiveAddress"
<el-input :rows="4" disabled maxlength="100" >
placeholder="选择收货地址联动" type="textarea" <el-input
v-model="formData.receiveAddress"></el-input> :rows="4"
disabled
maxlength="100"
placeholder="选择收货地址联动"
type="textarea"
v-model="formData.receiveAddress"
></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
</template> </template>
<el-form-item :rules="{required:true,message: '请签字', trigger: 'blur'}" <el-form-item
label="签字" prop="sign" v-if="projectInfo.signMode===2"> :rules="{required:true,message: '请签字', trigger: 'blur'}"
label="签字"
prop="sign"
v-if="projectInfo.signMode===2"
>
<template v-if="isChoice===0||!isView"> <template v-if="isChoice===0||!isView">
<sign :is_value_base64="false" :qz.sync="formData.sign" <sign :is_value_base64="false" :qz.sync="formData.sign" prefix="welfare" ref="sign"></sign>
prefix="welfare"
ref="sign"></sign>
</template> </template>
<template v-else> <template v-else>
<el-image :src="'/signature/getSignData?path=' +formData.imageUrl" <el-image
:src="'/signature/getSignData?path=' +formData.imageUrl"
fit="contain" fit="contain"
style="height: 100px;width: 100%" v-if="formData.imageUrl"> style="height: 100px; width: 100%"
</el-image> v-if="formData.imageUrl"
></el-image>
<span v-else>暂无</span> <span v-else>暂无</span>
</template> </template>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
@@ -354,29 +342,17 @@ layout("/layouts/platform.html"){
</template> </template>
</guava> </guava>
<el-drawer <el-drawer :visible.sync="descDialogVisible" direction="rtl" size="50%" title="福利详情">
:visible.sync="descDialogVisible"
direction="rtl"
size="50%"
title="福利详情">
<el-card style="margin: 20px" shadow="never"> <el-card style="margin: 20px" shadow="never">
<div v-html="descData"></div> <div v-html="descData"></div>
</el-card> </el-card>
</el-drawer> </el-drawer>
<el-dialog <el-dialog :close-on-click-modal="false" :visible.sync="addressDialogVisible" title="收货地址" width="40%">
:close-on-click-modal="false" <el-form :model="formData" label-position="right" :rules="formRules" label-suffix=":" label-width="120px" ref="addForm">
:visible.sync="addressDialogVisible"
title="收货地址"
width="30%">
<el-form :model="formData" label-position="right"
label-suffix=":" label-width="120px" ref="addForm">
<el-row :gutter="60"> <el-row :gutter="60">
<el-col :span="24"> <el-col :span="24">
<el-form-item :rules="{required:true,message: '请选择地址信息', trigger: 'blur'}" <el-form-item label="地址信息" prop="addressList">
label="地址信息"
prop="addressList">
<el-cascader <el-cascader
:options="dzOptions" :options="dzOptions"
:props="{ expandTrigger: 'hover' }" :props="{ expandTrigger: 'hover' }"
@@ -384,40 +360,44 @@ layout("/layouts/platform.html"){
clearable clearable
placeholder="请选择地址信息" placeholder="请选择地址信息"
style="width: 100%" style="width: 100%"
v-model="formData.addressList"></el-cascader> v-model="formData.addressList"
></el-cascader>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item <el-form-item label="详细地址" prop="addressDetail">
:rules="{required:true,message: '请填写您的详细地址', trigger: 'blur'}" <el-input
label="详细地址" maxlength="100"
prop="addressDetail">
<el-input maxlength="100"
placeholder="请输入详细地址信息,如道路、门牌号、小区、楼栋号、单元等信息" placeholder="请输入详细地址信息,如道路、门牌号、小区、楼栋号、单元等信息"
rows="3" rows="3"
show-word-limit show-word-limit
type="textarea" type="textarea"
v-model="formData.addressDetail"></el-input> v-model="formData.addressDetail"
></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item <el-form-item label="收货人姓名" prop="userName">
:rules="{required:true,message: '请填写收货人姓名', trigger: 'blur'}" <el-input maxlength="11" placeholder="请填写收货人姓名" v-model="formData.userName"></el-input>
label="收货人姓名"
prop="userName">
<el-input maxlength="11"
placeholder="请填写收货人姓名"
v-model="formData.userName"></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item <el-form-item label="手机号码" prop="tel">
:rules="{required:true,message: '请填写手机号码', trigger: 'blur'}" <el-input maxlength="11" placeholder="请填写手机号码" clearable v-model="formData.tel"></el-input>
label="手机号码" </el-form-item>
prop="tel"> </el-col>
<el-input maxlength="11" placeholder="请填写手机号码"
type="tel" <el-col :span="24">
v-model="formData.tel"></el-input> <el-form-item label="是否默认" prop="isDefault">
<el-switch
v-model="formData.isDefault"
active-color="#13ce66"
inactive-color="#ff4949"
active-value="1"
inactive-value="0"
active-text="是"
inactive-text="否"
></el-switch>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -428,11 +408,10 @@ layout("/layouts/platform.html"){
<el-button @click="doSaveUserAddress" type="primary">保存</el-button> <el-button @click="doSaveUserAddress" type="primary">保存</el-button>
</span> </span>
</el-dialog> </el-dialog>
</div> </div>
<script> <script>
const vue = new Vue({ const vue = new Vue({
el: '#app', el: "#app",
mixins: [initTableMixins], mixins: [initTableMixins],
data() { data() {
return { return {
@@ -450,56 +429,78 @@ layout("/layouts/platform.html"){
welfareSubject: {}, welfareSubject: {},
pageForm: { pageForm: {
isChoose: false, isChoose: false,
year: moment().format('YYYY') year: moment().format("YYYY")
}, },
tableColumns: [ tableColumns: [
{prop: 'year', label: '年度'}, { prop: "year", label: "年度" },
{prop: 'name', label: '项目名称'}, { prop: "name", label: "项目名称" },
{prop: 'choiceTime', label: '选择时间'}, { prop: "choiceTime", label: "选择时间" },
{prop: 'isChoose', label: '是否选择'}, { prop: "isChoose", label: "是否选择" },
{prop: 'gist_list', label: '所选福利'}, { prop: "gist_list", label: "所选福利" },
{prop: 'receiveAddress', label: '收货地址'}, { prop: "receiveAddress", label: "收货地址" }
], ],
isView: false, isView: false,
isChoice: false, isChoice: false,
addressDialogVisible: false, addressDialogVisible: false,
formRules: {
addressList: [{ required: true, message: "请选择地址信息", trigger: ["blur", "change"] }],
addressDetail: [{ required: true, message: "请填写您的详细地址", trigger: ["blur", "change"] }],
userName: [{ required: true, message: "请填写收货人姓名", trigger: ["blur", "change"] }],
tel: [
{ required: true, message: "必填", trigger: ["blur", "change"] },
{ pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号" }
]
},
// 供应商
shoppingType: [],
// 门店地址
offlineStoresOption: []
} }
}, },
computed: { computed: {
sumSelectNum() { sumSelectNum() {
if (this.projectInfo && this.projectInfo.welfareProjectSubjects) { if (this.projectInfo && this.projectInfo.welfareProjectSubjects) {
return this.projectInfo.welfareProjectSubjects[0].options.map(v => v.selectNum).reduce((accumulator, currentValue) => accumulator + currentValue, 0) return this.projectInfo.welfareProjectSubjects[0].options
.map((v) => v.selectNum)
.reduce((accumulator, currentValue) => accumulator + currentValue, 0)
} }
return 0 return 0
}, }
}, },
methods: { methods: {
onKeydown(event) {
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") {
event.preventDefault()
}
},
confirmButtonInfo(row) { confirmButtonInfo(row) {
const {choiceTimeEnd, choiceTimeStart, overdueChoiceTimeEnd, isChoose, selectTime} = row const { choiceTimeEnd, choiceTimeStart, overdueChoiceTimeEnd, isChoose, selectTime } = row
const now = moment().valueOf() const now = moment().valueOf()
if (overdueChoiceTimeEnd == null || overdueChoiceTimeEnd === '') { if (overdueChoiceTimeEnd == null || overdueChoiceTimeEnd === "") {
if (now > moment(choiceTimeStart).valueOf() && now < moment(choiceTimeEnd).valueOf()) { if (now > moment(choiceTimeStart).valueOf() && now < moment(choiceTimeEnd).valueOf()) {
return {text: isChoose ? '确定修改' : '确定选择', disabled: false} return { text: isChoose ? "修改" : "选择", disabled: false }
} else if (now > moment(choiceTimeEnd).valueOf()) { } else if (now > moment(choiceTimeEnd).valueOf()) {
return {text: '选择已结束', disabled: true} return { text: "选择已结束", disabled: true }
} else if (now < moment(choiceTimeStart).valueOf()) { } else if (now < moment(choiceTimeStart).valueOf()) {
return {text: '选择未开始', disabled: true} return { text: "选择未开始", disabled: true }
} }
} else { } else {
//已选择了不能再动了 //已选择了不能再动了
if (isChoose) { if (isChoose) {
if(moment(selectTime).valueOf() > moment(choiceTimeEnd).valueOf() && now < moment(overdueChoiceTimeEnd).valueOf()){ if (moment(selectTime).valueOf() > moment(choiceTimeEnd).valueOf() && now < moment(overdueChoiceTimeEnd).valueOf()) {
return {text: '确定修改', disabled: false} return { text: "修改", disabled: false }
} }
return {text: '选择已结束', disabled: true} return { text: "选择已结束", disabled: true }
} else { } else {
if (now > moment(choiceTimeStart).valueOf() && now < moment(overdueChoiceTimeEnd).valueOf()) { if (now > moment(choiceTimeStart).valueOf() && now < moment(overdueChoiceTimeEnd).valueOf()) {
return {text: isChoose ? '确定修改' : '确定选择', disabled: false} return { text: isChoose ? "修改" : "选择", disabled: false }
} else if (now > moment(overdueChoiceTimeEnd).valueOf()) { } else if (now > moment(overdueChoiceTimeEnd).valueOf()) {
return {text: '选择已结束', disabled: true} return { text: "选择已结束", disabled: true }
} else if (now < moment(choiceTimeStart).valueOf()) { } else if (now < moment(choiceTimeStart).valueOf()) {
return {text: '选择未开始', disabled: true} return { text: "选择未开始", disabled: true }
} }
} }
} }
@@ -509,12 +510,12 @@ layout("/layouts/platform.html"){
let provinceName = "" let provinceName = ""
let cityName = "" let cityName = ""
let countyName = "" let countyName = ""
const province = this.dzOptions.find(c => c.value === val[0]) const province = this.dzOptions.find((c) => c.value === val[0])
provinceName = province.label provinceName = province.label
const city = province.children.find(p => p.value === val[1]) const city = province.children.find((p) => p.value === val[1])
cityName = city.label cityName = city.label
if (val.length === 3) { if (val.length === 3) {
const county = city.children.find(p => p.value === val[2]) const county = city.children.find((p) => p.value === val[2])
countyName = county.label countyName = county.label
this.$set(this.formData, "areaCode", county.value) this.$set(this.formData, "areaCode", county.value)
} else { } else {
@@ -523,7 +524,6 @@ layout("/layouts/platform.html"){
this.$set(this.formData, "province", provinceName) this.$set(this.formData, "province", provinceName)
this.$set(this.formData, "city", cityName) this.$set(this.formData, "city", cityName)
this.$set(this.formData, "county", countyName) this.$set(this.formData, "county", countyName)
} }
}, },
openAddress() { openAddress() {
@@ -540,64 +540,56 @@ layout("/layouts/platform.html"){
this.doSearch() this.doSearch()
this.$message({ this.$message({
message: resp.msg, message: resp.msg,
type: 'success' type: "success"
}); })
await this.selectUserAddress() await this.selectUserAddress()
this.addressDialogVisible = false this.addressDialogVisible = false
} else { } else {
this.$message.error(resp.msg); this.$message.error(resp.msg)
} }
} }
}) })
}, },
//数量更改 //数量更改
numChange(value, option, optionIndex) { numChange(value, option, optionIndex) {
this.$nextTick(() => { this.$nextTick(() => {
// 查找+1按钮 // 查找+1按钮
const plusButton = document.querySelector('.el-input-number__increase'); const plusButton = document.querySelector(".el-input-number__increase")
// 添加点击事件监听器 // 添加点击事件监听器
plusButton.addEventListener('click', this.handlePlusButtonClick(value, option, optionIndex)); plusButton.addEventListener("click", this.handlePlusButtonClick(value, option, optionIndex))
}) })
}, },
handlePlusButtonClick(value, option, optionIndex) { handlePlusButtonClick(value, option, optionIndex) {
const { const { isCheckBox, multiSelectNum, singleOptionSupportMultipleSelection } = this.projectInfo
isCheckBox, if (isCheckBox === "checkBox") {
multiSelectNum,
singleOptionSupportMultipleSelection
} = this.projectInfo
if (isCheckBox === 'checkBox') {
//判断是否支持单个多选 //判断是否支持单个多选
if (!singleOptionSupportMultipleSelection && value > 1) { if (!singleOptionSupportMultipleSelection && value > 1) {
this.$set(this.projectInfo.welfareProjectSubjects[0].options[optionIndex], 'selectNum', 1) this.$set(this.projectInfo.welfareProjectSubjects[0].options[optionIndex], "selectNum", 1)
this.$message.warning('此套餐最多只能选择1份'); this.$message.warning("此套餐最多只能选择1份")
return; return
} }
} }
//获取用户当前选择的数量 //获取用户当前选择的数量
const selectNums = this.projectInfo.welfareProjectSubjects[0].options.map(v => v.selectNum) const selectNums = this.projectInfo.welfareProjectSubjects[0].options.map((v) => v.selectNum)
const sum = selectNums.reduce((accumulator, currentValue) => accumulator + currentValue, 0) const sum = selectNums.reduce((accumulator, currentValue) => accumulator + currentValue, 0)
if (sum > multiSelectNum) { if (sum > multiSelectNum) {
this.$set(this.projectInfo.welfareProjectSubjects[0].options[optionIndex], 'selectNum', value - 1) this.$set(this.projectInfo.welfareProjectSubjects[0].options[optionIndex], "selectNum", value - 1)
this.$message.warning('此次福利最多只能选择' + multiSelectNum + '份'); this.$message.warning("此次福利最多只能选择" + multiSelectNum + "份")
} }
}, },
async getProjectInfo(id) { async getProjectInfo(id) {
const resp = await $.get('/platform/welfare/common/findOne', {projectId: id}) const resp = await $.get("/platform/welfare/common/findOne", { projectId: id })
if (resp.code === 0) { if (resp.code === 0) {
resp.data.multiSelectNum = resp.data.multiSelectNum ? resp.data.multiSelectNum : 1 resp.data.multiSelectNum = resp.data.multiSelectNum ? resp.data.multiSelectNum : 1
this.projectInfo = resp.data this.projectInfo = resp.data
await this.getUserSelection(id) await this.getUserSelection(id)
await this.getChoice() await this.getChoice()
await this.getShoppingType()
} }
}, },
async openView(row) { async openView(row) {
this.isView = true this.isView = true
await this.getProjectInfo(row.id) await this.getProjectInfo(row.id)
@@ -611,7 +603,7 @@ layout("/layouts/platform.html"){
this.$refs.guava.edit() this.$refs.guava.edit()
}, },
addressChange(val) { addressChange(val) {
const address = this.addressOptions.find(a => a.id === val) const address = this.addressOptions.find((a) => a.id === val)
if (address) { if (address) {
this.$set(this.formData, "receiveAddress", address.name) this.$set(this.formData, "receiveAddress", address.name)
} }
@@ -619,54 +611,76 @@ layout("/layouts/platform.html"){
doChoose() { doChoose() {
this.$refs["addForm"].validate(async (valid) => { this.$refs["addForm"].validate(async (valid) => {
if (valid) { if (valid) {
const { const { isCheckBox, multiSelectNum, singleOptionSupportMultipleSelection } = this.projectInfo
isCheckBox,
multiSelectNum,
singleOptionSupportMultipleSelection
} = this.projectInfo
if (isCheckBox === "checkBox") { if (isCheckBox === "checkBox") {
if (this.sumSelectNum < multiSelectNum) { if (this.sumSelectNum < multiSelectNum) {
//用户没有选择完 //用户没有选择完
this.$message('一共可以选择' + multiSelectNum + '份,您目前只选择了' + this.sumSelectNum + '份,快去选择吧!') this.$message.warning("一共可以选择" + multiSelectNum + "份,您目前只选择了" + this.sumSelectNum + "份,快去选择吧!")
return
}
} else {
if (this.sumSelectNum === 0) {
//用户选择了多份
this.$message.warning("您还没有选择福利套餐,快去选择吧!")
return return
} }
} }
if (this.formData.receiveAddress == null || this.formData.receiveAddress === '') {
this.$message.warning('请填写收货地址') // 判断门店是否选择
const chooseOptions = this.projectInfo.welfareProjectSubjects[0].options
.filter((v) => v.selectNum > 0)
.map((item) => {
return { optionName: item.optionName, selectNum: item.selectNum, receiveAddress: item.receiveAddress }
})
let isReceiveAddress = true
for (const item of chooseOptions) {
if (!item.receiveAddress) {
this.$message.warning(item.optionName + "还没有选择收货门店哦")
isReceiveAddress = false
break
}
}
if (!isReceiveAddress) {
return return
} }
if (this.formData.sign == null || this.formData.sign === '') {
this.$message.warning('请签字') if (this.projectInfo.provideMode == 3) {
if (this.formData.receiveAddress == null || this.formData.receiveAddress === "") {
this.$message.warning("请填写收货地址")
return return
} }
const formData = this.projectInfo.welfareProjectSubjects[0].options.filter(v => v.selectNum >= 1).map(v => { }
if (![1, 4].includes(this.projectInfo.signMode)) {
if (this.formData.sign == null || this.formData.sign === "") {
this.$message.warning("请签字")
return
}
}
const formData = this.projectInfo.welfareProjectSubjects[0].options
.filter((v) => v.selectNum >= 1)
.map((v) => {
return { return {
welfareId: this.projectInfo.id, welfareId: this.projectInfo.id,
subjectId: v.subjectId, subjectId: v.subjectId,
selectOptionId: v.id, selectOptionId: v.id,
receiveAddress: this.formData.receiveAddress, receiveAddress: this.projectInfo.provideMode === 3 ? this.formData.receiveAddress : v.receiveAddress,
userSign: this.formData.sign, userSign: this.formData.sign,
selectNum: v.selectNum selectNum: v.selectNum
} }
}) })
const { console.log(formData)
code, const { code, msg, data } = await $.post("/platform/welfare/userChoose/confirmSelect", {
msg,
data
} = await $.post('/platform/welfare/userChoose/confirmSelect', {
welfareUserSelections: JSON.stringify(formData), welfareUserSelections: JSON.stringify(formData),
projectId: this.projectInfo.id projectId: this.projectInfo.id
}) })
if (code === 0) { if (code === 0) {
this.$message({ this.$message.success("您已完成本次福利选择。")
message: msg,
type: 'success'
});
} else { } else {
this.$message({ this.$message({
message: msg, message: msg,
type: 'warning' type: "warning"
}); })
} }
this.doSearch() this.doSearch()
this.$refs.guava.index() this.$refs.guava.index()
@@ -695,7 +709,7 @@ layout("/layouts/platform.html"){
this.$set(this.formData, "addressId", null) this.$set(this.formData, "addressId", null)
this.$set(this.formData, "sign", this.userSelection[0].userSign) this.$set(this.formData, "sign", this.userSelection[0].userSign)
} else { } else {
const address = this.addressOptions.find(a => a.isDefault) const address = this.addressOptions.find((a) => a.isDefault)
if (address) { if (address) {
this.$set(this.formData, "receiveAddress", address.name) this.$set(this.formData, "receiveAddress", address.name)
this.$set(this.formData, "addressId", address.id) this.$set(this.formData, "addressId", address.id)
@@ -705,58 +719,67 @@ layout("/layouts/platform.html"){
}, },
//获取用户选择的数据 //获取用户选择的数据
async getUserSelection(projectId) { async getUserSelection(projectId) {
const resp = await $.get('/platform/welfare/mine/getUserSelection', {projectId: projectId}) const resp = await $.get("/platform/welfare/mine/getUserSelection", { projectId: projectId })
this.userSelection = resp.data this.userSelection = resp.data
this.echoUserSelection() this.echoUserSelection()
}, },
//回显用户选择的数据 //回显用户选择的数据
echoUserSelection() { echoUserSelection() {
//获取用户当前选择的数量 //获取用户当前选择的数量
this.projectInfo.welfareProjectSubjects[0].options.forEach(v => { this.projectInfo.welfareProjectSubjects[0].options.forEach((v) => {
const option = this.userSelection.find(x => x.selectOptionId === v.id) const option = this.userSelection.find((x) => x.selectOptionId === v.id)
if (option) { if (option) {
v.selectNum = option.selectNum v.selectNum = option.selectNum
this.$set(v, "receiveAddress", option.receiveAddress)
} else { } else {
v.selectNum = 0 v.selectNum = 0
this.$set(v, "receiveAddress", "")
} }
}) })
}, },
async getChoice() { async getChoice() {
const resp = await $.get('/mobile/welfare/mine/isChoice', {projectId: this.projectInfo.id}) const resp = await $.get("/mobile/welfare/mine/isChoice", { projectId: this.projectInfo.id })
this.isChoice = resp.data this.isChoice = resp.data
}, },
async selectUserAddress() { async selectUserAddress() {
const resp = await $.get('/platform/welfare/addressManage/selectUserAddress') const resp = await $.get("/platform/welfare/addressManage/selectUserAddress")
resp.data.map(r => { resp.data.map((r) => {
let defaultName = r.isDefault ? "默认地址" : "" let defaultName = r.isDefault ? "默认地址" : ""
r.defaultName = defaultName r.defaultName = defaultName
r.name = "收货地址:" + r.province + r.city + r.county + r.addressDetail + ",收件人:" + r.userName + ",联系方式:" + r.tel r.name = "收货地址:" + r.province + r.city + r.county + r.addressDetail + ",收件人:" + r.userName + ",联系方式:" + r.tel
}) })
this.addressOptions = resp.data this.addressOptions = resp.data
this.$nextTick(() => {
const address = this.addressOptions.find((v) => v.isDefault)
if (address) {
this.$set(this.formData, "addressId", address.id)
this.$set(this.formData, "receiveAddress", address.name)
}
})
}, },
// 获取供应商
async getShoppingType() {
const { data } = await $.get("/platform/shoppingType/apply/getShoppingType")
this.projectInfo.welfareProjectSubjects[0].options.forEach((item) => {
item.receiveAddressList = data.find((v) => v.id === item.shoppingId).offlineStores
})
console.log(this.projectInfo.welfareProjectSubjects[0])
}
}, },
async created() { async created() {
this.pageData() this.pageData()
this.selectUserAddress() this.selectUserAddress()
getEnumOptions("WelfareProvideMode").then(res => { getEnumOptions("WelfareProvideMode").then((res) => {
this.welfareProvideMode = res this.welfareProvideMode = res
}) })
getEnumOptions("WelfareSignMode").then(res => { getEnumOptions("WelfareSignMode").then((res) => {
this.welfareSignMode = res this.welfareSignMode = res
}) })
/* if ("${@shiro.hasRole('sysadmin')}" === 'false') {
this.dzOptions = this.dzOptions.filter(d => d.label === "江苏省")
this.dzOptions[0].children = this.dzOptions[0].children.filter(d => d.label === "无锡市")
}*/
} }
}) })
</script> </script>
<!--# <!--#
} }
#--> #-->
@@ -93,8 +93,8 @@ layout("/layouts/platform.html"){
<el-table-column show-overflow-tooltip label="所在单位" prop="be_unitname" header-align="center" <el-table-column show-overflow-tooltip label="所在单位" prop="be_unitname" header-align="center"
sortable sortable
align="center"></el-table-column> align="center"></el-table-column>
<el-table-column show-overflow-tooltip label="联系方式" prop="mobile" header-align="center" <!-- <el-table-column show-overflow-tooltip label="联系方式" prop="mobile" header-align="center"-->
align="center"></el-table-column> <!-- align="center"></el-table-column>-->
<el-table-column label="慰问类型" prop="type_name" header-align="center" sortable <el-table-column label="慰问类型" prop="type_name" header-align="center" sortable
align="center"></el-table-column> align="center"></el-table-column>
<el-table-column label="慰问方式" prop="way" header-align="center" <el-table-column label="慰问方式" prop="way" header-align="center"
@@ -101,9 +101,9 @@ layout("/layouts/platform.html"){
header-align="center" header-align="center"
sortable sortable
align="center"></el-table-column> align="center"></el-table-column>
<el-table-column show-overflow-tooltip label="联系方式" prop="mobile" <!-- <el-table-column show-overflow-tooltip label="联系方式" prop="mobile"-->
header-align="center" <!-- header-align="center"-->
align="center"></el-table-column> <!-- align="center"></el-table-column>-->
<el-table-column label="慰问类型" prop="type_name" header-align="center" sortable <el-table-column label="慰问类型" prop="type_name" header-align="center" sortable
align="center"></el-table-column> align="center"></el-table-column>
<!-- <el-table-column label="慰问方式" prop="way" header-align="center" <!-- <el-table-column label="慰问方式" prop="way" header-align="center"