基于javaweb+mysql的ssm+maven仓库管理系统(java+ssm+jsp+mysql+maven)

基于javaweb+mysql的ssm+maven仓库管理系统(java+ssm+jsp+mysql+maven)

运行环境

Java≥8、MySQL≥5.7、Tomcat≥8

开发工具

eclipse/idea/myeclipse/sts等均可配置运行

适用

课程设计,大作业,毕业设计,项目练习,学习演示等

功能说明

基于javaweb+mysql的SSM+Maven仓库管理系统(java+ssm+jsp+mysql+maven)

一、项目简述

功能包括: 仓库管理,出入库管理,仓库人员管理,基本信息管理, 供应商信息,系统管理等等。

二、项目运行

环境配置: Jdk1.8 + Tomcat8.5 + mysql + Eclispe (IntelliJ IDEA,Eclispe,MyEclispe,Sts 都支持)

项目技术: JSP +Spring + SpringMVC + MyBatis + html+ css + JavaScript + JQuery + Ajax + layui+ maven等等。

            } else {
                repositoryID = repositoryIDBelong;
            }
        }

        if (authorizeCheck && argumentCheck) {
            if (stockRecordManageService.stockOutOperation(customerID, goodsID, repositoryID, number, personInCharge))
                result = Response.RESPONSE_RESULT_SUCCESS;
        }

        // 设置 Response
        responseContent.setResponseResult(result);
        return responseContent.generateResponse();
    }

    /**
     * 货物入库操作
     *
     * @param supplierID      供应商ID
     * @param goodsID         货物ID
     * @param repositoryIDStr 仓库ID
     * @param number          入库数目
     * @return 返回一个map,key为result的值表示操作是否成功
     */
    @RequestMapping(value = "stockIn", method = RequestMethod.POST)
    public
    @ResponseBody
    Map<String, Object> stockIn(@RequestParam("supplierID") Integer supplierID,
                                @RequestParam("goodsID") Integer goodsID,
                                @RequestParam(value = "repositoryID", required = false) String repositoryIDStr,
                                @RequestParam("number") long number) throws StockRecordManageServiceException {
        // 初始化 Response
        Response responseContent = ResponseFactory.newInstance();
        String result = Response.RESPONSE_RESULT_ERROR;
        boolean authorizeCheck = true;
        boolean argumentCheck = true;
        Integer repositoryID = null;

        // 参数检查
        if (repositoryIDStr != null && repositoryIDStr.trim().length()>0) {
            if (StringUtils.isNumeric(repositoryIDStr)) {
                repositoryID = Integer.valueOf(repositoryIDStr);
            } else {
                argumentCheck = false;
                responseContent.setResponseMsg("request argument error");
            }
        }
        if (StringUtils.isBlank(repositoryID) || !StringUtils.isNumeric(repositoryID))
            isAvailable = false;
        if (StringUtils.isBlank(number) || !StringUtils.isNumeric(number))
            isAvailable = false;

        if (isAvailable) {
            isSuccess = storageManageService.addNewStorage(Integer.valueOf(goodsID), Integer.valueOf(repositoryID),
                    Integer.valueOf(number)) ? Response.RESPONSE_RESULT_SUCCESS : Response.RESPONSE_RESULT_ERROR;
        }

        // 设置 Response
        responseContent.setResponseResult(isSuccess);
        return responseContent.generateResponse();
    }

    /**
     * 更新库存信息
     *
     * @return 返回一个map,其中:key 为 result表示操作的结果,包括:success 与 error
     */
    @RequestMapping(value = "updateStorageRecord", method = RequestMethod.POST)
    public
    @ResponseBody
    Map<String, Object> updateStorageRecord(@RequestBody Map<String, Object> params) throws StorageManageServiceException {
        // 初始化 Response
        Response responseContent = ResponseFactory.newInstance();
        boolean isAvailable = true;
        String result = Response.RESPONSE_RESULT_ERROR;

        String goodsID = (String) params.get("goodsID");
        String repositoryID = (String) params.get("repositoryID");
        String number = (String) params.get("number");

        if (StringUtils.isBlank(goodsID) || !StringUtils.isNumeric(goodsID))
            isAvailable = false;
        if (StringUtils.isBlank(repositoryID) || !StringUtils.isNumeric(repositoryID))
            isAvailable = false;
        if (StringUtils.isBlank(number) || !StringUtils.isNumeric(number))
            isAvailable = false;

        if (isAvailable) {
            result = storageManageService.updateStorage(Integer.valueOf(goodsID), Integer.valueOf(repositoryID),
    public
    @ResponseBody
    Map<String, Object> stockIn(@RequestParam("supplierID") Integer supplierID,
                                @RequestParam("goodsID") Integer goodsID,
                                @RequestParam(value = "repositoryID", required = false) String repositoryIDStr,
                                @RequestParam("number") long number) throws StockRecordManageServiceException {
        // 初始化 Response
        Response responseContent = ResponseFactory.newInstance();
        String result = Response.RESPONSE_RESULT_ERROR;
        boolean authorizeCheck = true;
        boolean argumentCheck = true;
        Integer repositoryID = null;

        // 参数检查
        if (repositoryIDStr != null && repositoryIDStr.trim().length()>0) {
            if (StringUtils.isNumeric(repositoryIDStr)) {
                repositoryID = Integer.valueOf(repositoryIDStr);
            } else {
                argumentCheck = false;
                responseContent.setResponseMsg("request argument error");
            }
        }

        // 获取session中的信息
        Subject currentUser = SecurityUtils.getSubject();
        Session session = currentUser.getSession();
        UserInfoDTO userInfo = (UserInfoDTO) session.getAttribute("userInfo");
        String personInCharge = userInfo == null ? "none" : userInfo.getUserName();
        Integer repositoryIDBelong = userInfo == null ? -1 : userInfo.getRepositoryBelong();

        // 设置非管理员请求的仓库ID
        if (!currentUser.hasRole("systemAdmin")) {
            if (repositoryIDBelong < 0) {
                authorizeCheck = false;
                responseContent.setResponseMsg("You are not authorized");
            } else {
                repositoryID = repositoryIDBelong;
            }
        }

        // 执行 Service
        // 设置 Response
        responseContent.setResponseResult(result);
        return responseContent.generateResponse();
    }

    /**
     * 删除指定 ID 的仓库信息
     *
     * @param repositoryID 仓库ID
     * @return 返回一个map,其中:key 为 result 的值为操作的结果,包括:success 与 error;key 为 data
     * 的值为仓库信息
     */
    @RequestMapping(value = "deleteRepository", method = RequestMethod.GET)
    public
    @ResponseBody
    Map<String, Object> deleteRepository(@RequestParam("repositoryID") Integer repositoryID) throws RepositoryManageServiceException {
        // 初始化 Response
        Response responseContent = ResponseFactory.newInstance();

        // 删除记录
        String result = repositoryService.deleteRepository(repositoryID) ? Response.RESPONSE_RESULT_SUCCESS : Response.RESPONSE_RESULT_ERROR;

        // 设置 Response
        responseContent.setResponseResult(result);
        return responseContent.generateResponse();
    }

    /**
     * 从文件中导入仓库信息
     *
     * @param file 保存有仓库信息的文件
     * @return 返回一个map,其中:key 为 result表示操作的结果,包括:success 与
     * error;key为total表示导入的总条数;key为available表示有效的条数
     */
    @RequestMapping(value = "importRepository", method = RequestMethod.POST)
    public
    @ResponseBody
    Map<String, Object> importRepository(MultipartFile file) throws RepositoryManageServiceException {
        // 初始化 Response
        Response responseContent = ResponseFactory.newInstance();
        String result = Response.RESPONSE_RESULT_ERROR;

        // 读取文件
        int total = 0;
        int available = 0;
        if (file != null) {
            Map<String, Object> importInfo = repositoryService.importRepository(file);
            if (importInfo != null) {
                total = (int) importInfo.get("total");
                available = (int) importInfo.get("available");
                result = Response.RESPONSE_RESULT_SUCCESS;
            }
        }
     * @throws Exception exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        // 如果用户还没有登陆则继续后续的流程
        Subject subject = getSubject(servletRequest, servletResponse);
        if (!subject.isAuthenticated() && !subject.isRemembered())
            return true;

        // 判断当前用户登陆数量是否超出
        Session session = subject.getSession();
        String userName = (String) subject.getPrincipal();
        Serializable sessionId = session.getId();

        // 初始化用户的登陆队列,将用户的队列放入到缓存中
        Deque<Serializable> deque = cache.get(userName);
        if (deque == null) {
            deque = new LinkedList<>();
            cache.put(userName, deque);
        }

        // 如果队列中没有此用户的 sessionId 且用户没有被踢出,则放入队列
        if (!deque.contains(sessionId) && session.getAttribute("kickOut") == null) {
            deque.push(sessionId);
        }

        // 若队列中的 sessionId 是否超出最大会话数目, 则踢出用户
        while (deque.size() > maxSessionNum) {
            Serializable kickOutSessionId;
            if (kickOutAfter) {
                kickOutSessionId = deque.removeFirst();
            } else {
                kickOutSessionId = deque.removeLast();
            }

            // 设置 sessionId 对应的 session 中的字段,表示该用户已经被踢出
            try {
                Session kickOutSession = sessionManager.getSession(new DefaultSessionKey(kickOutSessionId));
                if (kickOutSession != null) {
                    kickOutSession.setAttribute("kickOut", true);
                }
            } catch (Exception e) {
                // do logging
                e.printStackTrace();
            }
        }

        // 如果当前登陆用户被踢出,则退出并跳转
        if (session.getAttribute("kickOut") != null && Boolean.TRUE.equals(session.getAttribute("kickOut"))) {
            try {
                // 登出
                subject.logout();

                                                   @RequestParam("offset") int offset,
                                                   @RequestParam("limit") int limit) throws SystemLogServiceException {
        // 创建 Response
        Response response = ResponseFactory.newInstance();
        List<UserOperationRecordDTO> rows = null;
        long total = 0;

        // 检查参数
        String regex = "([0-9]{4})-([0-9]{2})-([0-9]{2})";
        boolean startDateFormatCheck = (StringUtils.isEmpty(startDateStr) || startDateStr.matches(regex));
        boolean endDateFormatCheck = (StringUtils.isEmpty(endDateStr) || endDateStr.matches(regex));
        boolean userIDCheck = (StringUtils.isEmpty(userIDStr) || StringUtils.isNumeric(userIDStr));

        if (startDateFormatCheck && endDateFormatCheck && userIDCheck) {
            // 转到 Service 进行查询
            Integer userID = -1;
            if (StringUtils.isNumeric(userIDStr))
                userID = Integer.valueOf(userIDStr);
            Map<String, Object> queryResult = systemLogService.selectUserOperationRecord(userID, startDateStr, endDateStr, offset, limit);
            if (queryResult != null) {
                rows = (List<UserOperationRecordDTO>) queryResult.get("data");
                total = (long) queryResult.get("total");
            }
        } else
            response.setResponseMsg("Request argument error");

        if (rows == null)
            rows = new ArrayList<>(0);

        response.setCustomerInfo("rows", rows);
        response.setResponseTotal(total);
        return response.generateResponse();
    }
}

                HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
                if (!"XMLHttpRequest".equalsIgnoreCase(httpServletRequest.getHeader("X-Requested-with"))) {
                    // 普通请求
                    WebUtils.issueRedirect(httpServletRequest, httpServletResponse, kickOutUrl);
                } else {
                    // ajax 请求
                    httpServletResponse.setStatus(430);
                }

            } catch (Exception e) {
                // do nothing
            }
            return false;
        }

        return true;
    }
}

