Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
F
Ftt_Common
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Ftt_Common
Commits
0020a375
Commit
0020a375
authored
Oct 21, 2026
by
段廷瑞
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: Agent日志查看增加数据库链接配置;优化对话窗口交互
parent
2ecc48c8
Changes
13
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
753 additions
and
55 deletions
+753
-55
.gitignore
.gitignore
+1
-0
KbServiceSandboxTests.cs
AgentTest/KbServiceSandboxTests.cs
+19
-0
Tools.Agent.dll
AppHome/Tools.Agent.dll
+0
-0
Tools.Agent.xml
AppHome/Tools.Agent.xml
+76
-0
AgentRuntime.cs
Tools.Agent/AgentRuntime.cs
+23
-0
AgentDbConfigForm.Designer.cs
Tools.Agent/Forms/AgentDbConfigForm.Designer.cs
+223
-0
AgentDbConfigForm.cs
Tools.Agent/Forms/AgentDbConfigForm.cs
+126
-0
AgentDbConfigForm.resx
Tools.Agent/Forms/AgentDbConfigForm.resx
+71
-0
AgentRunLogForm.Designer.cs
Tools.Agent/Forms/AgentRunLogForm.Designer.cs
+24
-10
AgentRunLogForm.cs
Tools.Agent/Forms/AgentRunLogForm.cs
+34
-2
KbService.cs
Tools.Agent/Kb/KbService.cs
+32
-23
Tools.Agent.csproj
Tools.Agent/Tools.Agent.csproj
+9
-0
wMyAgent.cs
Tools.Agent/wMyAgent.cs
+115
-20
No files found.
.gitignore
View file @
0020a375
...
@@ -77,3 +77,4 @@ bin
...
@@ -77,3 +77,4 @@ bin
/temp
/temp
/AppHome/_backup
/AppHome/_backup
/Tools.Agent.ProbeKbPref
/Tools.Agent.ProbeKbPref
/working
AgentTest/KbServiceSandboxTests.cs
View file @
0020a375
...
@@ -138,6 +138,25 @@ namespace AgentTest
...
@@ -138,6 +138,25 @@ namespace AgentTest
}
}
}
}
[
Test
]
public
void
FileCount_RefreshesWhenScopeChanges
()
{
File
.
WriteAllText
(
Path
.
Combine
(
_root
,
"root.md"
),
"root"
);
File
.
WriteAllText
(
Path
.
Combine
(
_root
,
"docs"
,
"b.md"
),
"b"
);
using
(
var
refreshed
=
new
System
.
Threading
.
ManualResetEventSlim
(
false
))
{
_kb
.
StatsRefreshed
+=
()
=>
refreshed
.
Set
();
_kb
.
EnsureStats
();
Assert
.
True
(
refreshed
.
Wait
(
5000
),
"根目录统计应在后台完成"
);
Assert
.
Equal
(
3
,
_kb
.
FileCount
,
"根目录文件数应包含所有知识库文件"
);
refreshed
.
Reset
();
_kb
.
SetScope
(
Path
.
Combine
(
_root
,
"docs"
));
Assert
.
True
(
refreshed
.
Wait
(
5000
),
"切换范围后应重新统计"
);
Assert
.
Equal
(
2
,
_kb
.
FileCount
,
"切换范围后文件数应只包含当前目录"
);
}
}
[
Test
]
[
Test
]
public
void
SetScope_OutsideRoot_FallsBackToRoot
()
public
void
SetScope_OutsideRoot_FallsBackToRoot
()
{
{
...
...
AppHome/Tools.Agent.dll
View file @
0020a375
No preview for this file type
AppHome/Tools.Agent.xml
View file @
0020a375
...
@@ -59,6 +59,13 @@
...
@@ -59,6 +59,13 @@
RunDbConnection 已解密为明文。供无上下文的工具模块(Activator 无参创建)自取上报配置;失败返回 null。
RunDbConnection 已解密为明文。供无上下文的工具模块(Activator 无参创建)自取上报配置;失败返回 null。
</summary>
</summary>
</member>
</member>
<member
name=
"M:Tools.MyAgent.AgentRuntime.SaveLocalRunDbConfig(System.String,System.String,System.Boolean)"
>
<summary>
把对话上报连接(Agent 日志窗口"连接配置"保存)写回本机 AgentConfig.json。
<para>
以 JObject 原文补丁方式只改 RunDb* 三个字段,**不触碰其他配置**(避免全量投影覆盖宿主注入项);
连接串经
<see
cref=
"T:Tools.MyAgent.Config.SecretProtector"
/>
DPAPI 加密落盘,密码不落明文。返回是否成功。
</para>
</summary>
</member>
<member
name=
"T:Tools.MyAgent.AgentProductContext"
>
<member
name=
"T:Tools.MyAgent.AgentProductContext"
>
<summary>
<summary>
宿主声明的产品上下文。产品身份来自注册表,项目路径由宿主按权限注入。
宿主声明的产品上下文。产品身份来自注册表,项目路径由宿主按权限注入。
...
@@ -1581,6 +1588,12 @@
...
@@ -1581,6 +1588,12 @@
<para>
控件布局由 AgentRunLogForm.Designer.cs(设计器)实现;本文件仅含逻辑。
</para>
<para>
控件布局由 AgentRunLogForm.Designer.cs(设计器)实现;本文件仅含逻辑。
</para>
</summary>
</summary>
</member>
</member>
<member
name=
"F:Tools.MyAgent.Forms.AgentRunLogForm._connection"
>
<summary>
当前上报连接(明文,窗口内可经"连接配置"切换)。
</summary>
</member>
<member
name=
"F:Tools.MyAgent.Forms.AgentRunLogForm._table"
>
<summary>
当前日志表名。
</summary>
</member>
<member
name=
"F:Tools.MyAgent.Forms.AgentRunLogForm._currentRunId"
>
<member
name=
"F:Tools.MyAgent.Forms.AgentRunLogForm._currentRunId"
>
<summary>
当前选中行的 RunId(详情二次查询用)。
</summary>
<summary>
当前选中行的 RunId(详情二次查询用)。
</summary>
</member>
</member>
...
@@ -1610,6 +1623,12 @@
...
@@ -1610,6 +1623,12 @@
RichEdit 静默解析失败 ⇒ 空白)。
RichEdit 静默解析失败 ⇒ 空白)。
</summary>
</summary>
</member>
</member>
<member
name=
"M:Tools.MyAgent.Forms.AgentRunLogForm.OnConnConfigClick(System.Object,System.EventArgs)"
>
<summary>
"连接配置":IP → 账号 → 密码 → 库(下拉拉取 sys.databases);
确定后写回 AgentConfig.json(DPAPI 加密)并刷新本窗口的连接与列表。
</summary>
</member>
<member
name=
"M:Tools.MyAgent.Forms.AgentRunLogForm.Q(System.String)"
>
<member
name=
"M:Tools.MyAgent.Forms.AgentRunLogForm.Q(System.String)"
>
<summary>
表名标识(白名单已在 Reporter/配置层校验;此处再防御)。
</summary>
<summary>
表名标识(白名单已在 Reporter/配置层校验;此处再防御)。
</summary>
</member>
</member>
...
@@ -1630,6 +1649,51 @@
...
@@ -1630,6 +1649,51 @@
使用代码编辑器修改此方法的内容。
使用代码编辑器修改此方法的内容。
</summary>
</summary>
</member>
</member>
<member
name=
"T:Tools.MyAgent.Forms.AgentDbConfigForm"
>
<summary>
Agent 日志窗口的数据库连接配置对话框(2026-10-19):IP / 数据库 / 账号 / 密码 / 表名,
支持测试连接;确定后由 AgentRunLogForm 经
<see
cref=
"M:Tools.MyAgent.AgentRuntime.SaveLocalRunDbConfig(System.String,System.String,System.Boolean)"
/>
写回 AgentConfig.json(连接串 DPAPI 加密落盘,密码不落明文)。
</summary>
</member>
<member
name=
"F:Tools.MyAgent.Forms.AgentDbConfigForm._existing"
>
<summary>
现有连接串(预填用;可能为空)。
</summary>
</member>
<member
name=
"M:Tools.MyAgent.Forms.AgentDbConfigForm.Prefill"
>
<summary>
用现有连接串预填各输入框(解析失败保持空白,不阻断)。
</summary>
</member>
<member
name=
"M:Tools.MyAgent.Forms.AgentDbConfigForm.OnDbDropDown(System.Object,System.EventArgs)"
>
<summary>
数据库下拉展开时按当前 IP/账号/密码拉取实例库列表(SELECT name FROM sys.databases);
拉取失败静默保留已输入值(可手填)。每次展开都刷新,改过连接信息后无需重开对话框。
</summary>
</member>
<member
name=
"M:Tools.MyAgent.Forms.AgentDbConfigForm.BuildConnectionString"
>
<summary>
按输入拼装连接串(SqlConnectionStringBuilder 负责转义)。
</summary>
</member>
<member
name=
"P:Tools.MyAgent.Forms.AgentDbConfigForm.Table"
>
<summary>
表名(含校验,非法字符在保存侧再防御一层)。
</summary>
</member>
<member
name=
"P:Tools.MyAgent.Forms.AgentDbConfigForm.EnableReporting"
>
<summary>
是否同时启用对话上报(默认勾选,避免"测试通过但不落库"的旧坑)。
</summary>
</member>
<member
name=
"F:Tools.MyAgent.Forms.AgentDbConfigForm.components"
>
<summary>
必需的设计器变量。
</summary>
</member>
<member
name=
"M:Tools.MyAgent.Forms.AgentDbConfigForm.Dispose(System.Boolean)"
>
<summary>
清理所有正在使用的资源。
</summary>
<param
name=
"disposing"
>
如果应释放托管资源,为 true;否则为 false。
</param>
</member>
<member
name=
"M:Tools.MyAgent.Forms.AgentDbConfigForm.InitializeComponent"
>
<summary>
设计器支持所需的方法 - 不要修改
使用代码编辑器修改此方法的内容。
</summary>
</member>
<member
name=
"T:Tools.MyAgent.Forms.DocLineViewer"
>
<member
name=
"T:Tools.MyAgent.Forms.DocLineViewer"
>
<summary>
<summary>
文档行定位查看器(P4 引用行点击):只读展示文本类文件,并定位高亮到指定行。
文档行定位查看器(P4 引用行点击):只读展示文本类文件,并定位高亮到指定行。
...
@@ -3664,6 +3728,9 @@
...
@@ -3664,6 +3728,9 @@
<member
name=
"P:Tools.MyAgent.wMyAgent.DefaultKbRoot"
>
<member
name=
"P:Tools.MyAgent.wMyAgent.DefaultKbRoot"
>
<summary>
默认知识库路径:程序输出目录下的 Agent 文件夹(未设置知识库时生效)
</summary>
<summary>
默认知识库路径:程序输出目录下的 Agent 文件夹(未设置知识库时生效)
</summary>
</member>
</member>
<member
name=
"P:Tools.MyAgent.wMyAgent.ProductFixedScope"
>
<summary>
产品上下文真正固定的搜索子目录;旧宿主把根目录作为范围时视为未固定。
</summary>
</member>
<member
name=
"P:Tools.MyAgent.wMyAgent.AgentConfigFilePath"
>
<member
name=
"P:Tools.MyAgent.wMyAgent.AgentConfigFilePath"
>
<summary>
Agent 配置文件:默认 Agent 目录下的 config\AgentConfig.json
</summary>
<summary>
Agent 配置文件:默认 Agent 目录下的 config\AgentConfig.json
</summary>
</member>
</member>
...
@@ -3683,12 +3750,21 @@
...
@@ -3683,12 +3750,21 @@
<member
name=
"M:Tools.MyAgent.wMyAgent.WorkingDirForHistory"
>
<member
name=
"M:Tools.MyAgent.wMyAgent.WorkingDirForHistory"
>
<summary>
历史记录固定保存到默认 Agent 目录(与所选知识库无关)
</summary>
<summary>
历史记录固定保存到默认 Agent 目录(与所选知识库无关)
</summary>
</member>
</member>
<member
name=
"M:Tools.MyAgent.wMyAgent.ApplyWindowModePadding"
>
<summary>
独立窗口增加 10px 内边距;嵌入宿主 Tab 时保持原有布局。
</summary>
</member>
<member
name=
"M:Tools.MyAgent.wMyAgent.WireRtfEvents"
>
<member
name=
"M:Tools.MyAgent.wMyAgent.WireRtfEvents"
>
<summary>
RichTextBox 的点击/悬停交互绑定(启动时调用;新实例不会重复绑定)
</summary>
<summary>
RichTextBox 的点击/悬停交互绑定(启动时调用;新实例不会重复绑定)
</summary>
</member>
</member>
<member
name=
"M:Tools.MyAgent.wMyAgent.RefreshChatRtf"
>
<member
name=
"M:Tools.MyAgent.wMyAgent.RefreshChatRtf"
>
<summary>
RichBox 模式:整段 RTF 重建(增量渲染缓存)
</summary>
<summary>
RichBox 模式:整段 RTF 重建(增量渲染缓存)
</summary>
</member>
</member>
<member
name=
"M:Tools.MyAgent.wMyAgent.IsChatAtBottom(System.Int32@)"
>
<summary>
判断聊天区重绘前是否已经位于底部;用户上滚查看历史时保持其视口。
</summary>
</member>
<member
name=
"M:Tools.MyAgent.wMyAgent.RestoreChatScroll(System.Int32)"
>
<summary>
恢复聊天区重绘前的首行位置,避免后台刷新把用户拉回回答末尾。
</summary>
</member>
<member
name=
"M:Tools.MyAgent.wMyAgent.RebuildAnswerRefs"
>
<member
name=
"M:Tools.MyAgent.wMyAgent.RebuildAnswerRefs"
>
<summary>
<summary>
重建引用行表(P4):从渲染文本中扫出 📎 引用行并解析 路径/章节/行号。
重建引用行表(P4):从渲染文本中扫出 📎 引用行并解析 路径/章节/行号。
...
...
Tools.Agent/AgentRuntime.cs
View file @
0020a375
...
@@ -134,6 +134,29 @@ namespace Tools.MyAgent
...
@@ -134,6 +134,29 @@ namespace Tools.MyAgent
catch
{
return
null
;
}
catch
{
return
null
;
}
}
}
/// <summary>
/// 把对话上报连接(Agent 日志窗口"连接配置"保存)写回本机 AgentConfig.json。
/// <para>以 JObject 原文补丁方式只改 RunDb* 三个字段,**不触碰其他配置**(避免全量投影覆盖宿主注入项);
/// 连接串经 <see cref="Config.SecretProtector"/> DPAPI 加密落盘,密码不落明文。返回是否成功。</para>
/// </summary>
public
static
bool
SaveLocalRunDbConfig
(
string
plainConnection
,
string
table
,
bool
enabled
)
{
try
{
string
path
=
Path
.
Combine
(
AppDomain
.
CurrentDomain
.
BaseDirectory
,
"Agent"
,
"config"
,
"AgentConfig.json"
);
var
root
=
File
.
Exists
(
path
)
?
Newtonsoft
.
Json
.
Linq
.
JObject
.
Parse
(
File
.
ReadAllText
(
path
,
System
.
Text
.
Encoding
.
UTF8
))
:
new
Newtonsoft
.
Json
.
Linq
.
JObject
();
root
[
"RunDbEnabled"
]
=
enabled
;
root
[
"RunDbConnection"
]
=
Config
.
SecretProtector
.
Protect
(
plainConnection
??
""
);
root
[
"RunDbTable"
]
=
string
.
IsNullOrWhiteSpace
(
table
)
?
"Agent_RunLog"
:
table
.
Trim
();
Directory
.
CreateDirectory
(
System
.
IO
.
Path
.
GetDirectoryName
(
path
));
File
.
WriteAllText
(
path
,
root
.
ToString
(
Newtonsoft
.
Json
.
Formatting
.
Indented
),
System
.
Text
.
Encoding
.
UTF8
);
return
true
;
}
catch
{
return
false
;
}
}
private
void
EnsureDefaultResources
()
private
void
EnsureDefaultResources
()
{
{
Directory
.
CreateDirectory
(
DataRoot
);
Directory
.
CreateDirectory
(
DataRoot
);
...
...
Tools.Agent/Forms/AgentDbConfigForm.Designer.cs
0 → 100644
View file @
0020a375
This diff is collapsed.
Click to expand it.
Tools.Agent/Forms/AgentDbConfigForm.cs
0 → 100644
View file @
0020a375
using
System
;
using
System.Collections.Generic
;
using
System.Data.SqlClient
;
using
System.Windows.Forms
;
namespace
Tools.MyAgent.Forms
{
/// <summary>
/// Agent 日志窗口的数据库连接配置对话框(2026-10-19):IP / 数据库 / 账号 / 密码 / 表名,
/// 支持测试连接;确定后由 AgentRunLogForm 经 <see cref="AgentRuntime.SaveLocalRunDbConfig"/>
/// 写回 AgentConfig.json(连接串 DPAPI 加密落盘,密码不落明文)。
/// </summary>
public
partial
class
AgentDbConfigForm
:
Form
{
/// <summary>现有连接串(预填用;可能为空)。</summary>
private
readonly
string
_existing
;
public
AgentDbConfigForm
(
string
existingConnection
,
string
table
)
{
_existing
=
existingConnection
??
""
;
InitializeComponent
();
Prefill
();
txtTable
.
Text
=
string
.
IsNullOrWhiteSpace
(
table
)
?
"Agent_RunLog"
:
table
.
Trim
();
}
/// <summary>用现有连接串预填各输入框(解析失败保持空白,不阻断)。</summary>
private
void
Prefill
()
{
if
(
_existing
.
Trim
().
Length
==
0
)
return
;
try
{
var
b
=
new
SqlConnectionStringBuilder
(
_existing
);
txtServer
.
Text
=
b
.
DataSource
??
""
;
txtUser
.
Text
=
b
.
UserID
??
""
;
txtPwd
.
Text
=
b
.
Password
??
""
;
cmbDb
.
Text
=
b
.
InitialCatalog
??
""
;
}
catch
{
/* 旧连接串解析失败 → 留空白让用户重填 */
}
}
/// <summary>
/// 数据库下拉展开时按当前 IP/账号/密码拉取实例库列表(SELECT name FROM sys.databases);
/// 拉取失败静默保留已输入值(可手填)。每次展开都刷新,改过连接信息后无需重开对话框。
/// </summary>
private
void
OnDbDropDown
(
object
sender
,
EventArgs
e
)
{
try
{
if
(
txtServer
.
Text
.
Trim
().
Length
==
0
)
return
;
string
current
=
cmbDb
.
Text
;
// 保留手填值
var
names
=
new
List
<
string
>();
using
(
var
conn
=
new
SqlConnection
(
BuildConnectionString
()))
using
(
var
cmd
=
new
SqlCommand
(
"SELECT name FROM sys.databases WHERE state = 0 ORDER BY name"
,
conn
))
{
conn
.
Open
();
using
(
var
reader
=
cmd
.
ExecuteReader
())
while
(
reader
.
Read
())
names
.
Add
(
Convert
.
ToString
(
reader
[
"name"
]));
}
cmbDb
.
Items
.
Clear
();
cmbDb
.
Items
.
AddRange
(
names
.
ToArray
());
cmbDb
.
Text
=
current
;
}
catch
{
/* 连不上/权限不足 → 下拉为空,用户仍可手填 */
}
}
/// <summary>按输入拼装连接串(SqlConnectionStringBuilder 负责转义)。</summary>
public
string
BuildConnectionString
()
{
return
new
SqlConnectionStringBuilder
{
DataSource
=
txtServer
.
Text
.
Trim
(),
InitialCatalog
=
cmbDb
.
Text
.
Trim
(),
UserID
=
txtUser
.
Text
.
Trim
(),
Password
=
txtPwd
.
Text
,
ConnectTimeout
=
5
,
}.
ConnectionString
;
}
/// <summary>表名(含校验,非法字符在保存侧再防御一层)。</summary>
public
string
Table
=>
txtTable
.
Text
.
Trim
();
/// <summary>是否同时启用对话上报(默认勾选,避免"测试通过但不落库"的旧坑)。</summary>
public
bool
EnableReporting
=>
chkEnable
.
Checked
;
private
void
OnTestClick
(
object
sender
,
EventArgs
e
)
{
try
{
if
(
txtServer
.
Text
.
Trim
().
Length
==
0
||
cmbDb
.
Text
.
Trim
().
Length
==
0
)
{
MessageBox
.
Show
(
this
,
"请先填写服务器与数据库。"
,
"测试连接"
,
MessageBoxButtons
.
OK
,
MessageBoxIcon
.
Warning
);
return
;
}
Cursor
=
Cursors
.
WaitCursor
;
using
(
var
conn
=
new
SqlConnection
(
BuildConnectionString
()))
using
(
var
cmd
=
new
SqlCommand
(
"SELECT 1"
,
conn
))
{
conn
.
Open
();
cmd
.
ExecuteScalar
();
}
Cursor
=
Cursors
.
Default
;
MessageBox
.
Show
(
this
,
"连接成功。"
,
"测试连接"
,
MessageBoxButtons
.
OK
,
MessageBoxIcon
.
Information
);
}
catch
(
Exception
ex
)
{
Cursor
=
Cursors
.
Default
;
MessageBox
.
Show
(
this
,
"连接失败:"
+
ex
.
Message
,
"测试连接"
,
MessageBoxButtons
.
OK
,
MessageBoxIcon
.
Error
);
}
}
private
void
OnOkClick
(
object
sender
,
EventArgs
e
)
{
if
(
txtServer
.
Text
.
Trim
().
Length
==
0
||
cmbDb
.
Text
.
Trim
().
Length
==
0
)
{
MessageBox
.
Show
(
this
,
"服务器与数据库为必填项。"
,
"保存"
,
MessageBoxButtons
.
OK
,
MessageBoxIcon
.
Warning
);
return
;
}
DialogResult
=
DialogResult
.
OK
;
}
}
}
Tools.Agent/Forms/AgentDbConfigForm.resx
0 → 100644
View file @
0020a375
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
-->
<xsd:schema
id=
"root"
xmlns=
""
xmlns:xsd=
"http://www.w3.org/2001/XMLSchema"
xmlns:msdata=
"urn:schemas-microsoft-com:xml-msdata"
>
<xsd:import
namespace=
"http://www.w3.org/XML/1998/namespace"
/>
<xsd:element
name=
"root"
msdata:IsDataSet=
"true"
>
<xsd:complexType>
<xsd:choice
maxOccurs=
"unbounded"
>
<xsd:element
name=
"metadata"
>
<xsd:complexType>
<xsd:sequence>
<xsd:element
name=
"value"
type=
"xsd:string"
minOccurs=
"0"
/>
</xsd:sequence>
<xsd:attribute
name=
"name"
type=
"xsd:string"
use=
"required"
/>
<xsd:attribute
name=
"type"
type=
"xsd:string"
/>
<xsd:attribute
name=
"mimetype"
type=
"xsd:string"
/>
<xsd:attribute
ref=
"xml:space"
/>
</xsd:complexType>
</xsd:element>
<xsd:element
name=
"assembly"
>
<xsd:complexType>
<xsd:attribute
name=
"alias"
type=
"xsd:string"
/>
<xsd:attribute
name=
"name"
type=
"xsd:string"
/>
</xsd:complexType>
</xsd:element>
<xsd:element
name=
"data"
>
<xsd:complexType>
<xsd:sequence>
<xsd:element
name=
"value"
type=
"xsd:string"
minOccurs=
"0"
msdata:Ordinal=
"1"
/>
<xsd:element
name=
"comment"
type=
"xsd:string"
minOccurs=
"0"
msdata:Ordinal=
"2"
/>
</xsd:sequence>
<xsd:attribute
name=
"name"
type=
"xsd:string"
use=
"required"
msdata:Ordinal=
"1"
/>
<xsd:attribute
name=
"type"
type=
"xsd:string"
msdata:Ordinal=
"3"
/>
<xsd:attribute
name=
"mimetype"
type=
"xsd:string"
msdata:Ordinal=
"4"
/>
<xsd:attribute
ref=
"xml:space"
/>
</xsd:complexType>
</xsd:element>
<xsd:element
name=
"resheader"
>
<xsd:complexType>
<xsd:sequence>
<xsd:element
name=
"value"
type=
"xsd:string"
minOccurs=
"0"
msdata:Ordinal=
"1"
/>
</xsd:sequence>
<xsd:attribute
name=
"name"
type=
"xsd:string"
use=
"required"
/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader
name=
"resmimetype"
>
<value>
text/microsoft-resx
</value>
</resheader>
<resheader
name=
"version"
>
<value>
2.0
</value>
</resheader>
<resheader
name=
"reader"
>
<value>
System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader
name=
"writer"
>
<value>
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>
Tools.Agent/Forms/AgentRunLogForm.Designer.cs
View file @
0020a375
...
@@ -28,7 +28,7 @@
...
@@ -28,7 +28,7 @@
/// </summary>
/// </summary>
private
void
InitializeComponent
()
private
void
InitializeComponent
()
{
{
this
.
panelTop
=
new
System
.
Windows
.
Forms
.
Panel
();
this
.
panelTop
=
new
System
.
Windows
.
Forms
.
FlowLayout
Panel
();
this
.
lblFrom
=
new
System
.
Windows
.
Forms
.
Label
();
this
.
lblFrom
=
new
System
.
Windows
.
Forms
.
Label
();
this
.
dtpFrom
=
new
System
.
Windows
.
Forms
.
DateTimePicker
();
this
.
dtpFrom
=
new
System
.
Windows
.
Forms
.
DateTimePicker
();
this
.
lblTo
=
new
System
.
Windows
.
Forms
.
Label
();
this
.
lblTo
=
new
System
.
Windows
.
Forms
.
Label
();
...
@@ -39,6 +39,7 @@
...
@@ -39,6 +39,7 @@
this
.
cmbOutcome
=
new
System
.
Windows
.
Forms
.
ComboBox
();
this
.
cmbOutcome
=
new
System
.
Windows
.
Forms
.
ComboBox
();
this
.
btnRefresh
=
new
System
.
Windows
.
Forms
.
Button
();
this
.
btnRefresh
=
new
System
.
Windows
.
Forms
.
Button
();
this
.
btnExport
=
new
System
.
Windows
.
Forms
.
Button
();
this
.
btnExport
=
new
System
.
Windows
.
Forms
.
Button
();
this
.
btnConn
=
new
System
.
Windows
.
Forms
.
Button
();
this
.
splitMain
=
new
System
.
Windows
.
Forms
.
SplitContainer
();
this
.
splitMain
=
new
System
.
Windows
.
Forms
.
SplitContainer
();
this
.
dgv
=
new
System
.
Windows
.
Forms
.
DataGridView
();
this
.
dgv
=
new
System
.
Windows
.
Forms
.
DataGridView
();
this
.
tabDetails
=
new
System
.
Windows
.
Forms
.
TabControl
();
this
.
tabDetails
=
new
System
.
Windows
.
Forms
.
TabControl
();
...
@@ -60,8 +61,10 @@
...
@@ -60,8 +61,10 @@
this
.
statusStrip
.
SuspendLayout
();
this
.
statusStrip
.
SuspendLayout
();
this
.
SuspendLayout
();
this
.
SuspendLayout
();
//
//
// panelTop
// panelTop
(FlowLayoutPanel:控件从左到右自动排列,嵌入窄宿主时自动换行,永不重叠)
//
//
this
.
panelTop
.
AutoSize
=
true
;
this
.
panelTop
.
AutoSizeMode
=
System
.
Windows
.
Forms
.
AutoSizeMode
.
GrowAndShrink
;
this
.
panelTop
.
Controls
.
Add
(
this
.
lblFrom
);
this
.
panelTop
.
Controls
.
Add
(
this
.
lblFrom
);
this
.
panelTop
.
Controls
.
Add
(
this
.
dtpFrom
);
this
.
panelTop
.
Controls
.
Add
(
this
.
dtpFrom
);
this
.
panelTop
.
Controls
.
Add
(
this
.
lblTo
);
this
.
panelTop
.
Controls
.
Add
(
this
.
lblTo
);
...
@@ -72,17 +75,17 @@
...
@@ -72,17 +75,17 @@
this
.
panelTop
.
Controls
.
Add
(
this
.
cmbOutcome
);
this
.
panelTop
.
Controls
.
Add
(
this
.
cmbOutcome
);
this
.
panelTop
.
Controls
.
Add
(
this
.
btnRefresh
);
this
.
panelTop
.
Controls
.
Add
(
this
.
btnRefresh
);
this
.
panelTop
.
Controls
.
Add
(
this
.
btnExport
);
this
.
panelTop
.
Controls
.
Add
(
this
.
btnExport
);
this
.
panelTop
.
Controls
.
Add
(
this
.
btnConn
);
this
.
panelTop
.
Dock
=
System
.
Windows
.
Forms
.
DockStyle
.
Top
;
this
.
panelTop
.
Dock
=
System
.
Windows
.
Forms
.
DockStyle
.
Top
;
this
.
panelTop
.
Location
=
new
System
.
Drawing
.
Point
(
0
,
0
);
this
.
panelTop
.
Location
=
new
System
.
Drawing
.
Point
(
0
,
0
);
this
.
panelTop
.
Name
=
"panelTop"
;
this
.
panelTop
.
Name
=
"panelTop"
;
this
.
panelTop
.
Padding
=
new
System
.
Windows
.
Forms
.
Padding
(
8
,
6
,
8
,
4
);
this
.
panelTop
.
Padding
=
new
System
.
Windows
.
Forms
.
Padding
(
8
,
2
,
8
,
4
);
this
.
panelTop
.
Size
=
new
System
.
Drawing
.
Size
(
1024
,
46
);
this
.
panelTop
.
TabIndex
=
0
;
this
.
panelTop
.
TabIndex
=
0
;
//
//
// lblFrom
// lblFrom
//
//
this
.
lblFrom
.
AutoSize
=
true
;
this
.
lblFrom
.
AutoSize
=
true
;
this
.
lblFrom
.
Location
=
new
System
.
Drawing
.
Point
(
11
,
15
);
this
.
lblFrom
.
Margin
=
new
System
.
Windows
.
Forms
.
Padding
(
3
,
10
,
2
,
0
);
this
.
lblFrom
.
Name
=
"lblFrom"
;
this
.
lblFrom
.
Name
=
"lblFrom"
;
this
.
lblFrom
.
Text
=
"开始"
;
this
.
lblFrom
.
Text
=
"开始"
;
//
//
...
@@ -97,7 +100,7 @@
...
@@ -97,7 +100,7 @@
// lblTo
// lblTo
//
//
this
.
lblTo
.
AutoSize
=
true
;
this
.
lblTo
.
AutoSize
=
true
;
this
.
lblTo
.
Location
=
new
System
.
Drawing
.
Point
(
159
,
15
);
this
.
lblTo
.
Margin
=
new
System
.
Windows
.
Forms
.
Padding
(
6
,
10
,
2
,
0
);
this
.
lblTo
.
Name
=
"lblTo"
;
this
.
lblTo
.
Name
=
"lblTo"
;
this
.
lblTo
.
Text
=
"结束"
;
this
.
lblTo
.
Text
=
"结束"
;
//
//
...
@@ -112,7 +115,7 @@
...
@@ -112,7 +115,7 @@
// lblUser
// lblUser
//
//
this
.
lblUser
.
AutoSize
=
true
;
this
.
lblUser
.
AutoSize
=
true
;
this
.
lblUser
.
Location
=
new
System
.
Drawing
.
Point
(
309
,
15
);
this
.
lblUser
.
Margin
=
new
System
.
Windows
.
Forms
.
Padding
(
12
,
10
,
2
,
0
);
this
.
lblUser
.
Name
=
"lblUser"
;
this
.
lblUser
.
Name
=
"lblUser"
;
this
.
lblUser
.
Text
=
"用户"
;
this
.
lblUser
.
Text
=
"用户"
;
//
//
...
@@ -127,7 +130,7 @@
...
@@ -127,7 +130,7 @@
// lblOutcome
// lblOutcome
//
//
this
.
lblOutcome
.
AutoSize
=
true
;
this
.
lblOutcome
.
AutoSize
=
true
;
this
.
lblOutcome
.
Location
=
new
System
.
Drawing
.
Point
(
491
,
15
);
this
.
lblOutcome
.
Margin
=
new
System
.
Windows
.
Forms
.
Padding
(
12
,
10
,
2
,
0
);
this
.
lblOutcome
.
Name
=
"lblOutcome"
;
this
.
lblOutcome
.
Name
=
"lblOutcome"
;
this
.
lblOutcome
.
Text
=
"结果"
;
this
.
lblOutcome
.
Text
=
"结果"
;
//
//
...
@@ -147,7 +150,7 @@
...
@@ -147,7 +150,7 @@
this
.
btnRefresh
.
BackColor
=
System
.
Drawing
.
Color
.
FromArgb
(((
int
)(((
byte
)(
0
)))),
((
int
)(((
byte
)(
120
)))),
((
int
)(((
byte
)(
212
)))));
this
.
btnRefresh
.
BackColor
=
System
.
Drawing
.
Color
.
FromArgb
(((
int
)(((
byte
)(
0
)))),
((
int
)(((
byte
)(
120
)))),
((
int
)(((
byte
)(
212
)))));
this
.
btnRefresh
.
FlatStyle
=
System
.
Windows
.
Forms
.
FlatStyle
.
Flat
;
this
.
btnRefresh
.
FlatStyle
=
System
.
Windows
.
Forms
.
FlatStyle
.
Flat
;
this
.
btnRefresh
.
ForeColor
=
System
.
Drawing
.
Color
.
White
;
this
.
btnRefresh
.
ForeColor
=
System
.
Drawing
.
Color
.
White
;
this
.
btnRefresh
.
Location
=
new
System
.
Drawing
.
Point
(
619
,
9
);
this
.
btnRefresh
.
Margin
=
new
System
.
Windows
.
Forms
.
Padding
(
12
,
4
,
3
,
0
);
this
.
btnRefresh
.
Name
=
"btnRefresh"
;
this
.
btnRefresh
.
Name
=
"btnRefresh"
;
this
.
btnRefresh
.
Size
=
new
System
.
Drawing
.
Size
(
76
,
28
);
this
.
btnRefresh
.
Size
=
new
System
.
Drawing
.
Size
(
76
,
28
);
this
.
btnRefresh
.
Text
=
"刷新"
;
this
.
btnRefresh
.
Text
=
"刷新"
;
...
@@ -157,13 +160,23 @@
...
@@ -157,13 +160,23 @@
// btnExport
// btnExport
//
//
this
.
btnExport
.
FlatStyle
=
System
.
Windows
.
Forms
.
FlatStyle
.
Flat
;
this
.
btnExport
.
FlatStyle
=
System
.
Windows
.
Forms
.
FlatStyle
.
Flat
;
this
.
btnExport
.
Location
=
new
System
.
Drawing
.
Point
(
703
,
9
);
this
.
btnExport
.
Margin
=
new
System
.
Windows
.
Forms
.
Padding
(
6
,
4
,
3
,
0
);
this
.
btnExport
.
Name
=
"btnExport"
;
this
.
btnExport
.
Name
=
"btnExport"
;
this
.
btnExport
.
Size
=
new
System
.
Drawing
.
Size
(
76
,
28
);
this
.
btnExport
.
Size
=
new
System
.
Drawing
.
Size
(
76
,
28
);
this
.
btnExport
.
Text
=
"导出CSV"
;
this
.
btnExport
.
Text
=
"导出CSV"
;
this
.
btnExport
.
UseVisualStyleBackColor
=
true
;
this
.
btnExport
.
UseVisualStyleBackColor
=
true
;
this
.
btnExport
.
Click
+=
new
System
.
EventHandler
(
this
.
OnExportCsvClick
);
this
.
btnExport
.
Click
+=
new
System
.
EventHandler
(
this
.
OnExportCsvClick
);
//
//
// btnConn(窗口内数据库连接配置:IP/账号/密码/库下拉)
//
this
.
btnConn
.
FlatStyle
=
System
.
Windows
.
Forms
.
FlatStyle
.
Flat
;
this
.
btnConn
.
Margin
=
new
System
.
Windows
.
Forms
.
Padding
(
6
,
4
,
3
,
0
);
this
.
btnConn
.
Name
=
"btnConn"
;
this
.
btnConn
.
Size
=
new
System
.
Drawing
.
Size
(
88
,
28
);
this
.
btnConn
.
Text
=
"连接配置"
;
this
.
btnConn
.
UseVisualStyleBackColor
=
true
;
this
.
btnConn
.
Click
+=
new
System
.
EventHandler
(
this
.
OnConnConfigClick
);
//
// splitMain
// splitMain
//
//
this
.
splitMain
.
Dock
=
System
.
Windows
.
Forms
.
DockStyle
.
Fill
;
this
.
splitMain
.
Dock
=
System
.
Windows
.
Forms
.
DockStyle
.
Fill
;
...
@@ -320,6 +333,7 @@
...
@@ -320,6 +333,7 @@
private
System
.
Windows
.
Forms
.
ComboBox
cmbOutcome
;
private
System
.
Windows
.
Forms
.
ComboBox
cmbOutcome
;
private
System
.
Windows
.
Forms
.
Button
btnRefresh
;
private
System
.
Windows
.
Forms
.
Button
btnRefresh
;
private
System
.
Windows
.
Forms
.
Button
btnExport
;
private
System
.
Windows
.
Forms
.
Button
btnExport
;
private
System
.
Windows
.
Forms
.
Button
btnConn
;
private
System
.
Windows
.
Forms
.
SplitContainer
splitMain
;
private
System
.
Windows
.
Forms
.
SplitContainer
splitMain
;
private
System
.
Windows
.
Forms
.
DataGridView
dgv
;
private
System
.
Windows
.
Forms
.
DataGridView
dgv
;
private
System
.
Windows
.
Forms
.
TabControl
tabDetails
;
private
System
.
Windows
.
Forms
.
TabControl
tabDetails
;
...
...
Tools.Agent/Forms/AgentRunLogForm.cs
View file @
0020a375
...
@@ -21,8 +21,10 @@ namespace Tools.MyAgent.Forms
...
@@ -21,8 +21,10 @@ namespace Tools.MyAgent.Forms
{
{
private
const
int
MaxRows
=
500
;
private
const
int
MaxRows
=
500
;
private
readonly
string
_connection
;
/// <summary>当前上报连接(明文,窗口内可经"连接配置"切换)。</summary>
private
readonly
string
_table
;
private
string
_connection
;
/// <summary>当前日志表名。</summary>
private
string
_table
;
/// <summary>当前选中行的 RunId(详情二次查询用)。</summary>
/// <summary>当前选中行的 RunId(详情二次查询用)。</summary>
private
string
_currentRunId
;
private
string
_currentRunId
;
...
@@ -295,6 +297,36 @@ namespace Tools.MyAgent.Forms
...
@@ -295,6 +297,36 @@ namespace Tools.MyAgent.Forms
txtMetrics
.
Text
=
metrics
;
txtMetrics
.
Text
=
metrics
;
}
}
// ══════════════ 连接配置(窗口内直配,2026-10-19) ══════════════
/// <summary>
/// "连接配置":IP → 账号 → 密码 → 库(下拉拉取 sys.databases);
/// 确定后写回 AgentConfig.json(DPAPI 加密)并刷新本窗口的连接与列表。
/// </summary>
private
void
OnConnConfigClick
(
object
sender
,
EventArgs
e
)
{
using
(
var
dlg
=
new
AgentDbConfigForm
(
_connection
,
_table
))
{
if
(
dlg
.
ShowDialog
(
this
)
!=
DialogResult
.
OK
)
return
;
string
plain
=
dlg
.
BuildConnectionString
();
string
table
=
dlg
.
Table
;
if
(!
AgentRuntime
.
SaveLocalRunDbConfig
(
plain
,
table
,
dlg
.
EnableReporting
))
{
AgentUtils
.
Toast
(
"保存到配置文件失败(AgentConfig.json 不可写)"
,
4000
);
return
;
}
_connection
=
plain
;
// 本窗口立即生效,无需重开
_table
=
table
;
_currentRunId
=
null
;
SetDetailText
(
"(已切换连接,请选择记录)"
,
"(已切换连接)"
);
LoadUsers
();
RefreshList
();
AgentUtils
.
Toast
(
dlg
.
EnableReporting
?
"已保存并启用对话上报;引擎侧在下次应用配置(重启客户端或设置页确定)后生效"
:
"已保存连接;对话上报保持关闭(仅本窗口查询用)"
,
4000
);
}
}
// ══════════════ 导出 ══════════════
// ══════════════ 导出 ══════════════
private
void
OnExportCsvClick
(
object
sender
,
EventArgs
e
)
private
void
OnExportCsvClick
(
object
sender
,
EventArgs
e
)
...
...
Tools.Agent/Kb/KbService.cs
View file @
0020a375
...
@@ -116,6 +116,7 @@ namespace Tools.MyAgent.Kb
...
@@ -116,6 +116,7 @@ namespace Tools.MyAgent.Kb
private
volatile
int
_fileCount
=
FileCountUnknown
;
private
volatile
int
_fileCount
=
FileCountUnknown
;
private
volatile
string
_formatsSummary
=
""
;
private
volatile
string
_formatsSummary
=
""
;
private
volatile
string
_structureDigest
=
""
;
private
volatile
string
_structureDigest
=
""
;
private
volatile
string
_statsScope
=
""
;
private
DateTime
_fileCountStamp
=
DateTime
.
MinValue
;
private
DateTime
_fileCountStamp
=
DateTime
.
MinValue
;
private
readonly
object
_statsLock
=
new
object
();
private
readonly
object
_statsLock
=
new
object
();
private
bool
_statsRunning
;
private
bool
_statsRunning
;
...
@@ -146,7 +147,9 @@ namespace Tools.MyAgent.Kb
...
@@ -146,7 +147,9 @@ namespace Tools.MyAgent.Kb
_structureDigest
=
""
;
_structureDigest
=
""
;
return
;
return
;
}
}
if
(
_fileCount
>=
0
&&
DateTime
.
Now
-
_fileCountStamp
<
StatsTtl
)
if
(
_fileCount
>=
0
&&
string
.
Equals
(
_statsScope
,
SearchRoot
??
""
,
StringComparison
.
OrdinalIgnoreCase
)
&&
DateTime
.
Now
-
_fileCountStamp
<
StatsTtl
)
return
;
return
;
lock
(
_statsLock
)
lock
(
_statsLock
)
...
@@ -156,7 +159,6 @@ namespace Tools.MyAgent.Kb
...
@@ -156,7 +159,6 @@ namespace Tools.MyAgent.Kb
}
}
EnsureWatcher
();
EnsureWatcher
();
var
root
=
Root
;
var
searchRoot
=
SearchRoot
;
var
searchRoot
=
SearchRoot
;
// P1 扫描可中断:统计扫描带超时取消(60 秒),超时后真正终止后台枚举,避免残留任务占满 IO
// P1 扫描可中断:统计扫描带超时取消(60 秒),超时后真正终止后台枚举,避免残留任务占满 IO
var
statsCts
=
new
CancellationTokenSource
(
TimeSpan
.
FromSeconds
(
60
));
var
statsCts
=
new
CancellationTokenSource
(
TimeSpan
.
FromSeconds
(
60
));
...
@@ -168,7 +170,7 @@ namespace Tools.MyAgent.Kb
...
@@ -168,7 +170,7 @@ namespace Tools.MyAgent.Kb
var
groups
=
new
Dictionary
<
string
,
int
>(
StringComparer
.
OrdinalIgnoreCase
);
var
groups
=
new
Dictionary
<
string
,
int
>(
StringComparer
.
OrdinalIgnoreCase
);
try
try
{
{
foreach
(
var
file
in
SafeEnumerateFiles
(
r
oot
,
statsCts
.
Token
))
foreach
(
var
file
in
SafeEnumerateFiles
(
searchR
oot
,
statsCts
.
Token
))
{
{
count
++;
count
++;
var
ext
=
Path
.
GetExtension
(
file
).
ToLowerInvariant
();
var
ext
=
Path
.
GetExtension
(
file
).
ToLowerInvariant
();
...
@@ -184,12 +186,19 @@ namespace Tools.MyAgent.Kb
...
@@ -184,12 +186,19 @@ namespace Tools.MyAgent.Kb
catch
(
OperationCanceledException
)
{
count
=
FileCountUnknown
;
}
catch
(
OperationCanceledException
)
{
count
=
FileCountUnknown
;
}
catch
{
count
=
FileCountUnknown
;
}
catch
{
count
=
FileCountUnknown
;
}
try
{
digest
=
BuildStructureDigest
(
searchRoot
,
30
,
1000
,
IsConfiguredFileAllowed
);
}
catch
{
digest
=
""
;
}
try
{
digest
=
BuildStructureDigest
(
searchRoot
,
30
,
1000
,
IsConfiguredFileAllowed
);
}
catch
{
digest
=
""
;
}
bool
scopeChanged
=
!
string
.
Equals
(
SearchRoot
,
searchRoot
,
StringComparison
.
OrdinalIgnoreCase
);
lock
(
_statsLock
)
{
_statsRunning
=
false
;
}
try
{
statsCts
.
Dispose
();
}
catch
{
}
if
(
scopeChanged
)
{
EnsureStats
();
return
;
}
_fileCount
=
count
;
_fileCount
=
count
;
_formatsSummary
=
formats
;
_formatsSummary
=
formats
;
_structureDigest
=
digest
;
_structureDigest
=
digest
;
_statsScope
=
searchRoot
??
""
;
_fileCountStamp
=
DateTime
.
Now
;
_fileCountStamp
=
DateTime
.
Now
;
lock
(
_statsLock
)
{
_statsRunning
=
false
;
}
try
{
statsCts
.
Dispose
();
}
catch
{
}
StatsRefreshed
?.
Invoke
();
StatsRefreshed
?.
Invoke
();
});
});
}
}
...
@@ -221,6 +230,10 @@ namespace Tools.MyAgent.Kb
...
@@ -221,6 +230,10 @@ namespace Tools.MyAgent.Kb
private
void
InvalidateStats
()
private
void
InvalidateStats
()
{
{
_fileCount
=
FileCountUnknown
;
_fileCount
=
FileCountUnknown
;
_fileCountStamp
=
DateTime
.
MinValue
;
_statsScope
=
""
;
_formatsSummary
=
""
;
_structureDigest
=
""
;
EnsureStats
();
EnsureStats
();
// 索引不再全量失效:变更由 FileSystemWatcher → KbIndex 单文件增量处理(P1),
// 索引不再全量失效:变更由 FileSystemWatcher → KbIndex 单文件增量处理(P1),
// KbIndex 内部 15 分钟兜底重扫负责补齐丢事件场景
// KbIndex 内部 15 分钟兜底重扫负责补齐丢事件场景
...
@@ -241,6 +254,7 @@ namespace Tools.MyAgent.Kb
...
@@ -241,6 +254,7 @@ namespace Tools.MyAgent.Kb
_statsWatcher
=
null
;
_statsWatcher
=
null
;
_fileCount
=
FileCountUnknown
;
_fileCount
=
FileCountUnknown
;
_fileCountStamp
=
DateTime
.
MinValue
;
_fileCountStamp
=
DateTime
.
MinValue
;
_statsScope
=
""
;
_formatsSummary
=
""
;
_formatsSummary
=
""
;
_structureDigest
=
""
;
_structureDigest
=
""
;
}
}
...
@@ -382,26 +396,21 @@ namespace Tools.MyAgent.Kb
...
@@ -382,26 +396,21 @@ namespace Tools.MyAgent.Kb
/// <summary>设置搜索范围;空表示整个知识库根目录。越界或非法路径会回退为整个知识库,避免越权访问。</summary>
/// <summary>设置搜索范围;空表示整个知识库根目录。越界或非法路径会回退为整个知识库,避免越权访问。</summary>
public
void
SetScope
(
string
path
)
public
void
SetScope
(
string
path
)
{
{
if
(
string
.
IsNullOrWhiteSpace
(
path
))
string
next
=
""
;
if
(!
string
.
IsNullOrWhiteSpace
(
path
))
{
{
Scope
=
""
;
return
;
}
try
try
{
{
string
scope
=
NormPath
(
path
);
string
scope
=
NormPath
(
path
);
if
(
string
.
IsNullOrEmpty
(
Root
)
||
!
IsWithin
(
NormPath
(
Root
),
scope
))
if
(!
string
.
IsNullOrEmpty
(
Root
)
&&
IsWithin
(
NormPath
(
Root
),
scope
))
{
next
=
scope
;
Scope
=
""
;
return
;
}
Scope
=
scope
;
}
}
catch
catch
{
}
{
Scope
=
""
;
}
}
if
(
string
.
Equals
(
Scope
,
next
,
StringComparison
.
OrdinalIgnoreCase
))
return
;
Scope
=
next
;
InvalidateStats
();
}
}
/// <summary>实际检索根目录:限定目录优先,否则为知识库根目录</summary>
/// <summary>实际检索根目录:限定目录优先,否则为知识库根目录</summary>
...
@@ -678,7 +687,7 @@ namespace Tools.MyAgent.Kb
...
@@ -678,7 +687,7 @@ namespace Tools.MyAgent.Kb
try
try
{
{
int
count
=
0
;
int
count
=
0
;
foreach
(
var
_
in
SafeEnumerateFiles
(
Root
,
ct
))
count
++;
foreach
(
var
_
in
SafeEnumerateFiles
(
Search
Root
,
ct
))
count
++;
return
count
;
return
count
;
}
}
catch
(
OperationCanceledException
)
{
return
0
;
}
catch
(
OperationCanceledException
)
{
return
0
;
}
...
@@ -692,7 +701,7 @@ namespace Tools.MyAgent.Kb
...
@@ -692,7 +701,7 @@ namespace Tools.MyAgent.Kb
var
groups
=
new
Dictionary
<
string
,
int
>(
StringComparer
.
OrdinalIgnoreCase
);
var
groups
=
new
Dictionary
<
string
,
int
>(
StringComparer
.
OrdinalIgnoreCase
);
try
try
{
{
foreach
(
var
file
in
SafeEnumerateFiles
(
Root
,
ct
))
foreach
(
var
file
in
SafeEnumerateFiles
(
Search
Root
,
ct
))
{
{
var
ext
=
Path
.
GetExtension
(
file
).
ToLowerInvariant
();
var
ext
=
Path
.
GetExtension
(
file
).
ToLowerInvariant
();
if
(
string
.
IsNullOrEmpty
(
ext
))
ext
=
"(无扩展名)"
;
if
(
string
.
IsNullOrEmpty
(
ext
))
ext
=
"(无扩展名)"
;
...
...
Tools.Agent/Tools.Agent.csproj
View file @
0020a375
...
@@ -147,6 +147,12 @@
...
@@ -147,6 +147,12 @@
<Compile
Include=
"Forms\AgentRunLogForm.Designer.cs"
>
<Compile
Include=
"Forms\AgentRunLogForm.Designer.cs"
>
<DependentUpon>
AgentRunLogForm.cs
</DependentUpon>
<DependentUpon>
AgentRunLogForm.cs
</DependentUpon>
</Compile>
</Compile>
<Compile
Include=
"Forms\AgentDbConfigForm.cs"
>
<SubType>
Form
</SubType>
</Compile>
<Compile
Include=
"Forms\AgentDbConfigForm.Designer.cs"
>
<DependentUpon>
AgentDbConfigForm.cs
</DependentUpon>
</Compile>
<Compile
Include=
"Forms\DocLineViewer.cs"
>
<Compile
Include=
"Forms\DocLineViewer.cs"
>
<SubType>
Form
</SubType>
<SubType>
Form
</SubType>
</Compile>
</Compile>
...
@@ -197,6 +203,9 @@
...
@@ -197,6 +203,9 @@
<EmbeddedResource
Include=
"Forms\AgentRunLogForm.resx"
>
<EmbeddedResource
Include=
"Forms\AgentRunLogForm.resx"
>
<DependentUpon>
AgentRunLogForm.cs
</DependentUpon>
<DependentUpon>
AgentRunLogForm.cs
</DependentUpon>
</EmbeddedResource>
</EmbeddedResource>
<EmbeddedResource
Include=
"Forms\AgentDbConfigForm.resx"
>
<DependentUpon>
AgentDbConfigForm.cs
</DependentUpon>
</EmbeddedResource>
<EmbeddedResource
Include=
"Forms\AgentSettingsForm.resx"
>
<EmbeddedResource
Include=
"Forms\AgentSettingsForm.resx"
>
<DependentUpon>
AgentSettingsForm.cs
</DependentUpon>
<DependentUpon>
AgentSettingsForm.cs
</DependentUpon>
</EmbeddedResource>
</EmbeddedResource>
...
...
Tools.Agent/wMyAgent.cs
View file @
0020a375
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment