refactor: 移除不再使用的配置文件与代码,优化用户界面
- 删除 config.json 和 requirements.txt 文件,移除 Python 版相关代码,简化项目结构。 - 更新 README.md,调整工具说明,强调仅保留 C# WinForms 版本。 - 在 MainForm.cs 中添加输入框的占位提示,提升用户体验。 - 更新 .gitignore,添加 debug.log 文件以记录运行时日志。 - 移除与 Python 版相关的示例 CSV 文件,确保数据源一致性。
This commit is contained in:
+120
-29
@@ -17,11 +17,8 @@ namespace TfsExcelImporter
|
||||
private TextBox _txtUrl = new TextBox();
|
||||
private TextBox _txtProject = new TextBox();
|
||||
private TextBox _txtType = new TextBox();
|
||||
private ComboBox _cmbAuth = new ComboBox();
|
||||
private TextBox _txtUser = new TextBox();
|
||||
private TextBox _txtPwd = new TextBox { UseSystemPasswordChar = true };
|
||||
private TextBox _txtDomain = new TextBox();
|
||||
private CheckBox _chkProxy = new CheckBox();
|
||||
|
||||
private ComboBox _cmbIteration = new ComboBox();
|
||||
private TextBox _txtExcel = new TextBox();
|
||||
@@ -31,7 +28,6 @@ namespace TfsExcelImporter
|
||||
private Button _btnBrowse = new Button();
|
||||
private Button _btnTemplate = new Button();
|
||||
private CheckBox _chkSkip = new CheckBox();
|
||||
private CheckBox _chkBypass = new CheckBox();
|
||||
|
||||
private DataGridView _grid = new DataGridView();
|
||||
private Button _btnPreview = new Button();
|
||||
@@ -52,9 +48,12 @@ namespace TfsExcelImporter
|
||||
private Card _cardConn, _cardData, _cardPreview, _cardLog, _cardAdv;
|
||||
private Surface _actionBar;
|
||||
private StepBadge _badgeRun;
|
||||
private InputField _fUrl, _fProject, _fType, _fAuth, _fUser, _fPwd, _fDomain,
|
||||
private InputField _fUrl, _fProject, _fType, _fUser, _fPwd,
|
||||
_fIteration, _fExcel, _fParent, _fArea;
|
||||
private Label _errIteration, _errExcel, _errParent, _errArea;
|
||||
private Label[] _connRowCaptions; // 第 1 步第二行的标签(重排时要跟着一起摆)
|
||||
private InputField[] _connRowFields; // 同排的四个输入框
|
||||
private int _connRowY;
|
||||
private EmptyState _lblEmpty;
|
||||
private StatusChip _chipConn, _chipOk, _chipSkip, _chipFail;
|
||||
|
||||
@@ -237,35 +236,94 @@ namespace TfsExcelImporter
|
||||
private void BuildCardConn()
|
||||
{
|
||||
_cardConn = MakeCard(1, "连接 TFS 服务器", true, Theme.Px(44));
|
||||
_cmbAuth.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
_cmbAuth.Items.AddRange(new object[] { "ntlm", "basic", "default" });
|
||||
|
||||
_fUrl = NewField(_txtUrl, 620, true);
|
||||
_fProject = NewField(_txtProject, 150, false);
|
||||
_fType = NewField(_txtType, 180, false);
|
||||
_fAuth = NewField(_cmbAuth, 170, false);
|
||||
_fDomain = NewField(_txtDomain, 150, false);
|
||||
_fUser = NewField(_txtUser, 180, false);
|
||||
_fPwd = NewField(_txtPwd, 200, true);
|
||||
_fType = NewField(_txtType, 150, false);
|
||||
_fUser = NewField(_txtUser, 150, false);
|
||||
_fPwd = NewField(_txtPwd, 150, true);
|
||||
|
||||
// 空态占位提示(cue banner):只在该输入框没填内容时显示
|
||||
CueBanner.Set(_txtUrl, "如 http://server:8080/tfs/DefaultCollection");
|
||||
CueBanner.Set(_txtProject, "如 Tools_Dev");
|
||||
CueBanner.Set(_txtType, "如 Task");
|
||||
CueBanner.Set(_txtUser, "留空用当前 Windows 身份");
|
||||
CueBanner.Set(_txtPwd, "域账号密码(同上可选)");
|
||||
|
||||
_btnTest = NewButton("测试连接", BtnKind.Secondary, IconKind.Bolt, 130);
|
||||
_chkProxy = NewCheck("使用系统代理", "内网 TFS 请保持关闭,勾选后常被代理拦成 502");
|
||||
|
||||
int y = _cardConn.HeaderH + Theme.S12;
|
||||
// 三行表单共用一条字段左缘:标签列宽取各行最大值,同列字段宽度归一
|
||||
int w1 = MaxLabelWidth("服务器 URL", "团队项目", "域");
|
||||
int w2 = MaxLabelWidth("工作项类型", "用户");
|
||||
int w3 = MaxLabelWidth("认证方式", "密码");
|
||||
y = Row(_cardConn, y, 42, new Lbl("服务器 URL", w1), _fUrl);
|
||||
y = Row(_cardConn, y, 42, new Lbl("服务器 URL", MaxLabelWidth("服务器 URL")), _fUrl);
|
||||
Track(_fUrl, _cardConn, M, 0);
|
||||
y = Row(_cardConn, y, 42, new Lbl("团队项目", w1), _fProject,
|
||||
new Lbl("工作项类型", w2), _fType, new Lbl("认证方式", w3), _fAuth);
|
||||
y = Row(_cardConn, y, 42, new Lbl("域", w1), _fDomain,
|
||||
new Lbl("用户", w2), _fUser, new Lbl("密码", w3), _fPwd, G, _btnTest);
|
||||
y = Row(_cardConn, y, 26, _chkProxy);
|
||||
|
||||
// 第二行:项目 / 类型 / 用户 / 密码 + 测试连接同排,四个输入框等宽、整行铺满卡片内容区。
|
||||
// 标签自建并留引用——窗口变宽时要连标签一起重摆,Row() 建完就丢引用做不到。
|
||||
_connRowY = y;
|
||||
var captions = new[] { "团队项目", "工作项类型", "用户", "密码" };
|
||||
_connRowCaptions = new Label[captions.Length];
|
||||
_connRowFields = new[] { _fProject, _fType, _fUser, _fPwd };
|
||||
for (int i = 0; i < captions.Length; i++)
|
||||
{
|
||||
// 标签宽度由布局按各自文字量给(不死板地共用一条定宽列):四个标签字数不同
|
||||
// (2~5 字),共用定宽列会让「用户」「密码」和自己的输入框之间空出一大截。
|
||||
var lbl = new Label
|
||||
{
|
||||
Text = captions[i],
|
||||
Font = Theme.Body,
|
||||
ForeColor = Theme.Ink2,
|
||||
AutoSize = false, // 宽度每次重排时按文字量给
|
||||
TextAlign = ContentAlignment.MiddleRight, // 文字右缘贴住输入框
|
||||
BackColor = Theme.Card
|
||||
};
|
||||
_cardConn.Controls.Add(lbl);
|
||||
_connRowCaptions[i] = lbl;
|
||||
_connRowFields[i].AccessibleName = captions[i];
|
||||
_cardConn.Controls.Add(_connRowFields[i]);
|
||||
}
|
||||
_cardConn.Controls.Add(_btnTest);
|
||||
_layoutExtras.Add(LayoutConnRow);
|
||||
|
||||
y = _connRowY + Theme.Px(42);
|
||||
_cardConn.BodyH = y - _cardConn.HeaderH + Theme.S8;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 第 1 步第二行排布:四个输入框同宽,整行(含「测试连接」)刚好铺满卡片内容区。
|
||||
/// 每个标签只占自己文字的宽度,于是「文字 → 输入框」恒为 6px、「输入框 → 下一个标签」
|
||||
/// 恒为 S12,四组间距完全一致;省下的宽度全给输入框,输入框因此比按定宽标签列算的更宽。
|
||||
/// 每次重排按当期卡片宽度重算,缩放/拉伸下都不溢出、不留白。
|
||||
/// </summary>
|
||||
private void LayoutConnRow()
|
||||
{
|
||||
if (_connRowFields == null || _connRowCaptions == null) return;
|
||||
int gap = Theme.S12; // 组与组之间
|
||||
int lblGap = Theme.Px(6); // 标签文字 → 输入框(全行同一个值)
|
||||
int n = _connRowFields.Length;
|
||||
int avail = _cardConn.Width - M * 2;
|
||||
|
||||
// 每个标签只占自己文字宽度(+2px 防末字被裁),省下的宽度全部喂给输入框,
|
||||
// 这样「文字→输入框」和「输入框→下一个标签」两处间距在四组上都是同一个值。
|
||||
var lblW = new int[n];
|
||||
int textSum = 0;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
lblW[i] = Theme.TextWidth(_connRowCaptions[i].Text, Theme.Body) + Theme.Px(2);
|
||||
textSum += lblW[i];
|
||||
}
|
||||
int boxW = (avail - textSum - n * lblGap - (n - 1) * gap - G - _btnTest.Width) / n;
|
||||
boxW = Math.Max(Theme.Px(96), boxW);
|
||||
|
||||
int x = M;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
_connRowCaptions[i].SetBounds(x, _connRowY, lblW[i], Theme.FieldH);
|
||||
x += lblW[i] + lblGap;
|
||||
_connRowFields[i].SetBounds(x, _connRowY, boxW, Theme.FieldH);
|
||||
x += boxW + gap;
|
||||
}
|
||||
_btnTest.SetBounds(x - gap + G, _connRowY, _btnTest.Width, Theme.BtnH);
|
||||
}
|
||||
|
||||
// --- 步骤 2:迭代与数据源 ---
|
||||
private void BuildCardData()
|
||||
{
|
||||
@@ -276,11 +334,14 @@ namespace TfsExcelImporter
|
||||
_fExcel = NewField(_txtExcel, 500, true);
|
||||
_fParent = NewField(_txtParentPbi, 150, true);
|
||||
|
||||
CueBanner.Set(_cmbIteration, "选择或手填完整迭代路径,如 Tools_Dev\\Sprint 1");
|
||||
CueBanner.Set(_txtExcel, "选择 .xlsx 文件,或点右侧「浏览…」");
|
||||
CueBanner.Set(_txtParentPbi, "如 219975");
|
||||
|
||||
_btnLoadIterations = NewButton("加载迭代列表", BtnKind.Secondary, IconKind.Fetch, 130);
|
||||
_btnBrowse = NewButton("浏览…", BtnKind.Secondary, IconKind.Folder, 92);
|
||||
_btnTemplate = NewButton("导出 Excel 模板", BtnKind.Secondary, IconKind.Doc, 142);
|
||||
_chkSkip = NewCheck("跳过已存在标题", "");
|
||||
_chkBypass = NewCheck("bypassRules(绕过字段校验规则)", "");
|
||||
|
||||
// 三行字段对齐同一条左缘:标签列宽取最大值
|
||||
int wLbl = MaxLabelWidth("目标迭代", "Excel 文件", "父 PBI Id");
|
||||
@@ -292,8 +353,12 @@ namespace TfsExcelImporter
|
||||
AnchorRight(_btnTemplate, _cardData, M, _fExcel.Top);
|
||||
AnchorRight(_btnBrowse, _cardData, _btnTemplate.Width + G + M, _fExcel.Top);
|
||||
Track(_fExcel, _cardData, _btnTemplate.Width + _btnBrowse.Width + G * 2 + M, 0);
|
||||
y = Row(_cardData, y, 42, new Lbl("父 PBI Id", wLbl), _fParent, "Task 默认挂到该 backlog item;Excel 里加 PBI Id 列可逐行覆盖");
|
||||
y = Row(_cardData, y, 24, _chkSkip, 2 * G, _chkBypass);
|
||||
y = Row(_cardData, y, 42, new Lbl("父 PBI Id", wLbl), _fParent,
|
||||
new Hint("Task 默认挂到该 backlog item;Excel 里加 PBI Id 列可逐行覆盖"));
|
||||
// 勾选项不再贴着标签起头:整体右移到上面三行输入框的左缘(跳过标签列)。
|
||||
// 只有「去重」这一个开关;字段校验不可绕过(OM 14.x 无 BypassRules),失败时由
|
||||
// TfsClient 输出可操作的修复提示。
|
||||
y = Row(_cardData, y, 32, _fParent.Left - M, _chkSkip);
|
||||
|
||||
_errIteration = AddErrorUnder(_cardData, _fIteration);
|
||||
_errExcel = AddErrorUnder(_cardData, _fExcel);
|
||||
@@ -474,11 +539,13 @@ namespace TfsExcelImporter
|
||||
_cardAdv = MakeCard(0, "高级工具", true, Theme.Px(36));
|
||||
_cardAdv.ShowBadge = false;
|
||||
_fArea = NewField(_txtAreaPath, 420, true);
|
||||
CueBanner.Set(_txtAreaPath, "如 Tools_Dev\\导入工具,留空则沿用工作项现有 Area");
|
||||
_btnFixArea = NewButton("按迭代修 Area", BtnKind.Secondary, IconKind.Wrench, 158);
|
||||
_btnLinkParent = NewButton("补挂父项", BtnKind.Secondary, IconKind.Tree, 120);
|
||||
|
||||
int y = _cardAdv.HeaderH + Theme.S12;
|
||||
y = Row(_cardAdv, y, 52, "Area 路径", _fArea, "改 Area 与补挂父项都按上面的「目标迭代」筛选已有工作项");
|
||||
y = Row(_cardAdv, y, 52, "Area 路径", _fArea,
|
||||
new Hint("改 Area 与补挂父项都按上面的「目标迭代」筛选已有工作项"));
|
||||
y = Row(_cardAdv, y, 34, _btnFixArea, G, _btnLinkParent, G, "已关闭的工作项会被临时重新打开,完成后自动还原状态");
|
||||
_errArea = AddErrorUnder(_cardAdv, _fArea);
|
||||
_cardAdv.BodyH = y - _cardAdv.HeaderH + Theme.S8;
|
||||
@@ -494,6 +561,14 @@ namespace TfsExcelImporter
|
||||
public Lbl(string text, int minWidth) { Text = text; MinWidth = minWidth; }
|
||||
}
|
||||
|
||||
/// <summary>紧跟在字段后面的灰色说明(Caption 字号 + Ink3):非标签、不参与标签列宽计算。</summary>
|
||||
private class Hint
|
||||
{
|
||||
public readonly string Text;
|
||||
|
||||
public Hint(string text) { Text = text; }
|
||||
}
|
||||
|
||||
/// <summary>一组标签文字的最大实测宽度,用作对齐列宽。</summary>
|
||||
private static int MaxLabelWidth(params string[] texts)
|
||||
{
|
||||
@@ -532,6 +607,23 @@ namespace TfsExcelImporter
|
||||
|
||||
if (item is int) { x += (int)item; continue; }
|
||||
|
||||
var hint = item as Hint;
|
||||
if (hint != null)
|
||||
{
|
||||
var hl = new Label
|
||||
{
|
||||
Text = hint.Text,
|
||||
Font = Theme.Caption,
|
||||
ForeColor = Theme.Ink3,
|
||||
AutoSize = true,
|
||||
BackColor = Theme.Card
|
||||
};
|
||||
hl.SetBounds(x, y + (Theme.FieldH - hl.PreferredHeight) / 2, hl.PreferredWidth, hl.PreferredHeight);
|
||||
card.Controls.Add(hl);
|
||||
x += hl.Width + Theme.S12;
|
||||
continue;
|
||||
}
|
||||
|
||||
var c = item as Control;
|
||||
if (c == null) continue;
|
||||
int top = y + Math.Max(0, (Theme.FieldH - c.Height) / 2);
|
||||
@@ -793,8 +885,7 @@ namespace TfsExcelImporter
|
||||
{
|
||||
ShortHost(_txtUrl.Text.Trim()),
|
||||
_txtProject.Text.Trim(),
|
||||
_txtType.Text.Trim(),
|
||||
_cmbAuth.SelectedItem != null ? _cmbAuth.SelectedItem.ToString() : "ntlm"
|
||||
_txtType.Text.Trim()
|
||||
}));
|
||||
_cardData.SetSummary(string.Join(" · ", new[]
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user