/**
 * 扩展 FormAuthenticationFilter ,对部分方法重写,使其支持 Ajax 请求
 *
 */
public class ExtendFormAuthenticationFilter extends FormAuthenticationFilter {
    private static final Logger log = LoggerFactory.getLogger(FormAuthenticationFilter.class);

     * 删除一条库存信息
     *
     * @param goodsID      货物ID
     * @param repositoryID 仓库ID
     * @return 返回一个map,其中:key 为 result表示操作的结果,包括:success 与 error
     */
    @RequestMapping(value = "deleteStorageRecord", method = RequestMethod.GET)
    public
    @ResponseBody
    Map<String, Object> deleteStorageRecord(@RequestParam("goodsID") String goodsID,
                                            @RequestParam("repositoryID") String repositoryID) throws StorageManageServiceException {
        // 初始化 Response
        Response responseContent = ResponseFactory.newInstance();

        String result = Response.RESPONSE_RESULT_ERROR;
        boolean isAvailable = true;

        if (StringUtils.isBlank(goodsID) || !StringUtils.isNumeric(goodsID))
            isAvailable = false;
        if (StringUtils.isBlank(repositoryID) || !StringUtils.isNumeric(repositoryID))
            isAvailable = false;

        if (isAvailable) {
            result = storageManageService.deleteStorage(Integer.valueOf(goodsID), Integer.valueOf(repositoryID))
                    ? Response.RESPONSE_RESULT_SUCCESS : Response.RESPONSE_RESULT_ERROR;
        }

        // 设置 Response
        responseContent.setResponseResult(result);
        return responseContent.generateResponse();
    }

