早些年间学Erupt

Erupt部署

创建一个SpringBoot项目(此处为2.7.10)

目录结构

demo -- 项目名称
├── src
     └── main
     			├── java -- 代码文件目录
                └── com.example.demo -- 包名
											└── DemoApplication -- 入口类
				  └── resources -- 资源文件目录
								└── application.properties -- 配置文件
├── ......
└── pom.xml -- Maven依赖配置

创建数据库

数据库随便创一个本项目创建了一个名为erupt的数据库

导入依赖

<!--后端权限逻辑-->
<dependency>
  <groupId>xyz.erupt</groupId>
  <artifactId>erupt-admin</artifactId>
  <version>1.12.0</version>
</dependency>
<!--后台WEB界面-->
<dependency>
  <groupId>xyz.erupt</groupId>
  <artifactId>erupt-web</artifactId>
  <version>1.12.0</version>
</dependency>

这里需要注意,他的官方文档说是要去看一下版本号

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里有一个坑就是你去到官网提供的应该导入的是1.11.7

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

但是多次Maven导不进去说是不存在资源,于是去Erupt-Admin的Maven仓库发现这个支持只有1.12.0所以本项目需要导入的是1.12.0

配置application.yaml文件

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/erupt?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
  jpa:
    show-sql: true
    generate-ddl: true
    database: mysql

依赖

依赖需要包含web ,mysql driver 和官网提到的那两个依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.10</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>erupt-study</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>erupt-study</name>
    <description>erupt-study</description>
    <properties>
        <java.version>1.8</java.version>
        <erupt.version>1.11.7</erupt.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>

        <!--后端权限逻辑-->
        <dependency>
            <groupId>xyz.erupt</groupId>
            <artifactId>erupt-admin</artifactId>
            <version>1.12.0</version>
        </dependency>
        <!--后台WEB界面-->
        <dependency>
            <groupId>xyz.erupt</groupId>
            <artifactId>erupt-web</artifactId>
            <version>1.12.0</version>
        </dependency>



    </dependencies>


</project>

给启动类注入标签

@EntityScan@EruptScan

package com.example.eruptstudy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import xyz.erupt.core.annotation.EruptScan;

@SpringBootApplication
@EntityScan
@EruptScan
public class EruptStudyApplication {

    public static void main(String[] args) {
        SpringApplication.run(EruptStudyApplication.class, args);
    }
}

启动服务

直接运行启动类,会看到一堆Hibernate的东西,不得不说还是老架构NB

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

访问服务页面

由于没有配置serve.port所以默认8080

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

进入8080端口

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

默认账号密码均为erupt

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

进入到管理页面

入门示例

我们需要创建一个model的文件夹存放我们需要添加进来的页面类

这里用创建的一个user表来做测试

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建页面类

package com.example.eruptstudy.model;

import org.hibernate.annotations.GenericGenerator;
import xyz.erupt.annotation.Erupt;
import xyz.erupt.annotation.EruptField;
import xyz.erupt.annotation.sub_field.Edit;
import xyz.erupt.annotation.sub_field.View;

import javax.persistence.*;
import java.util.Date;


/*
 *	@Erupt注解修饰在类上,@EruptField注解修饰在字段上
 *	其他注解均为Jpa注解
 */
@Erupt(name = "简单的例子")
@Table(name = "user")
@Entity
public class DemoSimple {

    //主键
    @Id
    @GeneratedValue(generator = "generator")
    @GenericGenerator(name = "generator", strategy = "native")
    @Column(name = "id")
    @EruptField
    private Long id; //如果继承BaseModel不能再重复声明id

    //文本输入
    @EruptField(
            views = @View(title = "文本"),
            edit = @Edit(title = "文本")
    )
    private String input;
    
    //数值输入
    @EruptField(
            views = @View(title = "名称"),
            edit = @Edit(title = "名称")
    )
    @Column(name = "name")
    private String name;

    //布尔选择
    @EruptField(
            views = @View(title = "密码"),
            edit = @Edit(title = "密码")
    )
    @Column(name = "password")
    private String password;

    //时间选择
    @EruptField(
            views = @View(title = "时间"),
            edit = @Edit(title = "时间")
    )
    private Date date;

}

