Java课程设计-家庭财政管理软件

【摘要】

家庭理财管理系统是通过信息管理系统的方式记录和管理家庭日常的收入、支出和理财明细,能科学有效的管理家庭的财政情况。随着家庭平均消费水平的增加,很多家庭都面临的财务紧张的问题,如不能合理有效的管理家庭的财务数据,对整个家庭日常的消费都会带来困难,合理支配家庭的收入和支出已经变的越来越重要的。传统的家庭理财管理的方式都是采用人工记录的方式来完成,但数据的统计和管理比较麻烦,不能及时的统计收入和支出的总额,满足不了现在家庭对于理财管理的需求。基于Java的家庭理财管理系统是一个针对家庭内部使用的数据型的管理系统,实现了对家庭财务数据的录入、管理等功能。系统的开发是在Eclipse集成开发平台完成,并借助文件输入流、输出流完成对家庭理财数据的存储和查询。家庭理财管理系统主要包括了收入管理、支出管理、各种收支类型管理以及家庭财务数据总览等功能组成。统计中可以按照基本信息录用来统计收入支出,财务数据总览中可以对整个家庭的收入总额、支出总额以及参与投资理财的资金进行查看,进一步的设置支出上线,是家庭财务始终保持在安全线以内。

关键词: JAVA  文件输入、输出流  家庭财政管理  Eclipse

第一章 绪论

1.1课题研究的背景与意义

21世纪,随着科技水平水平的提高,手机支付越来越便利,消费支出变得悄无声息。许多人感叹到,不知不觉中余额不足。因此,记录生活的日常开销、经济来源,以规划自己行为变得更加重要。一个良好的理财观念,通过与家庭客观收入、支出水平进行结合才是为未来的生活奠定良好的物质基础。而其中统计每一笔收入、支出、各种收支类型是一个良好理财的必须。

1.2研究的目标

我选择做一个家庭财政管理小软件用来帮助家庭管理收入、支出,帮助他们远离盲目消费。通过对java课程的学习,我想用java语言来实现java逻辑方法与个人逻辑的结合,简言之将自己的想法用java语言来表达。关于家庭财政管理小软件,我想表达成一个可以记录每一笔收入、每一笔支出和每个投资理财的信息化管理软件,可以对理财数据进行分析,统计出每一笔收入和消费的支出,方便家庭成员及时对自己的消费作出相应的调整,使家庭的财务数据一直都处于一个安全水平线之内,为未来的生活奠定良好的物质基础。通过这个研究我想进一步巩固自己的java学习,并希望这个小软件成为是我编程路上的良好开端。

  • 技术介绍

2.1java语言的介绍

Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程   。

Java具有简单性、面向对象、分布式、安全性、平台独立与可移植性、多线程、动态性等特点 Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程,更加符合人类语言的惯性思维。Java可以编写桌面管理程序、Web应该程序分布式系统嵌入式应用程序等 本次程序编辑主要运用java对于窗口、文件的编写功能

2.2文件字符输入、输出流

借助文件将收入情况、支出情况、收支日期分别储存在D:\家庭财政管理\src下的income.txt,expend.txt,shouzhi.txt。

Java 对文件的写入和读取涉及到流的概念,写入为输出流,读取为输入流。如何理解流的概念呢?可以把流看成流动的自来水,打开水龙头,自来水就会通过自来水管从水源流到用户家中,同样的道理,水库中的水也会通过管道流入到水源。从水源流出到用户住家为自来水的输出流,从水库流入到水源为自来水的输入流,只有这样,自来水才能源源不断地流出到用户家中。如图2-1.

如果把水源看成文件,用户住家为读取文件的对象,水库为写入文件的对象,就很容易理解Java的输入与输出流了。当Java程序的写入对象(水库)需要将自来水写入到水源(文件)时,需要建立一条从写入对象(水库)到水源(文件)的通道,这个通道就是输入流;当Java程序的读取对象(用户住家)需要读取水源(文件)时,也需要建立一条从水源(文件)到读取对象(用户住家)的通道,这个通道就是输出流。