    /**
     * 导入库存信息
     *
     * @param file 保存有库存信息的文件
     * @return 返回一个map,其中:key 为 result表示操作的结果,包括:success 与
     * error;key为total表示导入的总条数;key为available表示有效的条数
     */
    @RequestMapping(value = "importStorageRecord", method = RequestMethod.POST)
    public
    @ResponseBody
    Map<String, Object> importStorageRecord(@RequestParam("file") MultipartFile file) throws StorageManageServiceException {
        // 初始化 Response
        Response responseContent = ResponseFactory.newInstance();
        String result = Response.RESPONSE_RESULT_ERROR;

        int total = 0;
        int available = 0;
        return responseContent.generateResponse();
    }

    /**
     * 导出仓库信息到文件中
     *
     * @param searchType 查询类型
     * @param keyWord    查询关键字
     * @param response   HttpServletResponse
     */
    @SuppressWarnings("unchecked")
    @RequestMapping(value = "exportRepository", method = RequestMethod.GET)
    public void exportRepository(@RequestParam("searchType") String searchType, @RequestParam("keyWord") String keyWord,
                                 HttpServletResponse response) throws RepositoryManageServiceException, IOException {

        // 导出文件名
        String fileName = "repositoryInfo.xlsx";

        // 查询
        List<Repository> repositories;

        Map<String, Object> queryResult = query(searchType, keyWord, -1, -1);

        if (queryResult != null)
            repositories = (List<Repository>) queryResult.get("data");
        else
            repositories = new ArrayList<>();

        // 生成文件
        File file = repositoryService.exportRepository(repositories);

        // 输出文件
        if (file != null) {
            // 设置响应头
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            FileInputStream inputStream = new FileInputStream(file);
            OutputStream outputStream = response.getOutputStream();
            byte[] buffer = new byte[8192];

            int len;
            while ((len = inputStream.read(buffer, 0, buffer.length)) > 0) {
                outputStream.write(buffer, 0, len);
                outputStream.flush();
            }

            inputStream.close();
            outputStream.close();
        }
    }
}

