示范程式-DOS版的简单联系簿

当我整理古老文件的时候挖出了18年前设计的DOS版的简单联系簿程式的时候,不禁感叹岁月不留人。为了避免这古老的程式湮灭在漫漫的时间长河里,我决定把它贴在网站大公开,权当教学样本了。

由于MS-DOS 6.22以及QuickBASIC实在太久远了,Windows XP 32位版也许还能直接运行由QuickBASCI创造出来的16位程式,但64位版的Windows上干脆只能用虚拟机器(Virtual PC)或者DOSBox了。

*虚拟机器中运行程式的效果

废话表过,言归正传,让我们看看这古老程式的源码。

该程式用QuickBASIC编写,储存为BAS文件。

' Contribute by Republic of Galaxy Community (Malaysia) at 1999
' Undertake by Hidden Laboratory Community (Malaysia) at 2009
' 星海共和国社区(马来西亚)呈现于1999年
' 由被隐藏的实验室(马来西亚)承续于2009年
' 
' Program Name: Simple Contact Book for DOS
' 程式名称:DOS版简单联系簿
'
' English:
' This sample is for education purpose, demonstrate
' how to save variable's into CSV text file.
' you may free to use, distribute and modify.
'
' Chinese (GB2312):
' 此样本用于教育目的,示范如何把那些变量储存进CSV文本文件。
' 你可以自由的使用、分发以及修改。

' --- this area generate by Microsoft QuickBASIC ---
' --- 这区域是由微软QuickBASIC生成的 ---
DECLARE SUB WelcomeMessage (TotalRecord%)
DECLARE SUB DisplayBoard (vName$, vTel$, vEmail$, vRoad$, vPostcode$, vTown$, vState$, RecordNo%)
DECLARE SUB InputRecord (MyFile$)
DECLARE FUNCTION KeyPressed! ()
' --- end of auto generate ---
' --- 自动生成结束 ---

' declare some variable
' 宣告一些变量
DIM i%
DIM MyName$, Tel$, Email$, Road$, Postcode$, Town$, State$
DIM m%, n%
DIM WelcomeFlag, InnerEnd, LoopEnd, GrandEnd, ProgramEnd
DIM FileName$

