永利最大(官方)网站

用 Silverlight 开发围棋在线对弈程序(一)UI 雏形

转帖|其它|编辑:郝浩|2009-03-31 09:44:02.000|阅读 533 次

概述:如何在 Silverlight下创建,开发图形棋盘问题。

#慧都22周年庆大促·界面/图表报表/文档/IDE/IOT/测试等千款热门软控件火热促销中>>

Silverlight 开发围棋在线对弈程序

作者: Neil Chen

第一部分:UI雏形

首先,介绍下围棋的简单规则:黑白双方交替落子,以占据棋盘上交叉点多者为胜。同时,双方为了争夺地盘,可能会发生“对杀”。一个棋子周围接触的空白交叉点数目叫做“气”,如果一个或多个棋子周围的气都被对方封死,气数=0,则这些棋子就称为死棋,需要从棋盘上移去。

一个围棋棋谱大致如下图所示(截图自Tom围棋网站):
wq1.png

在上图中,棋子上的数字一般在棋谱中显示,用于帮助了解棋局进行的次序。

下面我们来尝试用 Silverlight 2.0 开发一个围棋在线对弈程序。

首先,我们来创建围棋程序的 UI 部分。毕竟,这是最直观的东西。而且我喜欢边做边重构的开发方式,这样,不至于因为花了过多的时间做设计,而减慢了实际开发的进度。让我们先从一个小小的原型起步,然后不断的应用设计思维去改进它,最终达到目标。正如一部电影里的台词所说的:

Aim small, miss small.

好了,现在大概分析一下:

1.       我们打算在界面的左侧显示棋盘,而右侧是功能区域。

2.       棋盘是由19道横线,19道竖线,以及9个星位的标志组成的。为了方便查找棋盘上的位置,我们在棋盘的四周可能需要加上坐标。目前我们先只在左侧和上方加上坐标。右边和下面的位置留在那里。

对于棋盘的显示,我们打算用一个 Canvas 来实现。而其中的线条,圆点,棋子等视觉元素,只需往其中添加相应的 Line, Ellipse, Label 即可。

我们假定整个程序的大小为 800 * 600 (以后也许再考虑是否有必要支持任意比例的缩放)。现在,跟随直觉,我写了下面一些代码用于构建 UI:

Page.xaml:

<UserControl

       x:Class="WoodFoxWeiQi.UI.Page"

       xmlns="//schemas.microsoft.com/winfx/2006/xaml/presentation"

       xmlns:x="//schemas.microsoft.com/winfx/2006/xaml"

       Width="800"

       Height="600">

       <Grid

              x:Name="LayoutRoot"

              Background="White">

      &nbsp;  ;     <Grid.ColumnDefinitions>

 &nbsp;             ;      <ColumnDefinition

  &nbsp;                         Width="0.75*" />

                     <ColumnDefinition

               &nbsp;  &nbsp;         Width="0.25*" />

    &nbsp;     &nbsp;   </Grid.ColumnDefinitions>

&nbsp;    &nbsp;        <!-- 棋盘区域 -->

    &nbsp;  &nbsp;      <Border

           &nbsp;         Grid.Column="0">

         ;            <!-- 棋盘 -->

             &nbsp;       <Canvas

   &nbsp;                        x:Name="canvasBoard"

     ;  &nbsp;                    Background="LightYellow"

 &nbsp;                          Margin="10">

                &nbsp;    </Canvas>

              </Border>

       &nbsp;&nbsp;     <!-- 操作区域 -->

     &nbsp;        <Border

     ;                Grid.Column="1">

     &nbsp;               <StackPanel

             ;      &nbsp;        Margin="20"

      &nbsp;                     Orientation="Vertical">

         ;           &nbsp;      <Button

                                  x:Name="btnGo"

                     ;             Content="Go" />

                     </StackPanel>

    &nbsp;         </Border>

       </Grid>

</UserControl>

 

Page.xaml.cs:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

 

namespace WoodFoxWeiQi.UI

{

       public partial class Page : UserControl

       {

   &nbsp;          public Page()