/**
 * 扩展 FormAuthenticationFilter ,对部分方法重写,使其支持 Ajax 请求
 *
 */
public class ExtendFormAuthenticationFilter extends FormAuthenticationFilter {
    private static final Logger log = LoggerFactory.getLogger(FormAuthenticationFilter.class);

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception{
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        if (!"XMLHttpRequest".equalsIgnoreCase(httpServletRequest.getHeader("X-Requested-with"))){
            // 请求为普通请求
            if(this.isLoginRequest(request, response)) {
                if(this.isLoginSubmission(request, response)) {
                    if(log.isTraceEnabled()) {
                        log.trace("Login submission detected.  Attempting to execute login.");
                    }

                    return this.executeLogin(request, response);
                } else {
                    if(log.isTraceEnabled()) {
                        log.trace("Login page view.");
                    }

                    return true;
                }
            } else {
                if(log.isTraceEnabled()) {
                    log.trace("Attempting to access a path which requires authentication.  Forwarding to the Authentication url [" + this.getLoginUrl() + "]");
                }

                this.saveRequestAndRedirectToLogin(request, response);
                return false;
            }
        }else{
            default:
                // do other thing
                break;
        }

        return queryResult;
    }

    /**
     * 可指定仓库对库存信息查询
     *
     * @param keyword          查询关键字
     * @param searchType       查询类型
     * @param repositoryBelong 查询所属的仓库
     * @param offset           分页偏移值
     * @param limit            分页大小
     * @return 结果的一个Map,其中: key为 rows 的代表记录数据;key 为 total 代表结果记录的数量
     */
    @SuppressWarnings("unchecked")
    @RequestMapping(value = "getStorageListWithRepository", method = RequestMethod.GET)
    public
    @ResponseBody
    Map<String, Object> getStorageListWithRepoID(@RequestParam("keyword") String keyword,
                                                 @RequestParam("searchType") String searchType, @RequestParam("repositoryBelong") String repositoryBelong,
                                                 @RequestParam("offset") int offset, @RequestParam("limit") int limit) throws StorageManageServiceException {
        // 初始化 Response
        Response responseContent = ResponseFactory.newInstance();

        List<Storage> rows;
        long total = 0;

        // query
        Map<String, Object> queryResult = query(searchType, keyword, repositoryBelong, offset, limit);
        if (queryResult != null) {
            rows = (List<Storage>) queryResult.get("data");
            total = (long) queryResult.get("total");
        } else
            rows = new ArrayList<>();

        // 设置 Response
        responseContent.setCustomerInfo("rows", rows);
        responseContent.setResponseTotal(total);
        return responseContent.generateResponse();
    }