' Setup target file
' 设置目标文件
FileName$ = "record1.csv"
' Program start...
' 程式开始。。。
CLS
' Auto create blank file if target file no existed
' 当目标文件不存在,自动创造空白文件
OPEN FileName$ FOR APPEND AS #1
CLOSE #1
LOCATE 11, 25
PRINT "Please wait..."
WelcomeFlag = -1
ProgramEnd = 0
WHILE NOT ProgramEnd
	i% = 0
	OPEN FileName$ FOR INPUT AS #1
	' Loading file into memory
	' 加载文件到记忆
	WHILE NOT EOF(1)
		i% = i% + 1
		INPUT #1, MyName$(i%), Tel$(i%), Email$(i%), Road$(i%), Postcode$(i%), Town$(i%), State$(i%)
	WEND
	CLOSE #1
	' if WelcomeFlag is true, call the welcome message
	' 若WelcomeFlag为真,呼叫欢迎信息
	IF WelcomeFlag THEN CALL WelcomeMessage(i%)
	' Set WelcomeFlag as false
	' 设置WelcomeFlag为贾
	WelcomeFlag = 0
	' Call that display board subroutine
	' 呼叫展示板子程序
	CALL DisplayBoard(MyName$(i%), Tel$(i%), Email$(i%), Road$(i%), Postcode$(i%), Town$(i%), State$(i%), i%)

	GrandEnd = 0
	WHILE NOT GrandEnd
		LoopEnd = 0
		WHILE NOT LoopEnd
			SELECT CASE KeyPressed
				' When ENTER key pressed
				' 当 ENTER 键被按下
				CASE 13
					CALL InputRecord(FileName$)
					LoopEnd = -1
					GrandEnd = -1
				' When ESC key pressed
				' 当 ESC 键被按下
				CASE 27
					LoopEnd = -1
					GrandEnd = -1
					ProgramEnd = -1
				' When + key pressed
				' 当 + 键被按下
				CASE 43
					m% = m% + 1
					IF m% > i% THEN
						m% = 1
					END IF
					CALL DisplayBoard(MyName$(m%), Tel$(m%), Email$(m%), Road$(m%), Postcode$(m%), Town$(m%), State$(m%), m%)
				' When - key pressed
				' 当 - 键被按下
				CASE 45
					m% = m% - 1
					IF m% < 1 THEN m% = i% END IF CALL DisplayBoard(MyName$(m%), Tel$(m%), Email$(m%), Road$(m%), Postcode$(m%), Town$(m%), State$(m%), m%) ' When X key pressed ' 当 X 键被按下 CASE 88, 120 LOCATE 21, 1 PRINT "Delete the record?(Y/N)" InnerEnd = 0 WHILE NOT InnerEnd SELECT CASE KeyPressed ' When Y key pressed ' 当 Y 键被按下 CASE 89, 121 ' Make current variable to empty if wish to delete current contact record ' 把想要删除的当前联系纪录的变量变成空 MyName$(m%) = "" OPEN FileName$ FOR OUTPUT AS #1 FOR n% = 0 TO i% ' Only variable MyNames$ with content will rewrite into CSV text file ' Record wish to delete has been exclude from write back ' 只有有内容的变量MyNames$才会被重写进CSV文本文件 ' 想要删除的纪录将会被排除在外不会写回 IF LEN(MyName$(n%)) > 0 THEN
										WRITE #1, MyName$(n%), Tel$(n%), Email$(n%), Road$(n%), Postcode$(n%), Town$(n%), State$(n%)
									END IF
								NEXT
								CLOSE #1
								LOCATE 22, 1
								PRINT "Deleting completed!"
								SLEEP 2
								InnerEnd = -1
								LoopEnd = -1
								GrandEnd = -1
								' Erase all content inside variable
								' Because variable GrandEnd has been set to true
								' They will go back to loop and reload new record from CSV file
								' 删除全部变量中的内容
								' 由于变量GrandEnd已经设置为真
								' 将会回到循环并重新自CSV文件加载
								ERASE MyName$, Tel$, Email$, Road$, Postcode$, Town$, State$
							' When N key pressed
							' 当 N 键被按下
							CASE 78, 110
								CALL DisplayBoard(MyName$(m%), Tel$(m%), Email$(m%), Road$(m%), Postcode$(m%), Town$(m%), State$(m%), m%)
								InnerEnd = -1
						END SELECT
					WEND
			END SELECT
		WEND
	WEND
WEND
CLS
END
' Program End...
' 程式结束。。。

SUB DisplayBoard (vName$, vTel$, vEmail$, vRoad$, vPostcode$, vTown$, vState$, RecordNo%)
' Subroutine to display main page
' 展示主页的子程序
	CLS
	LOCATE 2, 1
	PRINT "Name: "; vName$
	LOCATE 4, 1
	PRINT "Telephone: "; vTel$
	LOCATE 6, 1
	PRINT "E-Mail: "; vEmail$
	LOCATE 8, 1
	PRINT "Address:"
	LOCATE 10, 10
	PRINT vRoad$
	LOCATE 12, 10
	PRINT vPostcode$
	LOCATE 14, 10
	PRINT vTown$
	LOCATE 16, 10
	PRINT vState$
	LOCATE 18, 1
	PRINT "Record Number:"; RecordNo%
	LOCATE 23, 1
	PRINT "<Exit=ESC> <Seek=+ or -> <Input=ENTER> <Delete=x>"
END SUB