   &nbsp;&nbsp;         {

         &nbsp;      ;     InitializeComponent();

 

       &nbsp;             canvasBoard.MouseLeftButtonDown += new MouseButtonEventHandler(canvasBoard_MouseLeftButtonDown);

&nbsp;                    canvasBoard.SizeChanged += new SizeChangedEventHandler(canvasBoard_SizeChanged);

 

              &nbsp;      btnGo.Click += new RoutedEventHandler(btnGo_Click);

         &nbsp;    }

 

   &nbsp;       ;   // 因为 Canvas 的尺寸是根据父控件的尺寸在运行时计算得到的,所以需要在 SizeChanged 方法里

  &nbsp;           // 才能获得其实际尺寸

       &nbsp;      void canvasBoard_SizeChanged(object sender, SizeChangedEventArgs e)

 &nbsp;            {

                  ; &nbsp; canvasBoard.Children.Clear();

&nbsp;                 ;   CreateBoardElements();

     ;         }

 

          &nbsp;   double boardSize;    // 棋盘宽度(不包含坐标)

              double cellSize;     // 网格宽度

        &nbsp;     double starSize;     // 星位的小圆点的直径

    &nbsp;         double stoneSize;    // 棋子直径

 

   ;           // 创建棋盘上的网格线,星位,坐标等显示元素

     &nbsp;    &nbsp;   private void CreateBoardElements()

    &nbsp;      &nbsp;  {

          &nbsp;          // 确保使用一个正方形区域作为棋盘显示区域

                  &nbsp;  boardSize = Math.Min(canvasBoard.ActualHeight, canvasBoard.ActualWidth);

 

                     // 根据棋盘尺寸计算出相应的其他尺寸

                ;     cellSize = boardSize / 20;

&nbsp;                 &nbsp;  starSize = cellSize / 4;

          &nbsp;      &nbsp;   stoneSize = cellSize * 0.8;

 

         &nbsp;         &nbsp; for (int i = 1; i <= 19; i++)

                   &nbsp; {

     &nbsp;                 &nbsp;   // 添加水平网格线

       ;                    var lineHorizontal = new Line();

   &nbsp;                       lineHorizontal.X1 = cellSize;

            &nbsp;  ;            lineHorizontal.X2 = cellSize * 19;

&nbsp;   &nbsp;         &nbsp;             lineHorizontal.Y1 = lineHorizontal.Y2 = cellSize * i;

 

                     &nbsp;     lineHorizontal.Stroke = new SolidColorBrush(Colors.Black);

        &nbsp;                  lineHorizontal.StrokeThickness = 1.0;

 

                           canvasBoard.Children.Add(lineHorizontal);

 

                           // 添加垂直网格线

                           var lineVertical = new Line();

                &nbsp;    ;      lineVertical.Y1 = cellSize;

                 &nbsp;         lineVertical.Y2 = cellSize * 19;

     &nbsp;                     lineVertical.X1 = lineVertical.X2 = cellSize * i;

 

        &nbsp;                  lineVertical.Stroke = new SolidColorBrush(Colors.Black);

                           lineVertical.StrokeThickness = 1.0;

 

          ;                 canvasBoard.Children.Add(lineVertical);

                     }

 

&nbsp;                 &nbsp;  // 添加9个星位的标志

            &nbsp;        for (int i = 4; i <= 16; i += 6)

&nbsp;    &nbsp;               {

                      &nbsp;    for (int j = 4; j <= 16; j += 6)

            &nbsp;         &nbsp;    {

    &nbsp;                    &nbsp;        double x = i * cellSize - starSize / 2;

         ;               &nbsp;         double y = j * cellSize - starSize / 2;

 

                        &nbsp;    ;     Ellipse ellipseStar = new Ellipse();

                 ;      &nbsp;          ellipseStar.Stroke = new SolidColorBrush(Colors.Black);

               ;      &nbsp;            ellipseStar.Fill = new SolidColorBrush(Colors.Black);

    &nbsp;            &nbsp;                ellipseStar.Width = ellipseStar.Height = starSize;

 ;                                 ellipseStar.SetValue(Canvas.LeftProperty, x);

          &nbsp;                       ellipseStar.SetValue(Canvas.TopProperty, y);

 

             &nbsp;                 &nbsp;  canvasBoard.Children.Add(ellipseStar);

                     ;      }

           &nbsp;         }

 

                   ;  // 画横坐标

       &nbsp;             for (int i = 1; i <= 19; i++)

           &nbsp;         {

                      &nbsp;    var txtLabel = new TextBlock();

          &nbsp;   &nbsp;            txtLabel.FontSize = 11.0;

   &nbsp;                       txtLabel.FontWeight = FontWeights.Thin;

                         ;  txtLabel.Text = i.ToString();

 

              ;            txtLabel.SetValue(Canvas.LeftProperty, i * cellSize - txtLabel.ActualWidth / 2);

                          txtLabel.SetValue(Canvas.TopProperty, cellSize / 2 - txtLabel.ActualHeight / 2);

&nbsp; &nbsp;                        txtLabel.Text = i.ToString();

 

                     ;      canvasBoard.Children.Add(txtLabel);

      &nbsp;              }

 

                   ;  // 画纵坐标

             &nbsp;       char c = 'A';

           &nbsp;         for (int i = 1; i <= 19; i++)

                &nbsp;    {

                     &nbsp;     var txtLabel = new TextBlock();

   &nbsp;       &nbsp;               txtLabel.FontSize = 11.0;

      &nbsp;                    txtLabel.FontWeight = FontWeights.Thin;

                   &nbsp;       txtLabel.Text = i.ToString();

 

                     &nbsp;    txtLabel.SetValue(Canvas.LeftProperty, cellSize / 2 - txtLabel.ActualWidth / 2);

                          txtLabel.SetValue(Canvas.TopProperty, i * cellSize - txtLabel.ActualHeight / 2);

                           txtLabel.Text = (c++).ToString();

 

       &nbsp;              &nbsp;    canvasBoard.Children.Add(txtLabel);

               &nbsp;     }

      &nbsp;     &nbsp; }

 