    /**
     * 查询库存信息,查询所属的仓库为session保存的信息
     *
     * @param keyword    查询关键字
     * @param searchType 查询类型
     * @param offset     分页偏移值
     * @param limit      分页大小
     * @param request    请求

        }
    }
}

/**
 * 用户账户请求 Handler
 *
 * @since 017/2/26.
 */
                                    HttpServletRequest request, HttpServletResponse response) throws StorageManageServiceException, IOException {
        String fileName = "storageRecord.xlsx";

        HttpSession session = request.getSession();
        UserInfoDTO userInfo = (UserInfoDTO) session.getAttribute("userInfo");
        Integer sessionRepositoryBelong = userInfo.getRepositoryBelong();
        if (sessionRepositoryBelong > 0)
            repositoryBelong = sessionRepositoryBelong.toString();

        List<Storage> storageList = null;
        Map<String, Object> queryResult = query(searchType, keyword, repositoryBelong, -1, -1);
        if (queryResult != null)
            storageList = (List<Storage>) queryResult.get("data");

        File file = storageManageService.exportStorage(storageList);
        if (file != null) {
            // 设置响应头
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            FileInputStream inputStream = new FileInputStream(file);
            OutputStream outputStream = response.getOutputStream();
            byte[] buffer = new byte[8192];

            int len;
            while ((len = inputStream.read(buffer, 0, buffer.length)) > 0) {
                outputStream.write(buffer, 0, len);
                outputStream.flush();
            }

            inputStream.close();
            outputStream.close();

        }
    }
}

}

/**
 * 处理文件下载请求
 *
 */
@Controller
@RequestMapping("/commons/fileSource")
public class FileSourceHandler {

    @RequestMapping(value = "download/{fileName:.+}", method = RequestMethod.GET)
    public void fileDownload(@PathVariable("fileName") String fileName, HttpServletRequest request,
                             HttpServletResponse response) throws IOException {

        if (fileName == null)
            return;

        // 获取文件
        ServletContext context = request.getServletContext();
        String directory = context.getRealPath("/WEB-INF/download");
        Path file = Paths.get(directory, fileName);
        if (Files.exists(file)) {
            // 设置响应头
            response.addHeader("Content-Disposition", "attachment;filename=" + file.getFileName());
            Files.copy(file, response.getOutputStream());
            response.getOutputStream().flush();
        }
    }
}