SUB InputRecord (MyFile$)
' Subroutine to enter new contact
' 输入新联系的子程序
	' Declare some variable for this subroutine
	' 宣告一些变量于这个子程序
	DIM uName$, uTel$, uEmail$, uRoad$, uPostcode$, uTown$, uState$
	DIM vName$, vTel$, vEmail$, vRoad$, vPostcode$, vTown$, vState$
	DIM LoopEnd, FlagEnd

	FlagEnd = 0
	WHILE NOT FlagEnd
		CLS
		LOCATE 2, 10
		PRINT "Process record..."
		LOCATE 4, 10
		LINE INPUT "Name: "; vName$
		LOCATE 6, 10
		LINE INPUT "Telephone number: "; vTel$
		LOCATE 8, 10
		LINE INPUT "E-mail: "; vEmail$
		LOCATE 10, 10
		PRINT "Address"
		LOCATE 10, 20
		LINE INPUT "Road: "; vRoad$
		LOCATE 12, 20
		LINE INPUT "Postcode: "; vPostcode$
		LOCATE 14, 20
		LINE INPUT "Town: "; vTown$
		LOCATE 16, 20
		LINE INPUT "State: "; vState$
		' Convert all inputed data to capital character or small capital character
		' 把全部所输入的数据转成大号字或小号字
		uName$ = UCASE$(vName$)
		uTel$ = UCASE$(vTel$)
		uEmail$ = LCASE$(vEmail$)
		uRoad$ = UCASE$(vRoad$)
		uPostcode$ = UCASE$(vPostcode$)
		uTown$ = UCASE$(vTown$)
		uState$ = UCASE$(vState$)
		LOCATE 22, 10
		PRINT "Save Record?(Y/N)"
		LoopEnd = 0
		WHILE NOT LoopEnd
			SELECT CASE KeyPressed
				' When Y key pressed
				' 当 Y 键被按下
				CASE 89, 121
					' Write and add all inputed data into CSV text file
					OPEN MyFile$ FOR APPEND AS #1
					WRITE #1, uName$, uTel$, uEmail$, uRoad$, uPostcode$, uTown$, uState$
					CLOSE #1
					LoopEnd = -1
				' When N key pressed
				' 当 N 键被按下
				CASE 78, 110
					LoopEnd = -1
			END SELECT
		WEND
		LOCATE 23, 10
		PRINT "Continue to Input?(Y/N)"
		LoopEnd = 0
		WHILE NOT LoopEnd
			SELECT CASE KeyPressed
				' When Y key pressed
				' 当 Y 键被按下
				CASE 89, 121
					LoopEnd = -1
				' When N key pressed
				' 当 N 键被按下
				CASE 78, 110
					FlagEnd = -1
					LoopEnd = -1
			END SELECT
		WEND
		CLS
	WEND
END SUB

FUNCTION KeyPressed
' function to capture signal from keyboard
' 捕捉键盘讯号的功能
	DIM ScanKey$
	ScanKey$ = INKEY$
	IF ScanKey$ <> "" THEN
		' Transform keyboard signal to integer ASCII number
		' 转换键盘讯号到ASCII整数号码
		KeyPressed = ASC(ScanKey$)
		ScanKey$ = ""
	ELSE
		KeyPressed = 0
	END IF
END FUNCTION

SUB WelcomeMessage (TotalRecord%)
' Subroutine to display welcome message
' 展示欢迎信息的子程序
	CLS
	PRINT "Simple Contact Book for DOS 1.6"
	PRINT "Hidden Laboratory Community 1999"
	LOCATE 22, 1
	PRINT "Total record is "; TotalRecord%
	LOCATE 23, 1
	PRINT "Please any key to continue"
	LOCATE 23, 1
	PRINT "Please any key to continue"
	WHILE INKEY$ = ""
	WEND
END SUB

只是啊,一部份超有钱的用户使用的电脑高于Intel Pentium 4,更大的记忆体,最新的操作系统Windows 10,绝对不可能安装到虚拟机器,DOSBox也不是什么人都会配置。所以对他们来说运行QuickBASIC几乎不可能。

不用担心!我为了这个情形把这古老的程式给“进化”成Visual BASIC 2015.Net了,大家可以花几个月的时间下载社区版Visual Studio 2015.Net ISO文件并安装到电脑然后试试运行以下的代码,或花一点钱拜托大城市的人寄DVD光盘来。

(社区版Visual Studio 2017.Net目前没有ISO文件,依靠微软安装器下载的话以马来西亚网络的状态几乎是不可能的任务。)

*复刻版的64位复古程式

就像图片展示的效果那样,外表看起来虽然与DOS版的程式毫无差别,但内核可是.Net架构驱动且64位的,无法运行在真正的MS-DOS环境里。

' Contribute by Republic of Galaxy Community (Malaysia) at 1999
' Undertake by Hidden Laboratory Community (Malaysia) at 2009
' 星海共和国社区(马来西亚)呈现于1999年
' 由被隐藏的实验室(马来西亚)承续于2009年
' 
' Program Name: Simple Contact Book for Windows Console (Remastered 2017)
' 程式名称:Windows提示符版简单联系簿(2017年复刻版)
'
' English:
' This retro program is for education purpose, and has been 
' evolved from QuickBASIC to Visual BASIC.Net 2015
' same as previous version, this program demonstrate
' how to save variable's into CSV text file
' you may free to use, distribute and modify.
'
' Chinese (GB2312):
' 此复古程式用于教育目的,已经从
' QuickBASIC进化到Visual BASIC.Net 2015
' 与之前的版本一样,这程式示范如何把那些变量储存进CSV文本文件。
' 你可以自由的使用、分发以及修改。

