feat: service console auto-connect, settings panel, and batch of enhancements
- Auto-connect WebSocket on page load in service console - Settings modal for editing sgclaw_config.json (API key, base URL, model, skills dir, etc.) - UpdateConfig/ConfigUpdated protocol messages for remote config save - save_to_path() for SgClawSettings serialization - ConfigUpdated handler in sg_claw_client binary - Protocol serialization tests for new message types - HTML test assertions for auto-connect and settings UI - Additional pending changes: deterministic submit, org units, lineloss xlsx export, browser script tool, and docs 🤖 Generated with [Qoder][https://qoder.com]
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
# Rust-Side Lineloss XLSX Export
|
||||
|
||||
## Problem
|
||||
|
||||
`collect_lineloss.js` runs on a remote page (`http://20.76.57.61:18080/gsllys`).
|
||||
The script successfully queries API data (12 rows), but cannot call
|
||||
`http://localhost:13313/.../faultDetailsExportXLSX` because the browser blocks
|
||||
cross-origin requests from a remote page to `localhost`.
|
||||
|
||||
The original scene architecture had a local scene page acting as a proxy,
|
||||
but skill mode has no local page -- so export is architecturally impossible
|
||||
from the browser side.
|
||||
|
||||
## Decision
|
||||
|
||||
Move XLSX generation to the Rust side. JS only collects data; Rust generates
|
||||
the `.xlsx` file locally after receiving the artifact.
|
||||
|
||||
Report log (`setReportLog`) is deferred to a later iteration.
|
||||
|
||||
## Design
|
||||
|
||||
### JS Changes (`collect_lineloss.js`)
|
||||
|
||||
1. Remove `exportWorkbook()` call and `writeReportLog()` call
|
||||
2. Return artifact with `rows` array and `column_defs` array
|
||||
3. Status is `ok` when rows > 0, `empty` when rows == 0, `error`/`blocked` unchanged
|
||||
|
||||
Artifact shape:
|
||||
```json
|
||||
{
|
||||
"type": "report-artifact",
|
||||
"report_name": "tq-lineloss-report",
|
||||
"status": "ok",
|
||||
"org": { "label": "...", "code": "..." },
|
||||
"period": { "mode": "month", "value": "2026-03" },
|
||||
"column_defs": [["ORG_NAME","供电单位"], ["YGDL","累计供电量"], ...],
|
||||
"rows": [
|
||||
{"ORG_NAME":"xxx", "YGDL":"12345.67", ...}
|
||||
],
|
||||
"counts": { "rows": 12 }
|
||||
}
|
||||
```
|
||||
|
||||
### Rust Changes
|
||||
|
||||
#### New file: `src/compat/lineloss_xlsx_export.rs`
|
||||
|
||||
Generates a standard `.xlsx` file using `zip` crate + OpenXML XML strings.
|
||||
Follows the pattern established in `openxml_office_tool.rs`.
|
||||
|
||||
Public API:
|
||||
```rust
|
||||
pub struct LinelossExportRequest {
|
||||
pub column_defs: Vec<(String, String)>, // (key, chinese_header)
|
||||
pub rows: Vec<Map<String, Value>>,
|
||||
pub sheet_name: String,
|
||||
pub output_path: PathBuf,
|
||||
}
|
||||
|
||||
pub fn export_lineloss_xlsx(request: &LinelossExportRequest) -> anyhow::Result<PathBuf>;
|
||||
```
|
||||
|
||||
Internals:
|
||||
- Build header row from `column_defs[*].1` (chinese names)
|
||||
- Build data rows by looking up `column_defs[*].0` keys in each row map
|
||||
- Generate `worksheet_xml` with inline string cells
|
||||
- Package with standard OpenXML boilerplate (content_types, rels, workbook)
|
||||
- Write to `output_path`
|
||||
|
||||
#### Modified: `src/compat/deterministic_submit.rs`
|
||||
|
||||
In `execute_deterministic_submit_with_browser_backend` (and the non-backend variant):
|
||||
|
||||
```
|
||||
let output = execute_browser_script_skill_raw_output_with_browser_backend(...)?;
|
||||
let artifact = parse_lineloss_artifact(&output);
|
||||
|
||||
if artifact has rows > 0 && column_defs present:
|
||||
let export_path = workspace_root/out/tq-lineloss-{timestamp}.xlsx
|
||||
export_lineloss_xlsx(LinelossExportRequest { ... })?
|
||||
// attach export_path to outcome summary
|
||||
|
||||
Ok(summarize_lineloss_output_with_export(&output, export_path))
|
||||
```
|
||||
|
||||
#### Modified: `src/compat/mod.rs`
|
||||
|
||||
Add `pub mod lineloss_xlsx_export;`
|
||||
|
||||
### Output Path
|
||||
|
||||
`{workspace_root}/out/tq-lineloss-{org_label}-{period}-{timestamp_nanos}.xlsx`
|
||||
|
||||
### Error Handling
|
||||
|
||||
- XLSX generation failure: outcome status = `partial`, reason = `xlsx_export_failed`
|
||||
- Artifact parse failure: fall through to existing `summarize_lineloss_output`
|
||||
|
||||
## Files Changed
|
||||
|
||||
| File | Change Type |
|
||||
|------|-------------|
|
||||
| `collect_lineloss.js` | Modify: remove export/log calls, add rows+column_defs to artifact |
|
||||
| `src/compat/lineloss_xlsx_export.rs` | New: XLSX generation |
|
||||
| `src/compat/deterministic_submit.rs` | Modify: post-process artifact, call XLSX export |
|
||||
| `src/compat/mod.rs` | Modify: register new module |
|
||||
|
||||
## Requires Recompilation
|
||||
|
||||
Yes. Rust code changes require `cargo build`.
|
||||
Reference in New Issue
Block a user