在Java程序中,要想从文件中读取数据,需要在程序和文件之间建立一条数据输入的通道,这样程序就可以从文件中读取数据了;反之,如果要在Java程序中把数据写入到文件中,也需要在程序和文件之间建立一条数据输出的通道。当程序创建输入流对象时,Java会自动建立这个数据输入通道,而创建输出流时,Java也会自动建立这个数据输出通道。

2.3 窗口设计

通过图形用户界面(GUI),用户和程序之间可以方便地进行交互。Java的java.awt包,即Java抽象窗口工具包(AWT)提供了许多用来设计GUI的组件类。关于窗口的两个重要概念:容器类和组件类。两者的关系就如酒席上的桌子和一盘盘菜,在桌子这个容器下,盛着一份份菜的盘子就如按钮、文本框等组件,是这个桌子上变得丰盛,也更加简洁地解决呈现问题。

第三章软件需求分析

3.1 软件需求分析

(1)登入界面。家庭财政收支是涉及家庭隐私的问题,所以需要使用账号密码登入,以保证隐私安全。(2)收支录用。这也是家庭财政管理软件的主要功能,以此做到财政管理,方便使用者能够了解自己的每一笔收支,利于管理家庭资金。(3)余额计算与支出上限。通过计算每一笔收支计算出家庭财政余额,方便于思考是否购买理财产品,对未来物质生活的改变有依据。支出上线使得使用者能够计算是否支出某笔消费,如果超出上线就需要再三考虑或者限制消费。

3.2 软件使用流程

(1)登入。输入账号密码进入软件。(2)收入支出录用。记录每一笔收入支出的具体类型、金额、日期,以方便查询。(3)设置上限。在设置上限具体金额,对自己的消费进行限制,如果超出限制就会发出警告。(4)账单分析。对收入支出进行具体计算得出家庭余额。

第四章 软件总体设计

4.1 功能模块设计

分成以下五个模块

  1. 登入。输入账号密码进入软件。(2)收入支出录用。记录每一笔收入支出的具体类型、金额、日期,以方便查询。(3)设置上限。在设置上限具体金额,对自己的消费进行限制,如果超出限制就会发出警告。(4)账单分析。对收入支出进行具体计算得出家庭余额。(5)进入收支文件夹。进入收支文件夹查看具体的收支情况。

4.2 软件呈现方式

目前,Java的学习只进入初级阶段,只能通过窗口来实现软件的简单功能,具有简单的GUI界面窗口是GUI编程的基础,小应用程序或图形界面的应用程序的可视组件都放在窗口中,在GUI中,窗口是用户屏幕的一部分,起着在屏幕中一个小屏幕的作用。Swing里的容器都可以添加组件,除了JPanel及其子类(JApplet)之外,其他的Swing容器不允许把组件直接加入。其他容器添加组件有两种方法:

一种是用getContentPane()方法获得内容面板,再将组件加入。程序中的代码:

    con.getContentPane().add(button);

该代码的意义是获得容器的内容面板,并将按钮button添加到这个内容面板中。

另一种是建立一个JPanel对象的中间容器,把组件添加到这个容器中,再用setContentPane()把这个容器置为内容面板。以此来实现软件。

第五章 软件详细设计与实验

5.1 软件架构设计

(1)程序构成

本程序设计了两个类,App类、InterFace类、Money类,App类为主类,InterFace负责登入窗口和窗口实现,Money类负责收支窗口布局和窗口实现。

(2)登录界面的构成

界面主要由四个Panel,三个JLabel,一个JTextField,一个JPasswordField以及两个按钮(一个确定按钮,一个取消按钮)构成。登录界面使用GridLayout布局,分为账号和密码两部分,JTextField用来输入账号,JPasswordField用来输入密码。“确定”按钮实现登录,若密码与设置密码不匹配,提示出错;“取消”按钮实现取消功能。

(3)软件主要界面构成与功能

界面由九个JLabel,七个JTextField,三个JTextArea,三个JButton构成。

主要实现日常收入与支出分类统计,预支日支出设置,账单分析等功能。

