WPF 做的天干地支 乾坤八卦时钟表盘 可以设置24小时制

WPF 做的天干地支 可以设置24小时制

一次偶然朋友看见别人卖一个有天干地支的时钟,2000大洋,就觉得这东西自己做一个不就行了,然后刚好最近研究WPF,就做了这个,先上效果图


主要分了几步,

第一步画个背景圆形,让指针动起来

第二步刻画表盘,刻画天干地支,乾坤八卦盘

第三步,实现24小时制度的表盘(因为聊到天干地支是一天24小时的)

第四步引入了Quartz Regular.ttf字体

第五步做了托盘模式的

直接上代码吧

<Window xmlns:my="clr-namespace:WpfClock"  x:Class="WpfClock.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" x:Name="myWindow" Margin="2" Height="387" Width="327" AllowsTransparency="True" 
          WindowStyle="None" Background="Transparent" WindowStartupLocation="CenterScreen"  ShowInTaskbar="False"
          ResizeMode="NoResize" Topmost="False" Opacity="1" Icon="/WpfClock;component/weather_clock.ico">
    <Window.Resources>
        <Style x:Key="QuartzRegular">
            <Setter Property="TextElement.FontFamily" Value="/WpfClock;component/Resources/#Quartz Regular"/>
        </Style>
    </Window.Resources>
    <Border Width="300" Height="360" BorderThickness="2" CornerRadius="20"  MouseLeftButtonDown="Grid_MouseLeftButtonDown">
        <Border.BorderBrush>
            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="#FFD9E5EF" Offset="0.846"/>
                <GradientStop Color="#FF5498DB" Offset="0.342"/>
            </LinearGradientBrush>
        </Border.BorderBrush>
        <Border.Background>
            <ImageBrush ImageSource="Back.png"></ImageBrush>
        </Border.Background>
      <Grid Width="300" Height="360">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"></RowDefinition>
                <RowDefinition Height="60"></RowDefinition>
            </Grid.RowDefinitions>
       <Grid Width="300" Height="300" Grid.Row="0">
        <!--背景-->
        <Ellipse x:Name="PointerCap" Width="280" Height="280" StrokeThickness="4" Opacity=".5" >
            <Ellipse.Stroke>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF000000" Offset="0.675"/>
                    <GradientStop Color="#FFC1B5B5" Offset="0.031"/>
                </LinearGradientBrush>
            </Ellipse.Stroke>
            <Ellipse.Fill>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF152029" Offset="0.846"/>
                    <GradientStop Color="#FF140204" Offset="0.342"/>
                </LinearGradientBrush>
            </Ellipse.Fill>
        </Ellipse>

        <!--外圈1-->
        <Ellipse Width="287" Height="287" StrokeThickness="3" Grid.Row="0" Grid.Column="0">
            <Ellipse.Stroke>
                <LinearGradientBrush>
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Color="LightBlue" Offset="0" />
                        <GradientStop Color="DarkBlue" Offset="1" />
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
            </Ellipse.Stroke>
        </Ellipse>
        <!--外圈2-->
        <Ellipse x:Name="OuterFrame" StrokeThickness="16" 
                                Width="280" Height="280">
            <Ellipse.Stroke>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF636060" Offset="1"/>
                    <GradientStop Color="#FF5F5C5C" Offset="0"/>
                    <GradientStop Color="#FFEEDEDE" Offset="0.35"/>
                    <GradientStop Color="#FFA09595" Offset="0.705"/>
                </LinearGradientBrush>
            </Ellipse.Stroke>
        </Ellipse>
        <Grid Width="300" Height="300" x:Name="rootGrid"></Grid>

        <Label Name="lab1" Foreground="White" Margin="0,0,0,190" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="Auto" Width="Auto" FontSize="10" >中国制造</Label>
        <Label Name="lab2" Foreground="White" Margin="0,100,0,0" HorizontalAlignment="Center" VerticalAlignment="Top" Height="Auto" Width="Auto" FontSize="10">Made In China</Label>
        <!-- 时针定义  -->
        <Rectangle Margin="147,80,147,150" Name="rectangleHour" Stroke="LightYellow" Fill="Red"  Height="80" VerticalAlignment="Bottom">
            <Rectangle.RenderTransform>
                <RotateTransform x:Name="hourPointer" CenterX="3" CenterY="80" Angle="{Binding ElementName=myWindow,Path=DataContext.Hour}" />
            </Rectangle.RenderTransform>
        </Rectangle>
        <!-- -->
        <!-- 分钟定义  -->
        <Rectangle Margin="148,60,148,150" Name="rectangleMinute" Stroke="LightGreen" Fill="DarkOrange" Height="100" VerticalAlignment="Bottom">
            <Rectangle.RenderTransform>
                <RotateTransform x:Name="minutePointer" CenterX="2" CenterY="100" Angle="{Binding ElementName=myWindow,Path=DataContext.Minute}"/>
            </Rectangle.RenderTransform>
        </Rectangle>
        <!-- -->
        <!-- 秒针定义  -->
        <Rectangle Margin="149,50,149,150" Name="rectangleSecond" Stroke="White" Fill="Black" Height="120" VerticalAlignment="Bottom">
            <Rectangle.RenderTransform>
                <RotateTransform x:Name="secondPointer" CenterX="1" CenterY="120" Angle="{Binding ElementName=myWindow,Path=DataContext.Second}" />
            </Rectangle.RenderTransform>
        </Rectangle>
        <!-- -->
        <!--圆心-->
        <Ellipse Width="8" Height="8" Fill="Black" />
        <!---->
        <Label Background="Blue" FontSize="14" FontWeight="ExtraBold" Foreground="Yellow" 
               Content="{Binding ElementName=myWindow,Path=DataContext.TimeTxt}" Style="{DynamicResource QuartzRegular}" Height="Auto" HorizontalAlignment="Center" Margin="114,0,113,96" Name="labTime" VerticalAlignment="Bottom" Width="Auto">
        </Label>
        <!--<Label Content="" FontSize="16" Foreground="White" Height="Auto" HorizontalAlignment="Center" Margin="114,0,113,96" Name="labTime" VerticalAlignment="Bottom" Width="Auto" />-->
     </Grid>
      <Grid Grid.Row="1" Width="300" Height="60">
          <my:SwitchButton  CheckedText="24小时制" Text="12小时制" IsChecked="{Binding ElementName=myWindow,Path=DataContext.IsChecked12_24}"/>
      </Grid> 
      </Grid>
      </Border>