/**
 * 全局异常处理器
    }

    /**
     * 导出客户信息
     *
     * @param searchType 查找类型
     * @param keyWord    查找关键字
     * @param response   HttpServletResponse
     */
    @SuppressWarnings("unchecked")
    @RequestMapping(value = "exportCustomer", method = RequestMethod.GET)
    public void exportCustomer(@RequestParam("searchType") String searchType, @RequestParam("keyWord") String keyWord,
                               HttpServletResponse response) throws CustomerManageServiceException, IOException {

        String fileName = "customerInfo.xlsx";

        List<Customer> customers = null;
        Map<String, Object> queryResult = query(searchType, keyWord, -1, -1);

        if (queryResult != null) {
            customers = (List<Customer>) queryResult.get("data");
        }

        // 获取生成的文件
        File file = customerManageService.exportCustomer(customers);

        // 写出文件
        if (file != null) {
            // 设置响应头
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            FileInputStream inputStream = new FileInputStream(file);
            OutputStream outputStream = response.getOutputStream();
            byte[] buffer = new byte[8192];

            int len;
            while ((len = inputStream.read(buffer, 0, buffer.length)) > 0) {
                outputStream.write(buffer, 0, len);
                outputStream.flush();
            }

            inputStream.close();
            outputStream.close();

        }
    }
}
                }
            }
        } else {
            errorMsg = "already login";
        }

        // 设置 Response
        response.setResponseResult(result);
        response.setResponseMsg(errorMsg);
        return response.generateResponse();
    }

    /**
     * 注销账户
     *
     * @return 返回一个 Map 对象,键值为 result 的内容代表注销操作的结果,值为 success 或 error
     */
    @RequestMapping(value = "logout", method = RequestMethod.GET)
    public
    @ResponseBody
    Map<String, Object> logout() {
        // 初始化 Response
        Response response = ResponseFactory.newInstance();

        Subject currentSubject = SecurityUtils.getSubject();
        if (currentSubject != null && currentSubject.isAuthenticated()) {
            // 执行账户注销操作
            currentSubject.logout();
            response.setResponseResult(Response.RESPONSE_RESULT_SUCCESS);
        } else {
            response.setResponseResult(Response.RESPONSE_RESULT_ERROR);
            response.setResponseMsg("did not login");
        }

        return response.generateResponse();
    }

    /**
     * 修改账户密码
     *
     * @param passwordInfo 密码信息
     * @param request      请求
     * @return 返回一个 Map 对象,其中键值为 result 代表修改密码操作的结果,
     * 值为 success 或 error;键值为 msg 代表需要返回给用户的信息
     */
    @RequestMapping(value = "passwordModify", method = RequestMethod.POST)
    public
    @ResponseBody
    Map<String, Object> passwordModify(@RequestBody Map<String, Object> passwordInfo,

/**
 * 用户账户请求 Handler
 *
 * @since 017/2/26.
 */
@Controller
@RequestMapping("/account")
public class AccountHandler {

    private static Logger log = Logger.getLogger("application");

    @Autowired
    private AccountService accountService;
    @Autowired
    private SystemLogService systemLogService;
    @Autowired
    private RepositoryAdminManageService repositoryAdminManageService;

    private static final String USER_ID = "id";
    private static final String USER_NAME = "userName";
    private static final String USER_PASSWORD = "password";

    /**
     * 登陆账户
     *
     * @param user 账户信息
     * @return 返回一个 Map 对象,其中包含登陆操作的结果
     */
    @RequestMapping(value = "login", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> login(@RequestBody Map<String, Object> user) {
        // 初始化 Response
        Response response = ResponseFactory.newInstance();
        String result = Response.RESPONSE_RESULT_ERROR;
        String errorMsg = "";

        // 获取当前的用户的 Subject
        Subject currentUser = SecurityUtils.getSubject();

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值