“收入文本框”:text1输入收入类型,text2输入收入金额,text6输入收入日期。b1按钮安装监视器,触发动作事件,将存入收入类型、收入金额income.txt文件、全部收入信息存入shouzhi.txt以及显示在area1中。

“支出文本框”:text3输入支出类型,text4输入支出金额,text7输入支出日期。b2按钮安装监视器,触发动作事件,将输入的信息存入expend.txt文件以及显示在area2中。

“支出上限”文本框:text5设置支出上限。

“账单分析”按钮:b3按钮安装监视器,对income.txt和income.txt进行分析,在area3中显示出总收入、总支出和结余。如果今日总支出超出支出上限,触发报警。

(4)数据的存储

借助字符输入、输出流,将收入存储在income.txt文件中,支出存储在expend.txt文件中。讲具体日期与收支详情储存在shouzhi.txt。

5.2 程序UML图

描述主类App,InterFace类,Money类的主要结构

App类中的InterFace方法调用InterFace类,以此来运行代码。

InterFace f=new InterFace();

InterFace类中构造方法InterFace()与int()方法进行登入窗口的布局与组件的建立。

label1 = new JLabel("账     号"); txt1 = new JTextField(10);

panel1 = new JPanel(); button1.addActionListener(this);

con.add(panel1);

5.3流程图

该软件的流程步骤分为以下5步。

(1)登入。输入账号密码进入软件。(2)收入支出录用。记录每一笔收入支出的具体类型、金额、日期,以方便查询。(3)设置上限。在设置上限具体金额,对自己的消费进行限制,如果超出限制就会发出警告。(4)账单分析。对收入支出进行具体计算得出家庭余额。(5)进入收支文件夹。进入收支文件夹查看具体的收支情况。

算法逻辑流程的具体情况,计算收支总额与剩余、判断是否发出警报。

5.4 详细实现

5.4.1主类App的实现 

主类App通过调用InterFace方法来实现登入窗口的建成,主要用来代码的运行。再通过InterFace类创建对象,而InterFace继承Java提供的JFrame类,因此可以设置窗口的位置和长宽。

InterFace f=new InterFace();

f.setBounds(600,300,310,260);

f.setTitle("软件登入");

5.4.2  InterFace类的实现

通过InterFace类继承JFrame类,以此来创建窗口,并通过类库中的类java.awt.*和java.swing.*提供的组件、容器完善登入窗口。如,将按钮、文本框添加到面板上进行排布等。InterFace类通过implements实现使用接口中的方法,implements ActionListener就是使得InterFace类能够注册为事件源的监视器。通过对事件源文本框、按钮的监视,并通知监视器做出相应的处理。

panel1.add(label1);

panel1.add(txt1);

panel2.add(label2);

panel2.add(txt2);

在面板上添加标签、文本框、按钮等组件,使得登入窗口获得更多功能。

button1.addActionListener(this);

button2.addActionListener(this);

对按钮button1button2安装监视器,在下一步中对监视到的事件进行处理。