       &nbsp;      void canvasBoard_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

         &nbsp;    {

                ;     var pos = e.GetPosition(canvasBoard);

        &nbsp;        &nbsp;   MessageBox.Show("Clicked on board, X: " + pos.X + ", Y: " + pos.Y);

&nbsp;             }

 

      ;      &nbsp; private void btnGo_Click(object sender, RoutedEventArgs e)

 ;           &nbsp; {

        &nbsp;            // 放置一个测试的棋子(白子)

          &nbsp;      &nbsp;   Ellipse e1 = new Ellipse();

         &nbsp;         &nbsp; e1.Stroke = new SolidColorBrush(Colors.Black);

     &nbsp;               e1.Fill = new SolidColorBrush(Colors.White);

      &nbsp; &nbsp;            e1.Width = e1.Height = stoneSize;

 

             &nbsp;       double x = 17 * cellSize - stoneSize / 2;

        &nbsp;            double y = 4 * cellSize - stoneSize / 2;

 

                  &nbsp;  e1.SetValue(Canvas.LeftProperty, x);

                     e1.SetValue(Canvas.TopProperty, y);

 

               &nbsp;     canvasBoard.Children.Add(e1);

 

&nbsp;                    // 再放一个黑子,带手数显示的

  &nbsp;                &nbsp; Ellipse e2 = new Ellipse();

     &nbsp;               e2.Stroke = new SolidColorBrush(Colors.Black);

   &nbsp;  &nbsp;              e2.Fill = new SolidColorBrush(Colors.Black);

 &nbsp;          &nbsp;        e2.Width = e2.Height = stoneSize;

 

  ;                   double x2 = 16 * cellSize - stoneSize / 2;

                     double y2 = 4 * cellSize - stoneSize / 2;

 

               &nbsp;     e2.SetValue(Canvas.LeftProperty, x2);

         ;            e2.SetValue(Canvas.TopProperty, y2);

 

                     canvasBoard.Children.Add(e2);

 

               &nbsp;     // 绘制手数显示的 Label

&nbsp;  &nbsp;                 TextBlock lbl2 = new TextBlock();

              &nbsp;      lbl2.FontSize = 10.0;

       &nbsp;             lbl2.FontWeight = FontWeights.Thin;

&nbsp; &nbsp;                  lbl2.Text = "203";

                 &nbsp;&nbsp;  lbl2.Foreground = new SolidColorBrush(Colors.White);

 

   &nbsp;  &nbsp;              lbl2.SetValue(Canvas.LeftProperty, 16 * cellSize - lbl2.ActualWidth / 2);

     &nbsp;        &nbsp;      lbl2.SetValue(Canvas.TopProperty, 4 * cellSize - lbl2.ActualHeight / 2);

 

           &nbsp;         canvasBoard.Children.Add(lbl2);

 

     &nbsp;    &nbsp;   }

       }

}

 

