职工管理系统

一、菜单功能

代码实现

创建职工管理头文件:workerManager.h,在其中设计管理类,在职工管理源文件中补全构造与析构函数。
菜单功能:在职工管理头文件中添加成员函数展示菜单函数并在源文件中实现该函数

workerManager.h代码:

#pragma once
#include<iostream>
using namespace std;


class WorkerManager
{
public:

	//构造函数
	WorkerManager();

	//展示菜单
	void Show_Menu();

	//析构函数
	~WorkerManager();

};

workerManager.cpp代码:

#include "workerManager.h"

WorkerManager::WorkerManager()
{
}

WorkerManager::~WorkerManager()
{
}

void WorkerManager::Show_Menu()
{
	cout << " 欢迎使用职工管理系统 " << endl;
	cout << " 0.退出管理程序  " << endl;
	cout << " 1.增加职工信息 " << endl;
	cout << " 2.显示职工信息 " << endl;
	cout << " 3.删除离职职工 " << endl;
	cout << " 4.修改职工信息 " << endl;
	cout << " 5.查找职工信息 " << endl;
	cout << " 6.按照编号排序 " << endl;
	cout << " 7.清空所有文档 " << endl;
	cout << endl;
}

职工管理系统.cpp代码:

#include<iostream>
using namespace std;
#include "workerManager.h"

int main() {

	WorkerManager wm;

	wm.Show_Menu();

	system("pause");

	return 0;
}

运行结果

二、提供功能接口


在主函数中用switch语句提供分支选择,提供每个功能接口。

int main() {

	WorkerManager wm;
	int choice = 0;
	while (true)
	{
		//展示菜单
		wm.Show_Menu();
		cout << "请输入您的选择:" << endl;
		cin >> choice;

		switch (choice)
		{
		case 0: //退出系统
			break;
		case 1: //添加职工
			break;
		case 2: //显示职工
			break;
		case 3: //删除职工
			break;
		case 4: //修改职工
			break;
		case 5: //查找职工
			break;
		case 6: //排序职工
			break;
		case 7: //清空文件
			break;
		default:
			system("cls");
			break;
		}
	}

	system("pause");
	return 0;
}

三、退出功能

在workerManager.cpp中提供退出系统的成员函数 void exitSystem()

void WorkerManager::exitSystem()
{
	cout << "欢迎下次使用" << endl;
	system("pause");
	exit(0);
}

四、创建职工类

1.职工抽象类

创建头文件worker.h并创建职工抽象类,在职工抽象类中设计成员个人信息和岗位名称

职工的属性为:职工编号、职工姓名、职工所在部门编号

职工的行为为:岗位职责信息描述,获取岗位名称

worker.h代码:

#pragma once
#include<iostream>
#include<string>
using namespace std;
 
//职工抽象基类
class Worker
{
public:
 
	//显示个人信息
	virtual void showInfo() = 0;
	//获取岗位名称
	virtual string getDeptName() = 0;
 
	int m_Id; //职工编号
	string m_Name; //职工姓名
	int m_DeptId; //职工所在部门名称编号
};

2.员工类、经理类、老板类

分别创建普通员工类,经理类,老板类的头文件和源文件,均继承职工抽象类,并继承职工抽象类中的两个纯虚函数:个人信息和岗位名称函数
先在各自的头文件中声明职工抽象类中的方法,并在源文件中实现头文件中声明的方法:输出个人信息和职责。

employee.h代码

#pragma once 
#include<iostream>
using namespace std;
#include "worker.h"

//员工类
class Employee :public Worker
{
public:

	//构造函数
	Employee(int id, string name, int dId);

	//显示个人信息
	virtual void showInfo();

	//获取职工岗位名称
	virtual string getDeptName();
};

employee.cpp代码

#include "employee.h"

Employee::Employee(int id, string name, int dId)
{
	this->m_Id = id;
	this->m_Name = name;
	this->m_DeptId = dId;
}

void Employee::showInfo()
{
	cout << "职工编号: " << this->m_Id
		<< " \t职工姓名: " << this->m_Name
		<< " \t岗位:" << this->getDeptName()
		<< " \t岗位职责:完成经理交给的任务" << endl;
}


string Employee::getDeptName()
{
	return string("员工");
}