这里需要注意,文本和时间这两个字段没删所以前端显示是空的

重启回到菜单管理页面进行修改

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

刷新一下重新打开页面就可以看到成功了

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

@Erupt注解

属性:

public @interface Erupt {

    String primaryKeyCol() default "id"; //主键列名称,默认值为id

    String name(); //功能名称

    String desc() default ""; //功能描述

    boolean authVerify() default true; //访问是否需要授权校验

    Power power() default @Power; //控制增删改查导入导出功能

    RowOperation[] rowOperation() default {}; //自定义操作按钮

    Drill[] drills() default {}; //自定义下钻关联视图

    Filter[] filter() default {}; //数据过滤

    String orderBy() default ""; //排序

    Class<? extends DataProxy>[] dataProxy() default {}; //代理回调接口方法集

    Tree tree() default @Tree; //树节点配置

    LinkTree linkTree() default @LinkTree(field = ""); //左树右表配置

    KV[] param() default {}; //自定义参数
}

一般常用

@Erupt(
       name = "Erupt",              //功能名称
       desc = "Erupt Framework",	//描述
       orderBy = "id desc", 		//排序表达式
       .....
)
public class EruptTest extends BaseModel {
    
    //TODO 
    
}

属性表

https://www.yuque.com/erupts/erupt/mzi9ry?inner=DtN58

布局属性@Layout
public @interface Layout {

    //表单大小
    FormSize formSize() default FormSize.DEFAULT;

    //表格左侧列固定数量
    int tableLeftFixed() default 0;

    //表格右侧列固定数量
    int tableRightFixed() default 0;


    enum FormSize {
        DEFAULT,  //默认布局,每行显示三个表单组件
        FULL_LINE //整行布局,每行显示一个表单组件
    }

}

@Power注解

用于权限控制

@Erupt(
       name = "Erupt",
       power = @Power(add = true, delete = true, 
                      edit = true, query = true, 
                      importable = false, export = false)
)
public class EruptTest extends BaseModel {
	
}

属性

public @interface Power {
    boolean add() default true; //数据新增功能

    boolean delete() default true; //数据删除功能

    boolean edit() default true; //数据修改功能

    boolean query() default true; //输入查询功能

    boolean viewDetails() default true; //数据查看功能

    boolean export() default false; //数据导出功能

    boolean importable() default false; //数据导入功能

    //实现此接口动态控制权限
    Class<? extends PowerHandler> powerHandler() default PowerHandler.class;
}

对于权限的管理,若需要动态控制权限这里主要是去实现 PowerHandler,这里传入一个PowerHandler类即可,但是如何区分角色权限又是另一回事这里需要研究

@Filter注解

数据过滤

@Erupt(
       name = "Test",
       filter = @Filter("EruptTest.name = '张三'"),
)
public class EruptTest extends BaseModel {
 	
    @EruptField(
            views = @View(title = "名称"),
            edit = @Edit(title = "名称")
    )
    private String name;
    
}

属性

public @interface Filter {
    
    String value() default ""; //条件表达式

    String[] params() default {}; //回调参数

    //动态控制过滤条件
    Class<? extends FilterHandler> conditionHandler() default FilterHandler.class; 
}

@EruptField注解

字段注解

