feat(schedules,classisland,server,plugin,shared): 课表行加来源字段,插件上报可真正同步删除
课表行新增 Schedule.source(manual / classisland):插件每次全量上报时,服务端 只清理「source=classisland 且本次未再上报」的行。原先 merge 只做 upsert,老师在 ClassIsland 里删掉或挪走一节,服务端会永远留着那行幽灵课;现在能真正同步下来, 而老师在小助手这边手排的课(manual)一律不删。 配套改动: - 插件上报时带回 machineKey,服务端回填到设备记录(避开 [classId, deviceKey] 唯一约束); - 新增迁移 20260930120000_add_schedule_source,存量数据保守地按 manual 处理; - verify:classisland 补「幽灵行清理」「手排课不被误删」用例。 另:.gitignore 补上 .zcode/ 与 .zcodeignore(AI 会话产物,不属于产品代码)。
This commit is contained in:
1 parent
9c678b3730
commit
7ea0e0f7c9
17 files changed
+620
-44
No files matched your search
@@ -127,9 +127,15 @@ public class Plugin : PluginBase
|
||||
settings.Normalize();
|
||||
if (needGenerateKey)
|
||||
{
|
||||
// 机器名 + 随机短码:既是人眼可读的"这台机器",又不会两台同名机器撞车
|
||||
// 机器名 + 随机短码:既是人眼可读的"这台机器",又不会两台同名机器撞车。
|
||||
// 注意长度:原先写的是 `[..Math.Min(24, machine.Length + 33)]`,而 machine.Length + 33
|
||||
// 恒大于 24,所以实际**永远只取前 24 个字符** —— 机器名稍长就把随机段整个切掉,
|
||||
// "同名机器不撞车"的保障就没了。这里改成"机器名按需截短 + 保留 8 位随机段"。
|
||||
var machine = Environment.MachineName.ToLowerInvariant();
|
||||
settings.DeviceKey = $"{machine}-{Guid.NewGuid():N}"[..Math.Min(24, machine.Length + 33)];
|
||||
var suffix = Guid.NewGuid().ToString("N")[..8];
|
||||
var maxMachineLength = Math.Max(4, 24 - suffix.Length - 1);
|
||||
if (machine.Length > maxMachineLength) machine = machine[..maxMachineLength];
|
||||
settings.DeviceKey = $"{machine}-{suffix}";
|
||||
}
|
||||
|
||||
Settings = settings;
|
||||
@@ -146,7 +152,15 @@ public class Plugin : PluginBase
|
||||
{
|
||||
var folder = Path.GetDirectoryName(path);
|
||||
if (!string.IsNullOrEmpty(folder)) Directory.CreateDirectory(folder);
|
||||
File.WriteAllText(path, JsonSerializer.Serialize(settings, JsonOptions));
|
||||
// 先写临时文件再原子替换。
|
||||
//
|
||||
// 设置页的地址/令牌输入框是 TwoWay 绑定(逐字符提交),直接 `File.WriteAllText`
|
||||
// 会就地截断原文件;一旦此刻进程被杀或断电,留下的是半截 JSON,而 LoadSettings 的
|
||||
// catch 会**静默回退到默认设置** —— 用户看到的是"令牌和地址莫名其妙没了",
|
||||
// 而且原文件已被覆盖,无从恢复。
|
||||
var temp = path + ".tmp";
|
||||
File.WriteAllText(temp, JsonSerializer.Serialize(settings, JsonOptions));
|
||||
File.Move(temp, path, overwrite: true);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user