运行一下看看效果如何:
ui1.png

 

看起来不赖。在这个界面中,如果点击 ”Go” 按钮,则会在棋盘上摆放两个测试用的棋子,其中黑棋上还标有表示棋步的数字。但是,我们的目标是要做一个能下棋的程序,因此,我们下面要加一些控制代码,比如,在用户点击某个位置的时候,落下棋子(如果该位置是允许落子的),以及控制棋局的开始、结束、认输等操作的按钮以及相关动作处理逻辑。

不过,在开始之前,有必要重构一下上面的 UI 代码,因为它看起来比较乱,一个方法里包含了太多的代码,如果这样继续下去的话,程序很快会变成一堆乱麻而难以为继。

由于很多对象的创建过程是类似的,因此我们可以将它提取到独立的方法中加以重用。另外,因为我们需要能够控制某些界面元素的显示/隐藏(比如坐标),将这些对象保存到当前窗体的字段里是一个不错的主意。

我们还添加了一个 CheckBox,用来控制坐标的显示和隐藏。Xaml 中添加的代码如下:

   &nbsp;         &nbsp;             <CheckBox

                        &nbsp;         x:Name="chkShowAxisLabels"

   &nbsp;                  &nbsp;           Content="Show Axis Labels"

           ;                       Margin="0,10,0,0"

                                  IsChecked="true" />

重构后的代码 Page.xaml.cs (每个方法代码大概510行左右)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

 

namespace WoodFoxWeiQi.UI

{

       public partial class Page : UserControl

       {

              public Page()

         &nbsp;    {

           &nbsp;         InitializeComponent();

 

                  ;   canvasBoard.MouseLeftButtonDown += canvasBoard_MouseLeftButtonDown;

          &nbsp;  ;        canvasBoard.SizeChanged += canvasBoard_SizeChanged;

 

      &nbsp;              btnGo.Click += btnGo_Click;

           &nbsp;         chkShowAxisLabels.Checked += chkShowAxisLabels_Checked;

  &nbsp;           &nbsp;      chkShowAxisLabels.Unchecked += chkShowAxisLabels_Checked;

       ;     &nbsp; }

 

      &nbsp; &nbsp;     #region Fields

   &nbsp;          private readonly Brush brush_White = new SolidColorBrush(Colors.White);

              private readonly Brush brush_Black = new SolidColorBrush(Colors.Black);

 

              private readonly List<TextBlock> yAxisLabels = new List<TextBlock>(20);

             ; private readonly List<TextBlock> xAxisLabels = new List<TextBlock>(20);

 

              double boardSize;    // 棋盘宽度(不包含坐标)

           &nbsp;  double cellSize;     // 网格宽度

     ;&nbsp;        double starSize;     // 星位的小圆点的直径

         &nbsp;    double stoneSize;    // 棋子直径

&nbsp;          &nbsp;  #endregion

 

      &nbsp;       // 因为 Canvas 的尺寸是根据父控件的尺寸在运行时计算得到的,
所以需要在
SizeChanged 方法里

   &nbsp;    &nbsp;     // 才能获得其实际尺寸

    &nbsp;         void canvasBoard_SizeChanged(object sender, SizeChangedEventArgs e)

     &nbsp;        {

          ;      &nbsp;    canvasBoard.Children.Clear();

  ;                   CreateBoardElements();

        &nbsp;     }

       

 &nbsp;            void canvasBoard_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