@EruptField(
    sort = 10,
    views = @View(title = "名称"),
    edit = @Edit(title = "名称")
)
private String name;
属性名描述
views表格项配置(允许不配置,则不展示在表格内,也不会参与查询
edit编辑项配置(允许不配置,则不展示组件,新增和编辑不信任任何前端值)
sort前端展示顺序,默认按照字段排列顺序进行排序,数字越小越靠前
params自定义参数
@View
属性名描述
title表格列名称
desc表格列描述
type数据展示形式,详见 type参照
show是否显示
sortable是否支持排序前端通过表格列进行排序操作
export是否支持Excel导出
className表格样式类名(可在app.css中定义类样式)
width列宽度(1.6.8及以上版本支持)
column如果修饰字段为对象类型,需要使用此属性指定,要展示哪一个字段在@ManyToOne时使用此配置
template字符串转换模板 该参数在前端使用eval方法解析支持变量:1、item(整行数据)2、item.xxx(数据中的某一列)3、value (当前数据)配置为 → template = "‘姓名:’ + value"展示效果 → 姓名xxxx
@View → type参照
属性名描述
AUTO根据@Edit → EditType或字段类型自动识别EditType.ATTACHMENT → ATTACHMENTEditType.ATTACHMENT.IMAGE → IMAGEEditType.HTML_EDITOR HTMLEditType.CODE_EDITOR CODEEditType.MAP MAPBoolean BOOLEANDate → DATEInteger NUMBERFloat NUMBERDouble NUMBER其他 TEXT
TEXT普通文本
IMAGE图片
IMAGE_BASE64base64格式图片
SWFflash动画
HTML渲染HTML代码段
MOBILE_HTML手机屏幕尺寸渲染HTML代码段
QR_CODE二维码
LINK新窗口方式打开链接
LINK_DIALOG对话框方式打开链接
DOWNLOAD直接下载
ATTACHMENT新窗口方式代开附件
ATTACHMENT_DIALOG对话框方式打开附件
DATE日期
BOOLEAN布尔
NUMBER数值
MAP地图
CODE代码
@Edit
属性名描述
title编辑框名称
desc描述
notNull是否为必填项
show是否显示
readonly是否只读 @Readonly
showBy组件在何种情况下显示,具体使用方法如下:showBy = @ShowBy(dependField = “number”, expr = “value == 1”)**dependField:展示此组件需要依赖的组件expr**:表达式返回true则本组件显示表达式说明:value表示依赖字段number的值,语法为JavaScript,如果number的输入值为1则显示本组件。
placeHolder描述输入字段预期值的提示信息
search是否支持搜索search = @Search*(vague = true)* vague 为 true 时各组件会有相应的 高级查询 查询策略
orderBy排序规则,参照hql语句 order by 语法当字段类型为@Erupt修饰的复杂对象时可用
filter过滤规则,参照hql语句where语法当字段类型为@Erupt修饰的复杂对象时可用
type编辑类型,详见 type参照
@Edit → type参照
类型描述搜索高级搜索使用方法
AUTO默认类型,可通过字段类型等特征进行推断#
INPUT文本输入框#
NUMBER数值输入框#
SLIDER滑动输入条#
DATE时间选择器#
BOOLEAN开关#
CHOICE单选框#
TAGS标签选择器#
AUTO_COMPLETE自动完成#
TEXTAREA多行文本输入框#
HTML_EDITOR富文本编辑器#
CODE_EDITOR代码编辑器#
ATTACHMENT附件,图片#
MAP地图#
DIVIDE分割线#
TPL自定义HTML模板
COMBINE表单联合
HIDDEN隐藏#
EMPTY空(仍占据组件位置)#
👇 如下组件使用较为复杂,建议充分了解JPA后使用
REFERENCE_TREE树引用#
REFERENCE_TABLE表格引用#
CHECKBOX复选框#
TAB_TREE多选树#
TAB_TABLE_REFER多选表格#
TAB_TABLE_ADD一对多新增#

一对一案例

首先创建两张表

Teacher表

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

_user表

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从数据库上我们可以初步分析我们需要通过用户的teacher_id访问到Teacher表的id

代码

package com.example.eruptstudy.model;

import lombok.Getter;
import lombok.Setter;
import org.apache.poi.ss.formula.functions.T;
import org.hibernate.annotations.GenericGenerator;
import xyz.erupt.annotation.Erupt;
import xyz.erupt.annotation.EruptField;
import xyz.erupt.annotation.sub_erupt.Filter;
import xyz.erupt.annotation.sub_erupt.Layout;
import xyz.erupt.annotation.sub_erupt.Power;
import xyz.erupt.annotation.sub_field.Edit;
import xyz.erupt.annotation.sub_field.EditType;
import xyz.erupt.annotation.sub_field.View;
import xyz.erupt.annotation.sub_field.sub_edit.Search;

import javax.persistence.*;
import java.util.Date;
import java.util.Set;


/*
 *	@Erupt注解修饰在类上,@EruptField注解修饰在字段上
 *	其他注解均为Jpa注解
 */
@Getter
@Setter
@Erupt(
        name = "简单的例子",
        layout = @Layout

)
@Table(name = "_user")
@Entity
public class DemoSimple {

    //主键
    @Id
    @GeneratedValue(generator = "generator")
    @GenericGenerator(name = "generator", strategy = "native")
    @Column(name = "id")
    @EruptField
    private Integer id; //如果继承BaseModel不能再重复声明id

    //数值输入
    @EruptField(
            views = @View(title = "名称"),
            edit = @Edit(title = "名称", search = @Search)
    )
    @Column(name = "name")
    private String name;

    //布尔选择
    @EruptField(
            views = @View(title = "密码"),
            edit = @Edit(title = "密码")
    )
    @Column(name = "password")
    private String password;


    @OneToOne(
            cascade = CascadeType.ALL
    )
    @EruptField(
//            views = @View(title = "扩展表姓名", column = "id"),
            edit = @Edit(title = "扩展表定义", type = EditType.COMBINE)
    )
    private Teacher teacher;

}
package com.example.eruptstudy.model;/*
 * Copyright © 2020-2035 erupt.xyz All rights reserved.
 * Author: YuePeng (erupts@126.com)
 */

import javax.persistence.*;

import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.GenericGenerator;
import xyz.erupt.annotation.*;
import xyz.erupt.annotation.sub_erupt.*;
import xyz.erupt.annotation.sub_field.*;
import xyz.erupt.annotation.sub_field.sub_edit.*;
import xyz.erupt.upms.model.base.HyperModel;
import xyz.erupt.jpa.model.BaseModel;

import java.util.Set;
import java.util.Date;

@Getter
@Setter
@Erupt(name = "教师")
@Table(name = "teacher")
@Entity
public class Teacher extends BaseModel {

    @EruptField(
            views = @View(title = "Id"),
            edit = @Edit(title = "Id", notNull = true)
    )
    private Long tid;

    @EruptField(
            views = @View(title = "名称"),
            edit = @Edit(title = "名称")
    )
    private String tname;

}
    

效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可删改查,增放到多对多

一对多案例

创建数据库

我们创建一个teacher2的数据库,字段:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后再最开始的_user表中添加字段teacher_id2

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建Teacher2类
package com.example.eruptstudy.model;


import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.GenericGenerator;
import xyz.erupt.annotation.Erupt;
import xyz.erupt.annotation.EruptField;
import xyz.erupt.annotation.sub_field.Edit;
import xyz.erupt.annotation.sub_field.View;
import xyz.erupt.jpa.model.BaseModel;
import javax.persistence.*;
import java.util.Collection;

@Getter
@Setter
@Entity
@Erupt(name = "测试教师2")
@Table(name = "teacher2")
public class Teacher2  {

    @Id
    @GeneratedValue(generator = "generator")
    @GenericGenerator(name = "generator", strategy = "native")
    @EruptField
    @Column(name = "tid")
    private Long id;

    @EruptField(
            views = @View(title = "名称"),
            edit = @Edit(title = "名称")
    )
    @Column(name = "tname")
    private String tname;

}

在一开始的DemoSimple类中加入

    @EruptField(
            edit = @Edit(
                    title = "多对多,关联多条数据",
                    type = EditType.TAB_TABLE_REFER
            )
    )
    @ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
    @JoinTable(name = "user_teacher2",
            joinColumns = @JoinColumn(name = "teacher_id2", referencedColumnName = "teacher_id2"),
            inverseJoinColumns = @JoinColumn(name = "tid", referencedColumnName = "tid")
    )
//    @JoinColumn(name = "use_id")
    private Set<Teacher2> teacher2;

这里解释一下

  • @JoinTable是创建一个表

    • name是这个表的名称
  • joinColumns是加入的当前表的字段

    • JoinColumn这个是映射字段,这里添加关联从而连接起来 name是映射出来创建出来表的字段的字段,来自的外键是来自这张表的referencedColumnNameteacher_id2字段

      就比如说我想要在user表中的teacher_id2字段映射为wuhu那么语句就是这样写

      joinColumns = @JoinColumn(name = "wuhu", referencedColumnName = "teacher_id2")
      
    • inverseJoinColumns这个是映射其他表的字段的这里做的事情和上面那个解释一样,也就是说这里是把teacher2的tid映射了

  • JoinColumn这个是用于增加的后面讲

一些注解坑

@Id与BaseModel

官网文档的后面都是用继承BaseModel来写,但是如果你的主键不是名字叫id的话他会给你自主生成id这个字段到数据库里面,如果是数据库的主键名为其他的那么在其字段加上@Id就不会在类上爆红了

一对一

我们需要清楚的是,我们原本的数据库的字段是需要全部搞到的,所以实体类的概念还是存在,只是多出来的属性需要自行添加加入,所以最开始的误区就是实体类的字段与之对应的数据库属性没有写全,这里需要注意

Caused by: org.hibernate.MappingException: Unable to find column with logical name…supertables and

这个是由于你在实体类中属性没有写全,缺少了这个属性,需要加上这个属性并且使用@Column注解

无法解决的BUG

一对多非官方设置的

主要的

    @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
    @JoinColumn(name="use_id")
    @EruptField(
            edit = @Edit(
                    title = "多对多,关联多条数据",
                    type = EditType.TAB_TABLE_REFER
            )
    )

调用其他表的

public class Teacher2  {
    @Id
    @GeneratedValue(generator = "generator")
    @GenericGenerator(name = "generator", strategy = "native")
    @EruptField
    @Column(name = "tid")
    private Long id;
    @EruptField(
            views = @View(title = "名称"),
            edit = @Edit(title = "名称")
    )
    @Column(name = "tname")
    private String tname;

    @EruptField(
            edit = @Edit(title = "学生学号")
    )
    @Column(name = "use_id")
    private Long use_id;
}

这样在页面上会显示了,对其删除会发生诡异的事情

我的数据库的数据:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

页面显示

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

删除123后点击修改保存,再次打开诡异的事情就发生了

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据库数据:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一对多官方配置方法(暂时没法解决的

把上面的改成这个

    @OneToMany //多对多
    @JoinColumn(name = "teacher_id2")
    @JoinTable(name = "teacher2_demo_simple", // Define a new join table name
            joinColumns = @JoinColumn(name = "demo_simple_id", referencedColumnName = "teacher_id2"), // Match the columns
            inverseJoinColumns = @JoinColumn(name = "use_id", referencedColumnName = "use_id")) // Match the columns
    @EruptField(
            edit = @Edit(
                    title = "多对多,关联多条数据",
                    type = EditType.TAB_TABLE_REFER
            )
    )
    private Set<Teacher2> teacher2;

查不到数据,非常的蹊跷

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Erupt 是一个快速开发企业级后台管理系统的开源框架,它提供了丰富的组件和工具,可以快速搭建出功能强大、易于维护的后台管理系统。其中,自定义按钮是 Erupt 非常实用的一个组件,可以自定义按钮的样式、文本、点击事件等属性,实现自定义的功能。下面是一个实现自定义按钮的示例: 首先,在 Erupt 的实体类中添加一个按钮属性: ```java @EruptField( views = @View(title = "操作", sortable = false), edit = @Edit(title = "操作"), search = @Search, actions = { @Action(title = "自定义按钮", name = "customButton") } ) private String button; public String getButton() { return button; } public void setButton(String button) { this.button = button; } ``` 这里使用了 `@Action` 注解来定义一个名为 "customButton" 的自定义按钮。 然后,在 Erupt 的页面中添加按钮的 HTML 代码: ```html <div class="btn-group"> <button class="btn btn-success" onclick="erupt.handleButtonClick(this, 'customButton')">自定义按钮</button> </div> ``` 这里使用了 Bootstrap 框架的样式来渲染按钮,并且通过 `erupt.handleButtonClick` 函数来触发按钮的点击事件。 最后,在 Erupt 的 Controller 中处理按钮的点击事件: ```java @RequestMapping("/erupt/customButton") @ResponseBody public Object customButton() { // 处理按钮的点击事件,返回响应结果 return "自定义按钮被点击了"; } ``` 这里使用了 `@RequestMapping` 注解来定义按钮的访问路径,并在方法中处理按钮的点击事件。返回的响应结果将在页面上显示出来。 这样就完成了自定义按钮的实现。你可以根据实际需求来定义按钮的样式、文本、点击事件等属性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艾米莉亚小汉堡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值