manager.h代码

#pragma once
#include<iostream>
#include<string>
using namespace std;
#include "worker.h"

class Manager :public Worker
{
public:
	//构造函数
	Manager(int id, string name, int did);
	//显示个人信息
	virtual void showInfo();
	//获取职工岗位名称
	virtual string getDeptName();
};

manager.cpp代码

#include "manager.h"

Manager::Manager(int id, string name, int dId)
{
	this->m_Id = id;
	this->m_Name = name;
	this->m_DeptId = dId;

}

void Manager::showInfo()
{
	cout << "职工编号: " << this->m_Id
		<< " \t职工姓名: " << this->m_Name
		<< " \t岗位:" << this->getDeptName()
		<< " \t岗位职责:完成老板交给的任务,并下发任务给员工" << endl;
}

string Manager::getDeptName()
{
	return string("经理");
}



boss.h代码

#pragma once
#include<iostream>
using namespace std;
#include "worker.h"

//老板类
class Boss :public Worker
{
public:

	Boss(int id, string name, int dId);

	//显示个人信息
	virtual void showInfo();

	//获取职工岗位名称
	virtual string getDeptName();
};

boss.cpp代码

#include "boss.h"

Boss::Boss(int id, string name, int dId)
{
	this->m_Id = id;
	this->m_Name = name;
	this->m_DeptId = dId;

}

void Boss::showInfo()
{
	cout << "职工编号: " << this->m_Id
		<< " \t职工姓名: " << this->m_Name
		<< " \t岗位:" << this->getDeptName()
		<< " \t岗位职责:管理公司所有事务" << endl;
}

string Boss::getDeptName()
{
	return string("总裁");
}

3.测试多态


在主函数中添加测试函数,新建worker指针在堆区建立新空间,调用三个类各自的构造函数实例化对象,调用展示个人信息函数,成功运行能产生多态。

Worker* worker = NULL;
worker = new Employee(1, "张三", 1);
worker->showInfo();
delete worker;

worker = new Manager(2, "李四", 2);
worker->showInfo();
delete worker;

worker = new Boss(3, "王五", 3);
worker->showInfo();
delete worker;

运行结果:

五、添加职工