Module Module1

    Sub Main()
        ' declare some variable
        ' 宣告一些变量
        Dim i%, m%, n%, LoadNumber%
        Dim WelcomeFlag, InnerEnd, LoopEnd, GrandEnd, ProgramEnd As Boolean
        Dim FileName$
        Dim MyField$()
        ' Setup target file
        ' 设置目标文件
        FileName$ = "record1.csv"
        ' Program start...
        ' 程式开始。。。
        System.Console.Clear()
        ' Auto create blank file if target file no existed
        ' 当目标文件不存在,自动创造空白文件
        FileSystem.FileOpen(1, FileName$, OpenMode.Append)
        FileSystem.FileClose(1)
        System.Console.SetCursorPosition(24, 10)
        System.Console.Write("Please wait...")
        WelcomeFlag = True
        ProgramEnd = False
        While Not ProgramEnd
            ' Because INPUT statement at VB.Net is different behavior 
            ' with QuickBASIC, so INPUT statement no longer used in
            ' this program
            ' 由于VB.Net里的INPUT声明与QuickBASIC的INPUT声明行为有差异
            ' 所以本程式不再使用INPUT声明
            Dim MyReader As New FileIO.TextFieldParser(FileName$)
            MyReader.TextFieldType = FileIO.FieldType.Delimited
            MyReader.SetDelimiters(",")
            MyReader.HasFieldsEnclosedInQuotes = True
            i% = IO.File.ReadAllLines(FileName$).Length
            ' After established text field parser and get lines count number
            ' assign variable with number of dimension according lines count number
            ' 建立完文本字段解析器并获得行数之后
            ' 根据行数给变量分配维数
            Dim MyName$(i%)
            Dim Tel$(i%)
            Dim Email$(i%)
            Dim Road$(i%)
            Dim Postcode$(i%)
            Dim Town$(i%)
            Dim State$(i%)
            ' Loading file into memory
            ' 加载文件到记忆
            For LoadNumber% = 1 To i% Step 1
                MyField$ = MyReader.ReadFields()
                MyName$(LoadNumber%) = MyField$(0)
                Tel$(LoadNumber%) = MyField$(1)
                Email$(LoadNumber%) = MyField$(2)
                Road$(LoadNumber%) = MyField$(3)
                Postcode$(LoadNumber%) = MyField$(4)
                Town$(LoadNumber%) = MyField$(5)
                State$(LoadNumber%) = MyField$(6)
            Next
            MyReader.Close()
            ' if WelcomeFlag is true, call the welcome message
            ' 若WelcomeFlag为真,呼叫欢迎信息
            If WelcomeFlag Then Call WelcomeMessage(i%)
            ' Set WelcomeFlag as false
            ' 设置WelcomeFlag为贾
            WelcomeFlag = False
            ' Call that display board subroutine
            ' 呼叫展示板子程序
            Call DisplayBoard(MyName$(i%), Tel$(i%), Email$(i%), Road$(i%), Postcode$(i%), Town$(i%), State$(i%), i%)

            GrandEnd = False
            While Not GrandEnd
                LoopEnd = False
                While Not LoopEnd
                    If System.Console.KeyAvailable Then
                        Select Case System.Console.ReadKey(True).Key
                            ' When ENTER key pressed
                            ' 当 ENTER 键被按下
                            Case System.ConsoleKey.Enter
                                Call InputRecord(FileName$)
                                LoopEnd = True
                                GrandEnd = True
                            ' When ESC key pressed
                            ' 当 ESC 键被按下
                            Case System.ConsoleKey.Escape
                                LoopEnd = True
                                GrandEnd = True
                                ProgramEnd = True
                            ' When + key pressed
                            ' 当 + 键被按下
                            Case System.ConsoleKey.Add
                                m% = m% + 1
                                If m% > i% Then
                                    m% = 1
                                End If
                                Call DisplayBoard(MyName$(m%), Tel$(m%), Email$(m%), Road$(m%), Postcode$(m%), Town$(m%), State$(m%), m%)
                            ' When - key pressed
                            ' 当 - 键被按下
                            Case System.ConsoleKey.Subtract
                                m% = m% - 1
                                If m% < 1 Then m% = i% End If Call DisplayBoard(MyName$(m%), Tel$(m%), Email$(m%), Road$(m%), Postcode$(m%), Town$(m%), State$(m%), m%) ' When X key pressed ' 当 X 键被按下 Case System.ConsoleKey.X System.Console.SetCursorPosition(0, 20) System.Console.Write("Delete the record?(Y/N)") InnerEnd = False While Not InnerEnd If System.Console.KeyAvailable Then Select Case System.Console.ReadKey(True).Key ' When Y key pressed ' 当 Y 键被按下 Case System.ConsoleKey.Y ' Make current variable to empty if wish to delete current contact record ' 把想要删除的当前联系纪录的变量变成空 MyName$(m%) = "" FileSystem.FileOpen(1, FileName$, OpenMode.Output) For n% = 0 To i% ' Only variable MyNames$ with content will rewrite into CSV text file ' Record wish to delete has been exclude from write back ' 只有有内容的变量MyNames$才会被重写进CSV文本文件 ' 想要删除的纪录将会被排除在外不会写回 If Len(MyName$(n%)) > 0 Then
                                                        FileSystem.WriteLine(1, MyName$(n%), Tel$(n%), Email$(n%), Road$(n%), Postcode$(n%), Town$(n%), State$(n%))
                                                    End If
                                                Next
                                                FileSystem.FileClose(1)
                                                System.Console.SetCursorPosition(0, 21)
                                                System.Console.Write("Deleting completed!")
                                                System.Threading.Thread.Sleep(2000)
                                                InnerEnd = True
                                                LoopEnd = True
                                                GrandEnd = True
                                                ' Erase all content inside variable
                                                ' Because variable GrandEnd has been set to true
                                                ' They will go back to loop and reload new record from CSV file
                                                ' 删除全部变量中的内容
                                                ' 由于变量GrandEnd已经设置为真
                                                ' 将会回到循环并重新自CSV文件加载
                                                Erase MyName$, Tel$, Email$, Road$, Postcode$, Town$, State$
                                                ' When N key pressed
                                                ' 当 N 键被按下
                                            Case System.ConsoleKey.N
                                                Call DisplayBoard(MyName$(m%), Tel$(m%), Email$(m%), Road$(m%), Postcode$(m%), Town$(m%), State$(m%), m%)
                                                InnerEnd = True
                                        End Select
                                    End If
                                End While
                        End Select
                    End If
                End While
            End While
        End While
        System.Console.Clear()
        End
        ' Program End...
        ' 程式结束。。。

    End Sub

    Sub DisplayBoard(vName$, vTel$, vEmail$, vRoad$, vPostcode$, vTown$, vState$, RecordNo%)
        ' Subroutine to display main page
        ' 展示主页的子程序
        System.Console.Clear()
        System.Console.SetCursorPosition(0, 1)
        System.Console.Write("Name: {0}", vName$)
        System.Console.SetCursorPosition(0, 3)
        System.Console.Write("Telephone: {0}", vTel$)
        System.Console.SetCursorPosition(0, 5)
        System.Console.Write("E-Mail: {0}", vEmail$)
        System.Console.SetCursorPosition(0, 7)
        System.Console.Write("Address:")
        System.Console.SetCursorPosition(9, 9)
        System.Console.Write(vRoad$)
        System.Console.SetCursorPosition(9, 11)
        System.Console.Write(vPostcode$)
        System.Console.SetCursorPosition(9, 13)
        System.Console.Write(vTown$)
        System.Console.SetCursorPosition(9, 15)
        System.Console.Write(vState$)
        System.Console.SetCursorPosition(0, 17)
        System.Console.Write("Record Number: {0}", RecordNo%)
        System.Console.SetCursorPosition(0, 22)
        System.Console.Write("<Exit=ESC> <Seek=+ or -> <Input=ENTER> <Delete=x>")
    End Sub

    Sub InputRecord(MyFile$)
        ' Subroutine to enter new contact
        ' 输入新联系的子程序
        ' Declare some variable for this subroutine
        ' 宣告一些变量于这个子程序
        Dim uName$, uTel$, uEmail$, uRoad$, uPostcode$, uTown$, uState$
        Dim vName$, vTel$, vEmail$, vRoad$, vPostcode$, vTown$, vState$
        Dim LoopEnd, FlagEnd

        FlagEnd = False
        While Not FlagEnd
            System.Console.Clear()
            System.Console.SetCursorPosition(9, 1)
            System.Console.Write("Process record...")
            System.Console.SetCursorPosition(9, 3)
            System.Console.Write("Name: ")
            vName$ = System.Console.ReadLine()
            System.Console.SetCursorPosition(9, 5)
            System.Console.Write("Telephone number: ")
            vTel$ = System.Console.ReadLine()
            System.Console.SetCursorPosition(9, 7)
            System.Console.Write("E-mail: ")
            vEmail$ = System.Console.ReadLine()
            System.Console.SetCursorPosition(9, 9)
            System.Console.Write("Address")
            System.Console.SetCursorPosition(19, 9)
            System.Console.Write("Road: ")
            vRoad$ = System.Console.ReadLine()
            System.Console.SetCursorPosition(19, 11)
            System.Console.Write("Postcode: ")
            vPostcode$ = System.Console.ReadLine()
            System.Console.SetCursorPosition(19, 13)
            System.Console.Write("Town: ")
            vTown$ = System.Console.ReadLine()
            System.Console.SetCursorPosition(19, 15)
            System.Console.Write("State: ")
            vState$ = System.Console.ReadLine()
            ' Convert all inputed data to capital character or small capital character
            ' 把全部所输入的数据转成大号字或小号字
            uName$ = UCase(vName$)
            uTel$ = UCase(vTel$)
            uEmail$ = LCase(vEmail$)
            uRoad$ = UCase(vRoad$)
            uPostcode$ = UCase(vPostcode$)
            uTown$ = UCase(vTown$)
            uState$ = UCase(vState$)
            System.Console.SetCursorPosition(9, 21)
            System.Console.Write("Save Record?(Y/N)")
            LoopEnd = False
            While Not LoopEnd
                If System.Console.KeyAvailable Then
                    Select Case System.Console.ReadKey(True).Key
                        ' When Y key pressed
                        ' 当 Y 键被按下
                        Case System.ConsoleKey.Y
                            ' Write and add all inputed data into CSV text file
                            ' 把所有输入内容写进CSV文本文件
                            FileSystem.FileOpen(1, MyFile$, OpenMode.Append)
                            FileSystem.WriteLine(1, uName$, uTel$, uEmail$, uRoad$, uPostcode$, uTown$, uState$)
                            FileSystem.FileClose(1)
                            LoopEnd = True
                        ' When N key pressed
                        ' 当 N 键被按下
                        Case System.ConsoleKey.N
                            LoopEnd = True
                    End Select
                End If
            End While
            System.Console.SetCursorPosition(9, 22)
            System.Console.Write("Continue to Input?(Y/N)")
            LoopEnd = False
            While Not LoopEnd
                If System.Console.KeyAvailable Then
                    Select Case System.Console.ReadKey(True).Key
                        ' When Y key pressed
                        ' 当 Y 键被按下
                        Case System.ConsoleKey.Y
                            LoopEnd = True
                        ' When N key pressed
                        ' 当 N 键被按下
                        Case System.ConsoleKey.N
                            FlagEnd = True
                            LoopEnd = True
                    End Select
                End If
            End While
            System.Console.Clear()
        End While
    End Sub

    Sub WelcomeMessage(TotalRecord%)
        ' Subroutine to display welcome message
        ' 展示欢迎信息的子程序
        System.Console.Clear()
        System.Console.Write("Simple Contact Book for Windows Console 1.6")
        System.Console.Write("Hidden Laboratory Community 2017")
        System.Console.SetCursorPosition(0, 21)
        System.Console.Write("Total record is {0}", TotalRecord%)
        System.Console.SetCursorPosition(0, 22)
        System.Console.Write("Please any key to continue")
        System.Console.ReadKey(True)
    End Sub

End Module

同一个古老程式,两种年代相差18年的代码,呵呵,你们可以从中学习一下BASIC系列语言的进化方向。

发表评论

电子邮件地址不会被公开。 必填项已用*标注