软件雏形
This commit is contained in:
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"python-envs.defaultEnvManager": "ms-python.python:conda",
|
||||||
|
"python-envs.defaultPackageManager": "ms-python.python:conda",
|
||||||
|
"python-envs.pythonProjects": []
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Configuration;
|
using System.Configuration;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ namespace CopyRou
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for App.xaml
|
/// Interaction logic for App.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class App : Application
|
public partial class App : System.Windows.Application
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
83
AppConfig.cs
Normal file
83
AppConfig.cs
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace CopyRou
|
||||||
|
{
|
||||||
|
public class AppConfig
|
||||||
|
{
|
||||||
|
public List<string> SourcePaths { get; set; } = new();
|
||||||
|
public string DestPath { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
private static readonly string ConfigPath = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
|
"CopyRou", "config.json");
|
||||||
|
|
||||||
|
public static AppConfig Load()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (File.Exists(ConfigPath))
|
||||||
|
{
|
||||||
|
var json = File.ReadAllText(ConfigPath);
|
||||||
|
return JsonSerializer.Deserialize<AppConfig>(json) ?? new AppConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// 如果加载失败,返回默认配置
|
||||||
|
System.Diagnostics.Debug.WriteLine($"加载配置失败: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AppConfig
|
||||||
|
{
|
||||||
|
SourcePaths = new List<string>
|
||||||
|
{
|
||||||
|
@"Z:\Routing\A1-ROUTING\NEW-ROUTING",
|
||||||
|
@"Z:\Routing\A2-ROUTING\NEW-ROUTING"
|
||||||
|
},
|
||||||
|
DestPath = @"D:\ARPTWork\rou"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var directory = Path.GetDirectoryName(ConfigPath);
|
||||||
|
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||||
|
Directory.CreateDirectory(directory);
|
||||||
|
|
||||||
|
var json = JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true });
|
||||||
|
File.WriteAllText(ConfigPath, json);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"保存配置失败: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetSourcePathsText()
|
||||||
|
{
|
||||||
|
return string.Join(Environment.NewLine, SourcePaths);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSourcePathsFromText(string text)
|
||||||
|
{
|
||||||
|
SourcePaths.Clear();
|
||||||
|
if (!string.IsNullOrWhiteSpace(text))
|
||||||
|
{
|
||||||
|
var paths = text.Split(new[] { Environment.NewLine, "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
foreach (var path in paths)
|
||||||
|
{
|
||||||
|
var trimmedPath = path.Trim();
|
||||||
|
if (!string.IsNullOrEmpty(trimmedPath))
|
||||||
|
{
|
||||||
|
SourcePaths.Add(trimmedPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<Platforms>AnyCPU;x86</Platforms>
|
<Platforms>AnyCPU;x86</Platforms>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
151
FileService.cs
Normal file
151
FileService.cs
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CopyRou
|
||||||
|
{
|
||||||
|
public class FileService : IFileService
|
||||||
|
{
|
||||||
|
public bool MatchFolderName(string folderName, string numPart, string versionPart)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(folderName) ||
|
||||||
|
string.IsNullOrEmpty(numPart) ||
|
||||||
|
string.IsNullOrEmpty(versionPart))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var folderNameLower = folderName.ToLower();
|
||||||
|
var numLength = numPart.Length;
|
||||||
|
|
||||||
|
// 检查文件夹名长度是否足够
|
||||||
|
if (folderNameLower.Length < 3 + numLength)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 从第4个字符开始匹配数字编号(索引3)
|
||||||
|
var numInName = folderNameLower.Substring(3, numLength);
|
||||||
|
if (numInName != numPart.ToLower())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查版本部分
|
||||||
|
var versionInName = folderNameLower.Substring(3 + numLength);
|
||||||
|
return versionInName.StartsWith(versionPart.ToLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> CopyRouFiles(string sourceFolder, string number, string destPath, ILogger logger)
|
||||||
|
{
|
||||||
|
var copiedFiles = new List<string>();
|
||||||
|
var edFoldersFound = 0;
|
||||||
|
var rouExtensions = new[] { ".rou", ".rou1", ".rou2", ".rou3" };
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 确保目标目录存在
|
||||||
|
Directory.CreateDirectory(destPath);
|
||||||
|
|
||||||
|
foreach (var item in Directory.GetDirectories(sourceFolder))
|
||||||
|
{
|
||||||
|
var folderName = Path.GetFileName(item);
|
||||||
|
if (folderName.StartsWith("ED", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
folderName.StartsWith("ROU", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
edFoldersFound++;
|
||||||
|
logger?.Log($"正在处理ED文件夹: {folderName}");
|
||||||
|
|
||||||
|
// 递归查找所有.rou文件
|
||||||
|
var rouFiles = Directory.GetFiles(item, "*.*", SearchOption.AllDirectories)
|
||||||
|
.Where(file => rouExtensions.Contains(Path.GetExtension(file).ToLower()))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var srcFile in rouFiles)
|
||||||
|
{
|
||||||
|
var fileName = Path.GetFileName(srcFile);
|
||||||
|
var baseName = $"{number}_{folderName}_{fileName}";
|
||||||
|
var destFile = Path.Combine(destPath, baseName);
|
||||||
|
|
||||||
|
File.Copy(srcFile, destFile, true);
|
||||||
|
copiedFiles.Add(baseName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edFoldersFound == 0)
|
||||||
|
{
|
||||||
|
logger?.LogWarning("未找到任何以ED或ROU开头的文件夹");
|
||||||
|
}
|
||||||
|
else if (!copiedFiles.Any())
|
||||||
|
{
|
||||||
|
logger?.LogWarning("在ED文件夹中未找到任何.rou系列文件");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger?.Log($"成功从 {edFoldersFound} 个ED文件夹复制 {copiedFiles.Count} 个文件");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger?.LogError($"复制文件时发生错误: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return copiedFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ProcessCodes(List<string> codes, List<string> sourcePaths, string destPath,
|
||||||
|
IProgress<int> progress, ILogger logger)
|
||||||
|
{
|
||||||
|
var totalCodes = codes.Count;
|
||||||
|
var processedCodes = 0;
|
||||||
|
|
||||||
|
foreach (var code in codes)
|
||||||
|
{
|
||||||
|
var trimmedCode = code.Trim();
|
||||||
|
if (string.IsNullOrEmpty(trimmedCode))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
logger?.Log($"\n处理编号: {trimmedCode}");
|
||||||
|
|
||||||
|
var numPart = trimmedCode.Length >= 5 ? trimmedCode.Substring(0, 5) : trimmedCode;
|
||||||
|
var versionPart = trimmedCode.Length > 5 ? trimmedCode.Substring(5) : "";
|
||||||
|
|
||||||
|
var found = false;
|
||||||
|
|
||||||
|
foreach (var sourceRoot in sourcePaths)
|
||||||
|
{
|
||||||
|
var numFolder = Path.Combine(sourceRoot, numPart);
|
||||||
|
if (!Directory.Exists(numFolder))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var folders = Directory.GetDirectories(numFolder);
|
||||||
|
foreach (var folder in folders)
|
||||||
|
{
|
||||||
|
var folderName = Path.GetFileName(folder);
|
||||||
|
if (MatchFolderName(folderName, numPart, versionPart))
|
||||||
|
{
|
||||||
|
logger?.Log($"找到匹配文件夹: {folder}");
|
||||||
|
CopyRouFiles(folder, numPart, destPath, logger ?? new Logger());
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger?.LogError($"访问文件夹 {numFolder} 时发生错误: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
logger?.Log("未找到匹配的文件夹");
|
||||||
|
}
|
||||||
|
|
||||||
|
processedCodes++;
|
||||||
|
progress?.Report((int)((double)processedCodes / totalCodes * 100));
|
||||||
|
|
||||||
|
// 添加小延迟以避免UI阻塞
|
||||||
|
await Task.Delay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
IFileService.cs
Normal file
12
IFileService.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CopyRou
|
||||||
|
{
|
||||||
|
public interface IFileService
|
||||||
|
{
|
||||||
|
bool MatchFolderName(string folderName, string numPart, string versionPart);
|
||||||
|
List<string> CopyRouFiles(string sourceFolder, string number, string destPath, ILogger logger);
|
||||||
|
Task ProcessCodes(List<string> codes, List<string> sourcePaths, string destPath, IProgress<int> progress, ILogger logger);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
ILogger.cs
Normal file
11
ILogger.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace CopyRou
|
||||||
|
{
|
||||||
|
public interface ILogger
|
||||||
|
{
|
||||||
|
void Log(string message);
|
||||||
|
void LogError(string message);
|
||||||
|
void LogWarning(string message);
|
||||||
|
void Clear();
|
||||||
|
event System.EventHandler<string>? MessageLogged;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
Logger.cs
Normal file
32
Logger.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace CopyRou
|
||||||
|
{
|
||||||
|
public class Logger : ILogger
|
||||||
|
{
|
||||||
|
public event EventHandler<string>? MessageLogged;
|
||||||
|
|
||||||
|
public void Log(string message)
|
||||||
|
{
|
||||||
|
var timestampedMessage = $"[{DateTime.Now:HH:mm:ss}] {message}";
|
||||||
|
MessageLogged?.Invoke(this, timestampedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogError(string message)
|
||||||
|
{
|
||||||
|
var timestampedMessage = $"[{DateTime.Now:HH:mm:ss}] [错误] {message}";
|
||||||
|
MessageLogged?.Invoke(this, timestampedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogWarning(string message)
|
||||||
|
{
|
||||||
|
var timestampedMessage = $"[{DateTime.Now:HH:mm:ss}] [警告] {message}";
|
||||||
|
MessageLogged?.Invoke(this, timestampedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
MessageLogged?.Invoke(this, "[LOG CLEARED]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
213
MainWindow.xaml
213
MainWindow.xaml
@@ -1,12 +1,215 @@
|
|||||||
<Window x:Class="CopyRou.MainWindow"
|
<Window
|
||||||
|
x:Class="CopyRou.MainWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:local="clr-namespace:CopyRou"
|
xmlns:local="clr-namespace:CopyRou"
|
||||||
mc:Ignorable="d"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
Title="MainWindow" Height="450" Width="800">
|
Title="ROU文件复制工具"
|
||||||
<Grid>
|
Width="586"
|
||||||
|
Height="631"
|
||||||
|
MinWidth="586"
|
||||||
|
MinHeight="631"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Grid Margin="10">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- 配置区域 -->
|
||||||
|
<GroupBox
|
||||||
|
Grid.Row="0"
|
||||||
|
Margin="0,0,0,10"
|
||||||
|
Header="路径配置">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Label
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="5"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Content="源路径:" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="SourcePathsTextBox"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="1"
|
||||||
|
Height="60"
|
||||||
|
Margin="5"
|
||||||
|
AcceptsReturn="True"
|
||||||
|
IsReadOnly="True"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
VerticalScrollBarVisibility="Auto" />
|
||||||
|
<Button
|
||||||
|
x:Name="AddSourceButton"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="2"
|
||||||
|
Width="60"
|
||||||
|
Height="25"
|
||||||
|
Margin="5"
|
||||||
|
Click="AddSourceButton_Click"
|
||||||
|
Content="添加" />
|
||||||
|
|
||||||
|
<Label
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="5"
|
||||||
|
Content="目标路径:" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="DestPathTextBox"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="5"
|
||||||
|
IsReadOnly="True" />
|
||||||
|
<Button
|
||||||
|
x:Name="BrowseDestButton"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="2"
|
||||||
|
Width="60"
|
||||||
|
Height="25"
|
||||||
|
Margin="5"
|
||||||
|
Click="BrowseDestButton_Click"
|
||||||
|
Content="浏览" />
|
||||||
|
|
||||||
|
<!-- 保存配置按钮 -->
|
||||||
|
<Button
|
||||||
|
x:Name="SaveConfigButton"
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="1"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
Width="100"
|
||||||
|
Height="25"
|
||||||
|
Margin="5"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Click="SaveConfigButton_Click"
|
||||||
|
Content="保存配置" />
|
||||||
|
</Grid>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
|
<!-- 输入区域 -->
|
||||||
|
<Grid Grid.Row="1" Margin="0,0,0,10">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="1.2*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- 单个料号输入区域 -->
|
||||||
|
<GroupBox
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="0,0,5,0"
|
||||||
|
Header="单个料号输入">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="0"
|
||||||
|
Margin="5"
|
||||||
|
Foreground="Gray"
|
||||||
|
Text="输入单个料号(如:27362a)" />
|
||||||
|
<StackPanel Margin="0,20,0,0" Orientation="Horizontal">
|
||||||
|
<TextBox
|
||||||
|
x:Name="SingleCodeTextBox"
|
||||||
|
Grid.Row="1"
|
||||||
|
MinWidth="150"
|
||||||
|
Margin="5"
|
||||||
|
KeyDown="SingleCodeTextBox_KeyDown" />
|
||||||
|
<Button
|
||||||
|
x:Name="AddSingleCodeButton"
|
||||||
|
Grid.Row="2"
|
||||||
|
Width="80"
|
||||||
|
Height="25"
|
||||||
|
Margin="5"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Click="AddSingleCodeButton_Click"
|
||||||
|
Content="添加" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
|
<!-- 批量料号输入区域 -->
|
||||||
|
<GroupBox
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="5,0,0,0"
|
||||||
|
Header="批量料号输入">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="0"
|
||||||
|
Margin="5"
|
||||||
|
Foreground="Gray"
|
||||||
|
Text="每行输入一个料号(如:27362a)" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="CodesTextBox"
|
||||||
|
Grid.Row="1"
|
||||||
|
Height="100"
|
||||||
|
Margin="5"
|
||||||
|
AcceptsReturn="True"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
VerticalScrollBarVisibility="Auto" />
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<StackPanel
|
||||||
|
Grid.Row="2"
|
||||||
|
Margin="5"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<Button
|
||||||
|
x:Name="StartButton"
|
||||||
|
Width="80"
|
||||||
|
Height="25"
|
||||||
|
Margin="5"
|
||||||
|
Click="StartButton_Click"
|
||||||
|
Content="开始处理" />
|
||||||
|
<Button
|
||||||
|
x:Name="ClearButton"
|
||||||
|
Width="80"
|
||||||
|
Height="25"
|
||||||
|
Margin="5"
|
||||||
|
Click="ClearButton_Click"
|
||||||
|
Content="清空" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</GroupBox>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- 进度条 -->
|
||||||
|
<ProgressBar
|
||||||
|
x:Name="ProgressBar"
|
||||||
|
Grid.Row="3"
|
||||||
|
Height="20"
|
||||||
|
Margin="0,0,0,10"
|
||||||
|
Maximum="100"
|
||||||
|
Minimum="0"
|
||||||
|
Value="0" />
|
||||||
|
|
||||||
|
<!-- 日志区域 -->
|
||||||
|
<GroupBox Grid.Row="4" Header="处理日志">
|
||||||
|
<TextBox
|
||||||
|
x:Name="LogTextBox"
|
||||||
|
Height="150"
|
||||||
|
Margin="5"
|
||||||
|
IsReadOnly="True"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
VerticalScrollBarVisibility="Auto" />
|
||||||
|
</GroupBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
using System.Text;
|
using Microsoft.Win32;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using MessageBox = System.Windows.MessageBox;
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Navigation;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
|
|
||||||
namespace CopyRou
|
namespace CopyRou
|
||||||
{
|
{
|
||||||
@@ -16,9 +16,269 @@ namespace CopyRou
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class MainWindow : Window
|
public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
|
private readonly IFileService _fileService;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private AppConfig _config;
|
||||||
|
private bool _isProcessing = false;
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
_fileService = new FileService();
|
||||||
|
_logger = new Logger();
|
||||||
|
_config = AppConfig.Load();
|
||||||
|
|
||||||
|
InitializeUI();
|
||||||
|
SubscribeToEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeUI()
|
||||||
|
{
|
||||||
|
// 加载配置到UI
|
||||||
|
SourcePathsTextBox.Text = _config.GetSourcePathsText();
|
||||||
|
DestPathTextBox.Text = _config.DestPath;
|
||||||
|
|
||||||
|
// 设置初始状态
|
||||||
|
StartButton.IsEnabled = true;
|
||||||
|
ProgressBar.Value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SubscribeToEvents()
|
||||||
|
{
|
||||||
|
// 订阅日志事件
|
||||||
|
_logger.MessageLogged += (sender, message) =>
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
LogTextBox.AppendText(message + Environment.NewLine);
|
||||||
|
LogTextBox.ScrollToEnd();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void StartButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_isProcessing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var codesText = CodesTextBox.Text;
|
||||||
|
if (string.IsNullOrWhiteSpace(codesText))
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show("请输入要处理的料号", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sourcePaths = GetSourcePaths();
|
||||||
|
if (!sourcePaths.Any())
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show("请至少配置一个源路径", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var destPath = DestPathTextBox.Text;
|
||||||
|
if (string.IsNullOrWhiteSpace(destPath))
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show("请配置目标路径", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isProcessing = true;
|
||||||
|
StartButton.IsEnabled = false;
|
||||||
|
ProgressBar.Value = 0;
|
||||||
|
LogTextBox.Clear();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Log("=== 开始处理 ===");
|
||||||
|
_logger.Log($"源路径: {string.Join(", ", sourcePaths)}");
|
||||||
|
_logger.Log($"目标路径: {destPath}");
|
||||||
|
|
||||||
|
var materialNumbers = codesText.Split(new[] { Environment.NewLine, "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var progress = new Progress<int>(value =>
|
||||||
|
{
|
||||||
|
ProgressBar.Value = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
await _fileService.ProcessCodes(materialNumbers, sourcePaths, destPath, progress, _logger);
|
||||||
|
|
||||||
|
_logger.Log("=== 处理完成 ===");
|
||||||
|
System.Windows.MessageBox.Show("处理完成!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError($"处理过程中发生错误: {ex.Message}");
|
||||||
|
System.Windows.MessageBox.Show($"处理过程中发生错误: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isProcessing = false;
|
||||||
|
StartButton.IsEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
CodesTextBox.Clear();
|
||||||
|
LogTextBox.Clear();
|
||||||
|
ProgressBar.Value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveConfigButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_config.SetSourcePathsFromText(SourcePathsTextBox.Text);
|
||||||
|
_config.DestPath = DestPathTextBox.Text;
|
||||||
|
_config.Save();
|
||||||
|
|
||||||
|
System.Windows.MessageBox.Show("配置已保存", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddSourceButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var dialog = new System.Windows.Forms.FolderBrowserDialog();
|
||||||
|
dialog.Description = "选择源路径";
|
||||||
|
|
||||||
|
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
||||||
|
{
|
||||||
|
var currentPaths = GetSourcePaths();
|
||||||
|
if (!currentPaths.Contains(dialog.SelectedPath))
|
||||||
|
{
|
||||||
|
currentPaths.Add(dialog.SelectedPath);
|
||||||
|
SourcePathsTextBox.Text = string.Join(Environment.NewLine, currentPaths);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BrowseDestButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var dialog = new System.Windows.Forms.FolderBrowserDialog();
|
||||||
|
dialog.Description = "选择目标路径";
|
||||||
|
|
||||||
|
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
||||||
|
{
|
||||||
|
DestPathTextBox.Text = dialog.SelectedPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<string> GetSourcePaths()
|
||||||
|
{
|
||||||
|
var paths = new List<string>();
|
||||||
|
if (!string.IsNullOrWhiteSpace(SourcePathsTextBox.Text))
|
||||||
|
{
|
||||||
|
paths = SourcePathsTextBox.Text.Split(new[] { Environment.NewLine, "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(p => p.Trim())
|
||||||
|
.Where(p => !string.IsNullOrEmpty(p))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SingleCodeTextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key == System.Windows.Input.Key.Enter)
|
||||||
|
{
|
||||||
|
ProcessSingleCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void AddSingleCodeButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
await ProcessSingleCodeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessSingleCode()
|
||||||
|
{
|
||||||
|
if (_isProcessing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var code = SingleCodeTextBox.Text.Trim();
|
||||||
|
if (string.IsNullOrWhiteSpace(code))
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show("请输入要处理的料号", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异步处理单个料号
|
||||||
|
_ = ProcessSingleCodeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcessSingleCodeAsync()
|
||||||
|
{
|
||||||
|
if (_isProcessing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var code = SingleCodeTextBox.Text.Trim();
|
||||||
|
if (string.IsNullOrWhiteSpace(code))
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show("请输入要处理的料号", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sourcePaths = GetSourcePaths();
|
||||||
|
if (!sourcePaths.Any())
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show("请至少配置一个源路径", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var destPath = DestPathTextBox.Text;
|
||||||
|
if (string.IsNullOrWhiteSpace(destPath))
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show("请配置目标路径", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isProcessing = true;
|
||||||
|
AddSingleCodeButton.IsEnabled = false;
|
||||||
|
SingleCodeTextBox.IsEnabled = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Log($"=== 开始处理单个料号: {code} ===");
|
||||||
|
_logger.Log($"源路径: {string.Join(", ", sourcePaths)}");
|
||||||
|
_logger.Log($"目标路径: {destPath}");
|
||||||
|
|
||||||
|
var materialNumbers = new List<string> { code };
|
||||||
|
|
||||||
|
// 创建一个简单的进度报告器,单个料号处理时直接设置为100%
|
||||||
|
var progress = new Progress<int>(value =>
|
||||||
|
{
|
||||||
|
// 对于单个料号,我们可以直接设置进度条
|
||||||
|
ProgressBar.Value = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
await _fileService.ProcessCodes(materialNumbers, sourcePaths, destPath, progress, _logger);
|
||||||
|
|
||||||
|
_logger.Log("=== 单个料号处理完成 ===");
|
||||||
|
|
||||||
|
// 清空输入框
|
||||||
|
SingleCodeTextBox.Clear();
|
||||||
|
|
||||||
|
// 将焦点返回到输入框,方便继续输入
|
||||||
|
SingleCodeTextBox.Focus();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError($"处理单个料号时发生错误: {ex.Message}");
|
||||||
|
System.Windows.MessageBox.Show($"处理单个料号时发生错误: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isProcessing = false;
|
||||||
|
AddSingleCodeButton.IsEnabled = true;
|
||||||
|
SingleCodeTextBox.IsEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnClosed(EventArgs e)
|
||||||
|
{
|
||||||
|
// 自动保存配置
|
||||||
|
_config.SetSourcePathsFromText(SourcePathsTextBox.Text);
|
||||||
|
_config.DestPath = DestPathTextBox.Text;
|
||||||
|
_config.Save();
|
||||||
|
|
||||||
|
base.OnClosed(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
87
README.md
Normal file
87
README.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# ROU文件复制工具
|
||||||
|
|
||||||
|
这是一个基于WPF的C#应用程序,用于根据编号和版本匹配文件夹,然后复制其中的.rou文件到目标位置。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- 根据输入的料号(如"27362a")自动匹配特定格式的文件夹
|
||||||
|
- 批量处理多个料号
|
||||||
|
- 复制匹配文件夹中的.rou、.rou1、.rou2、.rou3文件
|
||||||
|
- 实时显示处理进度和日志信息
|
||||||
|
- 配置管理(源路径、目标路径)
|
||||||
|
- 简洁易用的用户界面
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
### 1. 配置路径
|
||||||
|
|
||||||
|
- **源路径**:在"源路径"文本框中输入要搜索的根目录,每行一个路径
|
||||||
|
- 默认路径:
|
||||||
|
- `Z:\Routing\A1-ROUTING\NEW-ROUTING`
|
||||||
|
- `Z:\Routing\A2-ROUTING\NEW-ROUTING`
|
||||||
|
- **目标路径**:在"目标路径"文本框中输入复制文件的目标位置
|
||||||
|
- 默认路径:`D:\ARPTWork\rou`
|
||||||
|
|
||||||
|
### 2. 输入料号
|
||||||
|
|
||||||
|
在"料号输入"文本框中输入要处理的料号,每行一个,例如:
|
||||||
|
```
|
||||||
|
27362a
|
||||||
|
27363b
|
||||||
|
27364c
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 开始处理
|
||||||
|
|
||||||
|
点击"开始处理"按钮,应用程序将:
|
||||||
|
1. 根据每个料号的前5位作为数字部分,剩余部分作为版本部分
|
||||||
|
2. 在源路径中查找匹配的文件夹
|
||||||
|
3. 复制找到的.rou系列文件到目标路径
|
||||||
|
4. 显示处理进度和详细日志
|
||||||
|
|
||||||
|
### 4. 其他功能
|
||||||
|
|
||||||
|
- **清空**:清空输入的料号和日志
|
||||||
|
- **保存配置**:保存当前的路径配置
|
||||||
|
- **添加**:通过文件夹浏览器添加源路径
|
||||||
|
- **浏览**:通过文件夹浏览器选择目标路径
|
||||||
|
|
||||||
|
## 文件夹匹配规则
|
||||||
|
|
||||||
|
应用程序使用以下规则匹配文件夹:
|
||||||
|
- 料号格式:前5位为数字部分,剩余部分为版本部分
|
||||||
|
- 文件夹匹配:从文件夹名第4个字符开始匹配数字编号
|
||||||
|
- 搜索范围:在源路径下的数字编号文件夹中查找匹配的子文件夹
|
||||||
|
|
||||||
|
## 文件复制规则
|
||||||
|
|
||||||
|
- 只处理以"ED"或"ROU"开头的文件夹
|
||||||
|
- 复制扩展名为.rou、.rou1、.rou2、.rou3的文件
|
||||||
|
- 目标文件名格式:`{数字部分}_{文件夹名}_{原文件名}`
|
||||||
|
|
||||||
|
## 技术架构
|
||||||
|
|
||||||
|
- **框架**:.NET 6.0 WPF
|
||||||
|
- **架构模式**:分层架构,使用接口和依赖注入
|
||||||
|
- **主要组件**:
|
||||||
|
- `FileService`:核心文件操作逻辑
|
||||||
|
- `AppConfig`:配置管理
|
||||||
|
- `Logger`:日志记录
|
||||||
|
- `MainWindow`:用户界面
|
||||||
|
|
||||||
|
## 构建和运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 构建项目
|
||||||
|
dotnet build
|
||||||
|
|
||||||
|
# 运行应用程序
|
||||||
|
dotnet run
|
||||||
|
```
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
- 确保有足够的权限访问源路径和目标路径
|
||||||
|
- 目标路径会自动创建(如果不存在)
|
||||||
|
- 处理过程中请勿关闭应用程序
|
||||||
|
- 配置会自动保存,下次启动时会自动加载
|
||||||
108
demo/copy_rou.py
Normal file
108
demo/copy_rou.py
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
SOURCE_PATHS = [
|
||||||
|
r"Z:\Routing\A1-ROUTING\NEW-ROUTING",
|
||||||
|
r"Z:\Routing\A2-ROUTING\NEW-ROUTING"
|
||||||
|
]
|
||||||
|
DEST_PATH = r"D:\ARPTWork\rou"
|
||||||
|
|
||||||
|
def match_folder_name(folder_name, num_part, version_part):
|
||||||
|
"""匹配逻辑:从第四个字符开始匹配数字编号"""
|
||||||
|
folder_name_lower = folder_name.lower()
|
||||||
|
num_length = len(num_part)
|
||||||
|
|
||||||
|
if len(folder_name_lower) < 3 + num_length:
|
||||||
|
return False
|
||||||
|
|
||||||
|
num_in_name = folder_name_lower[4 : 4+num_length]
|
||||||
|
if num_in_name != num_part.lower():
|
||||||
|
return False
|
||||||
|
|
||||||
|
version_in_name = folder_name_lower[4+num_length:]
|
||||||
|
return version_in_name.startswith(version_part.lower())
|
||||||
|
|
||||||
|
def copy_rou_files(source_folder, number):
|
||||||
|
"""复制所有.rou系列文件"""
|
||||||
|
os.makedirs(DEST_PATH, exist_ok=True)
|
||||||
|
copied_files = []
|
||||||
|
ed_folders_found = 0
|
||||||
|
|
||||||
|
for item in os.listdir(source_folder):
|
||||||
|
item_path = os.path.join(source_folder, item)
|
||||||
|
|
||||||
|
if os.path.isdir(item_path) and (item.lower().startswith('ed') or item.lower().startswith('rou')):
|
||||||
|
ed_folders_found += 1
|
||||||
|
print(f"正在处理ED文件夹: {item}")
|
||||||
|
|
||||||
|
for root, _, files in os.walk(item_path):
|
||||||
|
for file in files:
|
||||||
|
if file.lower().endswith(('.rou', '.rou1', '.rou2', '.rou3')):
|
||||||
|
src_file = os.path.join(root, file)
|
||||||
|
base_name = f"{number}_{item}_{file}"
|
||||||
|
dest_file = os.path.join(DEST_PATH, base_name)
|
||||||
|
|
||||||
|
shutil.copy2(src_file, dest_file)
|
||||||
|
copied_files.append(base_name)
|
||||||
|
|
||||||
|
if ed_folders_found == 0:
|
||||||
|
print("警告: 未找到任何以ED开头的文件夹")
|
||||||
|
elif not copied_files:
|
||||||
|
print("警告: 在ED文件夹中未找到任何.rou系列文件")
|
||||||
|
else:
|
||||||
|
print(f"成功从 {ed_folders_found} 个ED文件夹复制 {len(copied_files)} 个文件:")
|
||||||
|
|
||||||
|
def process_codes(code_list):
|
||||||
|
"""处理多个代码"""
|
||||||
|
for code in code_list:
|
||||||
|
code = code.strip()
|
||||||
|
if not code:
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"\n处理编号: {code}")
|
||||||
|
num_part = code[:5]
|
||||||
|
version_part = code[len(num_part):]
|
||||||
|
|
||||||
|
found = False
|
||||||
|
for source_root in SOURCE_PATHS:
|
||||||
|
num_folder = os.path.join(source_root, num_part)
|
||||||
|
if not os.path.exists(num_folder):
|
||||||
|
continue
|
||||||
|
|
||||||
|
for folder in os.listdir(num_folder):
|
||||||
|
if match_folder_name(folder, num_part, version_part):
|
||||||
|
full_path = os.path.join(num_folder, folder)
|
||||||
|
print(f"找到匹配文件夹: {full_path}")
|
||||||
|
copy_rou_files(full_path, num_part)
|
||||||
|
found = True
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
print("未找到匹配的文件夹")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("=== 文件复制工具 ===")
|
||||||
|
print(f"搜索路径: {SOURCE_PATHS}")
|
||||||
|
print(f"目标路径: {DEST_PATH}")
|
||||||
|
print("输入说明:")
|
||||||
|
print("1. 直接输入单个编号,如: 27362a")
|
||||||
|
print("2. 输入多行编号(每行一个),最后输入end结束")
|
||||||
|
print("3. 输入exit退出程序")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
print("\n请输入编号(支持多行输入):")
|
||||||
|
user_inputs = []
|
||||||
|
|
||||||
|
while True:
|
||||||
|
line = input().strip()
|
||||||
|
if line.lower() == 'end':
|
||||||
|
break
|
||||||
|
if line.lower() == 'exit':
|
||||||
|
return
|
||||||
|
if line:
|
||||||
|
user_inputs.append(line)
|
||||||
|
|
||||||
|
if user_inputs:
|
||||||
|
process_codes(user_inputs)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user