</Window>
 public sealed class AngleService : INotifyPropertyChanged
    {
        
        public double Hour 
        {
            get { return _hour; }
            set
            {
                _hour = value;
                OnPropertyChanged("Hour");
            }
        }
        public double Minute
        {
            get { return _minute; }
            set
            {
                _minute = value;
                OnPropertyChanged("Minute");
            }
        }
        public double Second
        {
            get { return _second; }
            set
            {
                _second = value;
                OnPropertyChanged("Second");
            }
        }

        public string TimeTxt
        {
            get { return _timetxt; }
            set
            {
                _timetxt = value;
                OnPropertyChanged("TimeTxt");
            }
        }
        public Boolean IsChecked12_24
        {
            get { return _ischecked12_24; }
            set
            {
                _ischecked12_24 = value;
                OnPropertyChanged("IsChecked12_24");
                initialDateTime();
                //值更改后触发事件重绘表盘
            }
        }
        
        public event PropertyChangedEventHandler PropertyChanged;

        public AngleService()
        {
            initialDateTime();
            _tiemr = new Timer(1000);
            _tiemr.Elapsed += _tiemr_Elapsed;
            _tiemr.Start();
        }

        void _tiemr_Elapsed(object sender, ElapsedEventArgs e)
        {
            initialDateTime();
        }
        
        void initialDateTime()
        {
            DateTime dt = DateTime.Now;
            if (_ischecked12_24)
            {
                if (dt.Minute % 2 == 0)
                {
                    //秒针转动,秒针绕一圈360度,共120秒,所以1秒转动3度
                    Second = (dt.Second * 3) + 180;
                }
                else
                {
                    //秒针转动,秒针绕一圈360度,共120秒,所以1秒转动3度
                    Second = dt.Second * 3;
                }

                if (dt.Hour % 2 == 0)
                {
                    //分针转动,分针绕一圈360度,共1200分,所以1分转动3度
                    Minute = (dt.Minute * 3) + 180;
                }
                else
                {
                    //分针转动,分针绕一圈360度,共1200分,所以1分转动3度
                    Minute = dt.Minute * 3;
                }
              
                //时针转动,时针绕一圈360度,共24时,所以1时转动15度。
                //另外同一个小时内,随着分钟数的变化(绕一圈120分钟2小时),时针也在缓慢变化(转动15度,15/(120/2)=0.25)
                if (int.Parse(DateTime.Now.ToString("HH")) > 12)
                {
                    Hour = ((dt.Hour * 15) + (dt.Minute * 0.25));
                }
                else
                {
                    Hour = (dt.Hour * 15) + (dt.Minute * 0.25);
                }
            }
            else
            {
                //秒针转动,秒针绕一圈360度,共60秒,所以1秒转动6度
                Second = dt.Second * 6;
                //分针转动,分针绕一圈360度,共60分,所以1分转动6度
                Minute = dt.Minute * 6;
                //时针转动,时针绕一圈360度,共12时,所以1时转动30度。
                //另外同一个小时内,随着分钟数的变化(绕一圈60分钟),时针也在缓慢变化(转动30度,30/60=0.5)
                Hour = (dt.Hour * 30) + (dt.Minute * 0.5);
            }
            TimeTxt = DateTime.Now.ToString("HH:mm:ss");
        }

        private void OnPropertyChanged(string info)
        {
           
            if (this.PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
        private double _hour, _minute, _second;

        private string  _timetxt;

        private Boolean _ischecked12_24 = false;

        private Timer _tiemr;
    }
/// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        //托盘
        System.Windows.Forms.NotifyIcon notifyIcon;

        //计时器
        public MainWindow()
        {
            InitializeComponent();
            #region 托盘
            this.notifyIcon = new System.Windows.Forms.NotifyIcon();
            this.notifyIcon.BalloonTipText = "天干地支";
            this.notifyIcon.ShowBalloonTip(2000);
            this.notifyIcon.Text = "乾坤八卦";
            //this.notifyIcon.Icon = new System.Drawing.Icon(@"weather_clock.ico");
            this.notifyIcon.Icon = System.Drawing.Icon.ExtractAssociatedIcon(System.Windows.Forms.Application.ExecutablePath);
            this.notifyIcon.Visible = true;
            //打开菜单项
            System.Windows.Forms.MenuItem open = new System.Windows.Forms.MenuItem("Open");
            open.Click += new EventHandler(Show);
            //隐藏菜单项
            System.Windows.Forms.MenuItem hide = new System.Windows.Forms.MenuItem("Hide");
            hide.Click += new EventHandler(Hide);
            //退出菜单项
            System.Windows.Forms.MenuItem exit = new System.Windows.Forms.MenuItem("Exit");
            exit.Click += new EventHandler(Close);
            //关联托盘控件
            System.Windows.Forms.MenuItem[] childen = new System.Windows.Forms.MenuItem[] { open, hide, exit };
            notifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu(childen);

            this.notifyIcon.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler((o, e) =>
            {
                if (e.Button == System.Windows.Forms.MouseButtons.Left) this.Show(o, e);
            });
            #endregion

            AngleService  dt2as = new AngleService ();
            dt2as.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(dt2as_PropertyChanged);
            this.DataContext = dt2as;
            DrawScale(dt2as.IsChecked12_24);
        }

        void dt2as_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsChecked12_24")
            { 
                //重绘刻度表盘
                DrawScale((sender as DateTime2AngleService).IsChecked12_24);
            }
        }

        private void Show(object sender, EventArgs e)
        {
            this.Visibility = System.Windows.Visibility.Visible;
            //this.ShowInTaskbar = true;
            this.Activate();
        }

        private void Hide(object sender, EventArgs e)
        {
            //this.ShowInTaskbar = false;
            this.Visibility = System.Windows.Visibility.Hidden;
        }

        private void Close(object sender, EventArgs e)
        {
            System.Windows.Application.Current.Shutdown();
        }

        private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //进行拖放移动
            this.DragMove();
        }

        /// <summary>
        /// 画刻度
        /// </summary>
        private void DrawScale(Boolean IsChecked12_24)
        {
            rootGrid.Children.Clear();

            double ScaleStartAngle = 270;
            double ScaleSweepAngle = 360;
            double MajorDivisionsCount = 12;
            double MinorDivisionsCount = 5;

            double MaxValue = 12;

            if (IsChecked12_24)
            {
                MaxValue = 24;
                MajorDivisionsCount = 24;
            }
            double MinValue = 0;
            int ScaleValuePrecision = 0;
            Size MajorTickSize = new Size(10, 3);
            Size ScaleLabelSize = new Size(40, 20);
            Color MajorTickColor = Colors.LightGray;
           
            double ScaleLabelFontSize = 8;
            Color ScaleLabelForeground = Colors.LightGray;
            Color MinorTickColor = Colors.LightGray;
            Size MinorTickSize = new Size(3, 1);

            double ScaleRadius = 100;
            double ScaleLabelRadius = 80;

            //大刻度角度
            Double majorTickUnitAngle = ScaleSweepAngle / MajorDivisionsCount;

            //小刻度角度
            Double minorTickUnitAngle = ScaleSweepAngle / MinorDivisionsCount;

            //刻度单位值
            Double majorTicksUnitValue = (MaxValue - MinValue) / MajorDivisionsCount;
            majorTicksUnitValue = Math.Round(majorTicksUnitValue, ScaleValuePrecision);

            
            Double minvalue = MinValue; ;
            for (Double i = ScaleStartAngle; i <= (ScaleStartAngle + ScaleSweepAngle); i = i + majorTickUnitAngle)
            {
                //大刻度、刻度值角度
                Double i_radian = (i * Math.PI) / 180;

                #region 大刻度
                Rectangle majortickrect = new Rectangle();
                majortickrect.Height = MajorTickSize.Height;
                majortickrect.Width = MajorTickSize.Width;
                majortickrect.Fill = new SolidColorBrush(MajorTickColor);
                Point p = new Point(0.5, 0.5);
                majortickrect.RenderTransformOrigin = p;
                majortickrect.HorizontalAlignment = HorizontalAlignment.Center;
                majortickrect.VerticalAlignment = VerticalAlignment.Center;

                TransformGroup majortickgp = new TransformGroup();
                RotateTransform majortickrt = new RotateTransform();
                majortickrt.Angle = i;
                majortickgp.Children.Add(majortickrt);
                TranslateTransform majorticktt = new TranslateTransform();

                //在这里画点中心为(0,0)
                majorticktt.X = (int)((ScaleRadius) * Math.Cos(i_radian));
                majorticktt.Y = (int)((ScaleRadius) * Math.Sin(i_radian));

              
                majortickgp.Children.Add(majorticktt);
                majortickrect.RenderTransform = majortickgp;
                rootGrid.Children.Add(majortickrect);
                #endregion
                
                #region 刻度值

                TranslateTransform majorscalevaluett = new TranslateTransform();
                //在这里画点中心为(0,0)
                majorscalevaluett.X = (int)((ScaleLabelRadius) * Math.Cos(i_radian));
                majorscalevaluett.Y = (int)((ScaleLabelRadius) * Math.Sin(i_radian));
                //刻度值显示
                TextBlock tb = new TextBlock();

                tb.Height = ScaleLabelSize.Height;
                tb.Width = ScaleLabelSize.Width;
                tb.FontSize = ScaleLabelFontSize;
                tb.Foreground = new SolidColorBrush(ScaleLabelForeground);
                tb.TextAlignment = TextAlignment.Center;
                tb.VerticalAlignment = VerticalAlignment.Center;
                tb.HorizontalAlignment = HorizontalAlignment.Center;

                if (Math.Round(minvalue, ScaleValuePrecision) <= Math.Round(MaxValue, ScaleValuePrecision))
                {
                    minvalue = Math.Round(minvalue, ScaleValuePrecision);
                    if (minvalue > 0)
                    {
                        tb.Text = minvalue.ToString();
                    }
                    minvalue = minvalue + majorTicksUnitValue;
                }
                else
                {
                    break;
                }

                tb.RenderTransform = majorscalevaluett;
                rootGrid.Children.Add(tb);
              
                #endregion

                #region 小刻度
                Double onedegree = ((i + majorTickUnitAngle) - i) / (MinorDivisionsCount);
                if ((i < (ScaleStartAngle + ScaleSweepAngle)) && (Math.Round(minvalue, ScaleValuePrecision) <= Math.Round(MaxValue, ScaleValuePrecision)))
                {
                    //绘制小刻度
                    for (Double mi = i + onedegree; mi < (i + majorTickUnitAngle); mi = mi + onedegree)
                    {
                        Rectangle mr = new Rectangle();
                        mr.Height = MinorTickSize.Height;
                        mr.Width = MinorTickSize.Width;
                        mr.Fill = new SolidColorBrush(MinorTickColor);
                        mr.HorizontalAlignment = HorizontalAlignment.Center;
                        mr.VerticalAlignment = VerticalAlignment.Center;
                        Point p1 = new Point(0.5, 0.5);
                        mr.RenderTransformOrigin = p1;

                        TransformGroup minortickgp = new TransformGroup();
                        RotateTransform minortickrt = new RotateTransform();
                        minortickrt.Angle = mi;
                        minortickgp.Children.Add(minortickrt);
                        TranslateTransform minorticktt = new TranslateTransform();

                        //计算角度
                        Double mi_radian = (mi * Math.PI) / 180;
                        //刻度点
                        minorticktt.X = (int)((ScaleRadius) * Math.Cos(mi_radian));
                        minorticktt.Y = (int)((ScaleRadius) * Math.Sin(mi_radian));

                        minortickgp.Children.Add(minorticktt);
                        mr.RenderTransform = minortickgp;
                        rootGrid.Children.Add(mr);
                    }
                }
                #endregion

                #region 天干地支[子、丑、寅、卯、辰、巳、午、未、申、酉、戌、亥]
                TranslateTransform majorscalevaluett_tgdz = new TranslateTransform();
                //在这里画点中心为(0,0)
                majorscalevaluett_tgdz.X = (int)((ScaleLabelRadius_Tgdz) * Math.Cos(i_radian));
                majorscalevaluett_tgdz.Y = (int)((ScaleLabelRadius_Tgdz) * Math.Sin(i_radian));
                //刻度值显示
                TextBlock tb_tgdz = new TextBlock();

                tb_tgdz.Height = ScaleLabelSize.Height;
                tb_tgdz.Width = ScaleLabelSize.Width;
                tb_tgdz.FontSize = ScaleLabelFontSize;
                tb_tgdz.Foreground = new SolidColorBrush(ScaleLabelForeground);
                tb_tgdz.TextAlignment = TextAlignment.Center;
                tb_tgdz.VerticalAlignment = VerticalAlignment.Center;
                tb_tgdz.HorizontalAlignment = HorizontalAlignment.Center;
                if (int.Parse((minvalue - majorTicksUnitValue).ToString()) < tgdz.Length)
                {
                    tb_tgdz.Text = tgdz[int.Parse((minvalue - majorTicksUnitValue).ToString())];
                }
                tb_tgdz.RenderTransform = majorscalevaluett_tgdz;
                rootGrid.Children.Add(tb_tgdz);
                #endregion
            }

            #region 八卦
            string[] bg = new string[] { "乾", "巽", "坎", "艮", "坤", "震", "离", "兑" };
            string[] bg_tag = new string[] { "离", "坤", "兑", "乾", "坎", "艮", "震", "巽" };
            Color ScaleLabelForeground_bg = Colors.Red;
            Color ScaleLabelForeground_bg_tag = Colors.LightGray;
            Size ScaleLabelSize_bg = new Size(40, 20);
            double ScaleLabelFontSize_bg = 12;
            double ScaleLabelFontSize_bg_tag = 8;

            double MajorDivisionsCount_bg = 8;
            double MaxValue_bg = 8;
            double ScaleLabelRadius_bg = 113;
            //刻度角度
            Double majorTickUnitAngle_bg = ScaleSweepAngle / MajorDivisionsCount_bg;

            //刻度单位值
            Double majorTicksUnitValue_bg = (MaxValue_bg - MinValue) / MajorDivisionsCount_bg;
            majorTicksUnitValue_bg = Math.Round(majorTicksUnitValue_bg, ScaleValuePrecision);
            Double minvalue_bg = MinValue;
            for (Double i = ScaleStartAngle; i <= (ScaleStartAngle + ScaleSweepAngle); i = i + majorTickUnitAngle_bg)
            {
                Double i_radian = (i * Math.PI) / 180;
                Double i_radian_ta = ((i+8) * Math.PI) / 180;

                TranslateTransform majorscalevaluett = new TranslateTransform();
                //在这里画点中心为(0,0)
                majorscalevaluett.X = (int)((ScaleLabelRadius_bg) * Math.Cos(i_radian));
                majorscalevaluett.Y = (int)((ScaleLabelRadius_bg) * Math.Sin(i_radian));

                TranslateTransform majorscalevaluett_tag = new TranslateTransform();
                //在这里画点中心为(0,0)
                majorscalevaluett_tag.X = (int)((ScaleLabelRadius_bg) * Math.Cos(i_radian_ta));
                majorscalevaluett_tag.Y = (int)((ScaleLabelRadius_bg) * Math.Sin(i_radian_ta));
                //刻度值显示
                TextBlock tb = new TextBlock();

                tb.Height = ScaleLabelSize_bg.Height;
                tb.Width = ScaleLabelSize_bg.Width;
                tb.FontSize = ScaleLabelFontSize_bg;
                tb.Foreground = new SolidColorBrush(ScaleLabelForeground_bg);
                tb.TextAlignment = TextAlignment.Center;
                tb.VerticalAlignment = VerticalAlignment.Center;
                tb.HorizontalAlignment = HorizontalAlignment.Center;

                TextBlock tb_tag = new TextBlock();

                tb_tag.Height = ScaleLabelSize_bg.Height;
                tb_tag.Width = ScaleLabelSize_bg.Width;
                tb_tag.FontSize = ScaleLabelFontSize_bg_tag;
                tb_tag.Foreground = new SolidColorBrush(ScaleLabelForeground_bg_tag);
                tb_tag.TextAlignment = TextAlignment.Center;
                tb_tag.VerticalAlignment = VerticalAlignment.Center;
                tb_tag.HorizontalAlignment = HorizontalAlignment.Center;

                if (Math.Round(minvalue_bg, ScaleValuePrecision) <= Math.Round(MaxValue_bg, ScaleValuePrecision))
                {
                    minvalue_bg = Math.Round(minvalue_bg, ScaleValuePrecision);
                    if (int.Parse((minvalue_bg).ToString()) < bg.Length)
                    {
                        tb.Text = bg[int.Parse((minvalue_bg).ToString())];
                        tb_tag.Text = bg_tag[int.Parse((minvalue_bg).ToString())];
                    }
                    minvalue_bg = minvalue_bg + majorTicksUnitValue_bg;
                }
                else
                {
                    break;
                }

                tb.RenderTransform = majorscalevaluett;
                tb_tag.RenderTransform = majorscalevaluett_tag;
                rootGrid.Children.Add(tb);
                rootGrid.Children.Add(tb_tag);
            }

            #endregion
        }
    }



猜你喜欢

转载自blog.csdn.net/shishuwei111/article/details/79553419
今日推荐