将所有员工的指针维护到一个数组里,在堆区创建数组,数组中保存员工的指针,需用woker**来维护(数组里的指针是worker*类型,用new返回的是数组的指针,也就是worker*的指针,所以要用二级指针worker**来接收堆区空间
在职工管理头文件中添加记录人员个数成员属性代码和员工数组的指针woker**,并在构造函数中初始化人数为0和指针滞空
在增加职工函数中键盘录入增加员工数量,在堆区开辟新空间存放员工数组,用woker**接收;利用for循环遍历原空间内容,将原空间内容存放到新空间中;键盘录入新添加的职工的编号,姓名,职位并调用职位的构造函数实例化职工类;释放原有空间。

代码实现

void WorkerManager::Add_Emp()
{
	cout << "请输入增加职工数量: " << endl;

	int addNum = 0;
	cin >> addNum;

	if (addNum > 0)
	{
		//计算新空间大小
		int newSize = this->m_EmpNum + addNum;

		//开辟新空间
		Worker** newSpace = new Worker * [newSize];

		//将原空间下内容存放到新空间下
		if (this->m_EmpArray != NULL)
		{
			for (int i = 0; i < this->m_EmpNum; i++)
			{
				newSpace[i] = this->m_EmpArray[i];
			}
		}

		//输入新数据
		for (int i = 0; i < addNum; i++)
		{
			int id;
			string name;
			int dSelect;

			cout << "请输入第 " << i + 1 << " 个新职工编号:" << endl;
			cin >> id;


			cout << "请输入第 " << i + 1 << " 个新职工姓名:" << endl;
			cin >> name;


			cout << "请选择该职工的岗位:" << endl;
			cout << "1、普通职工" << endl;
			cout << "2、经理" << endl;
			cout << "3、老板" << endl;
			cin >> dSelect;


			Worker* worker = NULL;
			switch (dSelect)
			{
			case 1: //普通员工
				worker = new Employee(id, name, 1);
				break;
			case 2: //经理
				worker = new Manager(id, name, 2);
				break;
			case 3:  //老板
				worker = new Boss(id, name, 3);
				break;
			default:
				break;
			}


			newSpace[this->m_EmpNum + i] = worker;
		}

		//释放原有空间
		delete[] this->m_EmpArray;

		//更改新空间的指向
		this->m_EmpArray = newSpace;

		//更新新的个数
		this->m_EmpNum = newSize;

		//提示信息
		cout << "成功添加" << addNum << "名新职工!" << endl;
	}
	else
	{
		cout << "输入有误" << endl;
	}

	system("pause");
	system("cls");
}

在workerManager.cpp的析构函数中,释放堆区数据

WorkerManager::~WorkerManager()
{
	if (this->m_EmpArray != NULL)
	{
		delete[] this->m_EmpArray;
	}
}

运行结果

六、文件交互

添加功能中将所有的数据元素存储在堆区开辟的空间中,在程序运行结束时就会被释放,无法保存,因此需添加一个与文件进行交互的功能,将数据元素保存在文件中,对文件进行读写操作
在职工管理头文件中添加文件流fstream并定义宏常量文件路径

#include <fstream>
#define  FILENAME "empFile.txt"

1.写文件

在职工管理源文件中添加保存文件函数,用输出的方式打开文件;用for循环遍历整个数组将所有数据元素写入文件中;写文件操作结束后关闭文件

void WorkerManager::save()
{
	ofstream ofs;
	ofs.open(FILENAME, ios::out);
 
 
	for (int i = 0; i < this->m_EmpNum; i++)
	{
		ofs << this->m_EmpArray[i]->m_Id << " " 
			<< this->m_EmpArray[i]->m_Name << " " 
			<< this->m_EmpArray[i]->m_DeptId << endl;
	}
 
	ofs.close();
}

在主函数中调用保存文件函数在添加函数后,添加员工后在同级目录下会多出一个txt类型文件,里面存储新添加的员工的个人信息

2.读文件

判断文件是否存在

在职工管理头文件中定义布尔类型变量,用于判断文件是否为空


bool m_FileIsEmpty;


判断文件是否存在:在职工管理的构造函数中用输入的方式打开文件;用if语句判断文件是否被打开,如果没有被打开,说明文件不存在,此时初始化记录的人数位0,初始化数组指针为空,初始化布尔类型变量为true,return结束函数调用。

WorkerManager::WorkerManager()
{
	ifstream ifs;
	ifs.open(FILENAME, ios::in);
 
	//文件不存在情况
	if (!ifs.is_open())
	{
		cout << "文件不存在" << endl; //测试输出
		this->m_EmpNum = 0;  //初始化人数
		this->m_FileIsEmpty = true; //初始化文件为空标志
		this->m_EmpArray = NULL; //初始化数组
		ifs.close(); //关闭文件
		return;
	}
}

文件存在判断文件是否为空


文件存在时判断文件是否为空:定义一个字符变量ch,写下ifs >> ch表示右移读取一个字符,再用eof(end of file)标识符判断是否到达了文件的末尾,如果只读一个字符就是文件结尾标识,证明此时文件为空,然后初始化属性(和文件不存在时一样),return结束函数调用

char ch;
ifs >> ch;
if (ifs.eof())
{
	cout << "文件为空!" << endl;
	this->m_EmpNum = 0;
	this->m_FileIsEmpty = true;
	this->m_EmpArray = NULL;
	ifs.close();
	return;
}

添加职工后,将定义的布尔类型判断文件是否为空的变量更新为false,表示此时文件不为空。

		//更新职工不为空标志
		this->m_FileIsEmpty = false;

文件存在时保存职工数据


文件存在时保存职工数据:在职工管理源文件中添加统计人数函数同时读取目前存在的职工数据,用while循环读取当前存在的职工的个人信息并用num记录当前职工人数

int WorkerManager::get_EmpNum()
{
	ifstream ifs;
	ifs.open(FILENAME, ios::in);
 
	int id;
	string name;
	int dId;
 
	int num = 0;
 
	while (ifs >> id && ifs >> name && ifs >> dId)
	{
        //记录人数
		num++;
	}
	ifs.close();
 
	return num;
}

在构造函数中添加文件存在记录数据的代码,调用统计人数函数输出当前职工个数并更新成员属性。
 

//文件存在,记录数据
int num = this->get_EmpNum();
cout << "职工个数为:" << num << endl; 
this->m_EmpNum = num;  //更新成员属性 

测试结果

初始化数组

代码实现

在职工管理源文件中添加初始化数组函数,定义位置变量index,用于记录数组中数据元素的位置;用while循环读取数组中数据元素的信息,循环体内容:初始化worker指针置空;根据不同的部门id用if语句判断要创建的对象,在堆区创建新的内存空间存储职工的个人信息,用worker指针维护;将堆区新建的对象信息存放在数组中;close关闭文件

void WorkerManager::init_Emp()
{
	ifstream ifs;
	ifs.open(FILENAME, ios::in);
 
	int id;
	string name;
	int dId;
	
	int index = 0;
	while (ifs >> id && ifs >> name && ifs >> dId)
	{
		Worker * worker = NULL;
		//根据不同的部门Id创建不同对象
		if (dId == 1)  // 1普通员工
		{
			worker = new Employee(id, name, dId);
		}
		else if (dId == 2) //2经理
		{
			worker = new Manager(id, name, dId);
		}
		else //总裁
		{
			worker = new Boss(id, name, dId);
		}
		//存放在数组中
		this->m_EmpArray[index] = worker;
		index++;
	}
}

在职工管理源文件的构造函数中添加在堆区开辟空间创建worker指针类型数组代码;调用init初始化函数将文件中数据存放在数组中,用for循环遍历数组打印出数组内数据元素,测试从文件中获取初始化数据。

//根据职工数创建数组
this->m_EmpArray = new Worker * [this->m_EmpNum];
//初始化职工
init_Emp();

//测试初始化数据
for (int i = 0; i < m_EmpNum; i++)
{
	cout << "职工号: " << this->m_EmpArray[i]->m_Id
		<< " 职工姓名: " << this->m_EmpArray[i]->m_Name
		<< " 部门编号: " << this->m_EmpArray[i]->m_DeptId << endl;
}
运行结果

七、显示功能

在职工管理源文件中添加显示职工函数Show_Emp,用for循环遍历数组,利用多态调用员工,经理,老板三个对象的成员函数ShowInfo(),实现职工个人信息的显示,并在主函数中添加显示职工接口。

//显示职工
void WorkerManager::Show_Emp()
{
	if (this->m_FileIsEmpty)
	{
		cout << "文件不存在或记录为空!" << endl;
	}
	else
	{
		for (int i = 0; i < m_EmpNum; i++)
		{
			//利用多态调用接口
			this->m_EmpArray[i]->showInfo();
		}
	}
 
	system("pause");
	system("cls");
}

运行结果:

八、删除职工

代码实现

执行删除操作前先在职工管理源文件添加判断职工是否存在的函数,用for循环遍历数组中的所有元素,判断数组中的职工编号是否与传入的职工编号一样,如果一样,用index记录此时职工编号并返回index;如果不一样,表示传入的这个职工不存在,无法进行删除操作,返回index值为-1,结束函数调用。

int WorkerManager::IsExist(int id)
{
	int index = -1;
 
	for (int i = 0; i < this->m_EmpNum; i++)
	{
		if (this->m_EmpArray[i]->m_Id == id)
		{
			index = i;
 
			break;
		}
	}
 
	return index;
}


在职工管理源文件中添加删除职工函数,键盘录入要删除职工的编号,调用判断职工是否存在函数将index返回;用if语句判断index值是否为-1,如果不是,表示职工存在,执行删除操作:用for循环遍历数组,将数组数据前移实现删除操作,并更新数组中记录人员的个数;调用save函数将删除后数组内容同步更新到文件中。

//删除职工
void WorkerManager::Del_Emp()
{
	if (this->m_FileIsEmpty)
	{
		cout << "文件不存在或记录为空!" << endl;
	}
	else
	{
		//按职工编号删除
		cout << "请输入想要删除的职工号:" << endl;
		int id = 0;
		cin >> id;
 
		int index = this->IsExist(id);
 
		if (index != -1)  //说明index上位置数据需要删除
		{
			for (int i = index; i < this->m_EmpNum - 1; i++)
			{
				this->m_EmpArray[i] = this->m_EmpArray[i + 1];
			}
			this->m_EmpNum--;
 
			this->save(); //删除后数据同步到文件中
			cout << "删除成功!" << endl;
		}
		else
		{
			cout << "删除失败,未找到该职工" << endl;
		}
	}
	
	system("pause");
	system("cls");
}

运行结果

删除前显示职工信息

执行删除操作

删除后显示成员信息

文件中该职工也被删除

九、修改功能

代码实现

在职工管理源文件中添加修改职工函数,先用if语句判断文件是否存在,如果存在,键盘录入要修改的职工的编号,与删除操作一样调用输入编号是否存在函数判断键盘录入编号是否存在,
如果返回值结果是-1,证明输入编号不存在,结束函数调用;
如果返回值不是-1,将输入位置的职工信息先删除delete,定义新的变量:编号,姓名,职位;重新键盘录入补全信息;
由于修改后的职工岗位可能和修改前不同,所以要重新建立woker指针置空,用switch语句建立三个岗位的选择,分别用新建立的worker指针维护在堆区建立新的空间存放的修改后的职工信息
更改数据,将worker指针维护的新职工数据更改到数组中;最后调用save函数将修改后数组内容同步更新到文件中。

//修改职工
void WorkerManager::Mod_Emp()
{
	if (this->m_FileIsEmpty)
	{
		cout << "文件不存在或记录为空!" << endl;
	}
	else
	{
		cout << "请输入修改职工的编号:" << endl;
		int id;
		cin >> id;
 
		int ret = this->IsExist(id);
		if (ret != -1)
		{ 
			//查找到编号的职工
 
			delete this->m_EmpArray[ret];
			
			int newId = 0;
			string newName = "";
			int dSelect = 0;
 
			cout << "查到: " << id << "号职工,请输入新职工号: " << endl;
			cin >> newId;
 
			cout << "请输入新姓名: " << endl;
			cin >> newName;
 
			cout << "请输入岗位: " << endl;
			cout << "1、普通职工" << endl;
			cout << "2、经理" << endl;
			cout << "3、老板" << endl;
			cin >> dSelect;
 
			Worker * worker = NULL;
			switch (dSelect)
			{
			case1:
				worker = new Employee(newId, newName, dSelect);
				break;
			case2:
				worker = new Manager(newId, newName, dSelect);
				break;
			case 3:
				worker = new Boss(newId, newName, dSelect);
				break;
			default:
				break;
			}
 
			//更改数据 到数组中
			this->m_EmpArray[ret]= worker;
			
			cout << "修改成功!" << endl;
 
			//保存到文件中
			this->save();
		}
		else
		{
			cout << "修改失败,查无此人" << endl;
		}
	}
 
	//按任意键 清屏
	system("pause");
	system("cls");
}
 

运行结果

修改后显示职工信息:

十、查找功能

在职工管理源文件中添加查找职工函数,首先判断文件是否存在,存在后定义整型变量select并初始化为0,键盘录入两种选择1、按职工编号查找;2、按姓名查找。

if (this->m_FileIsEmpty)
{
	cout << "文件不存在或记录为空!" << endl;
}
else
{
	cout << "请输入查找的方式:" << endl;
	cout << "1、按职工编号查找" << endl;
	cout << "2、按姓名查找" << endl;

	int select = 0;
	cin >> select;

1.按职工编号查找


如果选择按职工编号查找,根据职工在数组中的位置直接调用该类的展示信息成员函数实现对职工信息的查找;

if (select == 1) 
{
	int id;
	cout << "请输入查找的职工编号:" << endl;
	cin >> id;

	int ret = IsExist(id);
	if (ret != -1)
	{
		cout << "查找成功!该职工信息如下:" << endl;
		this->m_EmpArray[ret]->showInfo();
	}
	else
	{
		cout << "查找失败,查无此人" << endl;
	}
}

2.按职工姓名查找


如果选择按姓名查找,利用for循环遍历数组直至输入姓名与数组内某一职工的姓名属性一样,再调用该职工的展示信息成员函数,实现查找目的。

else if (select == 2) 
{
	string name;
	cout << "请输入查找的姓名:" << endl;
	cin >> name;

	bool flag = false;  //查找到的标志
	for (int i = 0; i < m_EmpNum; i++)
	{
		if (m_EmpArray[i]->m_Name == name)
		{
			cout << "查找成功,职工编号为:"
				<< m_EmpArray[i]->m_Id
				<< " 号的信息如下:" << endl;

			flag = true;

			this->m_EmpArray[i]->showInfo();
		}
	}
	if (flag == false)
	{
		//查无此人
		cout << "查找失败,查无此人" << endl;
	}
}


由于可能会出现相同姓名的职工,在按姓名查找的循环时不能在找到一个姓名正确的职工就结束循环,需遍历整个职工数组。

运行结果

按姓名查找

按编号查找

十一、排序

代码实现

在职工管理源文件中添加排序函数,提供两种排序方式进行选择:1、按职工号升序;2、按职工号降序

利用for循环遍历数组所有职工,定义一个整型变量记录最大值或最小值;再写出一个for循环令循环体变量j=i+1;在循环体内判断选择的排序方式。
如果用升序的方式,判断位置为i的编号是否比位置为j的编号大,如果是,将j赋值给最小值;然后继续循环,直至遍历整个数组,排序成功。
如果用降序的方式,判断位置为i的编号是否比位置为j的编号小,如果是,将j赋值给最大值;然后继续循环,直至遍历整个数组,排序成功。
判定一开始认定的最小值或最大值是否是计算的最小值或最大值,如果不是,交换数据。
最后将排序后的结果保存到文件中。

//排序职工
void WorkerManager::Sort_Emp()
{
	if (this->m_FileIsEmpty)
	{
		cout << "文件不存在或记录为空" << endl;
		system("pause");
		system("cls");
	}
	else
	{
		cout << "请选择排序方式: " << endl;
		cout << "1、按职工号进行升序" << endl;
		cout << "2、按职工号进行降序" << endl;

		int select = 0;
		cin >> select;


		for (int i = 0; i < m_EmpNum; i++)
		{
			int minOrMax = i;
			for (int j = i + 1; j < m_EmpNum; j++)
			{
				if (select == 1) //升序
				{
					if (m_EmpArray[minOrMax]->m_Id > m_EmpArray[j]->m_Id)
					{
						minOrMax = j;
					}
				}
				else if(select == 2)
				{
					if (m_EmpArray[minOrMax]->m_Id < m_EmpArray[j]->m_Id)
					{
						minOrMax = j;
					}
				}
				else
				{
					cout << "排序失败" << endl;
				}
			}

			if (i != minOrMax)
			{
				Worker* temp = m_EmpArray[i];
				m_EmpArray[i] = m_EmpArray[minOrMax];
				m_EmpArray[minOrMax] = temp;
			}

		}

		cout << "排序成功,排序后结果为:" << endl;
		this->save();
		this->Show_Emp();
	}

}

运行结果

排序前:

升序:

降序:

十二、清空文件

代码实现

在职工管理源文件中添加清空文件函数,提供选择键确认,对应select变量的值为1
打开模式ios::trunc表示如果存文件,删除文件并重新创建,实现清空功能。
利用for循环遍历整个数组将数组内的成员删除;置空数组指针并初始化记录人数变量为0和布尔变量FileIsEmpty为true。

//清空文件
void WorkerManager::Clean_File()
{
	cout << "确认清空?" << endl;
	cout << "1、确认" << endl;
	cout << "2、返回" << endl;
 
	int select = 0;
	cin >> select;
 
	if (select == 1)
	{
		//打开模式 ios::trunc 如果存在删除文件并重新创建
		ofstream ofs(FILENAME, ios::trunc);
		ofs.close();
 
		if (this->m_EmpArray != NULL)
		{
            for (int i = 0; i < this->m_EmpNum; i++)
			{
				if (this->m_EmpArray[i] != NULL)
				{
					delete this->m_EmpArray[i];
				}
			}
			this->m_EmpNum = 0;
			delete[] this->m_EmpArray;
			this->m_EmpArray = NULL;
			this->m_FileIsEmpty = true;
		}
		cout << "清空成功!" << endl;
	}
 
	system("pause");
	system("cls");
}

运行结果

执行清空操作

清空后显示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值