public void actionPerformed(ActionEvent e) {//触发动作事件

if(e.getSource()==button1)  //按钮“确定”触发

  {

String s1 = txt1.getText();

String s2 = txt2.getText();

if(s1.equals("12345")==true&&s2.equals("88888")) //账号密码匹配,如果账号为12345,密码为88888则能够登入成功

{

       JOptionPane.showMessageDialog(null, "登录成功");

//弹出登陆成功对话框

setVisible(false); //窗口不可见

new Money(); //调用money类

}

5.4.3 Money类的实现

在方法Win()中对家庭收支界面进行排布如图

JLabel myname=new JLabel("家庭财政情况");

    JLabel shouru=new JLabel("收  入  类  型:");

    JTextField text1=new JTextField();

    myname.setBounds(220,1,300,50);

  add(myname);add(label);

Money类通过文件输入流和输出流进行储存收支情况,再对文件进行解析与对缓冲流中的数据就行处理

File file1=new File("D:\\家庭财政管理\\src\\income.txt");  //收入统计到file1中

File file2=new File("D:\\家庭财政管理\\src\\expend.txt");  //支出统计到file2中

File file3=new File("D:\\家庭财政管理\\src\\shouzhi.txt");//将收支情况放入file3中

sc1=new Scanner(file1); // 解析文件

br1=new BufferedReader(read1); //缓冲读取文本

b1.addActionListener(this); //给按钮添加监视器

FileWriter writer1=new FileWriter(file1,true);

writer.append(text6.getText()+"  "+"收入类型-—"+text1.getText()+":"+text2.getText()+"\r\n");

       //将收入信息读入income.txt中

area1.append(text6.getText()+""+text1.getText()+":"+text2.getText()+"\r\n");

      //将收入的内容显示到area1中

最后,通过正则表达式及字符串的替换与分解,提取出文件中的数字进行收入与支出的总额计算。

regex="[\\D]+";

//识别数字 \\D在正则表达式中代表任何一个非数字符号

s1=s1.replaceAll(regex,"#");

 //将所有的数字用#代替,课本188页。

StringTokenizer fenxi1=newStringTokenizer(s1,"#");

 //用#作为分隔符分隔字符串

while(fenxi1.hasMoreTokens()){

String item=fenxi1.nextToken();

   price1=Double.parseDouble(item);

   //将string转化成double型

   sum1+=price1; //收入总和

            }

再通过对按钮安装的监视器传来的事件进行处理来达到收支的录入。

程序代码

public class App{
	public static void main(String[] args) {
		InterFace f=new InterFace();
		f.setBounds(300,300,310,260);
		f.setTitle("软件登入");
		}
}

 

 

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class InterFace extends JFrame implements ActionListener{
	JLabel label1,label2,label3;
	JTextField txt1;
	JPasswordField txt2;
	JButton button1,button2;
	JPanel panel1,panel2,panel3,panel4;
	Container con;

	public InterFace() {
	init();
	setVisible(true);
	setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
	void init() {
		label1 = new JLabel("账     号"); 
		label2 = new JLabel("密     码");
		label3 = new JLabel("~感谢使用~");
		txt1 = new JTextField(10);
		txt2 = new JPasswordField(10);
		button1 = new JButton("确定");		
		button2 = new JButton("取消");
		con=getContentPane();
		con.setLayout(new GridLayout(4, 1));
		panel1 = new JPanel();
		panel2 = new JPanel();
		panel3 = new JPanel();
		panel4 = new JPanel();
		panel1.add(label1);
		panel1.add(txt1);
		panel2.add(label2);
		panel2.add(txt2);
		button1.addActionListener(this);
		button2.addActionListener(this);
		//按钮“确定”安装监视器
		panel3.add(button1);
		panel3.add(button2);
		panel4.add(label3); 
		con.add(panel1);
		con.add(panel2);
		con.add(panel3);
		con.add(panel4);	
	}
	
	
	public void actionPerformed(ActionEvent e) {//触发动作事件
		if(e.getSource()==button1)  //按钮“确定”触发	
	  {
		String s1 = txt1.getText();
		String s2 = txt2.getText();
		if(s1.equals("12345")==true&&s2.equals("88888")) //账号密码匹配
		{	
	       JOptionPane.showMessageDialog(null, "登录成功");
//弹出登陆成功对话框
			setVisible(false); //窗口不可见
			 
			new Money();	//调用money类	
		}
		else //账号密码匹配错误
		{
			//重置
			txt1.setText(null); //账号输入栏重置
			txt2.setText(null); //密码输入栏重置
			JOptionPane.showMessageDialog(null, "账号或密码错误,请重新输入"); //弹出输入错误提示框
		}
	  }
		
		else if(e.getSource()==button2) //按钮“取消”触发动作事件
	  {
			setVisible(false); //窗口不可见
	  }
		
    }
	}

 

import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.awt.*;
import java.io.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.Scanner;

public class Money extends JFrame
{
    	Win f=new Win(); //调用Win
}

class Win extends JFrame implements ActionListener{
	
	JLabel myname=new JLabel("家庭财政情况");
    JLabel shouru=new JLabel("收  入  类  型:");
    JTextField text1=new JTextField();
    JLabel jine1=new JLabel("金  额:");
    JTextField text2=new JTextField();
    JLabel date1=new JLabel("日期:");
    JTextField text6=new JTextField();
    JButton b1=new JButton("确  定");
    JLabel zhichu=new JLabel("支  出  类  型:");
    JTextField text3=new JTextField();
    JLabel jine2=new JLabel("金  额:");
    JTextField text4=new JTextField();
    JLabel date2=new JLabel("日期:");
    JTextField text7=new JTextField();
    JButton b2=new JButton("确  定");
    JTextField text5=new JTextField();
    JTextArea area1=new JTextArea();
    JTextArea area2=new JTextArea();
    JLabel shangxian=new JLabel("支 出 上 限:");
    JButton b3=new JButton("账单分析");
    JTextArea area3=new JTextArea();
    
File file1=new File("D:\\家庭财政管理\\src\\income.txt"); 		 //收入统计到file1中
	File file2=new File("D:\\家庭财政管理\\src\\expend.txt");	 //支出统计到file2中
	File file3=new File("D:\\家庭财政管理\\src\\shouzhi.txt");//将收支情况放入file3中
	Scanner sc1,sc2,sc3;
	Reader read1,read2,read3;
	BufferedReader br1,br2,br3; //输入缓冲
	String s1,s2,regex;
	double price1=0,sum1=0,price2=0,sum2=0,left=0;
	
    Win(){
	super();
	setVisible(true);
	this.getContentPane().setBackground(Color.PINK); //面板颜色
    setTitle("家庭的财务管理小程序");
    setSize(750, 650); //窗口大小
    setLocationRelativeTo(null);     
    setLayout(null); //首先设置布局为空
        JLabel label = new JLabel();
        label.setBounds(20, 150, 800, 650); 
        myname.setBounds(220,1,300,50);
     myname.setFont(new Font("仿宋",Font.BOLD,20));
        shouru.setBounds(30, 50, 60, 30);
        text1.setBounds(110,50,70,30);
        jine1.setBounds(210, 50, 60, 30);       
        text2.setBounds(300, 50, 70, 30);  
        date1.setBounds(390,50,60,30);
        text6.setBounds(470,50,70,30);
        b1.setBounds(560,40,80,30);       
        area1.setBounds(180, 90, 250, 100);       
        zhichu.setBounds(30, 210, 60, 30);       
        text3.setBounds(110,210,70,30);       
        jine2.setBounds(210, 210, 60, 30);        
        text4.setBounds(300, 210, 70, 30);   
        date2.setBounds(390,210,60,30);
        text7.setBounds(470,210,70,30);
        b2.setBounds(560,210,80,30);      
        area2.setBounds(180, 250, 250, 100);     
        shangxian.setBounds(100, 380, 100, 30);       
        text5.setBounds(190, 380, 100, 30);           
        b3.setBounds(190, 450, 100, 50);
        b3.setFont(new Font("仿宋",Font.BOLD,15));
        area3.setBounds(350,400,150,200);

        add(myname);add(label);add(shouru);add(text1);
        add(jine1);add(text2);add(date1);add(text6);add(b1);
        add(area1);add(zhichu);add(text3);
        add(jine2);add(text4);add(date2);add(text7);add(b2);
        add(area2);add(shangxian);add(text5);
        add(b3);add(area3);
     
            	try
            	{
            		sc1=new Scanner(file1); // 解析文件
            		sc2=new Scanner(file2);
            		sc3=new Scanner(file3);
            		read1=new FileReader(file1);
            		read2=new FileReader(file2);
            		read3=new FileReader(file3);
            		br1=new BufferedReader(read1); //缓冲读取文本
            		br2=new BufferedReader(read2); 
            		br3=new BufferedReader(read3); 
            	}catch(Exception ee) {}
            		b1.addActionListener(this); //给按钮添加监视器
            		b2.addActionListener(this);    
            		b3.addActionListener(this); 
            }
                
              public void actionPerformed(ActionEvent e) {
                	if(e.getSource()==b1) { //收入“确定”按钮触发动作事件
                	try {
                		
                		FileWriter writer=new FileWriter(file3,true);
                		FileWriter writer1=new FileWriter(file1,true);
                		writer.append(text6.getText()+"  "+"收入类型--"+text1.getText()+":"+text2.getText()+"\r\n");
        			//将收入信息读入income.txt中
                		writer1.append(text1.getText()+":"+text2.getText()+"\r\n");
                		writer.flush(); writer1.flush();//刷新缓冲区
                		writer.close(); writer1.close();//关闭数据流
                		area1.append(text6.getText()+"  "+text1.getText()+":"+text2.getText()+"\r\n");
        			//将收入的内容显示到area1中
                		text1.setText(null);text2.setText(null);text6.setText(null);
                	    }
                	catch(Exception e1) {
                		e1.printStackTrace();
        //抛出错误,打印异常信息在程序中出错位置及原因
                	}
                }
                	else if(e.getSource()==b2){ //支出“确定”按钮触发动作事件
                		try {
                    		FileWriter writer=new FileWriter(file2,true);
                    		FileWriter writer2=new FileWriter(file3,true);
                    		writer.append(text3.getText()+":"+text4.getText()+"\r\n");//将支出信息读入expend.txt中
                    		writer2.append(text7.getText()+"  "+"支出类型--"+text3.getText()+":"+text4.getText()+"\r\n");
        				//将支出信息读入shouzhi.txt中
                    		writer.flush(); writer2.flush();//刷新缓冲区
                    		writer.close(); writer2.close();//关闭数据流
                    		area2.append(text7.getText()+"  "+text3.getText()+":"+text4.getText()+"\r\n");
        				//将支出的内容显示到area2中
                    		text3.setText(null);text4.setText(null);text7.setText(null); //刷新输入框
                    	}
                    	catch(IOException e2) {
                    		e2.printStackTrace();
        //抛出错误,打印异常信息在程序中出错位置及原因
                    	}
                	}
                	else if(e.getSource()==b3) { //“账单分析”按钮触发动作事件
                		regex="[\\D]+"; //识别数字 \\D在正则表达式中代表任何一个非数字符号
                		try 
                		{
                			while((s1=br1.readLine())!=null) //遍历income.txt
                			{
                				s1=s1.replaceAll(regex,"#"); //将所有的数字用#代替,课本188页。
                				StringTokenizer fenxi1=new StringTokenizer(s1,"#"); 
        					//用#作为分隔符分隔字符串
                				while(fenxi1.hasMoreTokens()) 
                				{
                					String item=fenxi1.nextToken();
                					price1=Double.parseDouble(item); 
        //将string转化成double型
                					sum1+=price1; //收入总和
                				}
                			}br1.close();
                			while((s2=br2.readLine())!=null) //遍历expend.txt
                			{
                				s2=s2.replaceAll(regex,"#"); //将所有的数字用#代替
                				StringTokenizer fenxi2=new StringTokenizer(s2,"#");
        					//用#作为分隔符分隔字符串
                				while(fenxi2.hasMoreTokens()) 
                				{
                					String item=fenxi2.nextToken();
                					price2=Double.parseDouble(item);
        //将string转化成double型
                					sum2+=price2; //支出总和
                				}
                			}
                			br2.close();	//关闭输出流
                			left=sum1-sum2; //收支结余
                			area3.append("收入总计:"+"\n");
                			area3.append(sum1+""+"\n");
                			area3.append("支出总计:"+"\n");
                			area3.append(sum2+""+"\n");
                			area3.append("结余:"+left);
                			if(sum2>Double.parseDouble(text5.getText())) //支出达设置上限
                				JOptionPane.showMessageDialog(null, "WARNING!"+"\n"+"今日支出已达上限!请节省您的开支!"); //弹出警告框
                		}
                		catch(IOException e3) {}
                	}
        	  }
        }


 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

X-MTing

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

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

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

打赏作者

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

抵扣说明:

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

余额充值