mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
0.7.9.1
This commit is contained in:
440
docs/IMAGE_RECOMMENDATION_COMPONENT_FEASIBILITY.md
Normal file
440
docs/IMAGE_RECOMMENDATION_COMPONENT_FEASIBILITY.md
Normal file
@@ -0,0 +1,440 @@
|
||||
# 图片推荐组件可行性分析报告
|
||||
|
||||
## 需求概述
|
||||
|
||||
开发一个新的**图片推荐组件**,具备以下特性:
|
||||
- 最小尺寸:**2×2 cells**
|
||||
- 支持在组件设置界面**更换图片源**
|
||||
- 独立AXAML文件实现
|
||||
|
||||
---
|
||||
|
||||
## 可行性结论
|
||||
|
||||
**高度可行**。项目已具备完整的组件基础设施,包括设置编辑器系统、数据源切换机制。预计开发工作量 **6-10小时**。
|
||||
|
||||
---
|
||||
|
||||
## 1. 现有基础设施分析
|
||||
|
||||
### 1.1 参考实现:DailyArtworkWidget
|
||||
|
||||
`DailyArtworkWidget` 已具备图片展示 + 图片源切换功能,是最佳参考:
|
||||
|
||||
**组件定义** (`ComponentRegistry.cs`):
|
||||
```csharp
|
||||
new DesktopComponentDefinition(
|
||||
BuiltInComponentIds.DesktopDailyArtwork,
|
||||
"Daily Artwork",
|
||||
"Image",
|
||||
"Info",
|
||||
MinWidthCells: 4, // 当前最小4×2
|
||||
MinHeightCells: 2,
|
||||
AllowStatusBarPlacement: false,
|
||||
AllowDesktopPlacement: true)
|
||||
```
|
||||
|
||||
**设置编辑器** (`DailyArtworkComponentEditor.axaml`):
|
||||
```xml
|
||||
<ComboBox x:Name="SourceComboBox" SelectionChanged="OnSourceSelectionChanged">
|
||||
<ComboBoxItem Tag="Domestic" /> <!-- 国内镜像 -->
|
||||
<ComboBoxItem Tag="Overseas" /> <!-- 海外镜像 -->
|
||||
</ComboBox>
|
||||
```
|
||||
|
||||
### 1.2 组件设置系统架构
|
||||
|
||||
```
|
||||
用户点击设置
|
||||
↓
|
||||
ComponentEditorWindow 打开
|
||||
↓
|
||||
DesktopComponentEditorRegistry 查找编辑器
|
||||
↓
|
||||
创建对应的 ComponentEditor (如 DailyArtworkComponentEditor)
|
||||
↓
|
||||
编辑器通过 ComponentSettingsAccessor 读写配置
|
||||
↓
|
||||
配置变更通知组件刷新
|
||||
```
|
||||
|
||||
**关键接口**:
|
||||
- `IComponentSettingsContextAware` - 组件接收设置上下文
|
||||
- `ComponentEditorViewBase` - 编辑器基类,提供 `LoadSnapshot()` / `SaveSnapshot()`
|
||||
- `ComponentSettingsSnapshot` - 统一配置存储模型
|
||||
|
||||
---
|
||||
|
||||
## 2. 技术实现方案
|
||||
|
||||
### 2.1 文件结构
|
||||
|
||||
```
|
||||
LanMountainDesktop/
|
||||
├── ComponentSystem/
|
||||
│ ├── BuiltInComponentIds.cs # 添加组件ID常量
|
||||
│ └── ComponentRegistry.cs # 注册组件定义
|
||||
├── Views/
|
||||
│ ├── Components/
|
||||
│ │ ├── ImageRecommendationWidget.axaml # 新组件UI
|
||||
│ │ ├── ImageRecommendationWidget.axaml.cs # 新组件逻辑
|
||||
│ │ └── DesktopComponentRuntimeRegistry.cs # 注册运行时
|
||||
│ └── ComponentEditors/
|
||||
│ ├── ImageRecommendationComponentEditor.axaml # 设置编辑器UI
|
||||
│ ├── ImageRecommendationComponentEditor.axaml.cs # 设置编辑器逻辑
|
||||
│ └── DesktopComponentEditorRegistryFactory.cs # 注册编辑器
|
||||
├── Services/
|
||||
│ ├── IRecommendationDataService.cs # 添加查询接口
|
||||
│ └── RecommendationDataService.cs # 实现数据获取
|
||||
└── Models/
|
||||
└── ComponentSettingsSnapshot.cs # 添加配置字段
|
||||
```
|
||||
|
||||
### 2.2 组件定义 (2×2最小尺寸)
|
||||
|
||||
```csharp
|
||||
// BuiltInComponentIds.cs
|
||||
public const string DesktopImageRecommendation = "DesktopImageRecommendation";
|
||||
|
||||
// ComponentRegistry.cs
|
||||
new DesktopComponentDefinition(
|
||||
BuiltInComponentIds.DesktopImageRecommendation,
|
||||
"Image Recommendation",
|
||||
"Image",
|
||||
"Info",
|
||||
MinWidthCells: 2, // 最小2×2
|
||||
MinHeightCells: 2,
|
||||
AllowStatusBarPlacement: false,
|
||||
AllowDesktopPlacement: true,
|
||||
ResizeMode: DesktopComponentResizeMode.Proportional) // 保持比例
|
||||
```
|
||||
|
||||
### 2.3 数据源配置设计
|
||||
|
||||
**配置模型** (`ComponentSettingsSnapshot.cs`):
|
||||
```csharp
|
||||
public sealed class ComponentSettingsSnapshot
|
||||
{
|
||||
// 现有字段...
|
||||
|
||||
// 新增:图片推荐组件配置
|
||||
public string ImageRecommendationSource { get; set; } = ImageRecommendationSources.Bing;
|
||||
public bool ImageRecommendationAutoRefreshEnabled { get; set; } = true;
|
||||
public int ImageRecommendationAutoRefreshIntervalMinutes { get; set; } = 60;
|
||||
}
|
||||
|
||||
public static class ImageRecommendationSources
|
||||
{
|
||||
public const string Bing = "bing"; // Bing每日图片
|
||||
public const string Picsum = "picsum"; // Picsum随机图片
|
||||
public const string Unsplash = "unsplash"; // Unsplash精选
|
||||
|
||||
public static string Normalize(string? value) => value?.ToLowerInvariant() switch
|
||||
{
|
||||
"picsum" => Picsum,
|
||||
"unsplash" => Unsplash,
|
||||
_ => Bing
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 Widget实现要点
|
||||
|
||||
```csharp
|
||||
// ImageRecommendationWidget.axaml.cs
|
||||
public partial class ImageRecommendationWidget : UserControl,
|
||||
IDesktopComponentWidget,
|
||||
IRecommendationInfoAwareComponentWidget,
|
||||
IComponentSettingsContextAware, // 接收设置变更
|
||||
IComponentPlacementContextAware
|
||||
{
|
||||
private string _imageSource = ImageRecommendationSources.Bing;
|
||||
|
||||
public void SetComponentSettingsContext(DesktopComponentSettingsContext context)
|
||||
{
|
||||
// 读取组件实例配置
|
||||
var snapshot = context.ComponentSettingsAccessor
|
||||
.LoadSnapshot<ComponentSettingsSnapshot>();
|
||||
_imageSource = ImageRecommendationSources.Normalize(
|
||||
snapshot?.ImageRecommendationSource);
|
||||
|
||||
// 刷新图片
|
||||
_ = RefreshImageAsync();
|
||||
}
|
||||
|
||||
private async Task RefreshImageAsync()
|
||||
{
|
||||
var query = new ImageRecommendationQuery
|
||||
{
|
||||
Source = _imageSource
|
||||
};
|
||||
var result = await _recommendationService
|
||||
.GetImageRecommendationAsync(query);
|
||||
|
||||
if (result.Success && result.Data is not null)
|
||||
{
|
||||
await LoadImageAsync(result.Data.ImageUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.5 设置编辑器实现
|
||||
|
||||
```xml
|
||||
<!-- ImageRecommendationComponentEditor.axaml -->
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
x:Class="LanMountainDesktop.Views.ComponentEditors.ImageRecommendationComponentEditor">
|
||||
<StackPanel Spacing="16">
|
||||
<!-- 图片源选择 -->
|
||||
<Border Classes="component-editor-card" Padding="20">
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock x:Name="SourceLabelTextBlock"
|
||||
Classes="component-editor-section-title" />
|
||||
<ComboBox x:Name="SourceComboBox"
|
||||
Classes="component-editor-select"
|
||||
HorizontalAlignment="Stretch"
|
||||
SelectionChanged="OnSourceSelectionChanged">
|
||||
<ComboBoxItem x:Name="BingItem" Tag="bing" />
|
||||
<ComboBoxItem x:Name="PicsumItem" Tag="picsum" />
|
||||
<ComboBoxItem x:Name="UnsplashItem" Tag="unsplash" />
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 自动刷新设置 -->
|
||||
<Border Classes="component-editor-card" Padding="20">
|
||||
<StackPanel Spacing="12">
|
||||
<ToggleSwitch x:Name="AutoRefreshToggle"
|
||||
Toggled="OnAutoRefreshToggled" />
|
||||
<NumericUpDown x:Name="IntervalNumeric"
|
||||
Minimum="5"
|
||||
Maximum="1440"
|
||||
ValueChanged="OnIntervalChanged" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
```
|
||||
|
||||
```csharp
|
||||
// ImageRecommendationComponentEditor.axaml.cs
|
||||
public partial class ImageRecommendationComponentEditor : ComponentEditorViewBase
|
||||
{
|
||||
public ImageRecommendationComponentEditor(DesktopComponentEditorContext? context)
|
||||
: base(context)
|
||||
{
|
||||
InitializeComponent();
|
||||
ApplyState();
|
||||
}
|
||||
|
||||
private void ApplyState()
|
||||
{
|
||||
// 本地化
|
||||
SourceLabelTextBlock.Text = L("imgrec.settings.source", "Image Source");
|
||||
BingItem.Content = L("imgrec.settings.bing", "Bing Daily");
|
||||
PicsumItem.Content = L("imgrec.settings.picsum", "Random (Picsum)");
|
||||
UnsplashItem.Content = L("imgrec.settings.unsplash", "Unsplash");
|
||||
|
||||
// 加载当前配置
|
||||
var snapshot = LoadSnapshot();
|
||||
var source = ImageRecommendationSources.Normalize(snapshot.ImageRecommendationSource);
|
||||
SourceComboBox.SelectedItem = source switch
|
||||
{
|
||||
ImageRecommendationSources.Picsum => PicsumItem,
|
||||
ImageRecommendationSources.Unsplash => UnsplashItem,
|
||||
_ => BingItem
|
||||
};
|
||||
}
|
||||
|
||||
private void OnSourceSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (_suppressEvents) return;
|
||||
|
||||
var source = SourceComboBox.SelectedItem is ComboBoxItem item && item.Tag is string tag
|
||||
? ImageRecommendationSources.Normalize(tag)
|
||||
: ImageRecommendationSources.Bing;
|
||||
|
||||
var snapshot = LoadSnapshot();
|
||||
snapshot.ImageRecommendationSource = source;
|
||||
SaveSnapshot(snapshot, nameof(ComponentSettingsSnapshot.ImageRecommendationSource));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.6 数据服务扩展
|
||||
|
||||
```csharp
|
||||
// IRecommendationDataService.cs
|
||||
public sealed record ImageRecommendationQuery(
|
||||
string? Source = null,
|
||||
bool ForceRefresh = false);
|
||||
|
||||
public sealed record ImageRecommendationSnapshot(
|
||||
string ImageUrl,
|
||||
string? Title = null,
|
||||
string? Description = null,
|
||||
string? SourceName = null);
|
||||
|
||||
public interface IRecommendationInfoService
|
||||
{
|
||||
// 现有方法...
|
||||
|
||||
Task<RecommendationQueryResult<ImageRecommendationSnapshot>> GetImageRecommendationAsync(
|
||||
ImageRecommendationQuery query,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
```
|
||||
|
||||
```csharp
|
||||
// RecommendationDataService.cs
|
||||
public async Task<RecommendationQueryResult<ImageRecommendationSnapshot>> GetImageRecommendationAsync(
|
||||
ImageRecommendationQuery query,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var source = ImageRecommendationSources.Normalize(query?.Source);
|
||||
|
||||
return source switch
|
||||
{
|
||||
ImageRecommendationSources.Picsum => await GetPicsumImageAsync(query, cancellationToken),
|
||||
ImageRecommendationSources.Unsplash => await GetUnsplashImageAsync(query, cancellationToken),
|
||||
_ => await GetBingImageAsync(query, cancellationToken)
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<RecommendationQueryResult<ImageRecommendationSnapshot>> GetBingImageAsync(
|
||||
ImageRecommendationQuery? query,
|
||||
CancellationToken ct)
|
||||
{
|
||||
// Bing每日图片API
|
||||
var url = "https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN";
|
||||
// ... 解析返回获取图片URL
|
||||
var imageUrl = $"https://cn.bing.com{imageData.Url}";
|
||||
return RecommendationQueryResult<ImageRecommendationSnapshot>.Ok(
|
||||
new ImageRecommendationSnapshot(imageUrl, imageData.Title, imageData.Copyright));
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 2×2尺寸适配考虑
|
||||
|
||||
### 3.1 布局适配策略
|
||||
|
||||
```csharp
|
||||
// ImageRecommendationWidget.axaml.cs
|
||||
private void ApplyCellSize(double cellSize)
|
||||
{
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = _currentCellSize / BaseCellSize;
|
||||
|
||||
// 2×2尺寸较小,需要调整字体和间距
|
||||
var isSmallSize = _currentCellSize * 2 < 120; // 小于120px视为小尺寸
|
||||
|
||||
if (isSmallSize)
|
||||
{
|
||||
// 小尺寸模式:简化UI,只显示图片
|
||||
TitleTextBlock.IsVisible = false;
|
||||
DescriptionTextBlock.IsVisible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 正常模式:显示图片+文字
|
||||
TitleTextBlock.IsVisible = true;
|
||||
TitleTextBlock.FontSize = Math.Clamp(16 * scale, 10, 20);
|
||||
}
|
||||
|
||||
// 圆角随尺寸缩放
|
||||
RootBorder.CornerRadius = new CornerRadius(12 * scale);
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 比例约束
|
||||
|
||||
```csharp
|
||||
// MainWindow.ComponentSystem.cs 添加比例约束
|
||||
if (string.Equals(componentId, BuiltInComponentIds.DesktopImageRecommendation, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// 保持1:1比例(正方形),最小2×2
|
||||
return SnapSpanToScaleRules(
|
||||
span,
|
||||
new ComponentScaleRule(WidthUnit: 1, HeightUnit: 1, MinScale: 2));
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 开发工作量估算
|
||||
|
||||
| 任务 | 文件 | 预估工时 |
|
||||
|------|------|----------|
|
||||
| 添加组件ID | `BuiltInComponentIds.cs` | 5分钟 |
|
||||
| 注册组件定义 | `ComponentRegistry.cs` | 10分钟 |
|
||||
| 实现Widget UI | `ImageRecommendationWidget.axaml` | 1.5小时 |
|
||||
| 实现Widget逻辑 | `ImageRecommendationWidget.axaml.cs` | 2小时 |
|
||||
| 注册运行时 | `DesktopComponentRuntimeRegistry.cs` | 10分钟 |
|
||||
| 实现设置编辑器UI | `ImageRecommendationComponentEditor.axaml` | 1小时 |
|
||||
| 实现设置编辑器逻辑 | `ImageRecommendationComponentEditor.axaml.cs` | 1小时 |
|
||||
| 注册编辑器 | `DesktopComponentEditorRegistryFactory.cs` | 15分钟 |
|
||||
| 扩展数据服务接口 | `IRecommendationDataService.cs` | 15分钟 |
|
||||
| 实现数据获取 | `RecommendationDataService.cs` | 1.5小时 |
|
||||
| 添加配置字段 | `ComponentSettingsSnapshot.cs` | 15分钟 |
|
||||
| 添加比例约束 | `MainWindow.ComponentSystem.cs` | 15分钟 |
|
||||
| 添加本地化 | `Resources.resx` | 30分钟 |
|
||||
| **总计** | | **8-10小时** |
|
||||
|
||||
---
|
||||
|
||||
## 5. 风险与缓解
|
||||
|
||||
| 风险 | 等级 | 缓解措施 |
|
||||
|------|------|----------|
|
||||
| 2×2尺寸下UI过于拥挤 | 中 | 实现响应式布局,小尺寸隐藏文字 |
|
||||
| 图片源API不稳定 | 低 | 多源备选,本地缓存 |
|
||||
| 图片加载慢影响体验 | 低 | 异步加载,占位图过渡 |
|
||||
| 跨域问题 | 低 | 使用支持CORS的源或后端代理 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 建议图片源
|
||||
|
||||
| 源 | URL示例 | 特点 |
|
||||
|----|---------|------|
|
||||
| **Bing每日图片** | `https://cn.bing.com/HPImageArchive.aspx` | 高质量,每日更新 |
|
||||
| **Picsum** | `https://picsum.photos/400/400` | 随机图片,稳定快速 |
|
||||
| **Unsplash Source** | `https://source.unsplash.com/400x400` | 精选摄影,高质量 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 结论
|
||||
|
||||
### 7.1 可行性评级: **A级 (强烈推荐)**
|
||||
|
||||
| 维度 | 评分 | 说明 |
|
||||
|------|------|------|
|
||||
| 技术成熟度 | ★★★★★ | DailyArtworkWidget提供完整参考 |
|
||||
| 开发成本 | ★★★★★ | 8-10小时,模式清晰 |
|
||||
| 2×2适配 | ★★★★☆ | 需响应式布局适配小尺寸 |
|
||||
| 用户价值 | ★★★★★ | 图片组件是桌面美化核心需求 |
|
||||
|
||||
### 7.2 下一步行动
|
||||
|
||||
1. **确认图片源**:选择1-3个稳定的图片API
|
||||
2. **UI设计**:确认2×2尺寸下的视觉呈现
|
||||
3. **开发**:按文件清单逐项实现
|
||||
4. **测试**:验证不同尺寸、不同数据源切换
|
||||
|
||||
---
|
||||
|
||||
## 附录: 关键代码参考
|
||||
|
||||
### DailyArtworkWidget (现有参考)
|
||||
- `Views/Components/DailyArtworkWidget.axaml`
|
||||
- `Views/Components/DailyArtworkWidget.axaml.cs`
|
||||
|
||||
### DailyArtworkComponentEditor (设置编辑器参考)
|
||||
- `Views/ComponentEditors/DailyArtworkComponentEditor.axaml`
|
||||
- `Views/ComponentEditors/DailyArtworkComponentEditor.axaml.cs`
|
||||
|
||||
### 组件注册 (参考模式)
|
||||
- `Services/DesktopComponentEditorRegistryFactory.cs` 第69-71行
|
||||
248
docs/INFO_RECOMMENDATION_COMPONENT_FEASIBILITY.md
Normal file
248
docs/INFO_RECOMMENDATION_COMPONENT_FEASIBILITY.md
Normal file
@@ -0,0 +1,248 @@
|
||||
# 信息推荐类组件引入可行性分析报告
|
||||
|
||||
## 执行摘要
|
||||
|
||||
**结论:高度可行**。阑山桌面已具备完善的信息推荐类组件基础设施,引入新组件的技术门槛低,开发成本可控。
|
||||
|
||||
---
|
||||
|
||||
## 1. 现有基础设施评估
|
||||
|
||||
### 1.1 组件系统架构
|
||||
|
||||
项目采用**分层组件架构**,信息推荐类组件属于 `Info` 分类:
|
||||
|
||||
```
|
||||
LanMountainDesktop/ComponentSystem/
|
||||
├── DesktopComponentDefinition.cs # 组件元数据定义
|
||||
├── ComponentRegistry.cs # 组件注册中心
|
||||
├── BuiltInComponentIds.cs # 内置组件ID常量
|
||||
└── Extensions/ # 扩展组件支持
|
||||
```
|
||||
|
||||
### 1.2 现有信息推荐类组件清单
|
||||
|
||||
| 组件ID | 名称 | 分类 | 尺寸 | 数据源 |
|
||||
|--------|------|------|------|--------|
|
||||
| `DesktopDailyPoetry` | 每日诗词 | Info | 4x2 | jinrishici.com |
|
||||
| `DesktopDailyArtwork` | 每日画作 | Info | 4x2 | Art Institute API |
|
||||
| `DesktopDailyWord` | 每日单词 | Info | 4x2 | Youdao API |
|
||||
| `DesktopDailyWord2x2` | 每日单词(小) | Info | 2x2 | Youdao API |
|
||||
| `DesktopCnrDailyNews` | 央广新闻 | Info | 4x2 | CNR RSS |
|
||||
| `DesktopIfengNews` | 凤凰新闻 | Info | 4x4 | 凤凰网 |
|
||||
| `DesktopJuyaNews` | 橘鸦早报 | Info | 4x4 | 橘鸦API |
|
||||
| `DesktopBilibiliHotSearch` | B站热搜 | Info | 4x2 | Bilibili API |
|
||||
| `DesktopBaiduHotSearch` | 百度热搜 | Info | 4x2 | 百度API |
|
||||
| `DesktopStcn24Forum` | STCN论坛 | Info | 4x4 | SmartTeach Forum |
|
||||
|
||||
**分析**:已有10个信息推荐类组件,覆盖新闻、诗词、艺术、单词、热搜等类型,证明该类别组件需求旺盛且技术路径成熟。
|
||||
|
||||
---
|
||||
|
||||
## 2. 技术实现路径
|
||||
|
||||
### 2.1 数据服务层
|
||||
|
||||
**位置**: `LanMountainDesktop/Services/IRecommendationDataService.cs`
|
||||
|
||||
```csharp
|
||||
public interface IRecommendationInfoService
|
||||
{
|
||||
Task<RecommendationQueryResult<T>> GetXXXAsync(XXXQuery query, CancellationToken ct);
|
||||
void ClearCache();
|
||||
}
|
||||
```
|
||||
|
||||
**已有能力**:
|
||||
- 统一的查询/结果模式 (`RecommendationQueryResult<T>`)
|
||||
- 缓存机制 (按渠道/类型分桶缓存)
|
||||
- 超时控制 (默认8秒)
|
||||
- 错误处理标准化
|
||||
|
||||
### 2.2 组件实现层
|
||||
|
||||
**位置**: `LanMountainDesktop/Views/Components/`
|
||||
|
||||
**标准实现模式**:
|
||||
|
||||
```csharp
|
||||
public partial class XXXWidget : UserControl,
|
||||
IDesktopComponentWidget, // 基础组件接口
|
||||
IRecommendationInfoAwareComponentWidget // 推荐信息感知接口
|
||||
{
|
||||
private readonly IRecommendationInfoService _recommendationService;
|
||||
private readonly DispatcherTimer _refreshTimer;
|
||||
|
||||
// 标准生命周期
|
||||
// - 附加到视觉树时启动刷新
|
||||
// - 分离时清理资源
|
||||
// - 支持自动刷新配置
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 注册与集成
|
||||
|
||||
**步骤1**: 在 `BuiltInComponentIds.cs` 添加ID常量
|
||||
```csharp
|
||||
public const string DesktopNewInfoComponent = "DesktopNewInfoComponent";
|
||||
```
|
||||
|
||||
**步骤2**: 在 `ComponentRegistry.cs` 注册元数据
|
||||
```csharp
|
||||
new DesktopComponentDefinition(
|
||||
BuiltInComponentIds.DesktopNewInfoComponent,
|
||||
"New Info Component",
|
||||
"IconKey",
|
||||
"Info", // 分类
|
||||
MinWidthCells: 4,
|
||||
MinHeightCells: 2,
|
||||
AllowStatusBarPlacement: false,
|
||||
AllowDesktopPlacement: true)
|
||||
```
|
||||
|
||||
**步骤3**: 在 `DesktopComponentRuntimeRegistry.cs` 注册运行时
|
||||
```csharp
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopNewInfoComponent,
|
||||
"NewInfoComponent_DisplayName",
|
||||
ctx => new NewInfoComponentWidget())
|
||||
```
|
||||
|
||||
**步骤4**: 实现数据服务方法 (可选,如使用现有服务可跳过)
|
||||
|
||||
---
|
||||
|
||||
## 3. 开发工作量估算
|
||||
|
||||
### 3.1 最小可行实现 (MVP)
|
||||
|
||||
| 任务 | 文件 | 预估工时 |
|
||||
|------|------|----------|
|
||||
| 添加组件ID | `BuiltInComponentIds.cs` | 5分钟 |
|
||||
| 注册组件定义 | `ComponentRegistry.cs` | 10分钟 |
|
||||
| 注册运行时 | `DesktopComponentRuntimeRegistry.cs` | 10分钟 |
|
||||
| 实现Widget | `Views/Components/NewInfoWidget.axaml` | 2-4小时 |
|
||||
| 实现数据服务方法 | `RecommendationDataService.cs` | 1-2小时 |
|
||||
| 添加本地化 | `Localization/Resources.resx` | 15分钟 |
|
||||
| **总计** | | **4-8小时** |
|
||||
|
||||
### 3.2 参考实现
|
||||
|
||||
**简单组件** (如 `BaiduHotSearchWidget`): ~200行代码
|
||||
**复杂组件** (如 `IfengNewsWidget`): ~600行代码
|
||||
|
||||
---
|
||||
|
||||
## 4. 扩展性评估
|
||||
|
||||
### 4.1 数据源扩展
|
||||
|
||||
**支持的接入方式**:
|
||||
1. **REST API** (如 Bilibili API)
|
||||
2. **RSS Feed** (如 CNR RSS)
|
||||
3. **网页抓取** (如凤凰网)
|
||||
4. **第三方SDK** (可扩展)
|
||||
|
||||
**配置化选项** (`RecommendationApiOptions`):
|
||||
```csharp
|
||||
public sealed record RecommendationApiOptions
|
||||
{
|
||||
public string NewDataSourceUrl { get; init; }
|
||||
public TimeSpan CacheDuration { get; init; } = TimeSpan.FromMinutes(20);
|
||||
public TimeSpan RequestTimeout { get; init; } = TimeSpan.FromSeconds(8);
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 组件模板化
|
||||
|
||||
现有组件可按功能类型抽象模板:
|
||||
|
||||
| 模板类型 | 代表组件 | 特点 |
|
||||
|----------|----------|------|
|
||||
| 列表型 | IfengNews, BilibiliHotSearch | 滚动列表,支持点击跳转 |
|
||||
| 卡片型 | DailyPoetry, DailyWord | 单条内容展示 |
|
||||
| 画廊型 | DailyArtwork | 图片为主,支持缩放 |
|
||||
| 混合型 | JuyaNews | 图文混排 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 风险与缓解措施
|
||||
|
||||
### 5.1 技术风险
|
||||
|
||||
| 风险 | 等级 | 缓解措施 |
|
||||
|------|------|----------|
|
||||
| 数据源不稳定 | 中 | 实现本地缓存 + 降级显示 |
|
||||
| API限流 | 低 | 统一请求间隔控制 (已存在) |
|
||||
| 跨域问题 | 低 | 使用后端代理或CORS支持API |
|
||||
|
||||
### 5.2 维护风险
|
||||
|
||||
| 风险 | 等级 | 缓解措施 |
|
||||
|------|------|----------|
|
||||
| 数据源API变更 | 中 | 抽象数据适配层,隔离变化 |
|
||||
| 组件数量膨胀 | 低 | 考虑插件化迁移 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 建议方案
|
||||
|
||||
### 6.1 短期方案 (推荐)
|
||||
|
||||
**直接添加内置组件**,遵循现有模式:
|
||||
|
||||
```
|
||||
优点:
|
||||
- 开发成本低 (4-8小时/组件)
|
||||
- 与现有系统无缝集成
|
||||
- 用户体验一致
|
||||
|
||||
适用场景:
|
||||
- 核心信息源 (如官方新闻、学习资源)
|
||||
- 高频使用组件
|
||||
```
|
||||
|
||||
### 6.2 长期方案
|
||||
|
||||
**信息推荐组件插件化**:
|
||||
|
||||
```
|
||||
优点:
|
||||
- 数据源可热插拔
|
||||
- 社区可贡献组件
|
||||
- 减小主程序体积
|
||||
|
||||
实现路径:
|
||||
1. 定义信息推荐组件SDK接口
|
||||
2. 提供组件模板脚手架
|
||||
3. 市场发布审核流程
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 结论
|
||||
|
||||
### 7.1 可行性评级: **A级 (强烈推荐)**
|
||||
|
||||
| 维度 | 评分 | 说明 |
|
||||
|------|------|------|
|
||||
| 技术成熟度 | ★★★★★ | 已有10个同类组件,模式稳定 |
|
||||
| 开发成本 | ★★★★★ | 4-8小时/组件,成本低 |
|
||||
| 维护成本 | ★★★★☆ | 依赖外部API需持续维护 |
|
||||
| 用户价值 | ★★★★★ | 信息类组件是桌面核心场景 |
|
||||
| 扩展性 | ★★★★★ | 架构支持多种数据源 |
|
||||
|
||||
### 7.2 行动建议
|
||||
|
||||
1. **立即行动**: 选择1-2个高价值信息源进行试点开发
|
||||
2. **建立规范**: 制定信息推荐组件开发SOP
|
||||
3. **考虑插件化**: 当组件数量超过15个时评估插件化方案
|
||||
|
||||
---
|
||||
|
||||
## 附录: 参考文档
|
||||
|
||||
- `docs/ARCHITECTURE.md` - 系统架构概述
|
||||
- `docs/ECOSYSTEM_BOUNDARIES.md` - 生态边界定义
|
||||
- `LanMountainDesktop/ComponentSystem/README.md` - 组件系统说明
|
||||
- `LanMountainDesktop/Services/IRecommendationDataService.cs` - 数据服务接口
|
||||
128
docs/ZHIJIAO_HUB_COMPONENT_FINAL.md
Normal file
128
docs/ZHIJIAO_HUB_COMPONENT_FINAL.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# 智教Hub组件 - 最终实现总结
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
- ✅ **最小尺寸 2×2** - 符合要求
|
||||
- ✅ **自由缩放** - ResizeMode.Free,允许任意调整大小
|
||||
- ✅ **双数据源** - ClassIsland Hub 和 SECTL Hub
|
||||
- ✅ **上下滑动切换** - 像短视频一样的交互体验
|
||||
- ✅ **鼠标滚轮支持** - 滚轮上下滚动切换图片
|
||||
- ✅ **图片名称显示** - 左下角显示当前图片名称
|
||||
- ✅ **自动刷新** - 可配置间隔,可开启/关闭
|
||||
- ✅ **设置面板** - 数据源切换、自动刷新配置
|
||||
|
||||
### 交互方式
|
||||
1. **触摸/鼠标拖动**: 上下拖动超过50px切换图片
|
||||
2. **鼠标滚轮**: 滚轮上下滚动切换图片
|
||||
3. **自动刷新**: 定时刷新图片列表
|
||||
|
||||
## 技术实现
|
||||
|
||||
### 文件清单
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `Models/ComponentSettingsSnapshot.cs` | 配置字段 + ZhiJiaoHubSources常量 |
|
||||
| `Services/IRecommendationDataService.cs` | 数据接口和类型定义 |
|
||||
| `Services/RecommendationDataService.cs` | GitHub API数据获取实现 |
|
||||
| `Views/Components/ZhiJiaoHubWidget.axaml` | 组件UI布局 |
|
||||
| `Views/Components/ZhiJiaoHubWidget.axaml.cs` | 组件逻辑(滑动交互) |
|
||||
| `Views/ComponentEditors/ZhiJiaoHubComponentEditor.axaml` | 设置编辑器UI |
|
||||
| `Views/ComponentEditors/ZhiJiaoHubComponentEditor.axaml.cs` | 设置编辑器逻辑 |
|
||||
| `ComponentSystem/BuiltInComponentIds.cs` | 组件ID常量 |
|
||||
| `ComponentSystem/ComponentRegistry.cs` | 组件注册 |
|
||||
| `Views/Components/DesktopComponentRuntimeRegistry.cs` | 运行时注册 |
|
||||
| `Services/DesktopComponentEditorRegistryFactory.cs` | 编辑器注册 |
|
||||
| `Views/MainWindow.ComponentSystem.cs` | 比例约束 |
|
||||
|
||||
### 滑动交互实现
|
||||
|
||||
```csharp
|
||||
// 核心滑动逻辑
|
||||
private void OnPointerPressed(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
_isDragging = true;
|
||||
_dragStartPoint = e.GetPosition(this);
|
||||
}
|
||||
|
||||
private void OnPointerMoved(object? sender, PointerEventArgs e)
|
||||
{
|
||||
if (!_isDragging) return;
|
||||
var currentPoint = e.GetPosition(this);
|
||||
_dragOffset = currentPoint.Y - _dragStartPoint.Y;
|
||||
}
|
||||
|
||||
private void OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
if (!_isDragging) return;
|
||||
_isDragging = false;
|
||||
|
||||
// 超过阈值切换图片
|
||||
if (Math.Abs(_dragOffset) > SwipeThreshold)
|
||||
{
|
||||
if (_dragOffset > 0) SwitchToPrevImage(); // 向下滑动
|
||||
else SwitchToNextImage(); // 向上滑动
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 数据源
|
||||
|
||||
| 源 | API地址 | 图片数量 |
|
||||
|----|---------|----------|
|
||||
| ClassIsland Hub | api.github.com/repos/ClassIsland/classisland-hub/contents/images | ~70张 |
|
||||
| SECTL Hub | api.github.com/repos/SECTL/SECTL-hub/contents/docs/.vuepress/public/images | ~78张 |
|
||||
|
||||
### 缓存策略
|
||||
- 图片列表缓存:1小时
|
||||
- 图片缓存:最多5张(当前+前后各1张)
|
||||
- 预加载:自动加载相邻图片
|
||||
|
||||
## 设置选项
|
||||
|
||||
### 数据源选择
|
||||
- ClassIsland Hub(默认)
|
||||
- SECTL Hub
|
||||
|
||||
### 自动刷新
|
||||
- 开关:开启/关闭
|
||||
- 间隔:5-1440分钟(默认30分钟)
|
||||
|
||||
## 构建状态
|
||||
|
||||
✅ **构建成功** - 无错误
|
||||
|
||||
```
|
||||
23 个警告(与本次修改无关)
|
||||
0 个错误
|
||||
```
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 添加组件
|
||||
1. 进入桌面编辑模式
|
||||
2. 从组件库选择 "ZhiJiao Hub"
|
||||
3. 最小2×2,可自由调整大小
|
||||
|
||||
### 浏览图片
|
||||
- **上下滑动**:像短视频一样切换图片
|
||||
- **鼠标滚轮**:滚动切换
|
||||
- **指示器**:右侧显示当前位置
|
||||
|
||||
### 切换数据源
|
||||
1. 选中组件,点击设置按钮
|
||||
2. 选择 "Image Source"
|
||||
3. 选择 ClassIsland 或 SECTL
|
||||
|
||||
### 配置自动刷新
|
||||
1. 在设置面板中开关 "Auto Refresh"
|
||||
2. 设置刷新间隔(分钟)
|
||||
|
||||
## 后续优化建议
|
||||
|
||||
1. **动画效果**: 添加滑动时的图片过渡动画
|
||||
2. **本地缓存**: 持久化图片到本地磁盘
|
||||
3. **收藏功能**: 允许用户收藏喜欢的图片
|
||||
4. **分享功能**: 分享图片链接
|
||||
5. **更多源**: 添加更多教育技术社区图片源
|
||||
161
docs/ZHIJIAO_HUB_COMPONENT_SUMMARY.md
Normal file
161
docs/ZHIJIAO_HUB_COMPONENT_SUMMARY.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# 智教Hub组件实现总结
|
||||
|
||||
## 组件概述
|
||||
|
||||
智教Hub组件是一个图片展示组件,从两个GitHub仓库获取社区图片:
|
||||
- **ClassIsland Hub**: https://github.com/ClassIsland/classisland-hub
|
||||
- **SECTL Hub**: https://github.com/SECTL/SECTL-hub
|
||||
|
||||
## 功能特性
|
||||
|
||||
- ✅ 最小尺寸 2×2 cells
|
||||
- ✅ 允许自由调整大小 (ResizeMode.Free)
|
||||
- ✅ 支持两个数据源切换
|
||||
- ✅ 自动刷新功能(可配置间隔)
|
||||
- ✅ 图片左右导航
|
||||
- ✅ 左下角显示图片名称
|
||||
- ✅ 悬停显示导航按钮和指示器
|
||||
|
||||
## 文件清单
|
||||
|
||||
### 1. 数据模型和配置
|
||||
- `LanMountainDesktop/Models/ComponentSettingsSnapshot.cs`
|
||||
- 添加智教Hub配置字段
|
||||
- 添加 `ZhiJiaoHubSources` 常量类
|
||||
|
||||
### 2. 数据服务
|
||||
- `LanMountainDesktop/Services/IRecommendationDataService.cs`
|
||||
- 添加 `ZhiJiaoHubQuery`, `ZhiJiaoHubImageItem`, `ZhiJiaoHubSnapshot` 类型
|
||||
- 添加 `GetZhiJiaoHubImagesAsync` 接口方法
|
||||
- 添加 GitHub API URL 配置
|
||||
|
||||
- `LanMountainDesktop/Services/RecommendationDataService.cs`
|
||||
- 实现 `GetZhiJiaoHubImagesAsync` 方法
|
||||
- 实现 GitHub API 图片列表获取
|
||||
- 实现缓存机制(1小时缓存)
|
||||
|
||||
### 3. 组件实现
|
||||
- `LanMountainDesktop/Views/Components/ZhiJiaoHubWidget.axaml`
|
||||
- 组件UI布局(图片、渐变遮罩、名称、导航按钮、指示器)
|
||||
|
||||
- `LanMountainDesktop/Views/Components/ZhiJiaoHubWidget.axaml.cs`
|
||||
- 组件逻辑实现
|
||||
- 图片加载和显示
|
||||
- 导航功能(上一张/下一张)
|
||||
- 自动刷新
|
||||
- 设置持久化
|
||||
|
||||
### 4. 设置编辑器
|
||||
- `LanMountainDesktop/Views/ComponentEditors/ZhiJiaoHubComponentEditor.axaml`
|
||||
- 设置界面布局
|
||||
|
||||
- `LanMountainDesktop/Views/ComponentEditors/ZhiJiaoHubComponentEditor.axaml.cs`
|
||||
- 数据源选择
|
||||
- 自动刷新开关
|
||||
- 刷新间隔设置
|
||||
|
||||
### 5. 组件注册
|
||||
- `LanMountainDesktop/ComponentSystem/BuiltInComponentIds.cs`
|
||||
- 添加 `DesktopZhiJiaoHub` 常量
|
||||
|
||||
- `LanMountainDesktop/ComponentSystem/ComponentRegistry.cs`
|
||||
- 注册组件定义(2×2最小尺寸,Free调整模式)
|
||||
|
||||
- `LanMountainDesktop/Views/Components/DesktopComponentRuntimeRegistry.cs`
|
||||
- 注册组件运行时
|
||||
|
||||
- `LanMountainDesktop/Services/DesktopComponentEditorRegistryFactory.cs`
|
||||
- 注册组件设置编辑器
|
||||
|
||||
- `LanMountainDesktop/Views/MainWindow.ComponentSystem.cs`
|
||||
- 添加比例约束(允许自由调整大小)
|
||||
|
||||
## 技术实现细节
|
||||
|
||||
### 图片获取流程
|
||||
|
||||
```
|
||||
1. 调用 GitHub API 获取仓库图片目录
|
||||
- ClassIsland: /repos/ClassIsland/classisland-hub/contents/images
|
||||
- SECTL: /repos/SECTL/SECTL-hub/contents/docs/.vuepress/public/images
|
||||
|
||||
2. 解析 JSON 响应,提取图片文件信息
|
||||
- 文件名(解码URL编码)
|
||||
- 下载URL
|
||||
|
||||
3. 过滤非图片文件(只保留 .png, .jpg, .jpeg, .gif, .webp)
|
||||
|
||||
4. 缓存图片列表(1小时)
|
||||
|
||||
5. 按需加载单个图片
|
||||
```
|
||||
|
||||
### 数据源配置
|
||||
|
||||
```csharp
|
||||
public static class ZhiJiaoHubSources
|
||||
{
|
||||
public const string ClassIsland = "classisland";
|
||||
public const string Sectl = "sectl";
|
||||
}
|
||||
```
|
||||
|
||||
### 组件配置项
|
||||
|
||||
```csharp
|
||||
public string ZhiJiaoHubSource { get; set; } = ZhiJiaoHubSources.ClassIsland;
|
||||
public bool ZhiJiaoHubAutoRefreshEnabled { get; set; } = true;
|
||||
public int ZhiJiaoHubAutoRefreshIntervalMinutes { get; set; } = 30;
|
||||
public int ZhiJiaoHubCurrentImageIndex { get; set; } = 0;
|
||||
```
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 添加组件到桌面
|
||||
|
||||
1. 进入桌面编辑模式
|
||||
2. 从组件库选择 "ZhiJiao Hub"
|
||||
3. 组件最小尺寸为 2×2,可以自由调整大小
|
||||
|
||||
### 切换数据源
|
||||
|
||||
1. 选中组件,点击设置按钮
|
||||
2. 在设置面板中选择 "Image Source"
|
||||
3. 可选:ClassIsland Hub 或 SECTL Hub
|
||||
|
||||
### 配置自动刷新
|
||||
|
||||
1. 在设置面板中开启/关闭 "Auto Refresh"
|
||||
2. 设置刷新间隔(5-1440分钟)
|
||||
|
||||
### 浏览图片
|
||||
|
||||
- **自动**: 组件会自动轮播图片
|
||||
- **手动**: 鼠标悬停显示左右箭头,点击切换
|
||||
- **指示器**: 底部圆点显示当前位置
|
||||
|
||||
## 图片源信息
|
||||
|
||||
### ClassIsland Hub
|
||||
- **仓库**: https://github.com/ClassIsland/classisland-hub
|
||||
- **图片路径**: `/images/`
|
||||
- **内容**: ClassIsland交流群/频道的有趣内容
|
||||
- **数量**: 约70张图片
|
||||
|
||||
### SECTL Hub
|
||||
- **仓库**: https://github.com/SECTL/SECTL-hub
|
||||
- **图片路径**: `/docs/.vuepress/public/images/`
|
||||
- **内容**: SECTL交流群的趣图
|
||||
- **数量**: 约78张图片
|
||||
|
||||
## 后续优化建议
|
||||
|
||||
1. **本地缓存**: 将下载的图片缓存到本地,减少网络请求
|
||||
2. **缩略图**: 生成缩略图提高加载速度
|
||||
3. **收藏功能**: 允许用户收藏喜欢的图片
|
||||
4. **分享功能**: 支持分享图片链接
|
||||
5. **更多源**: 添加更多教育技术社区图片源
|
||||
|
||||
## 构建状态
|
||||
|
||||
✅ 构建成功,无错误
|
||||
Reference in New Issue
Block a user