   &nbsp;          {

    ;               &nbsp; var pos = e.GetPosition(canvasBoard);

&nbsp;                    MessageBox.Show("Clicked on board, X: " + pos.X + ", Y: " + pos.Y);

              }

 

   &nbsp;       &nbsp;  void btnGo_Click(object sender, RoutedEventArgs e)

              {

    &nbsp;       &nbsp;        // 放置一个测试的棋子(白子)

          ;          var e1 = BuildCircle(stoneSize, 17 * cellSize, 4 * cellSize, brush_Black, brush_White);

 

       ;              // 再放一个黑子,带手数显示的

&nbsp;           &nbsp;       var e2 = BuildCircle(stoneSize, 16 * cellSize, 4 * cellSize, brush_Black, brush_Black);

 

                     // 绘制手数显示的 Label

     &nbsp;     ;          var lbl2 = BuildLabel("203", brush_White, 10.0, 16 * cellSize, 4 * cellSize);

     &nbsp;        }

 

           &nbsp;  // 显示或隐藏坐标轴

           &nbsp;  void chkShowAxisLabels_Checked(object sender, RoutedEventArgs e)

      &nbsp;       {

                  &nbsp;  var show = chkShowAxisLabels.IsChecked.HasValue && chkShowAxisLabels.IsChecked.Value;

       &nbsp;     &nbsp;       foreach (var label in xAxisLabels.Union(yAxisLabels))

                 &nbsp;   {

   ;                        label.Visibility = show ? Visibility.Visible : Visibility.Collapsed;

 &nbsp;&nbsp;                  }

   &nbsp;          }

 

              #region Builder methods for children elements

 

   &nbsp;  &nbsp;       // 创建棋盘上的网格线,星位,坐标等显示元素

          ;    void CreateBoardElements()

        &nbsp;     {

       &nbsp;             CalculateSizes();

 

              &nbsp;      BuildGridLines();

 

             &nbsp;       BuildStarPointMarks();

 

   &nbsp;  &nbsp;              BuildXAxisLabels();

 

                   &nbsp; BuildYAxisLabels();

          &nbsp;   }

 

  ;            // 计算必要的一些尺寸定义值

              void CalculateSizes()

    &nbsp;         {

    &nbsp;                // 确保使用一个正方形区域作为棋盘显示区域

     &nbsp;      &nbsp;        boardSize = Math.Min(canvasBoard.ActualHeight, canvasBoard.ActualWidth);

 

&nbsp;                    // 根据棋盘尺寸计算出相应的其他尺寸

         &nbsp;           cellSize = boardSize / 20;

            ;         starSize = cellSize / 4;

               &nbsp;   &nbsp; stoneSize = cellSize * 0.8;

       &nbsp;      }

 

    &nbsp;         // 添加网格线

         &nbsp;    void BuildGridLines()

        &nbsp; &nbsp;   {

          &nbsp;          for (var i = 1; i <= 19; i++)

            &nbsp;        {

                           // 添加水平网格线

               &nbsp;           BuildLine(cellSize, cellSize * i, cellSize * 19, cellSize * i);

 

  &nbsp;               &nbsp;        // 添加垂直网格线

                 &nbsp;         BuildLine(cellSize * i, cellSize, cellSize * i, cellSize * 19);

                     }

           &nbsp;  }

 

         ;  &nbsp;  // 添加9个星位的标志

      ;        void BuildStarPointMarks()

         &nbsp;    {

     &nbsp;               for (var i = 4; i <= 16; i += 6)

                &nbsp;    {

&nbsp;                  &nbsp;       for (var j = 4; j <= 16; j += 6)

        &nbsp;                  {

           &nbsp;                      BuildCircle(starSize, i * cellSize, j * cellSize, brush_Black, brush_Black);

        &nbsp;  &nbsp;               }

                 &nbsp;   }

      &nbsp;       }

 

              // 画横坐标

     ;    &nbsp;    void BuildXAxisLabels()

