Browse Source

支付配置新增

zhangchen 1 month ago
parent
commit
1acee62c3e

+ 100 - 0
alien-entity/src/main/java/shop/alien/entity/store/StorePaymentConfig.java

@@ -0,0 +1,100 @@
+package shop.alien.entity.store;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * 支付配置表(支付宝等)
+ *
+ * @author system
+ */
+@Data
+@JsonInclude
+@TableName("store_payment_config")
+@ApiModel(value = "StorePaymentConfig对象", description = "支付配置表")
+public class StorePaymentConfig {
+
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "店铺ID")
+    @TableField("store_id")
+    private Integer storeId;
+
+    @ApiModelProperty(value = "应用ID")
+    @TableField("app_id")
+    private String appId;
+
+    @ApiModelProperty(value = "应用私钥")
+    @TableField("app_secret_cert")
+    private String appSecretCert;
+
+    @ApiModelProperty(value = "应用公钥证书文件(存储文件内容)")
+    @TableField("app_public_cert")
+    private String appPublicCert;
+
+    @ApiModelProperty(value = "应用公钥证书路径")
+    @TableField("app_public_cert_path")
+    private String appPublicCertPath;
+
+    @ApiModelProperty(value = "应用公钥证书文件名称")
+    @TableField("app_public_cert_name")
+    private String appPublicCertName;
+
+    @ApiModelProperty(value = "支付宝公钥证书文件(存储文件内容)")
+    @TableField("alipay_public_cert")
+    private String alipayPublicCert;
+
+    @ApiModelProperty(value = "支付宝公钥证书路径")
+    @TableField("alipay_public_cert_path")
+    private String alipayPublicCertPath;
+
+    @ApiModelProperty(value = "支付宝公钥证书文件名称")
+    @TableField("alipay_public_cert_name")
+    private String alipayPublicCertName;
+
+    @ApiModelProperty(value = "支付宝根证书文件(存储文件内容)")
+    @TableField("alipay_root_cert")
+    private String alipayRootCert;
+
+    @ApiModelProperty(value = "支付宝根证书路径")
+    @TableField("alipay_root_cert_path")
+    private String alipayRootCertPath;
+
+    @ApiModelProperty(value = "支付宝根证书文件名称")
+    @TableField("alipay_root_cert_name")
+    private String alipayRootCertName;
+
+    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
+    @TableField("delete_flag")
+    @TableLogic
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "创建人ID")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+
+    @ApiModelProperty(value = "修改时间")
+    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "修改人ID")
+    @TableField("updated_user_id")
+    private Integer updatedUserId;
+}

+ 15 - 0
alien-entity/src/main/java/shop/alien/mapper/StorePaymentConfigMapper.java

@@ -0,0 +1,15 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import shop.alien.entity.store.StorePaymentConfig;
+
+/**
+ * 支付配置表 Mapper 接口
+ *
+ * @author system
+ */
+@Mapper
+public interface StorePaymentConfigMapper extends BaseMapper<StorePaymentConfig> {
+
+}

+ 373 - 0
alien-store/src/main/java/shop/alien/store/controller/StorePaymentConfigController.java

@@ -0,0 +1,373 @@
+package shop.alien.store.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.annotations.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.StorePaymentConfig;
+import shop.alien.store.service.StorePaymentConfigService;
+import shop.alien.util.common.JwtUtil;
+
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 支付配置 前端控制器
+ *
+ * @author system
+ */
+@Slf4j
+@Api(tags = {"支付配置"})
+@ApiSort(18)
+@CrossOrigin
+@RestController
+@RequestMapping("/store/payment/config")
+@RequiredArgsConstructor
+public class StorePaymentConfigController {
+
+    private final StorePaymentConfigService storePaymentConfigService;
+
+    @ApiOperationSupport(order = 1)
+    @ApiOperation("新增支付配置(JSON  body)")
+    @PostMapping("/add")
+    public R<Boolean> add(@RequestBody StorePaymentConfig config) {
+        log.info("StorePaymentConfigController.add?config.storeId={}, appId={}", config.getStoreId(), config.getAppId());
+        if (config.getStoreId() == null) {
+            return R.fail("店铺ID不能为空");
+        }
+        if (config.getAppId() == null || config.getAppId().trim().isEmpty()) {
+            return R.fail("应用ID不能为空");
+        }
+        try {
+            fillCreatedUser(config);
+            boolean ok = storePaymentConfigService.save(config);
+            return ok ? R.success("新增成功") : R.fail("新增失败");
+        } catch (Exception e) {
+            log.error("新增支付配置失败", e);
+            return R.fail("新增失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperationSupport(order = 2)
+    @ApiOperation("修改支付配置(JSON body)")
+    @PostMapping("/update")
+    public R<Boolean> update(@RequestBody StorePaymentConfig config) {
+        log.info("StorePaymentConfigController.update?id={}", config.getId());
+        if (config.getId() == null) {
+            return R.fail("配置ID不能为空");
+        }
+        try {
+            fillUpdatedUser(config);
+            boolean ok = storePaymentConfigService.updateById(config);
+            return ok ? R.success("修改成功") : R.fail("修改失败");
+        } catch (Exception e) {
+            log.error("修改支付配置失败", e);
+            return R.fail("修改失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperationSupport(order = 2)
+    @ApiOperation(value = "新增支付配置(带三个证书文件,证书内容直接存入表 store_payment_config)", notes = "multipart:storeId、appId 必填;appSecretCert、*CertPath 选填;三个文件:appPublicCert、alipayPublicCert、alipayRootCert(.crt/.pem/.cer)")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "storeId", value = "店铺ID", dataType = "int", paramType = "form", required = true),
+            @ApiImplicitParam(name = "appId", value = "应用ID", dataType = "string", paramType = "form", required = true),
+            @ApiImplicitParam(name = "appSecretCert", value = "应用私钥", dataType = "string", paramType = "form"),
+            @ApiImplicitParam(name = "appPublicCert", value = "应用公钥证书文件", dataType = "file", paramType = "form"),
+            @ApiImplicitParam(name = "alipayPublicCert", value = "支付宝公钥证书文件", dataType = "file", paramType = "form"),
+            @ApiImplicitParam(name = "alipayRootCert", value = "支付宝根证书文件", dataType = "file", paramType = "form")
+    })
+    @PostMapping("/addWithCerts")
+    public R<Boolean> addWithCerts(
+            @RequestParam Integer storeId,
+            @RequestParam String appId,
+            @RequestParam(required = false) String appSecretCert,
+            @RequestParam(required = false) String appPublicCertPath,
+            @RequestParam(required = false) String alipayPublicCertPath,
+            @RequestParam(required = false) String alipayRootCertPath,
+            @RequestParam(value = "appPublicCert", required = false) MultipartFile appPublicCertFile,
+            @RequestParam(value = "alipayPublicCert", required = false) MultipartFile alipayPublicCertFile,
+            @RequestParam(value = "alipayRootCert", required = false) MultipartFile alipayRootCertFile) {
+        log.info("StorePaymentConfigController.addWithCerts storeId={}, appId={}", storeId, appId);
+        if (storeId == null) {
+            return R.fail("店铺ID不能为空");
+        }
+        if (appId == null || appId.trim().isEmpty()) {
+            return R.fail("应用ID不能为空");
+        }
+        try {
+            StorePaymentConfig config = new StorePaymentConfig();
+            config.setStoreId(storeId);
+            config.setAppId(appId.trim());
+            config.setAppSecretCert(appSecretCert);
+            config.setAppPublicCertPath(appPublicCertPath);
+            config.setAlipayPublicCertPath(alipayPublicCertPath);
+            config.setAlipayRootCertPath(alipayRootCertPath);
+            fillCertContent(config, appPublicCertFile, alipayPublicCertFile, alipayRootCertFile);
+            fillCreatedUser(config);
+            boolean ok = storePaymentConfigService.save(config);
+            return ok ? R.success("新增成功") : R.fail("新增失败");
+        } catch (Exception e) {
+            log.error("新增支付配置(带证书)失败", e);
+            return R.fail("新增失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperationSupport(order = 3)
+    @ApiOperation(value = "为已有配置上传/覆盖三个证书文件(内容存入表)", notes = "multipart:id 必填;三个文件:appPublicCert、alipayPublicCert、alipayRootCert,传哪个更新哪个")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "配置ID", dataType = "int", paramType = "form", required = true),
+            @ApiImplicitParam(name = "appPublicCert", value = "应用公钥证书文件", dataType = "file", paramType = "form"),
+            @ApiImplicitParam(name = "alipayPublicCert", value = "支付宝公钥证书文件", dataType = "file", paramType = "form"),
+            @ApiImplicitParam(name = "alipayRootCert", value = "支付宝根证书文件", dataType = "file", paramType = "form")
+    })
+    @PostMapping("/uploadCerts")
+    public R<Boolean> uploadCerts(
+            @RequestParam Integer id,
+            @RequestParam(value = "appPublicCert", required = false) MultipartFile appPublicCertFile,
+            @RequestParam(value = "alipayPublicCert", required = false) MultipartFile alipayPublicCertFile,
+            @RequestParam(value = "alipayRootCert", required = false) MultipartFile alipayRootCertFile) {
+        log.info("StorePaymentConfigController.uploadCerts id={}", id);
+        if (id == null) {
+            return R.fail("配置ID不能为空");
+        }
+        StorePaymentConfig existing = storePaymentConfigService.getById(id);
+        if (existing == null) {
+            return R.fail("配置不存在");
+        }
+        try {
+            fillCertContent(existing, appPublicCertFile, alipayPublicCertFile, alipayRootCertFile);
+            fillUpdatedUser(existing);
+            boolean ok = storePaymentConfigService.updateById(existing);
+            return ok ? R.success("证书已更新") : R.fail("更新失败");
+        } catch (Exception e) {
+            log.error("上传证书失败", e);
+            return R.fail("上传失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperationSupport(order = 3)
+    @ApiOperation(value = "将三个证书文件写入指定路径", notes = "从表读出证书内容,写入 targetPath 目录;文件名优先使用表中的 *_cert_name,未设置则用默认 app_public.crt、alipay_public.crt、alipay_root.crt。")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "配置ID", dataType = "int", paramType = "query", required = true),
+            @ApiImplicitParam(name = "targetPath", value = "目标目录(绝对路径或相对路径),如 D:/certs/export 或 /opt/certs", dataType = "string", paramType = "query", required = true)
+    })
+    @GetMapping("/downloadCerts")
+    public R<List<String>> downloadCerts(@RequestParam Integer id, @RequestParam String targetPath) {
+        log.info("StorePaymentConfigController.downloadCerts id={}, targetPath={}", id, targetPath);
+        if (id == null) {
+            return R.fail("配置ID不能为空");
+        }
+        if (targetPath == null || targetPath.trim().isEmpty()) {
+            return R.fail("目标路径不能为空");
+        }
+        if (targetPath.contains("..")) {
+            return R.fail("目标路径不允许包含 ..");
+        }
+        StorePaymentConfig config = storePaymentConfigService.getById(id);
+        if (config == null) {
+            return R.fail("配置不存在");
+        }
+        try {
+            List<String> writtenPaths = writeCertsToPath(config, targetPath.trim());
+            if (writtenPaths.isEmpty()) {
+                return R.fail("该配置下暂无证书内容可写入");
+            }
+            return R.data(writtenPaths);
+        } catch (Exception e) {
+            log.error("写入证书文件失败", e);
+            return R.fail("写入失败:" + e.getMessage());
+        }
+    }
+
+    /** 将表中三个证书内容写入指定目录,优先使用表存的文件名;UTF-8,返回已写入文件的绝对路径列表 */
+    private List<String> writeCertsToPath(StorePaymentConfig config, String targetPath) throws Exception {
+        Path dir = Paths.get(targetPath);
+        Files.createDirectories(dir);
+        List<String> written = new ArrayList<>();
+        if (config.getAppPublicCert() != null && !config.getAppPublicCert().isEmpty()) {
+            String name = safeCertFileName(config.getAppPublicCertName(), "app_public.crt");
+            Path file = dir.resolve(name);
+            Files.write(file, config.getAppPublicCert().getBytes(StandardCharsets.UTF_8));
+            written.add(file.toAbsolutePath().toString());
+        }
+        if (config.getAlipayPublicCert() != null && !config.getAlipayPublicCert().isEmpty()) {
+            String name = safeCertFileName(config.getAlipayPublicCertName(), "alipay_public.crt");
+            Path file = dir.resolve(name);
+            Files.write(file, config.getAlipayPublicCert().getBytes(StandardCharsets.UTF_8));
+            written.add(file.toAbsolutePath().toString());
+        }
+        if (config.getAlipayRootCert() != null && !config.getAlipayRootCert().isEmpty()) {
+            String name = safeCertFileName(config.getAlipayRootCertName(), "alipay_root.crt");
+            Path file = dir.resolve(name);
+            Files.write(file, config.getAlipayRootCert().getBytes(StandardCharsets.UTF_8));
+            written.add(file.toAbsolutePath().toString());
+        }
+        return written;
+    }
+
+    /** 使用表存的文件名(仅取最后一段且不含路径),非法则用默认名 */
+    private String safeCertFileName(String storedName, String defaultName) {
+        if (storedName == null || storedName.trim().isEmpty()) {
+            return defaultName;
+        }
+        String name = storedName.trim();
+        int last = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\'));
+        if (last >= 0 && last < name.length() - 1) {
+            name = name.substring(last + 1);
+        }
+        if (name.isEmpty() || name.contains("..")) {
+            return defaultName;
+        }
+        return name;
+    }
+
+    /** 将三个证书文件内容及文件名读入实体(存入表) */
+    private void fillCertContent(StorePaymentConfig config,
+                                 MultipartFile appPublicCertFile,
+                                 MultipartFile alipayPublicCertFile,
+                                 MultipartFile alipayRootCertFile) throws Exception {
+        if (appPublicCertFile != null && !appPublicCertFile.isEmpty()) {
+            config.setAppPublicCert(new String(appPublicCertFile.getBytes(), StandardCharsets.UTF_8));
+            String fn = appPublicCertFile.getOriginalFilename();
+            if (fn != null && !fn.trim().isEmpty()) {
+                config.setAppPublicCertName(fn.trim());
+            }
+        }
+        if (alipayPublicCertFile != null && !alipayPublicCertFile.isEmpty()) {
+            config.setAlipayPublicCert(new String(alipayPublicCertFile.getBytes(), StandardCharsets.UTF_8));
+            String fn = alipayPublicCertFile.getOriginalFilename();
+            if (fn != null && !fn.trim().isEmpty()) {
+                config.setAlipayPublicCertName(fn.trim());
+            }
+        }
+        if (alipayRootCertFile != null && !alipayRootCertFile.isEmpty()) {
+            config.setAlipayRootCert(new String(alipayRootCertFile.getBytes(), StandardCharsets.UTF_8));
+            String fn = alipayRootCertFile.getOriginalFilename();
+            if (fn != null && !fn.trim().isEmpty()) {
+                config.setAlipayRootCertName(fn.trim());
+            }
+        }
+    }
+
+    @ApiOperationSupport(order = 4)
+    @ApiOperation("删除支付配置")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "配置ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @PostMapping("/delete")
+    public R<Boolean> delete(@RequestParam Integer id) {
+        log.info("StorePaymentConfigController.delete?id={}", id);
+        if (id == null) {
+            return R.fail("配置ID不能为空");
+        }
+        try {
+            boolean ok = storePaymentConfigService.removeById(id);
+            return ok ? R.success("删除成功") : R.fail("删除失败");
+        } catch (Exception e) {
+            log.error("删除支付配置失败", e);
+            return R.fail("删除失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperationSupport(order = 5)
+    @ApiOperation("根据ID查询支付配置详情")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "配置ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/detail")
+    public R<StorePaymentConfig> detail(@RequestParam Integer id) {
+        log.info("StorePaymentConfigController.detail?id={}", id);
+        if (id == null) {
+            return R.fail("配置ID不能为空");
+        }
+        try {
+            StorePaymentConfig config = storePaymentConfigService.getById(id);
+            if (config == null) {
+                return R.fail("配置不存在");
+            }
+            return R.data(config);
+        } catch (Exception e) {
+            log.error("查询支付配置详情失败", e);
+            return R.fail("查询失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperationSupport(order = 6)
+    @ApiOperation("根据店铺ID查询支付配置")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "storeId", value = "店铺ID", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/getByStoreId")
+    public R<StorePaymentConfig> getByStoreId(@RequestParam Integer storeId) {
+        log.info("StorePaymentConfigController.getByStoreId?storeId={}", storeId);
+        if (storeId == null) {
+            return R.fail("店铺ID不能为空");
+        }
+        try {
+            StorePaymentConfig config = storePaymentConfigService.getByStoreId(storeId);
+            if (config == null) {
+                return R.fail("该店铺暂无支付配置");
+            }
+            return R.data(config);
+        } catch (Exception e) {
+            log.error("根据店铺ID查询支付配置失败", e);
+            return R.fail("查询失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperationSupport(order = 7)
+    @ApiOperation("分页查询支付配置列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "page", value = "页码", dataType = "Integer", paramType = "query", defaultValue = "1"),
+            @ApiImplicitParam(name = "size", value = "每页条数", dataType = "Integer", paramType = "query", defaultValue = "10"),
+            @ApiImplicitParam(name = "storeId", value = "店铺ID", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "appId", value = "应用ID(模糊)", dataType = "String", paramType = "query")
+    })
+    @GetMapping("/page")
+    public R<IPage<StorePaymentConfig>> page(
+            @RequestParam(defaultValue = "1") Integer page,
+            @RequestParam(defaultValue = "10") Integer size,
+            @RequestParam(required = false) Integer storeId,
+            @RequestParam(required = false) String appId) {
+        log.info("StorePaymentConfigController.page?page={}, size={}, storeId={}, appId={}", page, size, storeId, appId);
+        try {
+            Page<StorePaymentConfig> pageParam = new Page<>(page, size);
+            IPage<StorePaymentConfig> result = storePaymentConfigService.pageList(pageParam, storeId, appId);
+            return R.data(result);
+        } catch (Exception e) {
+            log.error("分页查询支付配置失败", e);
+            return R.fail("查询失败:" + e.getMessage());
+        }
+    }
+
+    private void fillCreatedUser(StorePaymentConfig config) {
+        try {
+            JSONObject userInfo = JwtUtil.getCurrentUserInfo();
+            if (userInfo != null) {
+                config.setCreatedUserId(userInfo.getInteger("userId"));
+            }
+        } catch (Exception e) {
+            log.warn("获取当前用户失败: {}", e.getMessage());
+        }
+    }
+
+    private void fillUpdatedUser(StorePaymentConfig config) {
+        try {
+            JSONObject userInfo = JwtUtil.getCurrentUserInfo();
+            if (userInfo != null) {
+                config.setUpdatedUserId(userInfo.getInteger("userId"));
+            }
+        } catch (Exception e) {
+            log.warn("获取当前用户失败: {}", e.getMessage());
+        }
+    }
+}

+ 32 - 0
alien-store/src/main/java/shop/alien/store/service/StorePaymentConfigService.java

@@ -0,0 +1,32 @@
+package shop.alien.store.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.store.StorePaymentConfig;
+
+/**
+ * 支付配置表 服务类
+ *
+ * @author system
+ */
+public interface StorePaymentConfigService extends IService<StorePaymentConfig> {
+
+    /**
+     * 根据店铺ID查询支付配置
+     *
+     * @param storeId 店铺ID
+     * @return 支付配置,不存在返回 null
+     */
+    StorePaymentConfig getByStoreId(Integer storeId);
+
+    /**
+     * 分页查询支付配置列表
+     *
+     * @param page   分页参数
+     * @param storeId 店铺ID(可选)
+     * @param appId  应用ID(可选,模糊)
+     * @return 分页结果
+     */
+    IPage<StorePaymentConfig> pageList(Page<StorePaymentConfig> page, Integer storeId, String appId);
+}

+ 49 - 0
alien-store/src/main/java/shop/alien/store/service/impl/StorePaymentConfigServiceImpl.java

@@ -0,0 +1,49 @@
+package shop.alien.store.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
+import shop.alien.entity.store.StorePaymentConfig;
+import shop.alien.mapper.StorePaymentConfigMapper;
+import shop.alien.store.service.StorePaymentConfigService;
+
+/**
+ * 支付配置表 服务实现类
+ *
+ * @author system
+ */
+@Slf4j
+@Service
+@Transactional(rollbackFor = Exception.class)
+@RequiredArgsConstructor
+public class StorePaymentConfigServiceImpl extends ServiceImpl<StorePaymentConfigMapper, StorePaymentConfig> implements StorePaymentConfigService {
+
+    @Override
+    public StorePaymentConfig getByStoreId(Integer storeId) {
+        if (storeId == null) {
+            return null;
+        }
+        LambdaQueryWrapper<StorePaymentConfig> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StorePaymentConfig::getStoreId, storeId);
+        return this.getOne(wrapper);
+    }
+
+    @Override
+    public IPage<StorePaymentConfig> pageList(Page<StorePaymentConfig> page, Integer storeId, String appId) {
+        LambdaQueryWrapper<StorePaymentConfig> wrapper = new LambdaQueryWrapper<>();
+        if (storeId != null) {
+            wrapper.eq(StorePaymentConfig::getStoreId, storeId);
+        }
+        if (StringUtils.hasText(appId)) {
+            wrapper.like(StorePaymentConfig::getAppId, appId);
+        }
+        wrapper.orderByDesc(StorePaymentConfig::getUpdatedTime);
+        return this.page(page, wrapper);
+    }
+}