            &nbsp; {

     &nbsp;         &nbsp;     for (var i = 1; i <= 19; i++)

&nbsp;     &nbsp;              {

                 &nbsp;     &nbsp;   var lbl = BuildLabel(i.ToString(), brush_Black, 11.0, i * cellSize, cellSize / 2);

 

 &nbsp;                 &nbsp;       xAxisLabels.Add(lbl);

           &nbsp;  &nbsp;      }

&nbsp;             }

 

         &nbsp; ;   // 画纵坐标

          &nbsp;   void BuildYAxisLabels()

    &nbsp;     &nbsp;   {

                     var c = 'A';

 &nbsp;              &nbsp;    for (var i = 1; i <= 19; i++)

                     {

    &nbsp;      &nbsp;               var text = (c++).ToString();

           &nbsp;               var lbl = BuildLabel(text, brush_Black, 11.0, cellSize / 2, i * cellSize);

 

               &nbsp;           yAxisLabels.Add(lbl);

      &nbsp;          &nbsp;   }

    &nbsp;         }

              #endregion

 

             ; #region Basic builder methods

 

       &nbsp;      Line BuildLine(double x1, double y1, double x2, double y2)

  ;            {

    &nbsp;        &nbsp;       var line = new Line {

              ;           &nbsp; X1 = x1,

          &nbsp;              ;  X2 = x2,

  &nbsp;    &nbsp;                   Y1 = y1,

               ;        &nbsp;   Y2 = y2,

                  &nbsp;      &nbsp; Stroke = brush_Black,

 ;                          StrokeThickness = 1.0

                  ;   };

            &nbsp;        canvasBoard.Children.Add(line);

 

      &nbsp;              return line;

      &nbsp;       }

 

    &nbsp;        Ellipse BuildCircle(double diameter, double centerX, double centerY, Brush stroke, Brush fill)

              {

  &nbsp;                  var ellipse = new Ellipse { Stroke = stroke, Fill = fill };

              &nbsp;      ellipse.Width = ellipse.Height = diameter;

      &nbsp;      &nbsp;       ellipse.SetValue(Canvas.LeftProperty, centerX - diameter / 2);

   ;                &nbsp; ellipse.SetValue(Canvas.TopProperty, centerY - diameter / 2);

 

        &nbsp;            canvasBoard.Children.Add(ellipse);

 ;      &nbsp;             return ellipse;

       &nbsp;      }

 

          ;    // 创建 Label

    &nbsp;         TextBlock BuildLabel(string text, Brush foreground, double fontSize,

   ;              &nbsp;   double centerX, double centerY)

 &nbsp;            {

&nbsp;              &nbsp;     var lbl = new TextBlock {

     &nbsp;       &nbsp;             FontSize = fontSize,

                           FontWeight = FontWeights.Thin,

   &nbsp;                   &nbsp;   Text = text,

            ;               Foreground = foreground

           &nbsp;        ; };

 

  &nbsp; &nbsp;                lbl.SetValue(Canvas.LeftProperty, centerX - lbl.ActualWidth / 2);

&nbsp;                 &nbsp;  lbl.SetValue(Canvas.TopProperty, centerY - lbl.ActualHeight / 2);

 

           &nbsp;         canvasBoard.Children.Add(lbl);

 

               &nbsp;  &nbsp;  return lbl;

          &nbsp; &nbsp; }

       &nbsp;      #endregion

       }

}


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@hmdbvip.cn

文章转载自:博客园

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP
PM娱乐城网络现金网站(官方)网站/网页版登录入口/手机版登录入口-最新版(已更新) PM娱乐城最大(官方)网站/网页版登录入口/手机版登录入口-最新版(已更新) 永利外围最新(官方)网站/网页版登录入口/手机版登录入口-最新版(已更新) 网络权威朗驰娱乐大全(官方)网站/网页版登录入口/手机版登录入口-最新版(已更新) 永利真人网上足球(官方)网站/网页版登录入口/手机版登录入口-最新版(已更新) 利记最火十大网(官方)网站/网页版登录入口/手机版登录入口-最新版(已更新) boyu·博鱼权威网络足球(官方)网站/网页版登录入口/手机版登录入口-最新版(已更新) PM娱乐城网上足球(官方)网站/网页版登录入口/手机版登录入口-最新版(已更新)