feat: add staged command center scene skills
Stage registry-driven report and monitor scene skills, including the packaged snapshot collectors and scene metadata needed to align with the command center workflow inventory. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"draft": true,
|
||||||
|
"id": "95598-repair-city-dispatch",
|
||||||
|
"name": "95598抢修-市指",
|
||||||
|
"inferred_from": [
|
||||||
|
"../../skills/95598-repair-city-dispatch/SKILL.toml",
|
||||||
|
"../../skills/95598-repair-city-dispatch/scripts/collect_repair_orders.js",
|
||||||
|
"../../skills/95598-repair-city-dispatch/references/collection-flow.md",
|
||||||
|
"../../skills/95598-repair-city-dispatch/references/data-quality.md",
|
||||||
|
"../../../大四区报告监测项/95598抢修-市指/index.html",
|
||||||
|
"../../../大四区报告监测项/95598抢修-市指_业务检测配置.txt",
|
||||||
|
"../../../大四区报告监测项/95598抢修-市指_自动处理配置.txt"
|
||||||
|
],
|
||||||
|
"confidence": {
|
||||||
|
"category": "high",
|
||||||
|
"inputs": "high",
|
||||||
|
"outputs": "high",
|
||||||
|
"dependencies": "high",
|
||||||
|
"actions": "medium"
|
||||||
|
},
|
||||||
|
"guesses": {
|
||||||
|
"category": "monitor",
|
||||||
|
"inputs": ["time"],
|
||||||
|
"dependencies": ["browser", "local-service", "repair-order-source", "history-log", "status-classification"],
|
||||||
|
"actions": ["monitor-queue", "classify-status", "compare-history", "write-local-log", "trigger-alert"]
|
||||||
|
},
|
||||||
|
"todo": [
|
||||||
|
"确认 trigger-alert 是否应拆分成 audio-alert、message-alert、callout 三类动作。",
|
||||||
|
"确认 configServices 是否需要在正式 dependencies 中单独暴露。"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"id": "95598-repair-city-dispatch",
|
||||||
|
"name": "95598抢修-市指",
|
||||||
|
"category": "monitor",
|
||||||
|
"entry": "index.html",
|
||||||
|
"summary": "监测 95598 抢修市指工单队列状态,并结合本地日志比较与提醒侧动作返回结构化监测快照。",
|
||||||
|
"inputs": ["time"],
|
||||||
|
"outputs": ["monitor-snapshot"],
|
||||||
|
"dependencies": ["browser", "local-service", "repair-order-source", "history-log", "dispose-log", "status-classification"],
|
||||||
|
"actions": ["monitor-queue", "classify-status", "compare-history", "write-local-log", "trigger-alert"],
|
||||||
|
"tags": ["95598", "repair", "dispatch", "monitoring", "config"],
|
||||||
|
"skill": {
|
||||||
|
"package": "95598-repair-city-dispatch",
|
||||||
|
"tool": "collect_repair_orders",
|
||||||
|
"artifact_type": "monitor-snapshot"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"scenario_path": "../../../大四区报告监测项/95598抢修-市指",
|
||||||
|
"skill_path": "../../skills/95598-repair-city-dispatch"
|
||||||
|
},
|
||||||
|
"status_semantics": {
|
||||||
|
"supports_partial": true,
|
||||||
|
"distinguish_blocked_from_empty": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"draft": true,
|
||||||
|
"id": "95598-weekly-monitor-report",
|
||||||
|
"name": "95598、12398及配网设备监控情况周统计",
|
||||||
|
"inferred_from": [
|
||||||
|
"../../skills/95598-weekly-monitor-report/SKILL.toml",
|
||||||
|
"../../skills/95598-weekly-monitor-report/scripts/collect_weekly_metrics.js",
|
||||||
|
"../../skills/95598-weekly-monitor-report/references/collection-flow.md",
|
||||||
|
"../../skills/95598-weekly-monitor-report/references/data-quality.md",
|
||||||
|
"../../../大四区报告监测项/95598、12398及配网设备监控情况周统计/index.html"
|
||||||
|
],
|
||||||
|
"confidence": {
|
||||||
|
"category": "high",
|
||||||
|
"inputs": "medium",
|
||||||
|
"outputs": "high",
|
||||||
|
"dependencies": "medium",
|
||||||
|
"actions": "medium"
|
||||||
|
},
|
||||||
|
"guesses": {
|
||||||
|
"category": "report",
|
||||||
|
"inputs": ["currentPeriod", "cumulativePeriod"],
|
||||||
|
"dependencies": ["browser", "multi-source", "period-alignment", "local-report-service"],
|
||||||
|
"actions": ["query", "collect-report", "aggregate-sections", "align-periods"]
|
||||||
|
},
|
||||||
|
"todo": [
|
||||||
|
"确认 scene.json 是否应把 period 拆成 currentPeriod 与 cumulativePeriod 两个正式输入。",
|
||||||
|
"确认 period-alignment 是否作为独立 dependency 保留,还是仅作为 action 语义。"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"id": "95598-weekly-monitor-report",
|
||||||
|
"name": "95598、12398及配网设备监控情况周统计",
|
||||||
|
"category": "report",
|
||||||
|
"entry": "index.html",
|
||||||
|
"summary": "采集 95598、12398 及配网设备多来源周统计指标并生成分区结构化周报产物。",
|
||||||
|
"inputs": ["period"],
|
||||||
|
"outputs": ["report-artifact"],
|
||||||
|
"dependencies": ["browser", "multi-source", "period-alignment", "local-report-service"],
|
||||||
|
"actions": ["query", "collect-report", "aggregate-sections", "align-periods"],
|
||||||
|
"tags": ["95598", "12398", "weekly-report", "browser", "report"],
|
||||||
|
"skill": {
|
||||||
|
"package": "95598-weekly-monitor-report",
|
||||||
|
"tool": "collect_weekly_metrics",
|
||||||
|
"artifact_type": "report-artifact"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"scenario_path": "../../../大四区报告监测项/95598、12398及配网设备监控情况周统计",
|
||||||
|
"skill_path": "../../skills/95598-weekly-monitor-report"
|
||||||
|
},
|
||||||
|
"status_semantics": {
|
||||||
|
"supports_partial": true,
|
||||||
|
"distinguish_blocked_from_empty": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"draft": true,
|
||||||
|
"id": "fault-details-report",
|
||||||
|
"name": "故障明细",
|
||||||
|
"inferred_from": [
|
||||||
|
"../../skills/fault-details-report/SKILL.toml",
|
||||||
|
"../../skills/fault-details-report/scripts/collect_fault_details.js",
|
||||||
|
"../../skills/fault-details-report/references/collection-flow.md",
|
||||||
|
"../../skills/fault-details-report/references/data-quality.md",
|
||||||
|
"../../../大四区报告监测项/故障明细/index.html"
|
||||||
|
],
|
||||||
|
"confidence": {
|
||||||
|
"category": "high",
|
||||||
|
"inputs": "high",
|
||||||
|
"outputs": "high",
|
||||||
|
"dependencies": "medium",
|
||||||
|
"actions": "medium"
|
||||||
|
},
|
||||||
|
"guesses": {
|
||||||
|
"category": "report",
|
||||||
|
"inputs": ["period"],
|
||||||
|
"dependencies": ["browser", "report-history", "local-report-service"],
|
||||||
|
"actions": ["query", "collect-report", "build-summary-section"]
|
||||||
|
},
|
||||||
|
"todo": [
|
||||||
|
"确认 period 在 generator 层是否保留为单字段,还是拆分为 startTime/endTime。",
|
||||||
|
"确认 local-report-service 是否需要统一归一到 local-service 词表。"
|
||||||
|
]
|
||||||
|
}
|
||||||
25
skills/skill_staging/scenes/fault-details-report/scene.json
Normal file
25
skills/skill_staging/scenes/fault-details-report/scene.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"id": "fault-details-report",
|
||||||
|
"name": "故障明细",
|
||||||
|
"category": "report",
|
||||||
|
"entry": "index.html",
|
||||||
|
"summary": "查询故障明细行并生成包含明细与汇总分区的结构化报表产物。",
|
||||||
|
"inputs": ["period"],
|
||||||
|
"outputs": ["report-artifact"],
|
||||||
|
"dependencies": ["browser", "report-history", "local-report-service"],
|
||||||
|
"actions": ["query", "collect-report", "build-summary-section"],
|
||||||
|
"tags": ["fault", "report", "xlsx", "details", "browser"],
|
||||||
|
"skill": {
|
||||||
|
"package": "fault-details-report",
|
||||||
|
"tool": "collect_fault_details",
|
||||||
|
"artifact_type": "report-artifact"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"scenario_path": "../../../大四区报告监测项/故障明细",
|
||||||
|
"skill_path": "../../skills/fault-details-report"
|
||||||
|
},
|
||||||
|
"status_semantics": {
|
||||||
|
"supports_partial": true,
|
||||||
|
"distinguish_blocked_from_empty": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"draft": true,
|
||||||
|
"id": "jiayuguan-meter-outage",
|
||||||
|
"name": "户表失电-嘉峪关",
|
||||||
|
"inferred_from": [
|
||||||
|
"../../skills/jiayuguan-meter-outage/SKILL.toml",
|
||||||
|
"../../skills/jiayuguan-meter-outage/scripts/collect_outage_events.js",
|
||||||
|
"../../skills/jiayuguan-meter-outage/references/collection-flow.md",
|
||||||
|
"../../skills/jiayuguan-meter-outage/references/data-quality.md",
|
||||||
|
"../../../大四区报告监测项/户表失电-嘉峪关/index.html",
|
||||||
|
"../../../大四区报告监测项/户表失电-嘉峪关_业务监测配置.txt",
|
||||||
|
"../../../大四区报告监测项/户表失电-嘉峪关_自动处理配置.txt"
|
||||||
|
],
|
||||||
|
"confidence": {
|
||||||
|
"category": "high",
|
||||||
|
"inputs": "high",
|
||||||
|
"outputs": "high",
|
||||||
|
"dependencies": "high",
|
||||||
|
"actions": "medium"
|
||||||
|
},
|
||||||
|
"guesses": {
|
||||||
|
"category": "monitor",
|
||||||
|
"inputs": ["time"],
|
||||||
|
"dependencies": ["browser", "local-service", "outage-source", "service-order-source", "history-log"],
|
||||||
|
"actions": ["collect-outage-events", "enrich-service-orders", "compare-history", "write-local-log", "trigger-alert"]
|
||||||
|
},
|
||||||
|
"todo": [
|
||||||
|
"确认 marketing token context 是否需要作为正式 dependency 单独暴露。",
|
||||||
|
"确认 trigger-alert 是否应与 auto-processing 拆成两个独立动作。"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"id": "jiayuguan-meter-outage",
|
||||||
|
"name": "户表失电-嘉峪关",
|
||||||
|
"category": "monitor",
|
||||||
|
"entry": "index.html",
|
||||||
|
"summary": "采集嘉峪关户表失电事件与关联工单状态,结合历史比较与本地日志侧动作返回结构化监测快照。",
|
||||||
|
"inputs": ["time"],
|
||||||
|
"outputs": ["monitor-snapshot"],
|
||||||
|
"dependencies": ["browser", "local-service", "outage-source", "service-order-source", "history-log", "dispose-log", "marketing-token-context"],
|
||||||
|
"actions": ["collect-outage-events", "enrich-service-orders", "compare-history", "write-local-log", "trigger-alert"],
|
||||||
|
"tags": ["jiayuguan", "meter-outage", "monitoring", "alert", "dispatch"],
|
||||||
|
"skill": {
|
||||||
|
"package": "jiayuguan-meter-outage",
|
||||||
|
"tool": "collect_outage_events",
|
||||||
|
"artifact_type": "monitor-snapshot"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"scenario_path": "../../../大四区报告监测项/户表失电-嘉峪关",
|
||||||
|
"skill_path": "../../skills/jiayuguan-meter-outage"
|
||||||
|
},
|
||||||
|
"status_semantics": {
|
||||||
|
"supports_partial": true,
|
||||||
|
"distinguish_blocked_from_empty": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"draft": true,
|
||||||
|
"id": "jinchang-business-environment-weekly-report",
|
||||||
|
"name": "国网金昌供电公司营商环境周例会报告",
|
||||||
|
"inferred_from": [
|
||||||
|
"../../skills/jinchang-business-environment-weekly-report/SKILL.toml",
|
||||||
|
"../../skills/jinchang-business-environment-weekly-report/scripts/collect_business_environment_metrics.js",
|
||||||
|
"../../skills/jinchang-business-environment-weekly-report/references/collection-flow.md",
|
||||||
|
"../../skills/jinchang-business-environment-weekly-report/references/data-quality.md",
|
||||||
|
"../../../大四区报告监测项/国网金昌供电公司营商环境周例会报告/index.html"
|
||||||
|
],
|
||||||
|
"confidence": {
|
||||||
|
"category": "high",
|
||||||
|
"inputs": "high",
|
||||||
|
"outputs": "high",
|
||||||
|
"dependencies": "medium",
|
||||||
|
"actions": "medium"
|
||||||
|
},
|
||||||
|
"guesses": {
|
||||||
|
"category": "report",
|
||||||
|
"inputs": ["period"],
|
||||||
|
"dependencies": ["browser", "multi-source", "local-report-service"],
|
||||||
|
"actions": ["query", "collect-report", "aggregate-sections"]
|
||||||
|
},
|
||||||
|
"todo": [
|
||||||
|
"确认 multi-source 是否要进一步细分为 source-session-cache 或 token-cache。",
|
||||||
|
"确认 dispatch-summary 等 section 名是否需要进入 scene 级 metadata。"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"id": "jinchang-business-environment-weekly-report",
|
||||||
|
"name": "国网金昌供电公司营商环境周例会报告",
|
||||||
|
"category": "report",
|
||||||
|
"entry": "index.html",
|
||||||
|
"summary": "采集金昌营商环境周例会多来源指标并组装为分区结构化周报产物。",
|
||||||
|
"inputs": ["period"],
|
||||||
|
"outputs": ["report-artifact"],
|
||||||
|
"dependencies": ["browser", "multi-source", "local-report-service"],
|
||||||
|
"actions": ["query", "collect-report", "aggregate-sections"],
|
||||||
|
"tags": ["jinchang", "business-environment", "weekly-report", "browser", "report"],
|
||||||
|
"skill": {
|
||||||
|
"package": "jinchang-business-environment-weekly-report",
|
||||||
|
"tool": "collect_business_environment_metrics",
|
||||||
|
"artifact_type": "report-artifact"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"scenario_path": "../../../大四区报告监测项/国网金昌供电公司营商环境周例会报告",
|
||||||
|
"skill_path": "../../skills/jinchang-business-environment-weekly-report"
|
||||||
|
},
|
||||||
|
"status_semantics": {
|
||||||
|
"supports_partial": true,
|
||||||
|
"distinguish_blocked_from_empty": true
|
||||||
|
}
|
||||||
|
}
|
||||||
77
skills/skill_staging/scenes/load-scene-registry.js
Normal file
77
skills/skill_staging/scenes/load-scene-registry.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
const fs = require('node:fs');
|
||||||
|
const path = require('node:path');
|
||||||
|
|
||||||
|
function readJson(filePath) {
|
||||||
|
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadSceneRegistry(registryPath) {
|
||||||
|
const resolvedRegistryPath = path.resolve(registryPath);
|
||||||
|
const registryDir = path.dirname(resolvedRegistryPath);
|
||||||
|
const registry = readJson(resolvedRegistryPath);
|
||||||
|
|
||||||
|
const items = registry.scenes.map((item) => {
|
||||||
|
const scenePath = path.resolve(registryDir, item.scene_file);
|
||||||
|
const draftPath = path.resolve(registryDir, item.draft_file);
|
||||||
|
const sceneDir = path.dirname(scenePath);
|
||||||
|
const scene = readJson(scenePath);
|
||||||
|
const draft = readJson(draftPath);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: scene.id,
|
||||||
|
name: scene.name,
|
||||||
|
category: scene.category,
|
||||||
|
scenePath,
|
||||||
|
draftPath,
|
||||||
|
skillPath: path.resolve(sceneDir, scene.source.skill_path),
|
||||||
|
scenarioPath: path.resolve(sceneDir, scene.source.scenario_path),
|
||||||
|
inferredFrom: draft.inferred_from.map((entry) => path.resolve(sceneDir, entry)),
|
||||||
|
tool: scene.skill.tool,
|
||||||
|
artifactType: scene.skill.artifact_type,
|
||||||
|
inputs: scene.inputs,
|
||||||
|
outputs: scene.outputs,
|
||||||
|
dependencies: scene.dependencies,
|
||||||
|
actions: scene.actions,
|
||||||
|
todoCount: Array.isArray(draft.todo) ? draft.todo.length : 0
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
registryPath: resolvedRegistryPath,
|
||||||
|
registryDir,
|
||||||
|
registry,
|
||||||
|
items
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCliSummary(result) {
|
||||||
|
return {
|
||||||
|
registryPath: result.registryPath,
|
||||||
|
sceneCount: result.registry.summary.scene_count,
|
||||||
|
items: result.items.map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
category: item.category,
|
||||||
|
tool: item.tool,
|
||||||
|
artifactType: item.artifactType,
|
||||||
|
scenePath: item.scenePath,
|
||||||
|
draftPath: item.draftPath,
|
||||||
|
skillPath: item.skillPath,
|
||||||
|
scenarioPath: item.scenarioPath,
|
||||||
|
todoCount: item.todoCount
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
const registryPath = process.argv[2]
|
||||||
|
? path.resolve(process.argv[2])
|
||||||
|
: path.resolve(__dirname, 'scene-registry.draft.json');
|
||||||
|
|
||||||
|
const result = loadSceneRegistry(registryPath);
|
||||||
|
process.stdout.write(`${JSON.stringify(buildCliSummary(result), null, 2)}\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
loadSceneRegistry,
|
||||||
|
buildCliSummary
|
||||||
|
};
|
||||||
23
skills/skill_staging/scenes/load-scene-registry.test.js
Normal file
23
skills/skill_staging/scenes/load-scene-registry.test.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const path = require('node:path');
|
||||||
|
|
||||||
|
test('loadSceneRegistry resolves registry, scene, draft, and source paths', () => {
|
||||||
|
const { loadSceneRegistry } = require('./load-scene-registry.js');
|
||||||
|
|
||||||
|
const registryPath = path.resolve(__dirname, 'scene-registry.draft.json');
|
||||||
|
const result = loadSceneRegistry(registryPath);
|
||||||
|
|
||||||
|
assert.equal(result.registry.kind, 'scene-registry');
|
||||||
|
assert.equal(result.registry.summary.scene_count, 5);
|
||||||
|
assert.equal(result.items.length, 5);
|
||||||
|
|
||||||
|
const fault = result.items.find((item) => item.id === 'fault-details-report');
|
||||||
|
assert.ok(fault);
|
||||||
|
assert.ok(fault.scenePath.endsWith(path.join('fault-details-report', 'scene.json')));
|
||||||
|
assert.ok(fault.draftPath.endsWith(path.join('fault-details-report', 'scene.draft.json')));
|
||||||
|
assert.ok(fault.skillPath.endsWith(path.join('skill_staging', 'skills', 'fault-details-report')));
|
||||||
|
assert.ok(fault.scenarioPath.endsWith(path.join('大四区报告监测项', '故障明细')));
|
||||||
|
assert.equal(fault.tool, 'collect_fault_details');
|
||||||
|
assert.equal(fault.artifactType, 'report-artifact');
|
||||||
|
});
|
||||||
156
skills/skill_staging/scenes/scene-registry-usage.md
Normal file
156
skills/skill_staging/scenes/scene-registry-usage.md
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
# scene-registry.draft.json 使用约定
|
||||||
|
|
||||||
|
## 1. 文件角色
|
||||||
|
|
||||||
|
`scene-registry.draft.json` 是 `skill_staging/scenes/` 下的聚合索引草稿。
|
||||||
|
|
||||||
|
它的作用是:
|
||||||
|
- 让 generator / registry 先读取一个总入口
|
||||||
|
- 再按需定位每个 scene 的 `scene.json` 或 `scene.draft.json`
|
||||||
|
- 避免调用方先遍历所有场景目录再自己拼装索引
|
||||||
|
|
||||||
|
当前它仍是 `draft`,含义是:
|
||||||
|
- 可以作为生成器输入基线
|
||||||
|
- 但仍允许人工复核 `pending_review` 中的待确认项
|
||||||
|
|
||||||
|
## 2. 相对路径解析基准
|
||||||
|
|
||||||
|
### 2.1 registry 内部路径的基准
|
||||||
|
|
||||||
|
`scene-registry.draft.json` 中出现的相对路径,**一律相对于该 registry 文件所在目录解析**。
|
||||||
|
|
||||||
|
也就是以这个目录为 base:
|
||||||
|
|
||||||
|
```text
|
||||||
|
skill_staging/scenes/
|
||||||
|
```
|
||||||
|
|
||||||
|
例如:
|
||||||
|
|
||||||
|
- `root = "."` 表示当前目录 `skill_staging/scenes/`
|
||||||
|
- `scene_file = "fault-details-report/scene.json"`
|
||||||
|
- `draft_file = "fault-details-report/scene.draft.json"`
|
||||||
|
|
||||||
|
调用方应按下面的方式理解:
|
||||||
|
|
||||||
|
```text
|
||||||
|
resolve(registry_dir, scene_file)
|
||||||
|
resolve(registry_dir, draft_file)
|
||||||
|
```
|
||||||
|
|
||||||
|
而不是相对于进程当前工作目录解析。
|
||||||
|
|
||||||
|
### 2.2 scene 文件内部路径的基准
|
||||||
|
|
||||||
|
每个 `scene.json` / `scene.draft.json` 内部出现的相对路径,**一律相对于该 scene 文件自身所在目录解析**。
|
||||||
|
|
||||||
|
也就是以:
|
||||||
|
|
||||||
|
```text
|
||||||
|
skill_staging/scenes/<scene-id>/
|
||||||
|
```
|
||||||
|
|
||||||
|
为 base。
|
||||||
|
|
||||||
|
例如在 `fault-details-report/scene.json` 中:
|
||||||
|
|
||||||
|
- `../../skills/fault-details-report`
|
||||||
|
- `../../../大四区报告监测项/故障明细`
|
||||||
|
|
||||||
|
调用方应按下面的方式理解:
|
||||||
|
|
||||||
|
```text
|
||||||
|
resolve(scene_dir, source.skill_path)
|
||||||
|
resolve(scene_dir, source.scenario_path)
|
||||||
|
```
|
||||||
|
|
||||||
|
对于 `scene.draft.json` 的 `inferred_from` 也是同一规则:
|
||||||
|
|
||||||
|
```text
|
||||||
|
resolve(scene_dir, inferred_from[i])
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 推荐读取顺序
|
||||||
|
|
||||||
|
推荐按下面顺序消费:
|
||||||
|
|
||||||
|
1. 读取 `skill_staging/scenes/scene-registry.draft.json`
|
||||||
|
2. 取 `scenes[]` 列表
|
||||||
|
3. 对每个条目优先读取 `scene_file`
|
||||||
|
4. 若需要查看推断依据或待确认项,再读取 `draft_file`
|
||||||
|
5. 若 `pending_review` 非空,不要默认认为所有 scene 都已完全定稿
|
||||||
|
|
||||||
|
## 4. 调用方约束
|
||||||
|
|
||||||
|
调用方应遵守以下约定:
|
||||||
|
|
||||||
|
- 不要把这些相对路径当作绝对路径缓存
|
||||||
|
- 不要依赖当前工作目录来解析路径
|
||||||
|
- 路径解析应使用“配置文件所在目录”作为 base
|
||||||
|
- 若整体目录被搬移,只要相对目录结构不变,这些引用就应继续有效
|
||||||
|
|
||||||
|
## 5. 当前约定的边界
|
||||||
|
|
||||||
|
这份 registry 当前只约定:
|
||||||
|
- scene 聚合入口
|
||||||
|
- scene / draft 文件定位方式
|
||||||
|
- 相对路径解析基准
|
||||||
|
|
||||||
|
这份 registry **还没有**约定:
|
||||||
|
- 热重载机制
|
||||||
|
- 自动注册完成语义
|
||||||
|
- dependency/action 词表最终标准化结果
|
||||||
|
- generator 的最终输入 schema
|
||||||
|
|
||||||
|
## 6. Consumer Example
|
||||||
|
|
||||||
|
下面给一个最小读取示例,说明调用方应如何解析这些相对路径。
|
||||||
|
|
||||||
|
### 6.1 读取 registry 并定位 scene 文件
|
||||||
|
|
||||||
|
```js
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
|
const registryPath = path.resolve(
|
||||||
|
"skill_staging/scenes/scene-registry.draft.json"
|
||||||
|
);
|
||||||
|
const registryDir = path.dirname(registryPath);
|
||||||
|
const registry = JSON.parse(fs.readFileSync(registryPath, "utf8"));
|
||||||
|
|
||||||
|
for (const item of registry.scenes) {
|
||||||
|
const scenePath = path.resolve(registryDir, item.scene_file);
|
||||||
|
const draftPath = path.resolve(registryDir, item.draft_file);
|
||||||
|
|
||||||
|
const scene = JSON.parse(fs.readFileSync(scenePath, "utf8"));
|
||||||
|
|
||||||
|
console.log({
|
||||||
|
id: scene.id,
|
||||||
|
scenePath,
|
||||||
|
draftPath,
|
||||||
|
tool: scene.skill.tool,
|
||||||
|
artifactType: scene.skill.artifact_type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 在 scene 内继续解析 source / inferred_from
|
||||||
|
|
||||||
|
```js
|
||||||
|
const sceneDir = path.dirname(scenePath);
|
||||||
|
|
||||||
|
const skillPath = path.resolve(sceneDir, scene.source.skill_path);
|
||||||
|
const scenarioPath = path.resolve(sceneDir, scene.source.scenario_path);
|
||||||
|
|
||||||
|
const draft = JSON.parse(fs.readFileSync(draftPath, "utf8"));
|
||||||
|
const inferredFiles = draft.inferred_from.map((p) => path.resolve(sceneDir, p));
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 实现要点
|
||||||
|
|
||||||
|
调用方只要遵守两条就不会解析错:
|
||||||
|
|
||||||
|
1. 先用 registry 文件所在目录解析 `scene_file` / `draft_file`
|
||||||
|
2. 再用 scene 文件所在目录解析 `source.*` / `inferred_from[]`
|
||||||
|
|
||||||
|
不要跳过这两层 base,直接拿相对路径拼当前工作目录。
|
||||||
165
skills/skill_staging/scenes/scene-registry.draft.json
Normal file
165
skills/skill_staging/scenes/scene-registry.draft.json
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
{
|
||||||
|
"draft": true,
|
||||||
|
"kind": "scene-registry",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"generated_on": "2026-04-02",
|
||||||
|
"root": ".",
|
||||||
|
"canonical_source": "scene.json",
|
||||||
|
"fallback_source": "scene.draft.json",
|
||||||
|
"generator_hints": {
|
||||||
|
"scene_id_equals_skill_package": true,
|
||||||
|
"prefer_scene_json_over_skill_package_scan": true,
|
||||||
|
"manual_review_required": true,
|
||||||
|
"reload_ready": false
|
||||||
|
},
|
||||||
|
"summary": {
|
||||||
|
"scene_count": 5,
|
||||||
|
"categories": {
|
||||||
|
"report": 3,
|
||||||
|
"monitor": 2
|
||||||
|
},
|
||||||
|
"artifact_types": {
|
||||||
|
"report-artifact": 3,
|
||||||
|
"monitor-snapshot": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scenes": [
|
||||||
|
{
|
||||||
|
"id": "fault-details-report",
|
||||||
|
"name": "故障明细",
|
||||||
|
"category": "report",
|
||||||
|
"scene_file": "fault-details-report/scene.json",
|
||||||
|
"draft_file": "fault-details-report/scene.draft.json",
|
||||||
|
"skill_package": "fault-details-report",
|
||||||
|
"tool": "collect_fault_details",
|
||||||
|
"artifact_type": "report-artifact",
|
||||||
|
"entry": "index.html",
|
||||||
|
"inputs": ["period"],
|
||||||
|
"outputs": ["report-artifact"],
|
||||||
|
"dependencies": ["browser", "report-history", "local-report-service"],
|
||||||
|
"actions": ["query", "collect-report", "build-summary-section"],
|
||||||
|
"status_semantics": {
|
||||||
|
"supports_partial": true,
|
||||||
|
"distinguish_blocked_from_empty": true
|
||||||
|
},
|
||||||
|
"todo_count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "jinchang-business-environment-weekly-report",
|
||||||
|
"name": "国网金昌供电公司营商环境周例会报告",
|
||||||
|
"category": "report",
|
||||||
|
"scene_file": "jinchang-business-environment-weekly-report/scene.json",
|
||||||
|
"draft_file": "jinchang-business-environment-weekly-report/scene.draft.json",
|
||||||
|
"skill_package": "jinchang-business-environment-weekly-report",
|
||||||
|
"tool": "collect_business_environment_metrics",
|
||||||
|
"artifact_type": "report-artifact",
|
||||||
|
"entry": "index.html",
|
||||||
|
"inputs": ["period"],
|
||||||
|
"outputs": ["report-artifact"],
|
||||||
|
"dependencies": ["browser", "multi-source", "local-report-service"],
|
||||||
|
"actions": ["query", "collect-report", "aggregate-sections"],
|
||||||
|
"status_semantics": {
|
||||||
|
"supports_partial": true,
|
||||||
|
"distinguish_blocked_from_empty": true
|
||||||
|
},
|
||||||
|
"todo_count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "95598-weekly-monitor-report",
|
||||||
|
"name": "95598、12398及配网设备监控情况周统计",
|
||||||
|
"category": "report",
|
||||||
|
"scene_file": "95598-weekly-monitor-report/scene.json",
|
||||||
|
"draft_file": "95598-weekly-monitor-report/scene.draft.json",
|
||||||
|
"skill_package": "95598-weekly-monitor-report",
|
||||||
|
"tool": "collect_weekly_metrics",
|
||||||
|
"artifact_type": "report-artifact",
|
||||||
|
"entry": "index.html",
|
||||||
|
"inputs": ["period"],
|
||||||
|
"outputs": ["report-artifact"],
|
||||||
|
"dependencies": ["browser", "multi-source", "period-alignment", "local-report-service"],
|
||||||
|
"actions": ["query", "collect-report", "aggregate-sections", "align-periods"],
|
||||||
|
"status_semantics": {
|
||||||
|
"supports_partial": true,
|
||||||
|
"distinguish_blocked_from_empty": true
|
||||||
|
},
|
||||||
|
"todo_count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "95598-repair-city-dispatch",
|
||||||
|
"name": "95598抢修-市指",
|
||||||
|
"category": "monitor",
|
||||||
|
"scene_file": "95598-repair-city-dispatch/scene.json",
|
||||||
|
"draft_file": "95598-repair-city-dispatch/scene.draft.json",
|
||||||
|
"skill_package": "95598-repair-city-dispatch",
|
||||||
|
"tool": "collect_repair_orders",
|
||||||
|
"artifact_type": "monitor-snapshot",
|
||||||
|
"entry": "index.html",
|
||||||
|
"inputs": ["time"],
|
||||||
|
"outputs": ["monitor-snapshot"],
|
||||||
|
"dependencies": ["browser", "local-service", "repair-order-source", "history-log", "status-classification"],
|
||||||
|
"actions": ["monitor-queue", "classify-status", "compare-history", "write-local-log", "trigger-alert"],
|
||||||
|
"status_semantics": {
|
||||||
|
"supports_partial": true,
|
||||||
|
"distinguish_blocked_from_empty": true
|
||||||
|
},
|
||||||
|
"todo_count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "jiayuguan-meter-outage",
|
||||||
|
"name": "户表失电-嘉峪关",
|
||||||
|
"category": "monitor",
|
||||||
|
"scene_file": "jiayuguan-meter-outage/scene.json",
|
||||||
|
"draft_file": "jiayuguan-meter-outage/scene.draft.json",
|
||||||
|
"skill_package": "jiayuguan-meter-outage",
|
||||||
|
"tool": "collect_outage_events",
|
||||||
|
"artifact_type": "monitor-snapshot",
|
||||||
|
"entry": "index.html",
|
||||||
|
"inputs": ["time"],
|
||||||
|
"outputs": ["monitor-snapshot"],
|
||||||
|
"dependencies": ["browser", "local-service", "outage-source", "service-order-source", "history-log"],
|
||||||
|
"actions": ["collect-outage-events", "enrich-service-orders", "compare-history", "write-local-log", "trigger-alert"],
|
||||||
|
"status_semantics": {
|
||||||
|
"supports_partial": true,
|
||||||
|
"distinguish_blocked_from_empty": true
|
||||||
|
},
|
||||||
|
"todo_count": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pending_review": [
|
||||||
|
{
|
||||||
|
"id": "fault-details-report",
|
||||||
|
"todo": [
|
||||||
|
"确认 period 在 generator 层是否保留为单字段,还是拆分为 startTime/endTime。",
|
||||||
|
"确认 local-report-service 是否需要统一归一到 local-service 词表。"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "jinchang-business-environment-weekly-report",
|
||||||
|
"todo": [
|
||||||
|
"确认 multi-source 是否要进一步细分为 source-session-cache 或 token-cache。",
|
||||||
|
"确认 dispatch-summary 等 section 名是否需要进入 scene 级 metadata。"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "95598-weekly-monitor-report",
|
||||||
|
"todo": [
|
||||||
|
"确认 scene.json 是否应把 period 拆成 currentPeriod 与 cumulativePeriod 两个正式输入。",
|
||||||
|
"确认 period-alignment 是否作为独立 dependency 保留,还是仅作为 action 语义。"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "95598-repair-city-dispatch",
|
||||||
|
"todo": [
|
||||||
|
"确认 trigger-alert 是否应拆分成 audio-alert、message-alert、callout 三类动作。",
|
||||||
|
"确认 configServices 是否需要在正式 dependencies 中单独暴露。"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "jiayuguan-meter-outage",
|
||||||
|
"todo": [
|
||||||
|
"确认 marketing token context 是否需要作为正式 dependency 单独暴露。",
|
||||||
|
"确认 trigger-alert 是否应与 auto-processing 拆成两个独立动作。"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
---
|
||||||
|
name: 95598-repair-city-dispatch
|
||||||
|
description: Use when the user wants to maintain city-dispatch repair-team configuration or monitor 95598 repair work orders, pending queues, and downstream alert states.
|
||||||
|
version: 0.1.0
|
||||||
|
author: sgclaw
|
||||||
|
tags:
|
||||||
|
- 95598
|
||||||
|
- repair
|
||||||
|
- dispatch
|
||||||
|
- monitoring
|
||||||
|
- config
|
||||||
|
---
|
||||||
|
|
||||||
|
# 95598 Repair City Dispatch
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
- The user asks to maintain 95598 city-dispatch team or class-list configuration.
|
||||||
|
- The user asks to monitor 95598 repair work orders and classify pending, audit, and processed states.
|
||||||
|
- The task needs a monitor snapshot derived from the current repair-order queue and local comparison logs.
|
||||||
|
- The task needs to detect new pending orders before downstream audio, message, or call-out actions.
|
||||||
|
|
||||||
|
Do not use this skill for:
|
||||||
|
|
||||||
|
- unrelated report generation
|
||||||
|
- arbitrary browser probing without the packaged collector
|
||||||
|
- claiming auto-dispatch or alert success without a fresh queue snapshot
|
||||||
|
- hiding BrowserAction, localhost service, or alert failures behind empty results
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Open or attach to the city-dispatch configuration page.
|
||||||
|
2. Read scheduled workflow rule scripts from desk source-of-truth (`D:/desk/智能体资料/大四区报告监测项/95598抢修-市指_业务检测配置.txt`, `D:/desk/智能体资料/大四区报告监测项/95598抢修-市指_自动处理配置.txt`) to understand queue, class-match, and auto-dispatch semantics.
|
||||||
|
3. Collect repair orders from the upstream queue for status codes `00`, `01`, `06`, and `08`.
|
||||||
|
4. Normalize the queue into `pending`, `audit`, and `processed` counters and derive `pending_ids` / `new_pending_ids`.
|
||||||
|
5. Return the monitor snapshot before downstream audio, message, call-out, or dispose-log side effects.
|
||||||
|
6. If local persistence, comparison, or alert-side effects fail after queue collection, keep the snapshot and mark the result as `partial`.
|
||||||
|
|
||||||
|
## Runtime Contract
|
||||||
|
|
||||||
|
- Treat configuration maintenance and queue monitoring as related but distinct operations.
|
||||||
|
- Prefer the packaged collector before generic browser probing or manual queue inspection.
|
||||||
|
- The scene page `assets/scene-snapshot/index.html` is configuration-only; treat it as class-list/config context, not workflow execution proof.
|
||||||
|
- Treat `getMonitorLog` / `getDisposeLog` as comparison context, not the upstream source of truth.
|
||||||
|
- BrowserAction execution, platform session context, and localhost `MonitorServices` dependencies are part of runtime truth and must be surfaced explicitly.
|
||||||
|
- Auto-dispatch, SMS, and voice-remind outcomes are downstream effects; they do not redefine whether queue collection succeeded.
|
||||||
|
|
||||||
|
## Partial-Failure Rule
|
||||||
|
|
||||||
|
- If queue collection succeeds but local monitor-log read/write, audio-log write, message-log write, or dispose-log write fails, report `partial`.
|
||||||
|
- Local monitor/dispose comparison context unavailable for pending-id diffing (`monitor_log_unavailable` / `dispose_log_unavailable`) while queue data exists, report `partial`.
|
||||||
|
- If auto-dispatch or reminder side effects fail after snapshot construction, keep the snapshot and report `partial`.
|
||||||
|
- Never report `no orders` when login, interception, request failure, or parse failure blocked the collection request.
|
||||||
|
|
||||||
|
## Export Artifact
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "monitor-snapshot",
|
||||||
|
"scene": "95598-repair-city-dispatch",
|
||||||
|
"time": "",
|
||||||
|
"pending": 0,
|
||||||
|
"audit": 0,
|
||||||
|
"processed": 0,
|
||||||
|
"pending_ids": [],
|
||||||
|
"new_pending_ids": [],
|
||||||
|
"status": "success",
|
||||||
|
"partial_reasons": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
Return:
|
||||||
|
|
||||||
|
- operation type
|
||||||
|
- scope or queue window
|
||||||
|
- pending, audit, processed counts
|
||||||
|
- pending ids and new pending ids
|
||||||
|
- complete or partial status
|
||||||
|
- missing class-match, log, audio, message, or dispose areas
|
||||||
|
- Export Artifact
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[skill]
|
||||||
|
name = "95598-repair-city-dispatch"
|
||||||
|
description = "Use when the user wants to maintain city-dispatch repair-team configuration or monitor 95598 repair work orders through desk rule-script workflow semantics with normalized monitor snapshots."
|
||||||
|
version = "0.1.0"
|
||||||
|
author = "sgclaw"
|
||||||
|
tags = ["95598", "repair", "dispatch", "monitoring", "config"]
|
||||||
|
|
||||||
|
prompts = [
|
||||||
|
"For 95598 repair monitoring, call 95598-repair-city-dispatch.collect_repair_orders first and treat desk rule scripts as workflow source-of-truth while `assets/scene-snapshot/index.html` remains config-only.",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[tools]]
|
||||||
|
name = "collect_repair_orders"
|
||||||
|
description = "Collect repair-order queue states and prepare the monitor snapshot shell from the browser-visible business page."
|
||||||
|
kind = "browser_script"
|
||||||
|
command = "scripts/collect_repair_orders.js"
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
let callbackName = "callBack_Repair_Taskli";
|
||||||
|
let list = []; //待处理数据列表
|
||||||
|
let shlist = []; //待审核数据列表
|
||||||
|
let ycjList = []; //已处理数据列表
|
||||||
|
let idList = [];
|
||||||
|
window[callbackName] = function (targeturl, actionurl, responseTxt) {
|
||||||
|
try {
|
||||||
|
const res = JSON.parse(
|
||||||
|
responseTxt
|
||||||
|
.replace(/%7B/g, "{")
|
||||||
|
.replace(/%27/g, "'")
|
||||||
|
.replace(/%7D/g, "}")
|
||||||
|
.replace(/'/g, '"')
|
||||||
|
.replace("}/", "}")
|
||||||
|
);
|
||||||
|
console.log(res);
|
||||||
|
if (res.msg == "success") {
|
||||||
|
if (res.page.list.length > 0) {
|
||||||
|
res.page.list.forEach((item) => {
|
||||||
|
if (item.status == "00" && item.status == "01") {
|
||||||
|
list.push(item);
|
||||||
|
list.forEach((x) => {
|
||||||
|
idList.push(x.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 06为待审核数据
|
||||||
|
if (item.status == "06") {
|
||||||
|
shlist.push(item);
|
||||||
|
}
|
||||||
|
// 08为已处理数据
|
||||||
|
if (item.status == "08") {
|
||||||
|
ycjList.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
let audioText = "";
|
||||||
|
audioFC(audioText);
|
||||||
|
}
|
||||||
|
let obj = {
|
||||||
|
time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), //监测时间
|
||||||
|
type: "95598抢修-市指", //监测工单类型
|
||||||
|
pending: list.length, //待处理数字
|
||||||
|
pendingList: JSON.stringify(idList), //待处理列表
|
||||||
|
audit: shlist.length, //待审核
|
||||||
|
processed: ycjList.length, //已处理
|
||||||
|
};
|
||||||
|
|
||||||
|
mac
|
||||||
|
.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/getMonitorLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: "95598抢修-市指" }), //必须是字符串格式
|
||||||
|
})
|
||||||
|
.then((res2) => {
|
||||||
|
if (res2.status == 200) {
|
||||||
|
let index = 0;
|
||||||
|
if (
|
||||||
|
res2.data.length < 1 &&
|
||||||
|
list.length > 0 &&
|
||||||
|
_this.queueObj.voiceRemind == "1"
|
||||||
|
) {
|
||||||
|
let audioText = "您有95598抢修工单,请及时处理";
|
||||||
|
audioFC(audioText);
|
||||||
|
}
|
||||||
|
if (res2.data.length > 0) {
|
||||||
|
let logList = JSON.parse(res2.data[0].pendingList);
|
||||||
|
if (!Array.isArray(logList)) {
|
||||||
|
logList = JSON.parse(logList);
|
||||||
|
}
|
||||||
|
idList.forEach((x) => {
|
||||||
|
index = logList.indexOf(x);
|
||||||
|
if (index == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (index == -1 && _this.queueObj.voiceRemind == "1") {
|
||||||
|
let audioText = "您有95598抢修工单,请及时处理";
|
||||||
|
audioFC(audioText);
|
||||||
|
}
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setMonitorData",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify(obj),
|
||||||
|
});
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setMonitorLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify(obj),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//执行 下一队列方法
|
||||||
|
_this.processQueue();
|
||||||
|
};
|
||||||
|
let time = `${mac.moment().format("YYYY-MM-DD")}+00:00:00,${mac
|
||||||
|
.moment()
|
||||||
|
.format("YYYY-MM-DD")}+23:59:59`;
|
||||||
|
const requestParam = `page=1&type=0101&statusName=00,01,06,08&orgNo=${_this.orgID}&slsj=${time}&limit=100`;
|
||||||
|
BrowserAction("sgBrowerserJsAjax2",
|
||||||
|
"window." + callbackName,
|
||||||
|
"http://21.77.244.194:18890/mainSystem/#/login",
|
||||||
|
`http://21.77.244.194:18890/qxgl/repairOrder/list?` + requestParam,
|
||||||
|
"POST",
|
||||||
|
`Content-Type:application/json;userId:${_this.userID};Access-Control-Allow-Credentials:true;Access-Control-Allow-Methods: GET, POST, OPTIONS,PUT,DELETE,OPTION;Access-Control-Allow-Origin:*`,
|
||||||
|
""
|
||||||
|
);
|
||||||
|
function audioFC(text) {
|
||||||
|
mac
|
||||||
|
.audioPlay(text)
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status == 200) {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({
|
||||||
|
type: text,
|
||||||
|
time: mac.moment().format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
status: "成功",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({
|
||||||
|
type: text,
|
||||||
|
time: mac.moment().format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
status: "失败",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({
|
||||||
|
type: text,
|
||||||
|
time: mac.moment().format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
status: "异常",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,350 @@
|
|||||||
|
var QXGDSZ = []; //95598抢修-市指工单去重
|
||||||
|
var QXGDSZList = [];
|
||||||
|
var qxszClassList = [];
|
||||||
|
|
||||||
|
var eventId = null; //派单日志参数
|
||||||
|
var eqPsrName = null; //派单日志参数
|
||||||
|
var phone = "";
|
||||||
|
var tel = [];
|
||||||
|
let objData = {
|
||||||
|
time: mac.moment().format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
type: "95598抢修-市指",
|
||||||
|
pending: 0,
|
||||||
|
pendingList: "进入自动派单",
|
||||||
|
audit: 0,
|
||||||
|
processed: 0
|
||||||
|
};
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setMonitorLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify(objData)
|
||||||
|
});
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/getDisposeLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: "95598抢修-市指" }), //必须是字符串格式
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status == 200) {
|
||||||
|
// 抢修工单
|
||||||
|
let arr = res.data.reverse();
|
||||||
|
obj.pendingList
|
||||||
|
.filter((x) => arr.findIndex((y) => y.orderID == x.id) == -1)
|
||||||
|
.forEach((item) => {
|
||||||
|
QXGDSZList.push(item);
|
||||||
|
});
|
||||||
|
if (QXGDSZList.length > 0) {
|
||||||
|
objData.pendingList = '未派过单-进入自动派单'
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setMonitorLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify(objData)
|
||||||
|
});
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/getClassList",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: "95598抢修" }),
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status == 200) {
|
||||||
|
res.data = res.data.filter(item => item.type != '95598抢修')
|
||||||
|
if (res.data.length == !0) {
|
||||||
|
res.data.forEach((item) => {
|
||||||
|
let arr = [];
|
||||||
|
if (item.scope != "") {
|
||||||
|
|
||||||
|
item.scope = item.scope.replace(/\s*/g, "");
|
||||||
|
arr.push(item.scope.split("、"));
|
||||||
|
item.scope = [].concat.apply([], arr);
|
||||||
|
} else {
|
||||||
|
item.scope = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
qxszClassList = res.data;
|
||||||
|
let callbackName = "callBacks_95598qiangxiusz";
|
||||||
|
window[callbackName] = function (
|
||||||
|
targeturl,
|
||||||
|
actionurl,
|
||||||
|
responseTxt
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const resData = JSON.parse(
|
||||||
|
decodeURI(responseTxt).replace(/'/g, '"').replace("}/", "}")
|
||||||
|
);
|
||||||
|
if (resData.code == 0) {
|
||||||
|
setTimeout(() => {
|
||||||
|
mac.audioPlay("95598抢修-市指工单自动派单成功").then(response => {
|
||||||
|
if (response.status == 200) {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单成功', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "成功" })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单成功', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "失败" })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单成功', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "异常" })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}, 6000);
|
||||||
|
let type = "95598抢修-市指";
|
||||||
|
let orderID = eventId;
|
||||||
|
let time = mac.moment().format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
let name = eqPsrName;
|
||||||
|
let state = "成功";
|
||||||
|
// i国网
|
||||||
|
const request = {
|
||||||
|
phoneList: [].concat.apply([], tel),
|
||||||
|
content: "【业数融合一平台】您有95598抢修-市指工单,请及时处理!", //短信内容
|
||||||
|
};
|
||||||
|
if (request.phoneList.length > 0) {
|
||||||
|
mac.sendMessages(request).then(res4 => {
|
||||||
|
if (res4.status == 200) {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setSendMessageLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "成功" })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setSendMessageLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "失败" })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setSendMessageLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "异常" })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 呼叫接口
|
||||||
|
setTimeout(() => {
|
||||||
|
const params = {
|
||||||
|
taskName: "95598抢修-市指",
|
||||||
|
phone: [].concat.apply([], tel),
|
||||||
|
content: "您有95598抢修-市指工单,请尽快接单处理",
|
||||||
|
name: "95598抢修-市指",
|
||||||
|
};
|
||||||
|
if (params.phone.length > 0) {
|
||||||
|
mac.callOutLogin(params);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setDisposeLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({
|
||||||
|
type,
|
||||||
|
orderID,
|
||||||
|
name,
|
||||||
|
time,
|
||||||
|
state,
|
||||||
|
}), //必须是字符串格式
|
||||||
|
}).then(re => {
|
||||||
|
if (re.status == 200) {
|
||||||
|
mac.exeTQueue();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
mac.audioPlay("95598抢修-市指工单自动派单失败,请及时处理!").then(response => {
|
||||||
|
if (response.status == 200) {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单失败', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "成功" })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单失败', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "失败" })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单失败', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "异常" })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}, 6000);
|
||||||
|
let type = "95598抢修-市指";
|
||||||
|
let orderID = eventId;
|
||||||
|
let time = mac.moment().format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
let name = eqPsrName;
|
||||||
|
let state = "失败";
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setDisposeLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({
|
||||||
|
type,
|
||||||
|
orderID,
|
||||||
|
name,
|
||||||
|
time,
|
||||||
|
state,
|
||||||
|
}), //必须是字符串格式
|
||||||
|
}).then(re => {
|
||||||
|
if (re.status == 200) {
|
||||||
|
mac.exeTQueue();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (x) {
|
||||||
|
setTimeout(() => {
|
||||||
|
mac.audioPlay("95598抢修-市指工单自动派单异常,请及时处理!").then(response => {
|
||||||
|
if (response.status == 200) {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单异常', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "成功" })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单异常', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "失败" })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单异常', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "异常" })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}, 6000);
|
||||||
|
let type = "95598抢修-市指";
|
||||||
|
let orderID = eventId;
|
||||||
|
let time = mac.moment().format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
let name = eqPsrName;
|
||||||
|
let state = "异常";
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setDisposeLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type, orderID, name, time, state }), //必须是字符串格式
|
||||||
|
}).then(re => {
|
||||||
|
if (re.status == 200) {
|
||||||
|
mac.exeTQueue();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (QXGDSZList.length > 0) {
|
||||||
|
let ppstatus = false;
|
||||||
|
eventId = QXGDSZList[0].id;
|
||||||
|
eqPsrName = QXGDSZList[0].gzdd;
|
||||||
|
// 区县级派单参数
|
||||||
|
var requestParam = {
|
||||||
|
processBusinessKey: QXGDSZList[0].id,
|
||||||
|
starter: "",
|
||||||
|
variables: {
|
||||||
|
cldw: QXGDSZList[0].cityCode, //处理单位
|
||||||
|
cldwmc: QXGDSZList[0].cityName, //处理单位名称
|
||||||
|
qxbz: "", //班组id
|
||||||
|
qxdy: "", //抢修队员
|
||||||
|
qxfzr: "", //抢修负责人编号
|
||||||
|
qxfzrName: "", //抢修负责人名称
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let a = []
|
||||||
|
qxszClassList.forEach((item) => {
|
||||||
|
item.scope.forEach((x) => {
|
||||||
|
if (QXGDSZList[0].gzdd.indexOf(x) !== -1) {
|
||||||
|
requestParam.variables.qxbz = item.orgId;
|
||||||
|
requestParam.starter = item.pCode;
|
||||||
|
requestParam.variables.qxfzr = item.pCode;
|
||||||
|
requestParam.variables.qxfzrName = item.pName;
|
||||||
|
if (item.wName !== null) {
|
||||||
|
// phone = item.wName.replace(/、/g, ",");
|
||||||
|
a.push(item.wName.split("、"));
|
||||||
|
} else {
|
||||||
|
// phone = "";
|
||||||
|
tel = [];
|
||||||
|
}
|
||||||
|
ppstatus = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
tel = Array.from(new Set(a))
|
||||||
|
if (ppstatus) {
|
||||||
|
objData.pendingList = '进入自动派单-匹配成功'
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setMonitorLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify(objData)
|
||||||
|
});
|
||||||
|
sgBrowerserJsAjax2(
|
||||||
|
"window." + callbackName,
|
||||||
|
// "http://21.77.244.194:18890/#/sczhEgis",
|
||||||
|
"http://21.77.244.194:18890/#/webview/1543953229739896",
|
||||||
|
`http://21.77.244.194:18890/qxgl/repairOrder/initProcess?lockBussinessId=${QXGDSZList[0].id}`,
|
||||||
|
"POST",
|
||||||
|
`Content-Type:application/json;userId:${_this.userID};Access-Control-Allow-Credentials:true;Access-Control-Allow-Methods: GET, POST, OPTIONS,PUT,DELETE,OPTION;Access-Control-Allow-Origin:*`,
|
||||||
|
JSON.stringify(requestParam)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
objData.pendingList = '进入自动派单-未匹配'
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setMonitorLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify(objData),
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
mac.audioPlay("95598抢修-市指工单自动派单未匹配到班组,请尽快手动处理!").then(response => {
|
||||||
|
if (response.status == 200) {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单未匹配', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "成功" })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单未匹配', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "失败" })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: '95598抢修-市指自动派单未匹配', time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "异常" })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}, 6000);
|
||||||
|
let type = "95598抢修-市指";
|
||||||
|
let orderID = eventId;
|
||||||
|
let time = mac.moment().format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
let name = eqPsrName;
|
||||||
|
let state = "未匹配";
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setDisposeLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type, orderID, name, time, state }), //必须是字符串格式
|
||||||
|
}).then(re => {
|
||||||
|
if (re.status == 200) {
|
||||||
|
mac.exeTQueue();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
mac.exeTQueue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,355 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<link rel="shortcut icon" href="./images/95598/logo.gif" type="image/x-icon" />
|
||||||
|
<link rel="stylesheet" href="./css/elementui.css" />
|
||||||
|
<link rel="stylesheet" href="./css/szhfn.css" />
|
||||||
|
<title>接单班组信息</title>
|
||||||
|
<script src="http://25.215.213.182:8080/a_js/axios.js"></script>
|
||||||
|
|
||||||
|
<script src="./js/jquery.js"></script>
|
||||||
|
<script src="./js/vue.js"></script>
|
||||||
|
<script src="./js/elementui.js"></script>
|
||||||
|
<script src="./js/moment.js"></script>
|
||||||
|
<script src="./js/dpage.min.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<el-table :data="allclassList" border height="945px">
|
||||||
|
<el-table-column label="接单单位名称" align="center" property="cName"></el-table-column>
|
||||||
|
<el-table-column label="当前接单单位管辖的所有地址名称" align="center" property="scope" width="240"> </el-table-column>
|
||||||
|
<el-table-column label="接单人姓名" align="center" property="pName"></el-table-column>
|
||||||
|
<el-table-column label="接单人工号" align="center" property="pCode"></el-table-column>
|
||||||
|
<el-table-column label="接单人手机号" align="center" property="wName"></el-table-column>
|
||||||
|
<el-table-column property="state" label="操作" width="160" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="primary" @click="viewBtnFC(scope.row)">查看</el-button>
|
||||||
|
<el-button size="mini" type="warning" @click="editBtnFC(scope.row)">修改</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 修改 -->
|
||||||
|
<el-dialog :visible.sync="editStatus" title="修改" :append-to-body="true" :before-close="edithandleClose">
|
||||||
|
<el-form :model="editClassForm" ref="editClassForm" label-width="110px">
|
||||||
|
<el-form-item label="接单单位名称" prop="cName">
|
||||||
|
<el-input v-model="editClassForm.cName" placeholder="请输入接单单位名称" disabled></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="editlabelText" prop="scope">
|
||||||
|
<el-input v-model="editClassForm.scope" :placeholder="'请输入当前接单单位管辖的所有'+editlabelText +',如果有多个请用、隔开(例:xx、xxx)'"
|
||||||
|
type="textarea"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="接单人姓名" prop="pName">
|
||||||
|
<el-input v-model="editClassForm.pName" placeholder="请输入接单人姓名"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="接单人账号" prop="pCode">
|
||||||
|
<el-input v-model="editClassForm.pCode" placeholder="请输入接单人账号"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="接单人手机号" prop="wName">
|
||||||
|
<el-input v-model="editClassForm.wName" placeholder="请输入接单人手机号"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="editClassFC()" size="small" style="background: #018c87; color: #fff">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
<!-- 查看 -->
|
||||||
|
<el-dialog :visible.sync="viewStatus" title="查看" :append-to-body="true" :before-close="viewhandleClose">
|
||||||
|
<el-form :model="editClassForm" ref="editClassForm" label-width="110px">
|
||||||
|
<el-form-item label="接单单位名称" prop="cName">
|
||||||
|
<el-input v-model="editClassForm.cName" placeholder="请输入接单单位名称" disabled></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="editlabelText" prop="scope">
|
||||||
|
<el-input v-model="editClassForm.scope" :placeholder="'请输入当前接单单位管辖的所有'+editlabelText +',如果有多个请用、隔开(例:xx、xxx)'"
|
||||||
|
disabled type="textarea"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="接单人姓名" prop="pName">
|
||||||
|
<el-input v-model="editClassForm.pName" placeholder="请输入接单人姓名" disabled></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="接单人账号" prop="pCode">
|
||||||
|
<el-input v-model="editClassForm.pCode" placeholder="请输入接单人账号" disabled></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="接单人手机号" prop="wName">
|
||||||
|
<el-input v-model="editClassForm.wName" placeholder="请输入接单人手机号" disabled></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
var mac = new Vue({
|
||||||
|
el: "#app",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 修改接单班组
|
||||||
|
editClassForm: {
|
||||||
|
orgId: "",
|
||||||
|
cName: "",
|
||||||
|
scope: "",
|
||||||
|
pName: "",
|
||||||
|
pCode: "",
|
||||||
|
type: "",
|
||||||
|
wName: "",
|
||||||
|
},
|
||||||
|
ids: '',
|
||||||
|
classList: [],
|
||||||
|
allclassList: [],
|
||||||
|
disabled: true,
|
||||||
|
editStatus: false,
|
||||||
|
viewStatus: false,
|
||||||
|
labelText: "",
|
||||||
|
editlabelText: "",
|
||||||
|
placeholder: "",
|
||||||
|
formInfo: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
sgBrowserExcuteJsCode(
|
||||||
|
"http://25.215.213.182:8080/#/monitorQueue",
|
||||||
|
`sgBrowserExcuteJsCode("${location.href}",\`mac.setStorage('\${localStorage.tGfUser}')\`);`
|
||||||
|
);
|
||||||
|
// this.getClassList("95598抢修")
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setStorage(obj) {
|
||||||
|
sessionStorage.setItem("tGfUser", obj);
|
||||||
|
const tGfUser = JSON.parse(sessionStorage.getItem("tGfUser"));
|
||||||
|
mac.formInfo = {
|
||||||
|
cityCode: tGfUser.orgNo, //机构码
|
||||||
|
cityName: tGfUser.orgName, //机构名称 比如 国网嘉峪关供电公司
|
||||||
|
userNameIV: tGfUser.name, //大四区登录的人名
|
||||||
|
userCodeIV: tGfUser.id, //大四区登录账号
|
||||||
|
};
|
||||||
|
mac.zdpdFc({ name: "95598抢修" });
|
||||||
|
},
|
||||||
|
// 自动派单配置图标点击弹出配置弹出框
|
||||||
|
zdpdFc(x) {
|
||||||
|
// 区县级表头名称
|
||||||
|
if (x.name == "95598抢修") {
|
||||||
|
this.labelText = "当前接单单位管辖的所有地址名称";
|
||||||
|
this.editlabelText = "地址名称";
|
||||||
|
this.placeholder = "请输入地址名称";
|
||||||
|
} else {
|
||||||
|
this.labelText = "当前接单单位管辖的所有配变名称";
|
||||||
|
this.editlabelText = "配变名称";
|
||||||
|
this.placeholder = "请输入配变名称";
|
||||||
|
}
|
||||||
|
this.editClassForm.type = x.name;
|
||||||
|
this.getUrl(x.name);
|
||||||
|
},
|
||||||
|
// 抓取浏览器地址
|
||||||
|
getUrl() {
|
||||||
|
window.getAllUrlCallBack = (urls) => {
|
||||||
|
var urlArr = urls.split(";");
|
||||||
|
console.log(urlArr);
|
||||||
|
let hasPage = false;
|
||||||
|
let hasPage1 = false;
|
||||||
|
let home = null;
|
||||||
|
urlArr.forEach((item) => {
|
||||||
|
if (item.indexOf("http://21.77.244.194:18890/") !== -1) {
|
||||||
|
hasPage = true;
|
||||||
|
home = item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (hasPage) {
|
||||||
|
mac.gethngdsList("95598抢修", home);
|
||||||
|
} else {
|
||||||
|
console.log("大四区未登录");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
dpage.dPageGetUrl(true, "window.getAllUrlCallBack");
|
||||||
|
},
|
||||||
|
// 获取大IV中班组信息
|
||||||
|
gethngdsList(name, home) {
|
||||||
|
window.callBackMethodYX = function (
|
||||||
|
targeturl,
|
||||||
|
actionurl,
|
||||||
|
responseTxt
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const resData = JSON.parse(
|
||||||
|
decodeURI(responseTxt).replace(/'/g, '"').replace("}/", "}")
|
||||||
|
);
|
||||||
|
console.log(resData);
|
||||||
|
if (resData.code == 0) {
|
||||||
|
mac.classList = [];
|
||||||
|
resData.orgs.forEach((item) => {
|
||||||
|
mac.classList.push({
|
||||||
|
orgId: item.orgId,
|
||||||
|
type: "",
|
||||||
|
cName: item.orgName,
|
||||||
|
scope: "",
|
||||||
|
pName: "",
|
||||||
|
pCode: "",
|
||||||
|
wName: "",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
mac.getClassList(name);
|
||||||
|
mac.$message({
|
||||||
|
message: "接单班组信息获取成功!",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
mac.$message({
|
||||||
|
message: "接单班组信息获取失败!",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (x) {
|
||||||
|
mac.$message({
|
||||||
|
message: "接单班组信息获取异常!",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const param = {
|
||||||
|
callbackfun: "window.callBackMethodYX",
|
||||||
|
urlpage: home,
|
||||||
|
ajaxurl:
|
||||||
|
"http://21.77.244.194:18890/system/organization/queryOrgBylevel/" + mac.formInfo.cityCode + "/bz",
|
||||||
|
requestType: "POST",
|
||||||
|
requestheder: `Content-Type:application/json;userId:${mac.formInfo.userCodeIV};Access-Control-Allow-Credentials:true;Access-Control-Allow-Methods: GET, POST, OPTIONS,PUT,DELETE,OPTION;Access-Control-Allow-Origin:*`,
|
||||||
|
requestParam: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
dpage.dPageAjax2(param);
|
||||||
|
},
|
||||||
|
generateUUID() {
|
||||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||||
|
const r = Math.random() * 16 | 0;
|
||||||
|
const v = c === 'x' ? r : (r & 0x3 | 0x8); // 保证符合 UUID v4 标准
|
||||||
|
return v.toString(16);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setDate() {
|
||||||
|
const params = {
|
||||||
|
sqlStr: `insert into qxClasslist (id,cName,orgId,pCode,pName,scope,type,wName) values ("${this.generateUUID()}","应急管控班","008df5db70319f73e0508eoac3a61127","","","","95598抢修-市指","")`
|
||||||
|
}
|
||||||
|
axios.post("http://localhost:13313/configServices/exeSql", JSON.stringify(params), {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
console.log(res)
|
||||||
|
}
|
||||||
|
).catch(err => { }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
// 查询接单班组
|
||||||
|
getClassList(name) {
|
||||||
|
$.ajax({
|
||||||
|
url: "http://localhost:13313/MonitorServices/getClassList",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
crossDomain: true,
|
||||||
|
data: JSON.stringify({ type: name }),
|
||||||
|
contentType: "application/json", //指定中容格式
|
||||||
|
success: (res) => {
|
||||||
|
//括号里的data是服务器返回的数据
|
||||||
|
if (res.status == 200) {
|
||||||
|
if (res.data.length > 0) {
|
||||||
|
res.data.forEach((item) => {
|
||||||
|
item.status = false; //按钮状态
|
||||||
|
});
|
||||||
|
res.data = res.data.filter(item => item.type != '95598抢修')
|
||||||
|
if (res.data.length == 0) {
|
||||||
|
mac.setDate()
|
||||||
|
setTimeout(() => {
|
||||||
|
this.getClassList(name);
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.ids = res.data[0].id
|
||||||
|
mac.allclassList = res.data;
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let arrList = [];
|
||||||
|
mac.classList.forEach((item) => {
|
||||||
|
if (!arrList.some((e) => e.orgId == item.orgId)) {
|
||||||
|
arrList.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
arrList.forEach((x) => {
|
||||||
|
x.type = name;
|
||||||
|
mac.setClassList(x);
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
this.getClassList(name);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 存储接单班组
|
||||||
|
setClassList(val) {
|
||||||
|
$.ajax({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setClassList",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
crossDomain: true,
|
||||||
|
data: JSON.stringify(val), //必须是字符串格式
|
||||||
|
contentType: "application/json",
|
||||||
|
success: (res) => { },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 修改
|
||||||
|
editBtnFC(e) {
|
||||||
|
this.editStatus = true;
|
||||||
|
this.editClassForm = JSON.parse(JSON.stringify(e));
|
||||||
|
},
|
||||||
|
// 查看
|
||||||
|
viewBtnFC(e) {
|
||||||
|
this.viewStatus = true;
|
||||||
|
this.editClassForm = JSON.parse(JSON.stringify(e));
|
||||||
|
},
|
||||||
|
edithandleClose() {
|
||||||
|
this.editStatus = false;
|
||||||
|
},
|
||||||
|
viewhandleClose() {
|
||||||
|
this.viewStatus = false;
|
||||||
|
},
|
||||||
|
editClassForm: {
|
||||||
|
orgId: "",
|
||||||
|
cName: "",
|
||||||
|
scope: "",
|
||||||
|
pName: "",
|
||||||
|
pCode: "",
|
||||||
|
type: "",
|
||||||
|
wName: "",
|
||||||
|
},
|
||||||
|
updateClass() {
|
||||||
|
const { orgId, cName, scope, pName, pCode, type, wName } = this.editClassForm
|
||||||
|
const params = {
|
||||||
|
sqlStr: `update qxClasslist set orgId='${orgId}',cName='${cName}',scope='${scope}',pName='${pName}',pCode='${pCode}',type='${type}',wName='${wName}' where id = '${this.ids}'`
|
||||||
|
}
|
||||||
|
axios.post("http://localhost:13313/configServices/exeSql", JSON.stringify(params), {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
if (res.status == 200) {
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "修改成功!",
|
||||||
|
});
|
||||||
|
this.editStatus = false;
|
||||||
|
mac.getClassList("95598抢修");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).catch(err => { }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
// 修改后保存按钮
|
||||||
|
editClassFC() {
|
||||||
|
this.updateClass()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# Collection Flow
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
- Source page: `D:\desk\智能体资料\大四区报告监测项\95598抢修-市指\index.html`
|
||||||
|
- Rule assets (scheduled workflow source-of-truth):
|
||||||
|
- `D:/desk/智能体资料/大四区报告监测项/95598抢修-市指_业务检测配置.txt`
|
||||||
|
- `D:/desk/智能体资料/大四区报告监测项/95598抢修-市指_自动处理配置.txt`
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
The page itself is configuration-oriented (`assets/scene-snapshot/index.html` is configuration-only). The monitoring package combines page-visible class-list context with scheduled queue-monitor and auto-dispatch semantics from the desk rule source-of-truth scripts.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- Current platform session and user context
|
||||||
|
- Current city/org context copied from the platform page
|
||||||
|
- Browser-visible class-list configuration
|
||||||
|
- Local monitor-log and dispose-log context from localhost services
|
||||||
|
- The current queue window, typically the current day
|
||||||
|
|
||||||
|
## First-pass Collection Steps
|
||||||
|
|
||||||
|
1. Open or attach to the city-dispatch configuration page.
|
||||||
|
2. Verify required platform-session and org/user context is available.
|
||||||
|
3. Read the scheduled workflow rule scripts from desk source-of-truth to understand status buckets, class matching, and downstream alert/dispatch behavior.
|
||||||
|
4. Trigger the deterministic repair-order collector through BrowserAction / browser-side request execution.
|
||||||
|
5. Query the upstream repair-order queue for status codes `00`, `01`, `06`, and `08`.
|
||||||
|
6. Normalize source results into `pending`, `audit`, `processed`, `pending_ids`, and `new_pending_ids` using packaged runtime collector logic aligned to the desk rule semantics.
|
||||||
|
7. Compare with local monitor/dispose logs only as downstream context.
|
||||||
|
8. Return a structured monitor snapshot before or alongside downstream logging, audio, message, or call-out side effects.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- BrowserAction or equivalent browser-side request execution
|
||||||
|
- Platform-visible session, org, and user context
|
||||||
|
- Upstream repair-order endpoints under `http://21.77.244.194:18890/qxgl/repairOrder/*`
|
||||||
|
- Localhost services under `http://localhost:13313/MonitorServices/*`
|
||||||
|
- Localhost config services under `http://localhost:13313/configServices/*`
|
||||||
|
- Optional downstream reminder services such as audio play, SMS send, and call-out hooks
|
||||||
|
|
||||||
|
## State Semantics
|
||||||
|
|
||||||
|
- Success: repair orders are collected, status buckets are derived, and the snapshot is assembled with `success` status.
|
||||||
|
- Partial result: queue collection succeeds but local comparison, logging, class matching, or downstream reminder/dispatch side effects are incomplete or fail.
|
||||||
|
- Empty result: a valid queue request returns zero repair orders for the chosen window.
|
||||||
|
- Blocked/error: login failure, missing platform context, interception failure, request failure, permission failure, or parse failure.
|
||||||
|
- Blocked/error must not be reported as empty data.
|
||||||
|
- Local monitor logs and dispose logs are downstream context, not the primary upstream business data source.
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# Data Quality
|
||||||
|
|
||||||
|
## Complete Result
|
||||||
|
|
||||||
|
A complete result means the upstream repair-order queue for the chosen window is available, the status buckets are normalized, and the monitor snapshot contains aligned values for:
|
||||||
|
|
||||||
|
- `pending`
|
||||||
|
- `audit`
|
||||||
|
- `processed`
|
||||||
|
- `pending_ids`
|
||||||
|
- `new_pending_ids`
|
||||||
|
|
||||||
|
## Classification Rules
|
||||||
|
|
||||||
|
The packaged first-pass snapshot standardizes queue status codes as:
|
||||||
|
|
||||||
|
- `00`, `01` -> `pending`
|
||||||
|
- `06` -> `audit`
|
||||||
|
- `08` -> `processed`
|
||||||
|
|
||||||
|
If the upstream queue returns additional states, keep them out of the first-pass counters unless the package contract is updated.
|
||||||
|
|
||||||
|
## Partial Rules
|
||||||
|
|
||||||
|
- If queue collection succeeds but status classification is incomplete or ambiguous, set `status` to `partial`.
|
||||||
|
- If queue collection succeeds but `pending_ids` cannot be compared against prior monitor/dispose logs, set `status` to `partial`.
|
||||||
|
- If local monitor-log write, monitor-data write, dispose-log write, audio-log write, or message-log write fails after snapshot assembly, keep the snapshot and set `status` to `partial`.
|
||||||
|
- If class matching or auto-dispatch derivation is incomplete after queue collection, keep the snapshot and set `status` to `partial`.
|
||||||
|
- Do not claim full completeness when only queue counts are present but downstream comparison context is missing.
|
||||||
|
|
||||||
|
## Common Weak Areas
|
||||||
|
|
||||||
|
- Missing platform session or org/user context
|
||||||
|
- Queue response parse failure
|
||||||
|
- Pending-id comparison against prior logs not available
|
||||||
|
- Local `MonitorServices` or `configServices` failure
|
||||||
|
- Audio, SMS, call-out, or dispose-log side effects failing after snapshot assembly
|
||||||
|
- Class-list configuration not aligned with queue matching scope
|
||||||
|
|
||||||
|
## Empty vs Failure
|
||||||
|
|
||||||
|
- A valid queue request with zero repair orders is empty data.
|
||||||
|
- Login failure, blocked page, missing context, request failure, interception failure, permission failure, or parse failure must be surfaced as failure or partial, not empty.
|
||||||
|
|
||||||
|
## Dependency Warnings
|
||||||
|
|
||||||
|
- Localhost service availability is part of result quality.
|
||||||
|
- Voice reminder, SMS send, call-out, or auto-dispatch side effects must never replace the underlying queue snapshot result.
|
||||||
|
- Historical monitor logs are comparison context only and must not redefine upstream queue truth.
|
||||||
@@ -0,0 +1,302 @@
|
|||||||
|
const STATUS_GROUPS = {
|
||||||
|
pending: ["00", "01"],
|
||||||
|
audit: ["06"],
|
||||||
|
processed: ["08"]
|
||||||
|
};
|
||||||
|
|
||||||
|
const LOCAL_SERVICE_ENDPOINTS = [
|
||||||
|
"http://localhost:13313/MonitorServices/getMonitorLog",
|
||||||
|
"http://localhost:13313/MonitorServices/setMonitorData",
|
||||||
|
"http://localhost:13313/MonitorServices/setMonitorLog",
|
||||||
|
"http://localhost:13313/MonitorServices/getDisposeLog",
|
||||||
|
"http://localhost:13313/MonitorServices/setDisposeLog",
|
||||||
|
"http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
"http://localhost:13313/MonitorServices/setSendMessageLog"
|
||||||
|
];
|
||||||
|
|
||||||
|
const WORKFLOW_RULE_SOURCES = [
|
||||||
|
"D:/desk/智能体资料/大四区报告监测项/95598抢修-市指_业务检测配置.txt",
|
||||||
|
"D:/desk/智能体资料/大四区报告监测项/95598抢修-市指_自动处理配置.txt"
|
||||||
|
];
|
||||||
|
|
||||||
|
const CONFIG_BASE_PAGE = "assets/scene-snapshot/index.html";
|
||||||
|
|
||||||
|
const KNOWN_ISSUES = [
|
||||||
|
"pending classification bug in rule script: status == \"00\" && status == \"01\""
|
||||||
|
];
|
||||||
|
|
||||||
|
function asArray(value) {
|
||||||
|
return Array.isArray(value) ? value : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeId(value) {
|
||||||
|
if (value === null || value === undefined || value === "") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function uniq(values) {
|
||||||
|
return Array.from(new Set(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
function looksLikeJsonString(value) {
|
||||||
|
if (typeof value !== "string") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const trimmed = value.trim();
|
||||||
|
return trimmed.startsWith("[") || trimmed.startsWith("{") || trimmed.startsWith("\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseLooseJson(value, depth = 0) {
|
||||||
|
if (depth > 3 || value === null || value === undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value !== "string") {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimmed = value.trim();
|
||||||
|
if (!trimmed) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(trimmed);
|
||||||
|
return parseLooseJson(parsed, depth + 1);
|
||||||
|
} catch {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function classifyRepairOrders(repairOrders = []) {
|
||||||
|
const pendingOrders = [];
|
||||||
|
const auditOrders = [];
|
||||||
|
const processedOrders = [];
|
||||||
|
const unknownStatuses = [];
|
||||||
|
|
||||||
|
asArray(repairOrders).forEach((item) => {
|
||||||
|
const status = normalizeId(item && item.status);
|
||||||
|
if (status && STATUS_GROUPS.pending.includes(status)) {
|
||||||
|
pendingOrders.push(item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (status && STATUS_GROUPS.audit.includes(status)) {
|
||||||
|
auditOrders.push(item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (status && STATUS_GROUPS.processed.includes(status)) {
|
||||||
|
processedOrders.push(item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (status) {
|
||||||
|
unknownStatuses.push(status);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
pendingOrders,
|
||||||
|
auditOrders,
|
||||||
|
processedOrders,
|
||||||
|
unknownStatuses: uniq(unknownStatuses)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractMonitorPendingIds(monitorLogs = []) {
|
||||||
|
const ids = [];
|
||||||
|
let malformed = false;
|
||||||
|
|
||||||
|
asArray(monitorLogs).forEach((item) => {
|
||||||
|
const pendingIds = asArray(item && item.pending_ids)
|
||||||
|
.map(normalizeId)
|
||||||
|
.filter(Boolean);
|
||||||
|
if (pendingIds.length > 0) {
|
||||||
|
ids.push(...pendingIds);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rawPendingList = item && item.pendingList;
|
||||||
|
const pendingList = parseLooseJson(rawPendingList);
|
||||||
|
if (Array.isArray(pendingList)) {
|
||||||
|
pendingList
|
||||||
|
.map(normalizeId)
|
||||||
|
.filter(Boolean)
|
||||||
|
.forEach((id) => ids.push(id));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (looksLikeJsonString(rawPendingList)) {
|
||||||
|
malformed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
ids: uniq(ids),
|
||||||
|
malformed
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractDisposeOrderIds(disposeLogs = []) {
|
||||||
|
const ids = [];
|
||||||
|
let malformed = false;
|
||||||
|
|
||||||
|
asArray(disposeLogs).forEach((item) => {
|
||||||
|
const rawOrderPayload = item && item.orderID;
|
||||||
|
const orderPayload = parseLooseJson(rawOrderPayload);
|
||||||
|
|
||||||
|
if (Array.isArray(orderPayload)) {
|
||||||
|
orderPayload.forEach((entry) => {
|
||||||
|
const id = normalizeId(entry && (entry.id || entry.orderID || entry.eventId));
|
||||||
|
if (id) {
|
||||||
|
ids.push(id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (entry && typeof entry === "object") {
|
||||||
|
malformed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const scalarEntry = normalizeId(entry);
|
||||||
|
if (scalarEntry) {
|
||||||
|
ids.push(scalarEntry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rawLooksJson = looksLikeJsonString(rawOrderPayload);
|
||||||
|
if (rawLooksJson && orderPayload === rawOrderPayload) {
|
||||||
|
malformed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const scalarId = normalizeId(orderPayload);
|
||||||
|
if (scalarId && (!rawLooksJson || orderPayload !== rawOrderPayload)) {
|
||||||
|
ids.push(scalarId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawLooksJson) {
|
||||||
|
malformed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
ids: uniq(ids),
|
||||||
|
malformed
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function determineStatus({ blocked, hasData, partialReasons }) {
|
||||||
|
if (blocked) {
|
||||||
|
return "blocked";
|
||||||
|
}
|
||||||
|
if (partialReasons.length > 0) {
|
||||||
|
return "partial";
|
||||||
|
}
|
||||||
|
if (!hasData) {
|
||||||
|
return "empty";
|
||||||
|
}
|
||||||
|
return "success";
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectRepairOrders(input = {}) {
|
||||||
|
const blockedReason = normalizeId(input.blocked_reason);
|
||||||
|
const repairOrders = asArray(input.repair_orders);
|
||||||
|
const monitorLogs = asArray(input.monitor_logs || input.monitor_log);
|
||||||
|
const disposeLogs = asArray(input.dispose_logs || input.dispose_log);
|
||||||
|
const localWriteFailures = asArray(input.local_write_failures)
|
||||||
|
.map(normalizeId)
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
const partialReasons = [];
|
||||||
|
|
||||||
|
const { pendingOrders, auditOrders, processedOrders, unknownStatuses } = classifyRepairOrders(repairOrders);
|
||||||
|
|
||||||
|
if (unknownStatuses.length > 0) {
|
||||||
|
partialReasons.push(`unclassified_statuses:${unknownStatuses.join(",")}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pendingIds = uniq(
|
||||||
|
pendingOrders
|
||||||
|
.map((item) => normalizeId(item && item.id))
|
||||||
|
.filter(Boolean)
|
||||||
|
);
|
||||||
|
|
||||||
|
let monitorPendingIds = [];
|
||||||
|
let disposedOrderIds = [];
|
||||||
|
|
||||||
|
if (pendingIds.length > 0) {
|
||||||
|
if (monitorLogs.length === 0) {
|
||||||
|
partialReasons.push("monitor_log_unavailable");
|
||||||
|
} else {
|
||||||
|
const extractedMonitor = extractMonitorPendingIds(monitorLogs);
|
||||||
|
monitorPendingIds = extractedMonitor.ids;
|
||||||
|
if (extractedMonitor.malformed) {
|
||||||
|
partialReasons.push("monitor_log_parse_failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disposeLogs.length === 0) {
|
||||||
|
partialReasons.push("dispose_log_unavailable");
|
||||||
|
} else {
|
||||||
|
const extractedDispose = extractDisposeOrderIds(disposeLogs);
|
||||||
|
disposedOrderIds = extractedDispose.ids;
|
||||||
|
if (extractedDispose.malformed) {
|
||||||
|
partialReasons.push("dispose_log_parse_failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
localWriteFailures.forEach((failure) => {
|
||||||
|
partialReasons.push(`local_write_failed:${failure}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
const monitorSet = new Set(monitorPendingIds);
|
||||||
|
const disposeSet = new Set(disposedOrderIds);
|
||||||
|
const newPendingIds = pendingIds.filter((id) => !monitorSet.has(id) && !disposeSet.has(id));
|
||||||
|
|
||||||
|
const hasData = repairOrders.length > 0;
|
||||||
|
const blocked = Boolean(input.blocked) || Boolean(blockedReason);
|
||||||
|
|
||||||
|
const snapshot = {
|
||||||
|
type: "monitor-snapshot",
|
||||||
|
scene: "95598-repair-city-dispatch",
|
||||||
|
time: input.time || "",
|
||||||
|
pending: pendingOrders.length,
|
||||||
|
audit: auditOrders.length,
|
||||||
|
processed: processedOrders.length,
|
||||||
|
pending_ids: pendingIds,
|
||||||
|
new_pending_ids: newPendingIds,
|
||||||
|
status: determineStatus({
|
||||||
|
blocked,
|
||||||
|
hasData,
|
||||||
|
partialReasons
|
||||||
|
}),
|
||||||
|
partial_reasons: uniq(
|
||||||
|
blockedReason ? [...partialReasons, blockedReason] : partialReasons
|
||||||
|
),
|
||||||
|
evidence: {
|
||||||
|
workflow_rule_sources: WORKFLOW_RULE_SOURCES,
|
||||||
|
config_base_page: CONFIG_BASE_PAGE,
|
||||||
|
config_base_role: "configuration-only",
|
||||||
|
packaged_collector_role: "runtime-snapshot-collector"
|
||||||
|
},
|
||||||
|
known_issues: KNOWN_ISSUES
|
||||||
|
};
|
||||||
|
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
STATUS_GROUPS,
|
||||||
|
LOCAL_SERVICE_ENDPOINTS,
|
||||||
|
WORKFLOW_RULE_SOURCES,
|
||||||
|
CONFIG_BASE_PAGE,
|
||||||
|
KNOWN_ISSUES,
|
||||||
|
classifyRepairOrders,
|
||||||
|
extractMonitorPendingIds,
|
||||||
|
extractDisposeOrderIds,
|
||||||
|
determineStatus,
|
||||||
|
collectRepairOrders
|
||||||
|
};
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
|
||||||
|
const {
|
||||||
|
classifyRepairOrders,
|
||||||
|
extractMonitorPendingIds,
|
||||||
|
extractDisposeOrderIds,
|
||||||
|
determineStatus,
|
||||||
|
collectRepairOrders
|
||||||
|
} = require('./collect_repair_orders.js');
|
||||||
|
|
||||||
|
test('classifyRepairOrders buckets pending/audit/processed and keeps unknown statuses', () => {
|
||||||
|
const result = classifyRepairOrders([
|
||||||
|
{ id: 'A1', status: '00' },
|
||||||
|
{ id: 'A2', status: '01' },
|
||||||
|
{ id: 'A3', status: '06' },
|
||||||
|
{ id: 'A4', status: '08' },
|
||||||
|
{ id: 'A5', status: '77' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert.equal(result.pendingOrders.length, 2);
|
||||||
|
assert.equal(result.auditOrders.length, 1);
|
||||||
|
assert.equal(result.processedOrders.length, 1);
|
||||||
|
assert.deepEqual(result.unknownStatuses, ['77']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('extractMonitorPendingIds reads both pending_ids and pendingList payloads', () => {
|
||||||
|
const logs = [
|
||||||
|
{ pending_ids: ['A1', 'A2'] },
|
||||||
|
{ pendingList: JSON.stringify(['A3']) },
|
||||||
|
{ pendingList: JSON.stringify(JSON.stringify(['A4'])) }
|
||||||
|
];
|
||||||
|
|
||||||
|
assert.deepEqual(extractMonitorPendingIds(logs), { ids: ['A1', 'A2', 'A3', 'A4'], malformed: false });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('extractDisposeOrderIds supports list payloads and scalar payloads', () => {
|
||||||
|
const logs = [
|
||||||
|
{ orderID: JSON.stringify([{ id: 'D1' }, { eventId: 'D2' }]) },
|
||||||
|
{ orderID: JSON.stringify(JSON.stringify([{ id: 'D3' }])) },
|
||||||
|
{ orderID: 'D4' }
|
||||||
|
];
|
||||||
|
|
||||||
|
assert.deepEqual(extractDisposeOrderIds(logs), { ids: ['D1', 'D2', 'D3', 'D4'], malformed: false });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('extractors mark malformed payloads when JSON-like strings cannot be parsed', () => {
|
||||||
|
const monitor = extractMonitorPendingIds([{ pendingList: '{bad-json' }]);
|
||||||
|
const dispose = extractDisposeOrderIds([{ orderID: '[{"id":"A1"}, {' }]);
|
||||||
|
|
||||||
|
assert.deepEqual(monitor, { ids: [], malformed: true });
|
||||||
|
assert.deepEqual(dispose, { ids: [], malformed: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('determineStatus follows blocked > partial > empty > success precedence', () => {
|
||||||
|
assert.equal(determineStatus({ blocked: true, hasData: true, partialReasons: [] }), 'blocked');
|
||||||
|
assert.equal(determineStatus({ blocked: false, hasData: true, partialReasons: ['x'] }), 'partial');
|
||||||
|
assert.equal(determineStatus({ blocked: false, hasData: false, partialReasons: [] }), 'empty');
|
||||||
|
assert.equal(determineStatus({ blocked: false, hasData: true, partialReasons: [] }), 'success');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('collectRepairOrders builds snapshot and computes new pending ids', () => {
|
||||||
|
const snapshot = collectRepairOrders({
|
||||||
|
time: '2026-04-08 10:00:00',
|
||||||
|
repair_orders: [
|
||||||
|
{ id: 'A1', status: '00' },
|
||||||
|
{ id: 'A2', status: '01' },
|
||||||
|
{ id: 'A3', status: '06' },
|
||||||
|
{ id: 'A4', status: '08' }
|
||||||
|
],
|
||||||
|
monitor_logs: [{ pendingList: JSON.stringify(['A1']) }],
|
||||||
|
dispose_logs: [{ orderID: JSON.stringify([{ id: 'A9' }]) }]
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(snapshot.scene, '95598-repair-city-dispatch');
|
||||||
|
assert.equal(snapshot.pending, 2);
|
||||||
|
assert.equal(snapshot.audit, 1);
|
||||||
|
assert.equal(snapshot.processed, 1);
|
||||||
|
assert.deepEqual(snapshot.pending_ids, ['A1', 'A2']);
|
||||||
|
assert.deepEqual(snapshot.new_pending_ids, ['A2']);
|
||||||
|
assert.equal(snapshot.status, 'success');
|
||||||
|
assert.deepEqual(snapshot.partial_reasons, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('collectRepairOrders reports partial when comparison context is missing', () => {
|
||||||
|
const snapshot = collectRepairOrders({
|
||||||
|
repair_orders: [{ id: 'A1', status: '00' }],
|
||||||
|
monitor_logs: [],
|
||||||
|
dispose_logs: []
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(snapshot.status, 'partial');
|
||||||
|
assert.deepEqual(snapshot.partial_reasons.sort(), ['dispose_log_unavailable', 'monitor_log_unavailable']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('collectRepairOrders reports blocked when blocked reason is provided', () => {
|
||||||
|
const snapshot = collectRepairOrders({
|
||||||
|
blocked_reason: 'missing_browser_session',
|
||||||
|
repair_orders: [{ id: 'A1', status: '00' }],
|
||||||
|
monitor_logs: [{ pendingList: '[]' }],
|
||||||
|
dispose_logs: [{ orderID: '[]' }]
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(snapshot.status, 'blocked');
|
||||||
|
assert.ok(snapshot.partial_reasons.includes('missing_browser_session'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('collectRepairOrders reports empty for valid empty queue', () => {
|
||||||
|
const snapshot = collectRepairOrders({
|
||||||
|
repair_orders: []
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(snapshot.status, 'empty');
|
||||||
|
assert.equal(snapshot.pending, 0);
|
||||||
|
assert.deepEqual(snapshot.pending_ids, []);
|
||||||
|
assert.deepEqual(snapshot.new_pending_ids, []);
|
||||||
|
});
|
||||||
112
skills/skill_staging/skills/95598-weekly-monitor-report/SKILL.md
Normal file
112
skills/skill_staging/skills/95598-weekly-monitor-report/SKILL.md
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
---
|
||||||
|
name: 95598-weekly-monitor-report
|
||||||
|
description: Use when the user wants to collect 95598, 12398, and distribution-monitor weekly metrics and generate a weekly report artifact.
|
||||||
|
version: 0.1.0
|
||||||
|
author: sgclaw
|
||||||
|
tags:
|
||||||
|
- 95598
|
||||||
|
- 12398
|
||||||
|
- weekly-report
|
||||||
|
- browser
|
||||||
|
- report
|
||||||
|
---
|
||||||
|
|
||||||
|
# 95598 Weekly Monitor Report
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
- The user asks to collect weekly metrics for 95598, 12398, or distribution-monitor workflows.
|
||||||
|
- The user asks to generate a weekly report artifact from browser-visible business data.
|
||||||
|
- The task needs a structured weekly summary for downstream Office export.
|
||||||
|
- The task needs one report assembled from current-period and cumulative-period inputs across multiple source groups.
|
||||||
|
|
||||||
|
Do not use this skill for:
|
||||||
|
|
||||||
|
- arbitrary business-system browsing
|
||||||
|
- direct editing of report templates without fresh collection
|
||||||
|
- claiming full completeness when some source systems failed
|
||||||
|
- treating history-report entries as the upstream source of truth
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Read the current-period and cumulative-period inputs from the page.
|
||||||
|
2. Verify required system-session context is available.
|
||||||
|
3. Collect weekly metrics from the relevant source groups.
|
||||||
|
4. Normalize the metrics into section-based weekly report data.
|
||||||
|
5. Return the structured artifact before prose.
|
||||||
|
6. If one or more source groups are missing or the two periods are inconsistent, mark the result as partial.
|
||||||
|
|
||||||
|
## Runtime Contract
|
||||||
|
|
||||||
|
- Prefer deterministic packaged collection before generic probing.
|
||||||
|
- Treat login failure, permission failure, blocked page, partial source availability, and empty result separately.
|
||||||
|
- Keep the structured report artifact as the primary output.
|
||||||
|
- Historical report lists and final report downloads are downstream artifacts, not the primary business data source.
|
||||||
|
- Localhost report services must not redefine upstream collection success.
|
||||||
|
|
||||||
|
## Partial-Failure Rule
|
||||||
|
|
||||||
|
- If only part of the weekly metrics are available, report `partial`.
|
||||||
|
- If current-period and cumulative-period metrics are not aligned, report `partial`.
|
||||||
|
- If downstream export or report-log writing fails after section collection succeeds, keep the artifact and report `partial`.
|
||||||
|
- Do not report the run as fully complete when upstream sections are missing.
|
||||||
|
|
||||||
|
## Export Artifact
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "report-artifact",
|
||||||
|
"report_name": "95598-weekly-monitor-report",
|
||||||
|
"period": "",
|
||||||
|
"columns": [],
|
||||||
|
"rows": [],
|
||||||
|
"sections": [
|
||||||
|
{
|
||||||
|
"name": "fault-repair",
|
||||||
|
"columns": ["metric", "current_period", "cumulative", "year_over_year", "note"],
|
||||||
|
"rows": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "frequent-outage",
|
||||||
|
"columns": ["metric", "current_period", "cumulative", "year_over_year", "note"],
|
||||||
|
"rows": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "full-aperture-work-orders",
|
||||||
|
"columns": ["metric", "current_period", "cumulative", "year_over_year", "note"],
|
||||||
|
"rows": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "key-opinion-control",
|
||||||
|
"columns": ["metric", "value", "note"],
|
||||||
|
"rows": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "device-monitoring",
|
||||||
|
"columns": ["metric", "value", "note"],
|
||||||
|
"rows": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "proactive-dispatch",
|
||||||
|
"columns": ["metric", "value", "note"],
|
||||||
|
"rows": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "ok",
|
||||||
|
"partial_reasons": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
Return:
|
||||||
|
|
||||||
|
- current period
|
||||||
|
- cumulative period
|
||||||
|
- included source groups
|
||||||
|
- section count
|
||||||
|
- complete or partial status
|
||||||
|
- missing areas
|
||||||
|
- period alignment issues
|
||||||
|
- downstream export/logging failures
|
||||||
|
- Export Artifact
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[skill]
|
||||||
|
name = "95598-weekly-monitor-report"
|
||||||
|
description = "Use when the user wants to collect 95598, 12398, and distribution-monitor weekly metrics and generate a weekly report artifact."
|
||||||
|
version = "0.1.0"
|
||||||
|
author = "sgclaw"
|
||||||
|
tags = ["95598", "12398", "weekly-report", "browser", "report"]
|
||||||
|
|
||||||
|
prompts = [
|
||||||
|
"For weekly monitor collection, call 95598-weekly-monitor-report.collect_weekly_metrics before generic browser probing.",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[tools]]
|
||||||
|
name = "collect_weekly_metrics"
|
||||||
|
description = "Collect multi-section weekly monitor metrics and prepare the report artifact shell."
|
||||||
|
kind = "browser_script"
|
||||||
|
command = "scripts/collect_weekly_metrics.js"
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
|
|||||||
|
# Collection Flow
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
- Source scenario: `D:\desk\智能体资料\大四区报告监测项\95598、12398及配网设备监控情况周统计\index.html`
|
||||||
|
- Entry page provides two date-range inputs: current-period and cumulative-period.
|
||||||
|
- The page also exposes execution logs and historical reports.
|
||||||
|
- The page orchestrates multiple source groups and combines them into one weekly report.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- Current-period datetime range
|
||||||
|
- Cumulative-period datetime range
|
||||||
|
- Current platform session and cached system account context
|
||||||
|
|
||||||
|
## First-pass Collection Steps
|
||||||
|
|
||||||
|
1. Open or attach to the source page.
|
||||||
|
2. Read both date ranges.
|
||||||
|
3. Verify required system-session context is available.
|
||||||
|
4. Trigger the deterministic weekly collector.
|
||||||
|
5. Collect metrics grouped by source system and report section.
|
||||||
|
6. Normalize source results into section-based weekly report data.
|
||||||
|
7. Return a structured weekly artifact before final report generation.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- Browser-visible page state
|
||||||
|
- Platform integration scripts such as `/a_js/YPTAPI.js`
|
||||||
|
- Multi-system account and token context
|
||||||
|
- Localhost report services under `http://localhost:13313/ReportServices/*`
|
||||||
|
|
||||||
|
## State Semantics
|
||||||
|
|
||||||
|
- Success: source groups are collected, period-aligned, and mapped into sections.
|
||||||
|
- Partial result: one or more source groups are missing, period alignment is inconsistent, or downstream reporting fails after collection.
|
||||||
|
- Empty result: a valid query returns zero rows for one source group.
|
||||||
|
- Blocked/error: login, interception, permission failure, request failure, or parsing failure.
|
||||||
|
- Blocked/error must not be reported as empty data.
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Data Quality
|
||||||
|
|
||||||
|
## Complete Result
|
||||||
|
|
||||||
|
A complete result means the expected weekly source groups for the selected current-period and cumulative-period ranges are all represented, period-aligned, and assembled into output sections.
|
||||||
|
|
||||||
|
## Core Section Groups
|
||||||
|
|
||||||
|
The first-pass package should preserve separate sections for:
|
||||||
|
|
||||||
|
- fault-repair
|
||||||
|
- frequent-outage
|
||||||
|
- full-aperture-work-orders
|
||||||
|
- key-opinion-control
|
||||||
|
- device-monitoring
|
||||||
|
- proactive-dispatch
|
||||||
|
|
||||||
|
## Partial Rules
|
||||||
|
|
||||||
|
- If any required source group is missing or weak, set `status` to `partial`.
|
||||||
|
- If the current-period and cumulative-period sections are inconsistent, set `status` to `partial`.
|
||||||
|
- If downstream report generation or report-log writing fails after section data is assembled, keep the artifact and record the downstream failure in `partial_reasons`.
|
||||||
|
- Do not claim full completeness when only some upstream groups are present.
|
||||||
|
|
||||||
|
## Common Weak Areas
|
||||||
|
|
||||||
|
- Current-period and cumulative-period mismatch
|
||||||
|
- Missing source-system blocks
|
||||||
|
- Incomplete summary sections
|
||||||
|
- Missing cached account or token context
|
||||||
|
- Downstream report generation failure after successful collection
|
||||||
|
|
||||||
|
## Empty vs Failure
|
||||||
|
|
||||||
|
- A valid query with zero rows for a source can be empty data.
|
||||||
|
- Login, interception, permission failure, request failure, or parsing failure must be surfaced as failure or partial, not empty.
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
const SECTION_TEMPLATES = [
|
||||||
|
{
|
||||||
|
name: "fault-repair",
|
||||||
|
columns: ["metric", "current_period", "cumulative", "year_over_year", "note"],
|
||||||
|
rows: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "frequent-outage",
|
||||||
|
columns: ["metric", "current_period", "cumulative", "year_over_year", "note"],
|
||||||
|
rows: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "full-aperture-work-orders",
|
||||||
|
columns: ["metric", "current_period", "cumulative", "year_over_year", "note"],
|
||||||
|
rows: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "key-opinion-control",
|
||||||
|
columns: ["metric", "value", "note"],
|
||||||
|
rows: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "device-monitoring",
|
||||||
|
columns: ["metric", "value", "note"],
|
||||||
|
rows: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "proactive-dispatch",
|
||||||
|
columns: ["metric", "value", "note"],
|
||||||
|
rows: []
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
function collectWeeklyMetrics(input = {}) {
|
||||||
|
return {
|
||||||
|
type: "report-artifact",
|
||||||
|
report_name: "95598-weekly-monitor-report",
|
||||||
|
period: input.period || "",
|
||||||
|
columns: [],
|
||||||
|
rows: [],
|
||||||
|
sections: SECTION_TEMPLATES.map((section) => ({ ...section, rows: [] })),
|
||||||
|
status: "ok",
|
||||||
|
partial_reasons: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
SECTION_TEMPLATES,
|
||||||
|
collectWeeklyMetrics
|
||||||
|
};
|
||||||
133
skills/skill_staging/skills/fault-details-report/SKILL.md
Normal file
133
skills/skill_staging/skills/fault-details-report/SKILL.md
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
---
|
||||||
|
name: fault-details-report
|
||||||
|
description: Use when the user wants to collect fault-detail rows and export a structured fault report artifact or spreadsheet.
|
||||||
|
version: 0.1.0
|
||||||
|
author: sgclaw
|
||||||
|
tags:
|
||||||
|
- fault
|
||||||
|
- report
|
||||||
|
- xlsx
|
||||||
|
- details
|
||||||
|
- browser
|
||||||
|
---
|
||||||
|
|
||||||
|
# Fault Details Report
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
- The user asks to collect fault-detail rows from the business system.
|
||||||
|
- The user asks to normalize fault rows into a standard export schema.
|
||||||
|
- The task needs spreadsheet or document output from structured fault data.
|
||||||
|
- The task needs the fault-detail table plus the per-station summary table derived from the same query period.
|
||||||
|
|
||||||
|
Do not use this skill for:
|
||||||
|
|
||||||
|
- unrelated outage monitoring
|
||||||
|
- editing export templates without fresh data
|
||||||
|
- claiming successful export when row collection, normalization, or export generation failed
|
||||||
|
- treating history-report entries as the primary source of truth
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Read the selected start and end time from the page date-range control.
|
||||||
|
2. Collect raw fault-detail rows from the source page's repair-order query.
|
||||||
|
3. Normalize rows into the canonical detail-column order defined by the page export schema.
|
||||||
|
4. Derive the summary rows used by the secondary summary sheet.
|
||||||
|
5. Return the structured artifact before any prose summary.
|
||||||
|
6. If required columns are missing or summary derivation is incomplete, mark the result as partial.
|
||||||
|
|
||||||
|
## Runtime Contract
|
||||||
|
|
||||||
|
- Prefer a packaged deterministic collector before generic browser probing.
|
||||||
|
- Keep raw row collection, field normalization, and summary derivation as separate steps.
|
||||||
|
- Distinguish blocked, failed, partial, and empty-result states explicitly.
|
||||||
|
- Source-page history logs are report history, not the primary business data source.
|
||||||
|
- Export and report-log localhost services are downstream dependencies and must not redefine collection success.
|
||||||
|
|
||||||
|
## Partial-Failure Rule
|
||||||
|
|
||||||
|
- If rows are collected but one or more required fields cannot be normalized, report `partial`.
|
||||||
|
- If detail rows are collected but the summary sheet cannot be derived completely, report `partial`.
|
||||||
|
- If export-file generation or report-log writing fails after rows are collected, keep the artifact and report `partial`.
|
||||||
|
- Do not treat failed collection as an empty table.
|
||||||
|
|
||||||
|
## Export Artifact
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "report-artifact",
|
||||||
|
"report_name": "fault-details-report",
|
||||||
|
"period": "",
|
||||||
|
"columns": [
|
||||||
|
"qxdbh",
|
||||||
|
"gssgs",
|
||||||
|
"sgs",
|
||||||
|
"gddw",
|
||||||
|
"gds",
|
||||||
|
"slsj",
|
||||||
|
"yjflMc",
|
||||||
|
"ejflMc",
|
||||||
|
"sjflMc",
|
||||||
|
"gzms",
|
||||||
|
"yhbh",
|
||||||
|
"yhmc",
|
||||||
|
"lxr",
|
||||||
|
"gzdd",
|
||||||
|
"lxdh",
|
||||||
|
"bxsj",
|
||||||
|
"gdsj",
|
||||||
|
"clzt",
|
||||||
|
"qxxcjl",
|
||||||
|
"bdz",
|
||||||
|
"line",
|
||||||
|
"pb",
|
||||||
|
"sxfl1",
|
||||||
|
"sxfl2",
|
||||||
|
"sxfl3",
|
||||||
|
"gzsb",
|
||||||
|
"gzyy",
|
||||||
|
"bz"
|
||||||
|
],
|
||||||
|
"rows": [],
|
||||||
|
"sections": [
|
||||||
|
{
|
||||||
|
"name": "summary-sheet",
|
||||||
|
"columns": [
|
||||||
|
"index",
|
||||||
|
"gsName",
|
||||||
|
"fwDept",
|
||||||
|
"className",
|
||||||
|
"allCount",
|
||||||
|
"wxCount",
|
||||||
|
"khcCount",
|
||||||
|
"sbdSbCount",
|
||||||
|
"gyGzCount",
|
||||||
|
"dyGzCount",
|
||||||
|
"tqdzCount",
|
||||||
|
"tqbxCount",
|
||||||
|
"dyxlCount",
|
||||||
|
"bqxCount",
|
||||||
|
"jllCount",
|
||||||
|
"bhxCount",
|
||||||
|
"qftdCount"
|
||||||
|
],
|
||||||
|
"rows": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "ok",
|
||||||
|
"partial_reasons": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
Return:
|
||||||
|
|
||||||
|
- operation type
|
||||||
|
- selected period
|
||||||
|
- detail row count
|
||||||
|
- summary row count
|
||||||
|
- required column coverage
|
||||||
|
- complete or partial status
|
||||||
|
- missing columns, weak mappings, or downstream export/logging failures
|
||||||
|
- Export Artifact
|
||||||
16
skills/skill_staging/skills/fault-details-report/SKILL.toml
Normal file
16
skills/skill_staging/skills/fault-details-report/SKILL.toml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[skill]
|
||||||
|
name = "fault-details-report"
|
||||||
|
description = "Use when the user wants to collect fault-detail rows and export a structured fault report artifact or spreadsheet."
|
||||||
|
version = "0.1.0"
|
||||||
|
author = "sgclaw"
|
||||||
|
tags = ["fault", "report", "xlsx", "details", "browser"]
|
||||||
|
|
||||||
|
prompts = [
|
||||||
|
"For fault detail collection, call fault-details-report.collect_fault_details before generic browser probing.",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[tools]]
|
||||||
|
name = "collect_fault_details"
|
||||||
|
description = "Collect raw fault-detail rows and prepare the detail-plus-summary report artifact shell from the source business page."
|
||||||
|
kind = "browser_script"
|
||||||
|
command = "scripts/collect_fault_details.js"
|
||||||
@@ -0,0 +1,914 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="stylesheet" href="./css/elementui.css" />
|
||||||
|
<link rel="stylesheet" href="./css/page.css" />
|
||||||
|
<title>故障明细统计</title>
|
||||||
|
<link rel="shortcut icon" href="./images/favicon.svg" type="image/x-icon" />
|
||||||
|
<script src="./js/jquery.js"></script>
|
||||||
|
<script src="./js/vue.js"></script>
|
||||||
|
<script src="./js/unit.js"></script>
|
||||||
|
<script src="./js/elementui.js"></script>
|
||||||
|
<script src="./js/moment.js"></script>
|
||||||
|
<script src="./js/common.js"></script>
|
||||||
|
<script src="./js/dpage.min.js"></script>
|
||||||
|
<script src="/a_js/YPTAPI.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<div class="define_tabs">
|
||||||
|
<div class="sys_title">故障明细统计</div>
|
||||||
|
</div>
|
||||||
|
<div class="pageContainer">
|
||||||
|
<div class="sysLc">
|
||||||
|
<div class="sysLcLeft">
|
||||||
|
<div class="sizeBoxContainer">
|
||||||
|
<div class="sizeBoxTitle sizeBoxTitle1">作业信息</div>
|
||||||
|
<div class="sizeBoxContent">
|
||||||
|
<div class="workInfo">
|
||||||
|
<div class="line" v-for="(item,index) in workInfo">
|
||||||
|
<div class="title">{{ item.title }}:</div>
|
||||||
|
<div class="info">{{ item.info }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sysLcRight">
|
||||||
|
<div class="sysLcRightTop">
|
||||||
|
<div class="sizeBoxContainer">
|
||||||
|
<div class="sizeBoxTitle sizeBoxTitle2">
|
||||||
|
自动化工具执行过程
|
||||||
|
<div class="sizeBoxTitleExtre">
|
||||||
|
<el-button v-if="!runLoading" type="primary" class="showHandleBtn"
|
||||||
|
@click="toHandle(false)">开始执行</el-button>
|
||||||
|
<el-button v-else>下载中</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="setPeizhi">
|
||||||
|
<el-form ref="form" label-width="80px">
|
||||||
|
<el-form-item label="选择日期">
|
||||||
|
<el-date-picker size="small" style="width: 350px" v-model="date" type="datetimerange"
|
||||||
|
ramhe-separator="至" @change="dateChange" start-placeholder="开始日期" end-placeholder="结束日期">
|
||||||
|
</el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<el-progress color="#33b5b9" :text-inside="true" :stroke-width="25" :percentage="startYoy"></el-progress>
|
||||||
|
<div class="bottomContent">
|
||||||
|
<div class="borderInfoWrap">
|
||||||
|
<div class="tittle-content">
|
||||||
|
<img src="./images/Button.png" style="margin-right: 10px" />
|
||||||
|
<div style="color: rgb(39, 168, 163); font-weight: 700; margin-top: 15px">生成日志</div>
|
||||||
|
</div>
|
||||||
|
<div class="sizeBoxContent" style="height: 405px; overflow-y: auto" id="infoWrap">
|
||||||
|
<div v-for="(item,index) in handleList" :key="item" class="infoItem">
|
||||||
|
<div :id="index==handleList.length-1?'infolast':''" :class="item.type"
|
||||||
|
style="margin-bottom: 10px">{{item.item}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="borderInfoWrap">
|
||||||
|
<div class="tittle-content">
|
||||||
|
<img src="./images/Button.png" style="margin-right: 10px" />
|
||||||
|
<div style="color: rgb(39, 168, 163); font-weight: 700; margin-top: 15px">历史报告</div>
|
||||||
|
</div>
|
||||||
|
<div class="borderInfoWrapRightContent" style="height: 425px; overflow-y: auto">
|
||||||
|
<div v-for="(item,index) in reportLogList" :key="item" class="infoItem">
|
||||||
|
<div
|
||||||
|
style="display: flex; align-items: center; margin-bottom: 10px; height: 50px; margin-top: 10px; margin-left: 25px; color: blue">
|
||||||
|
<div :href="item.path">{{item.reportName}} <span
|
||||||
|
style="margin-left: 30px; color: #000">{{item.createdTime}}</span></div>
|
||||||
|
<el-button style="margin-left: 10px" @click="aSaveFile(item.path)">下载</el-button>
|
||||||
|
<el-button type="danger" style="margin-left: 10px"
|
||||||
|
@click="deleteReportLog(item.reportNo)">删除</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
const mac = new Vue({
|
||||||
|
el: "#app",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
userCodeIV: "", //sxbj2
|
||||||
|
passwordIV: "", //
|
||||||
|
isShow: true,
|
||||||
|
date: [moment().clone().subtract(1, "days").format("YYYY-MM-DD 16:00:00"), moment().format("YYYY-MM-DD 16:00:00")],
|
||||||
|
startDate: moment().clone().subtract(1, "days").format("YYYY-MM-DD 16:00:00"),
|
||||||
|
endDate: moment().format("YYYY-MM-DD 16:00:00"),
|
||||||
|
toDay: moment().format("MM月DD日"),
|
||||||
|
dayDate: "",
|
||||||
|
handleList: [],
|
||||||
|
dataObj: {},
|
||||||
|
fdList: [],
|
||||||
|
excleIni: [
|
||||||
|
{
|
||||||
|
sheet: `故障报修工单分析`,
|
||||||
|
cols: [
|
||||||
|
["qxdbh", "申请编号"],
|
||||||
|
["gssgs", "单位名称(省)"],
|
||||||
|
["sgs", "单位名称(城市)"],
|
||||||
|
["gddw", "供电单位"],
|
||||||
|
["gds", "供电所"],
|
||||||
|
["slsj", "受理时间"],
|
||||||
|
|
||||||
|
["yjflMc", "一级类型"],
|
||||||
|
["ejflMc", "二级类型"],
|
||||||
|
["sjflMc", "三级类型"],
|
||||||
|
["gzms", "报修内容"],
|
||||||
|
["yhbh", "客户编号"],
|
||||||
|
["yhmc", "客户名称"],
|
||||||
|
["lxr", "联系人"],
|
||||||
|
["gzdd", "联系地址"],
|
||||||
|
["lxdh", "联系电话"],
|
||||||
|
["gzdd", "现场地址"],
|
||||||
|
["bxsj", "工单下发时间"],
|
||||||
|
["gdsj", "归档时间"],
|
||||||
|
["clzt", "处理结果"],
|
||||||
|
["qxxcjl", "处理情况"],
|
||||||
|
["bdz", "变电站"],
|
||||||
|
["line", "线路"],
|
||||||
|
["pb", "配变"],
|
||||||
|
["sxfl1", "属性分类1"],
|
||||||
|
["sxfl2", "属性分类2"],
|
||||||
|
["sxfl3", "属性分类3"],
|
||||||
|
["gzsb", "故障设备"],
|
||||||
|
["gzyy", "故障原因"],
|
||||||
|
["bz", "备注"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sheet: "汇总模板",
|
||||||
|
cols: [
|
||||||
|
["index", "统计周期内故障报修工单情况", "序号", "序号", "序号", "序号", "序号"],
|
||||||
|
["gsName", "统计周期内故障报修工单情况", "供电公司", "供电公司", "供电公司", "供电公司", "供电公司"],
|
||||||
|
["fwDept", "统计周期内故障报修工单情况", "县公司", "县公司", "县公司", "县公司", "县公司"],
|
||||||
|
["className", "统计周期内故障报修工单情况", "供电所", "供电所", "供电所", "供电所", "供电所"],
|
||||||
|
["allCount", "统计周期内故障报修工单情况", "报修工单数量", "总数", "总数", "总数", "总数"],
|
||||||
|
["wxCount", "统计周期内故障报修工单情况", "报修工单数量", "无效工单", "无效工单", "无效工单", "无效工单"],
|
||||||
|
["khcCount", "统计周期内故障报修工单情况", "报修工单数量", "有效工单", "客户侧", "客户侧", "客户侧"],
|
||||||
|
["sbdSbCount", "统计周期内故障报修工单情况", "报修工单数量", "有效工单", "电网侧", "输变电设备", "输变电设备"],
|
||||||
|
["gyGzCount", "统计周期内故障报修工单情况", "报修工单数量", "有效工单", "电网侧", "配电设备", "高压故障"],
|
||||||
|
["dyGzCount", "统计周期内故障报修工单情况", "报修工单数量", "有效工单", "电网侧", "配电设备", "低压故障"],
|
||||||
|
|
||||||
|
["", "", "", "", "", "", ""],
|
||||||
|
["", "", "", "", "", "", ""],
|
||||||
|
["", "", "", "", "", "", ""],
|
||||||
|
|
||||||
|
["tqdzCount", "统计周期内低压故障分类", "台区刀闸", "", "", "", ""],
|
||||||
|
["tqbxCount", "统计周期内低压故障分类", "台区保险", "", "", "", ""],
|
||||||
|
["dyxlCount", "统计周期内低压故障分类", "低压线路", "", "", "", ""],
|
||||||
|
["bqxCount", "统计周期内低压故障分类", "表前线", "", "", "", ""],
|
||||||
|
["jllCount", "统计周期内低压故障分类", "计量类", "", "", "", ""],
|
||||||
|
["bhxCount", "统计周期内低压故障分类", "表后线", "", "", "", ""],
|
||||||
|
["khcCount", "统计周期内低压故障分类", "用户内部", "", "", "", ""],
|
||||||
|
["qftdCount", "统计周期内低压故障分类", "欠费停电", "", "", "", ""],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
infoObj: {},
|
||||||
|
mxList: [],
|
||||||
|
workInfo: [
|
||||||
|
{
|
||||||
|
title: "原创人员",
|
||||||
|
info: "朱志挺",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "工作痛点",
|
||||||
|
info: "每日导出故障明细信息需要人工从大IV区系统中复制粘贴各个工单的详情内容,耗费大量人力和时间,而且存在人工填写错误的情况。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "实现思路",
|
||||||
|
info: "在大IV系统中监测95598抢修工单数据,并将监测到的工单进行数据解析整合,然后按照模板自动填充数据,实现一键导出故障明细统计表!",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "适用岗位",
|
||||||
|
info: "供指",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
systemIndex: 0,
|
||||||
|
reportLogList: [],
|
||||||
|
runLoading: false,
|
||||||
|
startLoading: false,
|
||||||
|
reportType: "gzmxdc",
|
||||||
|
startYoy: 0,
|
||||||
|
timer: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
handleList: () => {
|
||||||
|
if (mac.handleList.length > 200) {
|
||||||
|
mac.handleList = mac.handleList.splice(150, mac.handleList.length);
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
$("#infoWrap").scrollTop(200000);
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
window.mac = this;
|
||||||
|
this.getReportLog();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
//查询报表日志
|
||||||
|
getReportLog() {
|
||||||
|
$.ajax({
|
||||||
|
url: "http://localhost:13313/ReportServices/Api/getReportLog",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
crossDomain: true,
|
||||||
|
headers: { "Content-Type": "application/json;charset=UTF-8" },
|
||||||
|
contentType: "application/json;charset=utf-8",
|
||||||
|
data: JSON.stringify({ type: this.reportType }),
|
||||||
|
success: function (res) {
|
||||||
|
// console.log('报表日志', res)
|
||||||
|
if (res.status == 200) {
|
||||||
|
mac.reportBaseUrl = res.baseurl;
|
||||||
|
console.log(mac.reportBaseUrl);
|
||||||
|
mac.reportLogList = res.data;
|
||||||
|
// mac.reportLogList = mac.reportLogList.slice(-5);
|
||||||
|
mac.reportLogList = mac.reportLogList?.sort((a, b) => new Date(b?.createdTime) - new Date(a?.createdTime));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//写入报表日志
|
||||||
|
setReportLog(reportName, path) {
|
||||||
|
let userinfo = localStorage.userinfo;
|
||||||
|
let account = "";
|
||||||
|
if (userinfo) {
|
||||||
|
account = JSON.parse(userinfo).account;
|
||||||
|
}
|
||||||
|
let data = { account, type: this.reportType, reportName: reportName, reportInfo: "", path: path };
|
||||||
|
$.ajax({
|
||||||
|
url: "http://localhost:13313/ReportServices/Api/setReportLog",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
crossDomain: true,
|
||||||
|
headers: { "Content-Type": "application/json;charset=UTF-8" },
|
||||||
|
contentType: "application/json;charset=utf-8",
|
||||||
|
data: JSON.stringify(data),
|
||||||
|
success: function (res) {
|
||||||
|
console.log("报表日志", res);
|
||||||
|
if (res.status == 200) {
|
||||||
|
mac.getReportLog();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//删除报表日志
|
||||||
|
deleteReportLog(reportNo) {
|
||||||
|
let data = { reportNo };
|
||||||
|
$.ajax({
|
||||||
|
url: "http://localhost:13313/ReportServices/Api/deleteReportLog",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
crossDomain: true,
|
||||||
|
headers: { "Content-Type": "application/json;charset=UTF-8" },
|
||||||
|
contentType: "application/json;charset=utf-8",
|
||||||
|
data: JSON.stringify(data),
|
||||||
|
success: function (res) {
|
||||||
|
if (res.status == 200) {
|
||||||
|
mac.getReportLog();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleSearch() {
|
||||||
|
console.log(this.formInline);
|
||||||
|
let list = JSON.stringify(this.formInline);
|
||||||
|
let locationUrl = JSON.stringify(location.href);
|
||||||
|
BrowserAction('sgBrowserExcuteJsCode', location.origin + "/#/monitorQueue", `window.mac.getLogint(true,${locationUrl},${list},false,'1')`);
|
||||||
|
},
|
||||||
|
async searchSystemStatusList() {
|
||||||
|
await searchSubscribeSystemList({
|
||||||
|
actionName: "searchAllSubscribeSystem",
|
||||||
|
authenticationInformation: "身份信息码",
|
||||||
|
dataSource: "mysql-operate",
|
||||||
|
data: {
|
||||||
|
userId: this.$store.state.userInfo.userId,
|
||||||
|
},
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.mutableSystemList = res.resultList.map((item) => {
|
||||||
|
console.log(item);
|
||||||
|
item.SysName = item.systemName;
|
||||||
|
item.SysID = item.systemId;
|
||||||
|
item.isLine = false;
|
||||||
|
item.loginURL = item.systemAddress;
|
||||||
|
item.successURL = item.afterLoginAddress;
|
||||||
|
item.jsCode = item.loginCommand;
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
loadingCloseTing(num) {
|
||||||
|
console.log(num);
|
||||||
|
if (num == "0") {
|
||||||
|
this.$message.error("登录系统失败,请检查相关配置!");
|
||||||
|
} else if (num == "1") {
|
||||||
|
this.$message.error("本地服务未启动,请启动本地服务!");
|
||||||
|
} else if (num == "2") {
|
||||||
|
this.$message.error("未匹配对应系统,请先订阅相关系统 !");
|
||||||
|
} else if (num == "3") {
|
||||||
|
this.$message.error("登陆超时,请重新登陆!");
|
||||||
|
if (this.formInline) {
|
||||||
|
mac.handleSearch();
|
||||||
|
}
|
||||||
|
} else if (num == "4") {
|
||||||
|
this.$message.error("未检测到跳转地址,请联系管理员!");
|
||||||
|
}
|
||||||
|
if (this.loading) {
|
||||||
|
this.loading = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 关闭loading
|
||||||
|
loadingClose() {
|
||||||
|
this.location();
|
||||||
|
},
|
||||||
|
location() {
|
||||||
|
console.log("初始化");
|
||||||
|
if (this.loading) {
|
||||||
|
this.loading = null;
|
||||||
|
}
|
||||||
|
let locationUrl = JSON.stringify(location.href);
|
||||||
|
BrowserAction('sgBrowserExcuteJsCode', location.origin + "/#/monitorQueue", `window.mac.getListIng(${locationUrl})`);
|
||||||
|
},
|
||||||
|
loginStatusFlushed(objList) {
|
||||||
|
if (!objList || objList.length == 0) {
|
||||||
|
mac.handleList.push({
|
||||||
|
item: `${moment().format("YYYY-MM-DD HH:mm:ss")}:未匹配到系统账号信息,请添加系统账号密码!`,
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.mutableSystemList = objList;
|
||||||
|
let locationUrl = JSON.stringify(location.href);
|
||||||
|
let dsqLoginFlag = true;
|
||||||
|
if (!this.runLoading) return;
|
||||||
|
this.formInline = null;
|
||||||
|
let dsqData = null;
|
||||||
|
console.log("this.systemIndex", this.systemIndex);
|
||||||
|
for (let i = 0; i < this.mutableSystemList.length; i++) {
|
||||||
|
const item = this.mutableSystemList[i];
|
||||||
|
if (this.systemIndex == 0) {
|
||||||
|
if (item.SysID == "9ad2e9ed2f7911ef978200155de4f645") {
|
||||||
|
//大四区
|
||||||
|
dsqLoginFlag = false;
|
||||||
|
dsqData = item;
|
||||||
|
this.systemIndex = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.systemIndex >= 1) {
|
||||||
|
if (item.SysID == "9ad2e9ed2f7911ef978200155de4f645") {
|
||||||
|
//大四区
|
||||||
|
if (!item.isLine) {
|
||||||
|
dsqLoginFlag = false;
|
||||||
|
// dsqData = item
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!dsqLoginFlag) {
|
||||||
|
if (dsqData) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.formInline = dsqData;
|
||||||
|
mac.handleSearch();
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
mac.handleList.push({
|
||||||
|
item: `${moment().format("YYYY-MM-DD HH:mm:ss")}:请配置大四区账号密码!`,
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
if (mac.timer) {
|
||||||
|
clearInterval(mac.timer);
|
||||||
|
mac.timer = null;
|
||||||
|
}
|
||||||
|
this.getInfo();
|
||||||
|
this.getData();
|
||||||
|
}, 2000);
|
||||||
|
},
|
||||||
|
toolObj(obj) {
|
||||||
|
console.log(obj);
|
||||||
|
let newArry = Object.keys(obj);
|
||||||
|
for (let i = 0; i < newArry.length; i++) {
|
||||||
|
sessionStorage.setItem(newArry[i], obj[newArry[i]]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getInfo() {
|
||||||
|
let tGfUser = localStorage.tGfUser;
|
||||||
|
// 大四区
|
||||||
|
if (tGfUser) {
|
||||||
|
tGfUser = JSON.parse(tGfUser);
|
||||||
|
this.userCodeIV = tGfUser.id;
|
||||||
|
this.infoObj.city = tGfUser.orgNo;
|
||||||
|
this.infoObj.cityName = tGfUser.orgName;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getTime() {
|
||||||
|
let startTime = this.dayDate
|
||||||
|
? moment(this.dayDate).clone().subtract(1, "days").format("YYYY-MM-DD HH:mm:ss")
|
||||||
|
: moment(this.date).clone().subtract(1, "days").format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
let endTime = this.dayDate ? moment(this.dayDate).format("YYYY-MM-DD HH:mm:ss") : this.date;
|
||||||
|
let endEndTime = this.dayDate
|
||||||
|
? moment(this.dayDate).clone().subtract(-1, "days").format("YYYY-MM-DD HH:mm:ss")
|
||||||
|
: moment(this.date).clone().subtract(-1, "days").format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
let lastStartTime = moment(startTime).clone().subtract(1, "days").format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
let lastEndTime = moment(endTime).clone().subtract(1, "days").format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
let lastMonthStartTime = moment(startTime).clone().subtract(1, "month").format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
return {
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
endEndTime,
|
||||||
|
lastStartTime,
|
||||||
|
lastEndTime,
|
||||||
|
lastMonthStartTime,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
dateChange(e) {
|
||||||
|
this.startDate = moment(e?.[0]).format("YYYY-MM-DD HH:mm:ss") || "";
|
||||||
|
this.endDate = moment(e?.[1]).format("YYYY-MM-DD HH:mm:ss") || "";
|
||||||
|
this.toDay = moment(e?.[1]).format("MM月DD日");
|
||||||
|
this.dayDate = moment(e?.[1]).format("YYYY-MM-DD HH:mm:ss") || "";
|
||||||
|
},
|
||||||
|
toHandle() {
|
||||||
|
this.mxList = [];
|
||||||
|
mac.startYoy = 0;
|
||||||
|
this.startLoading = false;
|
||||||
|
let dsqLoginFlag = false;
|
||||||
|
this.formInline = null;
|
||||||
|
let dsqData = null;
|
||||||
|
this.systemIndex = 0;
|
||||||
|
|
||||||
|
this.runLoading = true;
|
||||||
|
this.location();
|
||||||
|
mac.timer = setInterval(() => {
|
||||||
|
if (mac.startYoy < 20) {
|
||||||
|
mac.startYoy += 1;
|
||||||
|
} else {
|
||||||
|
clearInterval(mac.timer);
|
||||||
|
mac.timer = null;
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
exportFile() {
|
||||||
|
mac.startYoy = 100;
|
||||||
|
if (mac.timer) {
|
||||||
|
clearInterval(mac.timer);
|
||||||
|
mac.timer = null;
|
||||||
|
}
|
||||||
|
let excleInI = [];
|
||||||
|
mac.excleIni.forEach((x) => {
|
||||||
|
let obj = x;
|
||||||
|
obj.sheet = x.sheet + moment(mac.QueryType == 0 ? mac.dayRange[1] : mac.proMonth).format("(MM)");
|
||||||
|
excleInI.push(obj);
|
||||||
|
});
|
||||||
|
|
||||||
|
mac.fdList = mac.fdList?.sort((a, b) => new Date(a?.bxsj)?.getTime() - new Date(b?.bxsj)?.getTime());
|
||||||
|
console.log(mac.fdList);
|
||||||
|
let params = {
|
||||||
|
titles: excleInI,
|
||||||
|
date: mac.infoObj.cityName + "故障报修明细表(" + this.toDay + ")",
|
||||||
|
datas: [mac.fdList, mac.mxList],
|
||||||
|
};
|
||||||
|
this.runLoading = false;
|
||||||
|
$.ajax({
|
||||||
|
url: "http://localhost:13313/SurfaceServices/personalBread/export/faultDetailsExportXLSXS",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
crossDomain: true,
|
||||||
|
data: JSON.stringify(params), //必须是字符串格式
|
||||||
|
contentType: "application/json", //指定内容格式
|
||||||
|
success: (res) => {
|
||||||
|
//括号里的data是服务器返回的数据
|
||||||
|
let url = res?.data?.data;
|
||||||
|
mac.aSaveFile(url);
|
||||||
|
this.setReportLog(mac.infoObj.cityName + "故障报修明细表(" + this.toDay + ")", url);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 导出文件
|
||||||
|
aSaveFile(url) {
|
||||||
|
var a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
},
|
||||||
|
// 大四区登录
|
||||||
|
getData() {
|
||||||
|
window.getAllUrlCallBack = function (urls) {
|
||||||
|
const urlArr = urls.split(";");
|
||||||
|
let hasPage = false;
|
||||||
|
let hasLoginPage = false;
|
||||||
|
for (var i = 0; i < urlArr.length; i++) {
|
||||||
|
if (urlArr[i]?.indexOf(`http://21.77.244.194:18890/mainSystem/#/login`) != -1) {
|
||||||
|
hasPage = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasPage) {
|
||||||
|
let jsCode = `function refDpage() {
|
||||||
|
const jss = document.createElement("script")
|
||||||
|
jss.src = "${location.href}/js/jquery.js"
|
||||||
|
document.head.appendChild(jss)
|
||||||
|
}
|
||||||
|
refDpage()`;
|
||||||
|
BrowserAction('sgBrowserExcuteJsCode', "http://21.77.244.194:18890/mainSystem/#/login", jsCode);
|
||||||
|
setTimeout(() => {
|
||||||
|
mac.getDataFromTargetPage();
|
||||||
|
}, 12000);
|
||||||
|
} else {
|
||||||
|
BrowserAction('sgHideBrowerserOpenPage', `http://21.77.244.194:18890/mainSystem/#/login`);
|
||||||
|
setTimeout(() => {
|
||||||
|
mac.getData();
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
BrowserAction('sgHideBrowerserGetUrls', "window.getAllUrlCallBack");
|
||||||
|
},
|
||||||
|
// 95598抢修工单监测
|
||||||
|
getDataFromTargetPage() {
|
||||||
|
if (mac.startLoading) return;
|
||||||
|
mac.timer = setInterval(() => {
|
||||||
|
if (mac.startYoy < 90) {
|
||||||
|
mac.startYoy += 1;
|
||||||
|
} else {
|
||||||
|
clearInterval(mac.timer);
|
||||||
|
mac.timer = null;
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
mac.startLoading = true;
|
||||||
|
mac.handleList.push({ item: `${moment().format("YYYY-MM-DD HH:mm:ss")}:正在查询故障明细工单!`, type: "" });
|
||||||
|
var slsj = `${this.startDate},${this.endDate}`;
|
||||||
|
let jsCode = `
|
||||||
|
$.ajax({
|
||||||
|
url: 'http://21.77.244.194:18890/qxgl/repairOrder/list?page=1&type=0101&orgNo=${mac.infoObj?.city}&gdsj=${slsj}&limit=500',
|
||||||
|
type: "GET",
|
||||||
|
dataType: 'json',
|
||||||
|
crossDomain: true,
|
||||||
|
headers:{
|
||||||
|
'Content-Type':'application/json;',
|
||||||
|
'userId':'${mac.userCodeIV}',
|
||||||
|
'Access-Control-Allow-Credentials':true,
|
||||||
|
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS,PUT,DELETE,OPTION;',
|
||||||
|
'Access-Control-Allow-Origin':'*'
|
||||||
|
},
|
||||||
|
data: '', //必须是字符串格式
|
||||||
|
contentType: "application/json", //指定内容格式
|
||||||
|
success: function (res) { //括号里的data是服务器返回的数据
|
||||||
|
let jsCode1 = \`mac.callbackfunGetZDJX(\${JSON.stringify(res)})\`;
|
||||||
|
__prototype__('sgBrowserExcuteJsCode', '${window.location.href}', jsCode1);
|
||||||
|
},
|
||||||
|
error:function(e){
|
||||||
|
let jsCode1 = \`mac.callbackfunGetZDJX(\${JSON.stringify(e)})\`;
|
||||||
|
__prototype__('sgBrowserExcuteJsCode', '${window.location.href}', jsCode1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
`;
|
||||||
|
BrowserAction('sgBrowserExcuteJsCode', "http://21.77.244.194:18890/mainSystem/#/login", jsCode);
|
||||||
|
},
|
||||||
|
callbackfunGetZDJX(resData) {
|
||||||
|
console.log(resData);
|
||||||
|
mac.fdList = [];
|
||||||
|
this.setByData(resData);
|
||||||
|
},
|
||||||
|
setByData(resData) {
|
||||||
|
if (resData.msg == "success") {
|
||||||
|
if (resData.page.list.length > 0) {
|
||||||
|
let list = [];
|
||||||
|
// this.excleIni[1].cols = this.excleIni[1].cols.slice(0,10)
|
||||||
|
let flList = [
|
||||||
|
{
|
||||||
|
name: "欠费停电",
|
||||||
|
reList: ["欠费", "余额不足"],
|
||||||
|
type: "用户侧",
|
||||||
|
dwcFl: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "客户内部故障",
|
||||||
|
reList: ["客户内部故障"],
|
||||||
|
type: "用户侧",
|
||||||
|
dwcFl: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "表后线",
|
||||||
|
reList: ["表后线"],
|
||||||
|
type: "用户侧",
|
||||||
|
dwcFl: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "输变电设备",
|
||||||
|
reList: ["输变电设备"],
|
||||||
|
type: "电网侧",
|
||||||
|
dwcFl: "输变电设备",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "高压故障",
|
||||||
|
reList: [
|
||||||
|
"电杆(塔)",
|
||||||
|
"杆(塔)基础",
|
||||||
|
"连接线-架空线路",
|
||||||
|
'"连接线-高压计量设备"',
|
||||||
|
"柱上隔离开关-架空线路",
|
||||||
|
"横担-架空线路",
|
||||||
|
"绝缘子-架空线路",
|
||||||
|
"导线-架空线路",
|
||||||
|
"跌落式熔断器",
|
||||||
|
"柱上断路器",
|
||||||
|
"二次及自动化装置",
|
||||||
|
"柱上负荷开关",
|
||||||
|
"金具-架空线路",
|
||||||
|
"高压电容器",
|
||||||
|
"避雷装置-架空线路",
|
||||||
|
"避雷装置-电缆线路",
|
||||||
|
"避雷装置-配电站房设备",
|
||||||
|
"接地装置-架空线路",
|
||||||
|
"接地装置-电缆线路",
|
||||||
|
"接地装置-配电站房设备",
|
||||||
|
"电缆本体-电缆线路",
|
||||||
|
"电缆终端头-电缆线路",
|
||||||
|
"电缆中间接头-电缆线路",
|
||||||
|
"油浸式变压器",
|
||||||
|
"干式变压器",
|
||||||
|
"隔离开关-配电站房设备",
|
||||||
|
"基础-配电站房设备",
|
||||||
|
"端子排-配电站房设备",
|
||||||
|
"电流互感器-配电站房设备",
|
||||||
|
"电流互感器-高压计量设备",
|
||||||
|
"电压互感器",
|
||||||
|
"穿墙套管",
|
||||||
|
"母排-配电站房设备",
|
||||||
|
"熔断器-配电站房设备",
|
||||||
|
"断路器-配电站房设备",
|
||||||
|
"负荷开关",
|
||||||
|
"计量表计-高压计量设备",
|
||||||
|
"接线端子盒",
|
||||||
|
"计量柜",
|
||||||
|
"电压互感器",
|
||||||
|
],
|
||||||
|
type: "电网侧",
|
||||||
|
dwcFl: "高压故障",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "台区刀闸",
|
||||||
|
reList: ["柱上隔离开关-低压架空线路", "电缆终端头", "隔离开关-低压设备"],
|
||||||
|
type: "电网侧",
|
||||||
|
dwcFl: "低压故障",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "台区保险",
|
||||||
|
reList: [
|
||||||
|
"绝缘子-低压架空线路",
|
||||||
|
"熔断器-低压设备",
|
||||||
|
"断路器-低压设备",
|
||||||
|
"漏电保护器",
|
||||||
|
],
|
||||||
|
type: "电网侧",
|
||||||
|
dwcFl: "低压故障",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "低压线路",
|
||||||
|
reList: [
|
||||||
|
"连接线-低压架空线路",
|
||||||
|
"导线-低压架空线路",
|
||||||
|
"横担-低压架空线路",
|
||||||
|
"金具-低压架空线路",
|
||||||
|
"避雷装置-低压架空线路",
|
||||||
|
"避雷装置-低压电缆线路路",
|
||||||
|
"避雷装置-低压设备",
|
||||||
|
"接地装置-低压架空线路",
|
||||||
|
"接地装置-低压设备",
|
||||||
|
"电缆本体-低压电缆线路路",
|
||||||
|
"电缆终端头-低压电缆线路路",
|
||||||
|
"电缆中间接头-低压电缆线路路",
|
||||||
|
"基础-低压架空线路",
|
||||||
|
"基础-低压设备",
|
||||||
|
"端子排-低压设备",
|
||||||
|
"电流互感器-低压设备",
|
||||||
|
"母排-低压设备",
|
||||||
|
"接户线",
|
||||||
|
"电杆",
|
||||||
|
"连接装置",
|
||||||
|
"电容器",
|
||||||
|
"交流接触器",
|
||||||
|
"低压母线槽",
|
||||||
|
"频率异常",
|
||||||
|
"谐波异常",
|
||||||
|
"电压异常",
|
||||||
|
],
|
||||||
|
type: "电网侧",
|
||||||
|
dwcFl: "低压故障",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "表前线",
|
||||||
|
reList: ["连接线-低压计量设备", "接线端子", "主干线", "表前线"],
|
||||||
|
type: "电网侧",
|
||||||
|
dwcFl: "低压故障",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "计量类",
|
||||||
|
reList: ["电流互感器-低压计量设备", "计量表计-低压计量设备", "计量箱(柜)", "表前开关(熔丝)"],
|
||||||
|
type: "电网侧",
|
||||||
|
dwcFl: "低压故障",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
resData.page.list = resData.page.list.filter((item) => item.statusName != "回退营销");
|
||||||
|
resData.page.list.forEach((item) => {
|
||||||
|
item.slsj = item.bxsj;
|
||||||
|
item.gssgs = "甘肃省电力公司";
|
||||||
|
item.sgs = mac.infoObj.cityName?.indexOf("嘉峪关") != -1 ? mac.infoObj.cityName : item.cityName;
|
||||||
|
item.gddw = item.maintOrgName;
|
||||||
|
item.gds = item.maintGroupName;
|
||||||
|
item.clzt = "处理完成";
|
||||||
|
item.bdz = item.bdzMc;
|
||||||
|
item.line = item.xlmc10;
|
||||||
|
item.pb = item.byqmc;
|
||||||
|
let fl1 = "无效";
|
||||||
|
let fl2 = "用户侧";
|
||||||
|
let fl3 = "高压";
|
||||||
|
let f14 = item.sjflMc;
|
||||||
|
let dwcFl = "";
|
||||||
|
let gzyy = "";
|
||||||
|
|
||||||
|
if (item.sjflMc && item.sjflMc != "" && item.sjflMc != "无故障") {
|
||||||
|
flList.forEach((it) => {
|
||||||
|
it.reList.forEach((i) => {
|
||||||
|
let twoName = "";
|
||||||
|
let threeName = "";
|
||||||
|
let flag = false;
|
||||||
|
if (i.indexOf("-") != -1) {
|
||||||
|
threeName = i.split("-")[0];
|
||||||
|
twoName = i.split("-")[1];
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
if (flag) {
|
||||||
|
if (item.sjflMc?.indexOf(threeName) != -1 && item.ejflMc == twoName) {
|
||||||
|
fl1 = "有效";
|
||||||
|
fl2 = it.type;
|
||||||
|
fl3 = "低压";
|
||||||
|
f14 = it.name;
|
||||||
|
dwcFl = it.dwcFl;
|
||||||
|
let firstIndex = item.qxxcjl?.indexOf("故障现象是");
|
||||||
|
if (threeName == "计量表计" && twoName == "低压计量设备" && item.qxxcjl?.indexOf("客户原因导致表计烧损") != -1) {
|
||||||
|
fl2 = "用户侧";
|
||||||
|
fl4 = "客户内部故障";
|
||||||
|
}
|
||||||
|
if (threeName == "表前线" && twoName == "低压计量设备" && item.qxxcjl?.indexOf("客户原因导致表前线断线") != -1) {
|
||||||
|
fl2 = "用户侧";
|
||||||
|
fl4 = "客户内部故障";
|
||||||
|
}
|
||||||
|
if (firstIndex != -1) {
|
||||||
|
let content = item.qxxcjl?.substr(firstIndex + 5, item.qxxcjl.length);
|
||||||
|
let secondIndex = content?.indexOf(",");
|
||||||
|
if (secondIndex > -1) {
|
||||||
|
gzyy = content.substr(0, secondIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gzyy == "") {
|
||||||
|
firstIndex = item.qxxcjl?.indexOf("经查");
|
||||||
|
if (firstIndex != -1) {
|
||||||
|
let content = item.qxxcjl?.substr(firstIndex + 5, item.qxxcjl.length);
|
||||||
|
let secondIndex = content?.indexOf("。");
|
||||||
|
if (secondIndex > -1) {
|
||||||
|
gzyy = content.substr(0, secondIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (item.sjflMc?.indexOf(i) != -1) {
|
||||||
|
fl1 = "有效";
|
||||||
|
fl2 = it.type;
|
||||||
|
fl3 = "低压";
|
||||||
|
f14 = it.name;
|
||||||
|
dwcFl = it.dwcFl;
|
||||||
|
if (i == "表前开关(熔丝)" && item.qxxcjl?.indexOf("客户原因导致表前开关跳闸") != -1) {
|
||||||
|
fl2 = "用户侧";
|
||||||
|
fl4 = "客户内部故障";
|
||||||
|
}
|
||||||
|
let firstIndex = item.qxxcjl?.indexOf("故障现象是");
|
||||||
|
if (firstIndex != -1) {
|
||||||
|
let content = item.qxxcjl?.substr(firstIndex + 5, item.qxxcjl.length);
|
||||||
|
let secondIndex = content?.indexOf(",");
|
||||||
|
if (secondIndex > -1) {
|
||||||
|
gzyy = content.substr(0, secondIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gzyy == "") {
|
||||||
|
firstIndex = item.qxxcjl?.indexOf("经查");
|
||||||
|
if (firstIndex != -1) {
|
||||||
|
let content = item.qxxcjl?.substr(firstIndex + 5, item.qxxcjl.length);
|
||||||
|
let secondIndex = content?.indexOf("。");
|
||||||
|
if (secondIndex > -1) {
|
||||||
|
gzyy = content.substr(0, secondIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (fl1 == "无效") {
|
||||||
|
fl2 = "";
|
||||||
|
fl3 = "";
|
||||||
|
f14 = "";
|
||||||
|
dwcFl = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
item.sxfl1 = fl1;
|
||||||
|
item.sxfl2 = fl2;
|
||||||
|
item.sxfl3 = dwcFl;
|
||||||
|
item.gzsb = f14;
|
||||||
|
item.dwcFl = dwcFl;
|
||||||
|
item.gzyy = gzyy;
|
||||||
|
item.fl1 = fl1;
|
||||||
|
});
|
||||||
|
console.log("抢修", resData.page.list);
|
||||||
|
let dwcList = resData.page.list.filter((item) => item.fl1?.indexOf("电网侧") != -1);
|
||||||
|
let yhcList = resData.page.list.filter((item) => item.fl1?.indexOf("用户侧") != -1);
|
||||||
|
let wxgdList = resData.page.list.filter((item) => item.fl1?.indexOf("无效工单") != -1);
|
||||||
|
list = resData.page.list;
|
||||||
|
mac.fdList = list;
|
||||||
|
let gdsObj = {};
|
||||||
|
list.forEach((item) => {
|
||||||
|
if (!gdsObj[item.gds]) {
|
||||||
|
gdsObj[item.gds] = [item];
|
||||||
|
} else {
|
||||||
|
gdsObj[item.gds].push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(gdsObj);
|
||||||
|
Object.keys(gdsObj).forEach((key, i) => {
|
||||||
|
let newObj = {
|
||||||
|
index: i + 1,
|
||||||
|
gsName: mac.infoObj.cityName,
|
||||||
|
fwDept: mac.infoObj.cityName == "国网嘉峪关供电公司" ? "供电服务部" : gdsObj[key][0]?.gddw,
|
||||||
|
className: mac.infoObj.cityName == "国网嘉峪关供电公司" ? "急修班" : key,
|
||||||
|
wxCount: gdsObj[key].filter((item) => item.sxfl1 == "无效").length,
|
||||||
|
khcCount: gdsObj[key].filter((item) => item.sxfl2 == "用户侧" && item.f14 != "表后线" && item.fl4 != "欠费停电").length,
|
||||||
|
gyGzCount: gdsObj[key].filter((item) => item.sxfl2 == "电网侧").filter((item) => item.dwcFl == "高压故障").length,
|
||||||
|
dyGzCount: gdsObj[key].filter((item) => item.sxfl2 == "电网侧").filter((item) => item.dwcFl == "低压故障").length,
|
||||||
|
sbdSbCount: gdsObj[key].filter((item) => item.sxfl2 == "电网侧").filter((item) => item.dwcFl == "输变电设备").length, //输变电设备
|
||||||
|
// -------------------------------------------
|
||||||
|
tqdzCount: gdsObj[key].filter((item) => item.gzsb == "台区刀闸").length, //台区刀闸
|
||||||
|
tqbxCount: gdsObj[key].filter((item) => item.gzsb == "台区保险").length, //台区保险
|
||||||
|
dyxlCount: gdsObj[key].filter((item) => item.gzsb == "低压线路").length, //低压线路
|
||||||
|
jllCount: gdsObj[key].filter((item) => item.gzsb == "计量类").length, //计量类
|
||||||
|
bhxCount: gdsObj[key].filter((item) => item.gzsb == "表后线").length, //表后线
|
||||||
|
bqxCount: gdsObj[key].filter((item) => item.gzsb == "表前线").length, //表前线
|
||||||
|
qftdCount: gdsObj[key].filter((item) => item.gzsb == "欠费停电").length, //欠费停电
|
||||||
|
};
|
||||||
|
newObj.allCount = newObj.wxCount + newObj.khcCount + newObj.gyGzCount + newObj.dyGzCount + newObj.sbdSbCount;
|
||||||
|
|
||||||
|
mac.mxList.push(newObj);
|
||||||
|
});
|
||||||
|
mac.exportFile();
|
||||||
|
mac.handleList.push({ item: `${moment().format("YYYY-MM-DD HH:mm:ss")}:故障明细导出${resData.page.list.length}条数据!`, type: "" });
|
||||||
|
} else {
|
||||||
|
mac.handleList.push({ item: `${moment().format("YYYY-MM-DD HH:mm:ss")}:查询成功,暂无故障明细数据!`, type: "" });
|
||||||
|
mac.fdList = [{ qxdbh: "今日无数据" }];
|
||||||
|
mac.exportFile();
|
||||||
|
}
|
||||||
|
const list = [];
|
||||||
|
resData.page.list.forEach((item) => {
|
||||||
|
list.push(item.id);
|
||||||
|
});
|
||||||
|
mac.dataObj.qxgd = list;
|
||||||
|
} else {
|
||||||
|
mac.handleList.push({ item: `${moment().format("YYYY-MM-DD HH:mm:ss")}:故障明细查询失败,重新查询中...`, type: "" });
|
||||||
|
mac.getData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# Collection Flow
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
- Source scenario: `D:\desk\智能体资料\大四区报告监测项\故障明细\index.html`
|
||||||
|
- Entry page presents a datetime range selector and a one-click execution button.
|
||||||
|
- The page also exposes generation logs and historical reports, but those are report-history views rather than the primary collection source.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- Start and end datetime from the page-level datetime range picker.
|
||||||
|
- Current platform session and subscribed system account context.
|
||||||
|
|
||||||
|
## First-pass Collection Steps
|
||||||
|
|
||||||
|
1. Open or attach to the source page.
|
||||||
|
2. Read the selected start and end datetime.
|
||||||
|
3. Ensure the D4 business page session is available.
|
||||||
|
4. Trigger the repair-order query used by the page logic.
|
||||||
|
5. Collect raw fault-detail rows.
|
||||||
|
6. Normalize rows using the canonical column order declared in `excleIni[0].cols`.
|
||||||
|
7. Derive the summary-sheet rows from grouped detail rows.
|
||||||
|
8. Return a structured artifact before any export-file or prose step.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- Browser-visible business page state
|
||||||
|
- Page scripts and platform integration (`/a_js/YPTAPI.js`)
|
||||||
|
- D4 login/session context and BrowserAction execution
|
||||||
|
- Localhost report services under `http://localhost:13313/ReportServices/*`
|
||||||
|
- Localhost export service under `http://localhost:13313/SurfaceServices/personalBread/export/faultDetailsExportXLSXS`
|
||||||
|
|
||||||
|
## State Semantics
|
||||||
|
|
||||||
|
- Collection success: detail rows are available and mapped into the canonical schema, and summary derivation is complete.
|
||||||
|
- Partial result: detail rows are collected, but some field normalization, summary derivation, export generation, or report-log writing fails.
|
||||||
|
- Empty result: request succeeds for the chosen period but zero fault rows match.
|
||||||
|
- Blocked/error result: login failure, request failure, script failure, page interception, or parse failure.
|
||||||
|
- Blocked/error must not be reported as an empty result.
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
# Data Quality
|
||||||
|
|
||||||
|
## Canonical Detail Columns
|
||||||
|
|
||||||
|
The first-pass canonical detail-column order follows the source page export schema:
|
||||||
|
|
||||||
|
- `qxdbh`
|
||||||
|
- `gssgs`
|
||||||
|
- `sgs`
|
||||||
|
- `gddw`
|
||||||
|
- `gds`
|
||||||
|
- `slsj`
|
||||||
|
- `yjflMc`
|
||||||
|
- `ejflMc`
|
||||||
|
- `sjflMc`
|
||||||
|
- `gzms`
|
||||||
|
- `yhbh`
|
||||||
|
- `yhmc`
|
||||||
|
- `lxr`
|
||||||
|
- `gzdd`
|
||||||
|
- `lxdh`
|
||||||
|
- `bxsj`
|
||||||
|
- `gdsj`
|
||||||
|
- `clzt`
|
||||||
|
- `qxxcjl`
|
||||||
|
- `bdz`
|
||||||
|
- `line`
|
||||||
|
- `pb`
|
||||||
|
- `sxfl1`
|
||||||
|
- `sxfl2`
|
||||||
|
- `sxfl3`
|
||||||
|
- `gzsb`
|
||||||
|
- `gzyy`
|
||||||
|
- `bz`
|
||||||
|
|
||||||
|
## Required Columns
|
||||||
|
|
||||||
|
At minimum, the first-pass artifact must preserve these keys for each collected detail row:
|
||||||
|
|
||||||
|
- `qxdbh`
|
||||||
|
- `gssgs`
|
||||||
|
- `sgs`
|
||||||
|
- `gddw`
|
||||||
|
- `gds`
|
||||||
|
- `slsj`
|
||||||
|
- `yjflMc`
|
||||||
|
- `ejflMc`
|
||||||
|
- `sjflMc`
|
||||||
|
- `gzms`
|
||||||
|
- `bxsj`
|
||||||
|
- `gdsj`
|
||||||
|
- `clzt`
|
||||||
|
- `qxxcjl`
|
||||||
|
|
||||||
|
## Nullable Columns
|
||||||
|
|
||||||
|
These may be blank in some rows but should still be preserved when present:
|
||||||
|
|
||||||
|
- `yhbh`
|
||||||
|
- `yhmc`
|
||||||
|
- `lxr`
|
||||||
|
- `gzdd`
|
||||||
|
- `lxdh`
|
||||||
|
- `bdz`
|
||||||
|
- `line`
|
||||||
|
- `pb`
|
||||||
|
- `sxfl1`
|
||||||
|
- `sxfl2`
|
||||||
|
- `sxfl3`
|
||||||
|
- `gzsb`
|
||||||
|
- `gzyy`
|
||||||
|
- `bz`
|
||||||
|
|
||||||
|
## Summary-Derivation Expectations
|
||||||
|
|
||||||
|
The first-pass package should also be able to derive summary rows keyed around:
|
||||||
|
|
||||||
|
- `index`
|
||||||
|
- `gsName`
|
||||||
|
- `fwDept`
|
||||||
|
- `className`
|
||||||
|
- `allCount`
|
||||||
|
- `wxCount`
|
||||||
|
- `khcCount`
|
||||||
|
- `sbdSbCount`
|
||||||
|
- `gyGzCount`
|
||||||
|
- `dyGzCount`
|
||||||
|
|
||||||
|
## Partial Rules
|
||||||
|
|
||||||
|
- If detail rows are collected but one or more required detail columns cannot be mapped, set `status` to `partial`.
|
||||||
|
- If the detail table is available but the summary sheet cannot be derived completely, set `status` to `partial`.
|
||||||
|
- If export generation or report-log writing fails after collection succeeds, keep the artifact and record the downstream failure in `partial_reasons`.
|
||||||
|
- Do not silently drop required columns.
|
||||||
|
|
||||||
|
## Empty vs Failure
|
||||||
|
|
||||||
|
- Zero rows for a valid date range is an empty result.
|
||||||
|
- Request, login, interception, export-service, or parsing failure is not an empty result and must be surfaced explicitly.
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
const DETAIL_COLUMNS = [
|
||||||
|
"qxdbh",
|
||||||
|
"gssgs",
|
||||||
|
"sgs",
|
||||||
|
"gddw",
|
||||||
|
"gds",
|
||||||
|
"slsj",
|
||||||
|
"yjflMc",
|
||||||
|
"ejflMc",
|
||||||
|
"sjflMc",
|
||||||
|
"gzms",
|
||||||
|
"yhbh",
|
||||||
|
"yhmc",
|
||||||
|
"lxr",
|
||||||
|
"gzdd",
|
||||||
|
"lxdh",
|
||||||
|
"bxsj",
|
||||||
|
"gdsj",
|
||||||
|
"clzt",
|
||||||
|
"qxxcjl",
|
||||||
|
"bdz",
|
||||||
|
"line",
|
||||||
|
"pb",
|
||||||
|
"sxfl1",
|
||||||
|
"sxfl2",
|
||||||
|
"sxfl3",
|
||||||
|
"gzsb",
|
||||||
|
"gzyy",
|
||||||
|
"bz"
|
||||||
|
];
|
||||||
|
|
||||||
|
const SUMMARY_COLUMNS = [
|
||||||
|
"index",
|
||||||
|
"gsName",
|
||||||
|
"fwDept",
|
||||||
|
"className",
|
||||||
|
"allCount",
|
||||||
|
"wxCount",
|
||||||
|
"khcCount",
|
||||||
|
"sbdSbCount",
|
||||||
|
"gyGzCount",
|
||||||
|
"dyGzCount",
|
||||||
|
"tqdzCount",
|
||||||
|
"tqbxCount",
|
||||||
|
"dyxlCount",
|
||||||
|
"bqxCount",
|
||||||
|
"jllCount",
|
||||||
|
"bhxCount",
|
||||||
|
"qftdCount"
|
||||||
|
];
|
||||||
|
|
||||||
|
function collectFaultDetails(input = {}) {
|
||||||
|
return {
|
||||||
|
type: "report-artifact",
|
||||||
|
report_name: "fault-details-report",
|
||||||
|
period: input.period || "",
|
||||||
|
columns: DETAIL_COLUMNS,
|
||||||
|
rows: [],
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
name: "summary-sheet",
|
||||||
|
columns: SUMMARY_COLUMNS,
|
||||||
|
rows: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
status: "ok",
|
||||||
|
partial_reasons: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
DETAIL_COLUMNS,
|
||||||
|
SUMMARY_COLUMNS,
|
||||||
|
collectFaultDetails
|
||||||
|
};
|
||||||
84
skills/skill_staging/skills/jiayuguan-meter-outage/SKILL.md
Normal file
84
skills/skill_staging/skills/jiayuguan-meter-outage/SKILL.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
---
|
||||||
|
name: jiayuguan-meter-outage
|
||||||
|
description: Use when the user wants to monitor Jiayuguan meter-outage events, compare pending cases against historical logs, and evaluate downstream alert or auto-processing flows.
|
||||||
|
version: 0.1.0
|
||||||
|
author: sgclaw
|
||||||
|
tags:
|
||||||
|
- jiayuguan
|
||||||
|
- meter-outage
|
||||||
|
- monitoring
|
||||||
|
- alert
|
||||||
|
- dispatch
|
||||||
|
---
|
||||||
|
|
||||||
|
# Jiayuguan Meter Outage
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
- The user asks to monitor Jiayuguan meter-outage events.
|
||||||
|
- The user asks to compare current pending cases against historical monitor or dispose logs.
|
||||||
|
- The task needs one snapshot assembled from outage events plus related service-order state enrichment.
|
||||||
|
- The task needs to detect newly pending outage cases before downstream audio reminder or auto-processing.
|
||||||
|
|
||||||
|
Do not use this skill for:
|
||||||
|
|
||||||
|
- generic outage browsing without snapshot output
|
||||||
|
- arbitrary browser probing before the packaged collector
|
||||||
|
- hiding local-service or cross-system failures behind `no pending cases`
|
||||||
|
- treating incomplete outage/event/order joins as fully complete
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Open or attach to the outage configuration page.
|
||||||
|
2. Read scheduled workflow rule scripts from desk source-of-truth (`D:/desk/智能体资料/大四区报告监测项/户表失电-嘉峪关_业务监测配置.txt`, `D:/desk/智能体资料/大四区报告监测项/户表失电-嘉峪关_自动处理配置.txt`) to understand outage-event, service-order, and auto-processing semantics.
|
||||||
|
3. Collect current outage events from the outage source.
|
||||||
|
4. Collect related service-order states from the work-order source.
|
||||||
|
5. Normalize the result into `pending`, `audit`, `processed`, `pending_ids`, and `new_pending_ids`.
|
||||||
|
6. Return the monitor snapshot before downstream audio, reminder, or dispose-log side effects.
|
||||||
|
7. If log comparison, enrichment, or alert-side effects fail after snapshot assembly, keep the snapshot and mark the result as `partial`.
|
||||||
|
|
||||||
|
## Runtime Contract
|
||||||
|
|
||||||
|
- Keep outage-event collection and service-order-state collection separate, then join them into one snapshot.
|
||||||
|
- Prefer the packaged collector before generic probing or manual page inspection.
|
||||||
|
- The scene page `assets/scene-snapshot/index.html` is configuration-only; treat it as class-list/config context, not workflow execution proof.
|
||||||
|
- Treat historical monitor and dispose logs as comparison context, not the upstream business source of truth.
|
||||||
|
- BrowserAction execution, platform session context, marketing token context, and localhost `MonitorServices` dependencies are part of runtime truth and must be surfaced explicitly.
|
||||||
|
- Audio remind and auto-dispatch outcomes are downstream effects; they do not redefine whether snapshot collection succeeded.
|
||||||
|
|
||||||
|
## Partial-Failure Rule
|
||||||
|
|
||||||
|
- If outage events are collected but service-order enrichment fails, report `partial`.
|
||||||
|
- If outage events and order states are collected but monitor-log or dispose-log parsing/comparison fails, report `partial`.
|
||||||
|
- If outage rows do not provide enough crosswalk information to reconcile one `consNo` cleanly against dispose-side `eventId` values, keep the snapshot and report `partial`.
|
||||||
|
- If snapshot construction succeeds but downstream audio or auto-processing side effects fail, keep the snapshot and report `partial`.
|
||||||
|
- Never collapse collection, login, interception, permission, or parse failures into empty lists.
|
||||||
|
|
||||||
|
## Export Artifact
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "monitor-snapshot",
|
||||||
|
"scene": "jiayuguan-meter-outage",
|
||||||
|
"time": "",
|
||||||
|
"pending": 0,
|
||||||
|
"audit": 0,
|
||||||
|
"processed": 0,
|
||||||
|
"pending_ids": [],
|
||||||
|
"new_pending_ids": [],
|
||||||
|
"status": "success",
|
||||||
|
"partial_reasons": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
Return:
|
||||||
|
|
||||||
|
- city
|
||||||
|
- monitoring time or queue window
|
||||||
|
- pending, audit, processed counts
|
||||||
|
- pending ids and new pending ids
|
||||||
|
- complete or partial status
|
||||||
|
- missing outage, order-state, log, audio, or auto-processing areas
|
||||||
|
- Export Artifact
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[skill]
|
||||||
|
name = "jiayuguan-meter-outage"
|
||||||
|
description = "Use when the user wants to monitor Jiayuguan meter-outage events through desk rule-script workflow semantics, compare pending cases against logs, and evaluate downstream processing states."
|
||||||
|
version = "0.1.0"
|
||||||
|
author = "sgclaw"
|
||||||
|
tags = ["jiayuguan", "meter-outage", "monitoring", "alert", "dispatch"]
|
||||||
|
|
||||||
|
prompts = [
|
||||||
|
"For Jiayuguan outage monitoring, call jiayuguan-meter-outage.collect_outage_events first and treat desk rule scripts as workflow source-of-truth while `assets/scene-snapshot/index.html` remains config-only.",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[tools]]
|
||||||
|
name = "collect_outage_events"
|
||||||
|
description = "Collect outage-event and service-order states and prepare the monitor snapshot shell from the source outage page."
|
||||||
|
kind = "browser_script"
|
||||||
|
command = "scripts/collect_outage_events.js"
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
let callbackName = "callBack_hubiaoshidianjiayuguan";
|
||||||
|
let callbackName1 = "callBack_hubiaoshidianjiayuguan01";
|
||||||
|
let list = []
|
||||||
|
let alist = []
|
||||||
|
let alist1 = []
|
||||||
|
let idList = []
|
||||||
|
let pendingList = []
|
||||||
|
window[callbackName] = function (targeturl, actionurl, responseTxt) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
const res = JSON.parse(responseTxt
|
||||||
|
.replace(/%7B/g, '{')
|
||||||
|
.replace(/%27/g, "'")
|
||||||
|
.replace(/%7D/g, "}")
|
||||||
|
.replace(/'/g, '"')
|
||||||
|
.replace("}/", "}")
|
||||||
|
);
|
||||||
|
console.log(res);
|
||||||
|
if (res.msg && res.msg == "success") {
|
||||||
|
list = res.page.list;
|
||||||
|
// list =[{
|
||||||
|
// "eventId": "5e8dcb5c-7add-4812-98e7-46ae3714ebc7",
|
||||||
|
// "outageType": "2",
|
||||||
|
// "outageTypeName": "单户停电",
|
||||||
|
// "ifOutage": "停电",
|
||||||
|
// "ifOutageName": null,
|
||||||
|
// "eventStatus": "处理中",
|
||||||
|
// "offTime": "2026-01-08 19:02:33",
|
||||||
|
// "onTime": null,
|
||||||
|
// "consNo": "6261250673482",
|
||||||
|
// "consType": "0",
|
||||||
|
// "consTypeName": "非重要用户",
|
||||||
|
// "consName": "樊微",
|
||||||
|
// "consAddr": "甘肃省嘉峪关市峪泉镇安远沟村机场路安远沟村六组",
|
||||||
|
// "phoneNum": "13014182867",
|
||||||
|
// "eqPsrId": "7036a473218a54727b73001fcd0173703307ad1ea8",
|
||||||
|
// "eqPsrName": "安远沟六组养殖区变",
|
||||||
|
// "eqPsrType": "0110",
|
||||||
|
// "eqPsrTypeName": "柱上变压器",
|
||||||
|
// "feederPsrId": "27DKX-6541",
|
||||||
|
// "feederPsrName": "110kV雄关变电站126雄开一回线",
|
||||||
|
// "startStationId": "6EFB88B2-07C8-43FB-A288-569A21BDBD93-02444",
|
||||||
|
// "startStationName": "110kV雄关变电站",
|
||||||
|
// "cityId": "8a5470c55ccb982b015d8840bfcc2a93",
|
||||||
|
// "cityName": "嘉峪关",
|
||||||
|
// "maintenanceOrgId": "8a5470c55ccb982b015d884190fb2a94",
|
||||||
|
// "maintenanceOrgName": null,
|
||||||
|
// "maintenanceGroupId": "72d5b4c09a034c60aeca73e0fbba5dd6",
|
||||||
|
// "maintenanceGroupName": "配网无人机巡检班(含运维业务)",
|
||||||
|
// "orderId": "ZDFW20260108210159684446849",
|
||||||
|
// "orderNo": "ZDFW20260108210159684446849",
|
||||||
|
// "orderStatus": "02",
|
||||||
|
// "sourceMarking": "1",
|
||||||
|
// "sourceMarkingName": "用采上送",
|
||||||
|
// "sourceReply": null,
|
||||||
|
// "sourceReplyName": null,
|
||||||
|
// "batchNumber": "5e8dcb5c-7add-4812-98e7-46ae3714ebc7",
|
||||||
|
// "createTime": "2026-01-08 19:12:33",
|
||||||
|
// "upTime": "2026-01-08 19:12:33",
|
||||||
|
// "qxdbh": null,
|
||||||
|
// "powerTypeOne": null,
|
||||||
|
// "powerTypeTwo": null,
|
||||||
|
// "showFlag": "1",
|
||||||
|
// "orgshortName": null,
|
||||||
|
// "id": null
|
||||||
|
// }]
|
||||||
|
list.forEach(item => {
|
||||||
|
// 户号
|
||||||
|
idList.push(item.consNo)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
//执行 下一队列方法
|
||||||
|
_this.processQueue();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
let audioText = ""
|
||||||
|
audioFC(audioText)
|
||||||
|
}
|
||||||
|
window[callbackName1] = function (targeturl, actionurl, responseTxt) {
|
||||||
|
try {
|
||||||
|
const res = JSON.parse(responseTxt
|
||||||
|
.replace(/%7B/g, '{')
|
||||||
|
.replace(/%27/g, "'")
|
||||||
|
.replace(/%7D/g, "}")
|
||||||
|
.replace(/'/g, '"')
|
||||||
|
.replace("}/", "}")
|
||||||
|
);
|
||||||
|
if (res.msg == "success") {
|
||||||
|
res.page.list.forEach((item) => {
|
||||||
|
if (item.gdztmc == "待审核") {
|
||||||
|
alist.push(item);
|
||||||
|
}
|
||||||
|
if (item.gdztmc == "已归档") {
|
||||||
|
alist1.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
let obj = {
|
||||||
|
time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), //监测时间
|
||||||
|
type: "户表失电-嘉峪关", //监测工单类型
|
||||||
|
pending: list.length, //待处理数字
|
||||||
|
pendingList: JSON.stringify(idList), //待处理列表
|
||||||
|
audit: alist.length, //待审核
|
||||||
|
processed: alist1.length, //已处理
|
||||||
|
};
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/getMonitorLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: "户表失电-嘉峪关" }), //必须是字符串格式
|
||||||
|
}).then((res2) => {
|
||||||
|
if (res2.status == 200) {
|
||||||
|
let index = 0
|
||||||
|
if (res2.data.length < 1 && list.length > 0 && _this.queueObj.voiceRemind == '1') {
|
||||||
|
let audioText = "您有户表失电工单,请及时处理"
|
||||||
|
audioFC(audioText)
|
||||||
|
}
|
||||||
|
if (res2.data.length > 0) {
|
||||||
|
let logList = []
|
||||||
|
if (res2.data[0].pendingList && res2.data[0].pendingList?.indexOf('解析异常') == -1) {
|
||||||
|
logList = JSON.parse(res2.data[0].pendingList)
|
||||||
|
}
|
||||||
|
if (!Array.isArray(logList)) {
|
||||||
|
logList = JSON.parse(logList)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
idList.forEach(x => {
|
||||||
|
index = logList.indexOf(x)
|
||||||
|
if (index == -1) {
|
||||||
|
throw new Error("停止循环")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.log("跳出循环");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index == -1 && _this.queueObj.voiceRemind == '1') {
|
||||||
|
let audioText = "您有户表失电工单,请及时处理"
|
||||||
|
audioFC(audioText)
|
||||||
|
}
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setMonitorData",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify(obj)
|
||||||
|
})
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setMonitorLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify(obj),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 将派过的工单去重
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/getDisposeLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: "户表失电-嘉峪关" }), //必须是字符串格式
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.status == 200) {
|
||||||
|
let resList = []
|
||||||
|
try {
|
||||||
|
res.data.forEach(item => {
|
||||||
|
if (item.orderID != '') {
|
||||||
|
let logList = JSON.parse(item.orderID)
|
||||||
|
if (!Array.isArray(logList)) {
|
||||||
|
logList = JSON.parse(logList)
|
||||||
|
if (!Array.isArray(logList)) {
|
||||||
|
logList = JSON.parse(logList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logList.forEach(i => {
|
||||||
|
resList.push(i.id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
resList = Array.from(new Set(resList))
|
||||||
|
list.forEach(y => {
|
||||||
|
if (resList.indexOf(y.eventId) == -1) {
|
||||||
|
pendingList.push(y)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
obj.pendingList = "解析异常" + error
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setMonitorLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify(obj)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (pendingList.length > 0) {
|
||||||
|
//执行 下一队列方法
|
||||||
|
_this.queueObj.pendingList = pendingList;
|
||||||
|
_this.autoTask();
|
||||||
|
} else {
|
||||||
|
//执行 下一队列方法
|
||||||
|
_this.processQueue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let slsj = `${mac.moment().format("YYYY-MM-DD")}+00:00:00,${mac.moment().format("YYYY-MM-DD")}+23:59:59`;
|
||||||
|
const requestParam = `page=1&createTime=${slsj}&orgNo=${_this.orgID}&limit=200`;
|
||||||
|
// sgBrowerserJsAjax2(
|
||||||
|
// "window." + callbackName1,
|
||||||
|
// "http://21.77.244.194:18890/mainSystem/#/login",
|
||||||
|
// `http://21.77.244.194:18890/gdgl/active/service/order/list?` + requestParam,
|
||||||
|
// "GET",
|
||||||
|
// `Content-Type:application/json;userId:${_this.userID};Access-Control-Allow-Credentials:true;Access-Control-Allow-Methods: GET, POST, OPTIONS,PUT,DELETE,OPTION;Access-Control-Allow-Origin:*`,
|
||||||
|
// ""
|
||||||
|
// );
|
||||||
|
BrowserAction(
|
||||||
|
'sgBrowerserJsAjax2',
|
||||||
|
"window." + callbackName1,
|
||||||
|
"http://21.77.244.194:18890/mainSystem/#/login",
|
||||||
|
`http://21.77.244.194:18890/gdgl/active/service/order/list?` + requestParam,
|
||||||
|
"GET",
|
||||||
|
`Content-Type:application/json;userId:${_this.userID};Access-Control-Allow-Credentials:true;Access-Control-Allow-Methods: GET, POST, OPTIONS,PUT,DELETE,OPTION;Access-Control-Allow-Origin:*`,
|
||||||
|
""
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let slsj = `${mac.moment(new Date().setDate(new Date().getDate() - 2)).format("YYYY-MM-DD")}+00:00:00,${mac.moment().format("YYYY-MM-DD")}+23:59:59`;
|
||||||
|
let requestParam = `page=1&sortFiled=off_time&ifAsc=false&outageType=2&flag=0&eventStatus=1&offTime=${slsj}&orgNo=${_this.orgID}&limit=100`;
|
||||||
|
// sgBrowerserJsAjax2(
|
||||||
|
// "window." + callbackName,
|
||||||
|
// "http://21.77.244.194:18890/mainSystem/#/login",
|
||||||
|
// `http://21.77.244.194:18890/outage/dhsd/dhsdList?` + requestParam,
|
||||||
|
// "POST",
|
||||||
|
// `Content-Type:application/json;userId:${_this.userID};Access-Control-Allow-Credentials:true;Access-Control-Allow-Methods: GET, POST, OPTIONS,PUT,DELETE,OPTION;Access-Control-Allow-Origin:*`,
|
||||||
|
// ""
|
||||||
|
// );
|
||||||
|
BrowserAction(
|
||||||
|
'sgBrowerserJsAjax2',
|
||||||
|
"window." + callbackName,
|
||||||
|
"http://21.77.244.194:18890/mainSystem/#/login",
|
||||||
|
`http://21.77.244.194:18890/outage/dhsd/dhsdList?` + requestParam,
|
||||||
|
"POST",
|
||||||
|
`Content-Type:application/json;userId:${_this.userID};Access-Control-Allow-Credentials:true;Access-Control-Allow-Methods: GET, POST, OPTIONS,PUT,DELETE,OPTION;Access-Control-Allow-Origin:*`,
|
||||||
|
""
|
||||||
|
)
|
||||||
|
function audioFC(text) {
|
||||||
|
mac.audioPlay(text).then(response => {
|
||||||
|
if (response.status == 200) {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: text, time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "成功" })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: text, time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "失败" })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: text, time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "异常" })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,470 @@
|
|||||||
|
console.log("户表失电嘉峪关进入自动派单==")
|
||||||
|
let a = JSON.parse(localStorage.getItem("markYXObj"))
|
||||||
|
let loginUserInfo = JSON.parse(a.sessionStorage.loginUserInfo)
|
||||||
|
let tokens = JSON.parse(localStorage["markYXObj"])?.sessionStorage?.token;
|
||||||
|
var HBSD = [];
|
||||||
|
var hbsdList = [];
|
||||||
|
var hbsdClassList = [];
|
||||||
|
var consName = null;
|
||||||
|
let tel = []
|
||||||
|
let ecssMgtOrgCode = ''
|
||||||
|
let objData = {
|
||||||
|
time: mac.moment().format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
type: "户表失电-嘉峪关",
|
||||||
|
pending: 0,
|
||||||
|
pendingList: "",
|
||||||
|
audit: 0,
|
||||||
|
processed: 0
|
||||||
|
};
|
||||||
|
let successList = [];
|
||||||
|
let flag = false;
|
||||||
|
let callbackName1 = "callBack_hubiaoshidianjiayuguanpaidan01";
|
||||||
|
//将同一个配变(eqPsrName)下的工单合并一块
|
||||||
|
obj.pendingList.filter((x) => HBSD.findIndex((y) => y.id == x.eventId) == -1).forEach((x) => {
|
||||||
|
let index = hbsdList.findIndex((y) => y.eqPsrName == x.eqPsrName);
|
||||||
|
if (index == -1) {
|
||||||
|
hbsdList.push({
|
||||||
|
eqPsrName: x.eqPsrName,
|
||||||
|
eventId: x.eventId,
|
||||||
|
obj: x,
|
||||||
|
gdbh: "",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
hbsdList[index].eventId += "," + x.eventId;
|
||||||
|
// hbsdList 是最后整合出来需要派发的工单
|
||||||
|
}
|
||||||
|
HBSD.push({ id: x.eventId });
|
||||||
|
});
|
||||||
|
// 查询大四区班组
|
||||||
|
if (hbsdList.length > 0) {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/getClassList",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: objData.type }),
|
||||||
|
}).then((res) => {
|
||||||
|
//括号里的res是服务器返回的数据
|
||||||
|
if (res.status == 200) {
|
||||||
|
res.data.forEach((item) => {
|
||||||
|
let arr = [];
|
||||||
|
if (item.scope != "") {
|
||||||
|
item.scope = item.scope.replace(/\s*/g, "");
|
||||||
|
arr.push(item.scope.split("、"));
|
||||||
|
item.scope = [].concat.apply([], arr);
|
||||||
|
} else {
|
||||||
|
item.scope = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
hbsdClassList = res.data;
|
||||||
|
console.log(hbsdClassList);
|
||||||
|
getTeamData(hbsdList)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拿着大四区工单中的用户编号去营销系统查询,查到哪个班组就给哪个班组派发
|
||||||
|
function getTeamData(hbsdList) {
|
||||||
|
console.log(hbsdList)
|
||||||
|
const requestParam1 = {
|
||||||
|
mgtOrgCode: loginUserInfo.orgNo,
|
||||||
|
mgtOrgCodeList: ['62411', '624110105', '624110106', '6241102', '624110101', '6241101', '624110102', '624110201'],
|
||||||
|
mgtOrgName: "国网嘉峪关供电公司",
|
||||||
|
orgFlag: true,
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
searchMode: "all",
|
||||||
|
someLink: hbsdList[0].obj.consNo
|
||||||
|
}
|
||||||
|
BrowserAction(
|
||||||
|
'sgBrowerserJsAjax2',
|
||||||
|
"window.callbackName_yx360_hbsd",
|
||||||
|
"http://yx.gs.sgcc.com.cn",
|
||||||
|
`http://yxgateway.gs.sgcc.com.cn/emss-custmgtf-custview-front//member/custElecEP/queryEleCust`,
|
||||||
|
"POST",
|
||||||
|
`Content-Type:application/json;auth_token:${tokens}`,
|
||||||
|
window.encrypt_old(requestParam1)
|
||||||
|
)
|
||||||
|
window['callbackName_yx360_hbsd'] = (targeturl, actionurl, responseTxt) => {
|
||||||
|
try {
|
||||||
|
const resData = decodeURI(responseTxt).replace(/'/g, '"').replace("}/", "}");
|
||||||
|
let jsonData = resData.slice(0, resData.lastIndexOf("]") + 1);
|
||||||
|
jsonData += "}";
|
||||||
|
let res = eval("(" + jsonData + ")");
|
||||||
|
if (res.code == "00000") {
|
||||||
|
let data = res.data;
|
||||||
|
if (data.length > 0) {
|
||||||
|
// 624110102一班 624110106二班 624110105城郊
|
||||||
|
ecssMgtOrgCode = data[0].eccs[0].mgtOrgCode;
|
||||||
|
getgdbh();
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
let audioText = `户号${hbsdList[0].obj.consNo}在营销系统中未查到相关信息,请手动派发相关工单!`;
|
||||||
|
audioFC(audioText);
|
||||||
|
}, 6000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getgdbh() {
|
||||||
|
let callbackName = "callBack_hubiaoshidianjiayuguanpaidan";
|
||||||
|
// 派单前获取工单编号,用来调接口时作为参数传递
|
||||||
|
window[callbackName] = function (targeturl, actionurl, responseTxt) {
|
||||||
|
try {
|
||||||
|
const resData = JSON.parse(responseTxt
|
||||||
|
.replace(/%7B/g, '{')
|
||||||
|
.replace(/%27/g, "'")
|
||||||
|
.replace(/%7D/g, "}")
|
||||||
|
.replace(/'/g, '"')
|
||||||
|
.replace("}/", "}")
|
||||||
|
);
|
||||||
|
if (resData.code == 0) {
|
||||||
|
if (hbsdList.length > 0) {
|
||||||
|
hbsdList[0].gdbh = resData.gdbh;
|
||||||
|
}
|
||||||
|
// 自动派单接口
|
||||||
|
zdpdFc();
|
||||||
|
}
|
||||||
|
} catch (x) {
|
||||||
|
setTimeout(() => {
|
||||||
|
let audioText = "户表失电工单编号获取异常,请手动派单";
|
||||||
|
audioFC(audioText)
|
||||||
|
}, 6000);
|
||||||
|
let type = "户表失电-嘉峪关";
|
||||||
|
let orderID = "";
|
||||||
|
let time = mac.moment().format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
let name = "";
|
||||||
|
let state = "工单编号获取异常" + x;
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setDisposeLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type, orderID, name, time, state }), //必须是字符串格式
|
||||||
|
}).then(re => {
|
||||||
|
if (re.status == 200) {
|
||||||
|
mac.exeTQueue();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
BrowserAction(
|
||||||
|
'sgBrowerserJsAjax2',
|
||||||
|
"window." + callbackName,
|
||||||
|
`http://21.77.244.194:18890/#/webview/1543953229739896`,
|
||||||
|
`http://21.77.244.194:18890/gdgl/zdfw/tgforderzdfw/gdbh`,
|
||||||
|
"GET",
|
||||||
|
`Content-Type:application/json;userId:${_this.userID};Access-Control-Allow-Credentials:true;Access-Control-Allow-Methods: GET, POST, OPTIONS,PUT,DELETE,OPTION;Access-Control-Allow-Origin:*`,
|
||||||
|
""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// 派单接口
|
||||||
|
function zdpdFc() {
|
||||||
|
window[callbackName1] = function (targeturl, actionurl, responseTxt) {
|
||||||
|
try {
|
||||||
|
const resData = JSON.parse(responseTxt.replace(/%7B/g, '{').replace(/%27/g, "'").replace(/%7D/g, "}").replace(/'/g, '"').replace("}/", "}"));
|
||||||
|
if (resData.code == 0) {
|
||||||
|
setTimeout(() => {
|
||||||
|
let audioText = "户表失电工单自动派单成功";
|
||||||
|
audioFC(audioText)
|
||||||
|
}, 6000);
|
||||||
|
// let type = "户表失电";
|
||||||
|
// let orderID = JSON.stringify(HBSD);
|
||||||
|
// let time = mac.moment().format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
// let name = consName;
|
||||||
|
// let state = "成功";
|
||||||
|
// // i国网
|
||||||
|
// const request = {
|
||||||
|
// phoneList: [].concat.apply([], tel),
|
||||||
|
// content: "【业数融合一平台】您有户表失电工单,请及时处理!", //短信内容
|
||||||
|
// };
|
||||||
|
// if (request.phoneList.length > 0) {
|
||||||
|
// msgFC(request)
|
||||||
|
// }
|
||||||
|
// // 呼叫接口
|
||||||
|
// setTimeout(() => {
|
||||||
|
// const params = {
|
||||||
|
// taskName: "户表失电",
|
||||||
|
// phone: [].concat.apply([], tel),
|
||||||
|
// content: "您有户表失电工单,请尽快接单处理",
|
||||||
|
// name: "户表失电",
|
||||||
|
// };
|
||||||
|
// if (params.phone.length > 0) {
|
||||||
|
// mac.callOutLogin(params);
|
||||||
|
// }
|
||||||
|
// }, 1000);
|
||||||
|
let type = "户表失电-嘉峪关";
|
||||||
|
let orderID = JSON.stringify(successList);
|
||||||
|
let time = mac.moment().format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
let name = consName;
|
||||||
|
let state = '成功';
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setDisposeLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type, orderID, name, time, state, }), //必须是字符串格式
|
||||||
|
}).then(re => {
|
||||||
|
if (re.status == 200) {
|
||||||
|
mac.exeTQueue();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let type = "户表失电-嘉峪关";
|
||||||
|
setTimeout(() => {
|
||||||
|
let audioText = "户表失电工单自动派单失败,请及时处理"
|
||||||
|
audioFC(audioText)
|
||||||
|
}, 6000);
|
||||||
|
let orderID = JSON.stringify(successList);
|
||||||
|
let time = mac.moment().format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
let name = consName;
|
||||||
|
let state = "失败";
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setDisposeLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type, orderID, name, time, state, }), //必须是字符串格式
|
||||||
|
}).then(re => {
|
||||||
|
if (re.status == 200) {
|
||||||
|
mac.exeTQueue();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (x) {
|
||||||
|
setTimeout(() => {
|
||||||
|
let audioText = "户表失电工单自动派单异常,请及时处理";
|
||||||
|
audioFC(audioText)
|
||||||
|
}, 6000);
|
||||||
|
let type = "户表失电-嘉峪关";
|
||||||
|
let orderID = JSON.stringify(successList);
|
||||||
|
let time = mac.moment().format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
let name = consName;
|
||||||
|
let state = "异常" + x;
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setDisposeLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type, orderID, name, time, state, }), //必须是字符串格式
|
||||||
|
}).then(re => {
|
||||||
|
if (re.status == 200) {
|
||||||
|
mac.exeTQueue();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (hbsdList.length > 0) {
|
||||||
|
consName = hbsdList[0].obj.consName;
|
||||||
|
let t = mac.moment().format("YYYY-MM-DD") + " " + "23:00:00";
|
||||||
|
// 区县级参数
|
||||||
|
var requestParam = {
|
||||||
|
comment: "",
|
||||||
|
processBusinessKey: hbsdList[0].gdbh, //工单编号id
|
||||||
|
processDefKey: "gdfw_zdfwgd_202305", //固定
|
||||||
|
starter: _this.userID, //登录账号
|
||||||
|
variables: {
|
||||||
|
data: {
|
||||||
|
address: hbsdList[0].obj.consAddr, //联系地址
|
||||||
|
content: "【自动派单】单户失电", //受理内容
|
||||||
|
eventId: hbsdList[0].eventId, //每一项的eventId,如有多项用,隔开
|
||||||
|
eventType: "01",
|
||||||
|
fdly: "05", //复电来源固定
|
||||||
|
flag: "01",
|
||||||
|
gdbh: hbsdList[0].gdbh, //工单编号
|
||||||
|
hfbz: "01", // 回复标志固定
|
||||||
|
mobile: hbsdList[0].obj.phoneNum, //联系电话
|
||||||
|
slyj: "请及时处理", //受理意见
|
||||||
|
yhbh: hbsdList[0].obj.consNo, //用户编号
|
||||||
|
yhmc: hbsdList[0].obj.consName, //用户名称
|
||||||
|
yqfksj: t, //要求反馈时间
|
||||||
|
ywlb: "07", //业务类别 大概率固定
|
||||||
|
},
|
||||||
|
maintGroup: "", //班组code
|
||||||
|
maintGroupName: "", //班组名称
|
||||||
|
maintOrg: "", //接单单位Code
|
||||||
|
maintOrgName: "", //接单单位
|
||||||
|
personType: "", //班组
|
||||||
|
receivePerson: "", //接单人工号
|
||||||
|
receivePersonName: "", //接单人
|
||||||
|
receiveType: true, //是否班组接单
|
||||||
|
sendType: "city",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// var week = "日一二三四五六".charAt(new Date().getDay());
|
||||||
|
function getTodayChineseWeekday() {
|
||||||
|
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||||
|
const today = new Date();
|
||||||
|
return weekdays[today.getDay()]
|
||||||
|
}
|
||||||
|
function isTodayIn(weekdayStr) {
|
||||||
|
const today = getTodayChineseWeekday();
|
||||||
|
const allowerDays = weekdayStr.split(',').map(day => day.trim());
|
||||||
|
return allowerDays.includes(today)
|
||||||
|
}
|
||||||
|
// 时间比对,范围:08:30 ~ 17:50 范围判断方法
|
||||||
|
function isInTimeRange() {
|
||||||
|
// 获取当前时间的HHmm格式(0830、1750)
|
||||||
|
const currentTime = mac.moment().format("HHmm");
|
||||||
|
// 定义边界范围
|
||||||
|
const startTime = 830;
|
||||||
|
const endTime = 1750;
|
||||||
|
// 核心逻辑判断,当前时间在08:30 ~ 17:50 范围
|
||||||
|
const currentNum = Number(currentTime);
|
||||||
|
return currentNum >= startTime && currentNum <= endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
let assigned = false; // 标记是否已成功分配到班组
|
||||||
|
for (const item of hbsdClassList) {
|
||||||
|
// 判断是否满足派单条件:设置接单 + 今天在周期 + 时间在工作时段
|
||||||
|
if (item.isSetcTime === '1' && isTodayIn(item.cTime) && isInTimeRange()) {
|
||||||
|
if (ecssMgtOrgCode === '624110102' && item.orgId == "5c3512baaafd4d86b2683f49001b755d") {
|
||||||
|
// 一班
|
||||||
|
requestParam.variables.maintGroup = item.orgId;
|
||||||
|
requestParam.variables.maintGroupName = item.cName;
|
||||||
|
requestParam.variables.maintOrg = "77e0c17eac9a405492c393e70ffd8479";
|
||||||
|
requestParam.variables.maintOrgName = "市场部";
|
||||||
|
requestParam.variables.personType = "member";
|
||||||
|
requestParam.variables.receivePerson = item.pCode;
|
||||||
|
requestParam.variables.receivePersonName = item.pName;
|
||||||
|
console.log('进入一班===');
|
||||||
|
} else if (ecssMgtOrgCode === '624110106' && item.orgId == "e69661b8bc7945df838d9690ea126e6f") {
|
||||||
|
// 二班
|
||||||
|
requestParam.variables.maintGroup = item.orgId;
|
||||||
|
requestParam.variables.maintGroupName = item.cName;
|
||||||
|
requestParam.variables.maintOrg = "77e0c17eac9a405492c393e70ffd8479";
|
||||||
|
requestParam.variables.maintOrgName = "市场部";
|
||||||
|
requestParam.variables.personType = "member";
|
||||||
|
requestParam.variables.receivePerson = item.pCode;
|
||||||
|
requestParam.variables.receivePersonName = item.pName;
|
||||||
|
console.log('进入二班===');
|
||||||
|
} else if (ecssMgtOrgCode === '624110105' && item.orgId == "b9af53b58f594f4f9e8fc70bd4135833") {
|
||||||
|
// 城郊
|
||||||
|
requestParam.variables.maintGroup = item.orgId;
|
||||||
|
requestParam.variables.maintGroupName = item.cName;
|
||||||
|
requestParam.variables.maintOrg = "b57f5cb612864627807e7a603aa190c8";
|
||||||
|
requestParam.variables.maintOrgName = "配网管理部";
|
||||||
|
requestParam.variables.personType = "member";
|
||||||
|
requestParam.variables.receivePerson = item.pCode;
|
||||||
|
requestParam.variables.receivePersonName = item.pName;
|
||||||
|
console.log('进入城郊班===');
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
successList.push({ id: hbsdList[0].eventId });
|
||||||
|
autoTask_fun(requestParam);
|
||||||
|
assigned = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// if (item.cName == '配网抢修班') {
|
||||||
|
// requestParam.variables.maintGroup = item.orgId;
|
||||||
|
// requestParam.variables.maintGroupName = item.cName;
|
||||||
|
// requestParam.variables.maintOrg = "b57f5cb612864627807e7a603aa190c8";
|
||||||
|
// requestParam.variables.maintOrgName = "配网管理部";
|
||||||
|
// requestParam.variables.personType = "bz";
|
||||||
|
// requestParam.variables.receivePerson = item.pCode || '';
|
||||||
|
// requestParam.variables.receivePersonName = item.pName || '';
|
||||||
|
// successList.push({ id: hbsdList[0].eventId });
|
||||||
|
// console.log('进入抢修班===');
|
||||||
|
// autoTask_fun(requestParam);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
// 派单配网抢修班
|
||||||
|
if (!assigned) {
|
||||||
|
for (const item of hbsdClassList) {
|
||||||
|
if (item.cName == '配网抢修班') {
|
||||||
|
requestParam.variables.maintGroup = item.orgId;
|
||||||
|
requestParam.variables.maintGroupName = item.cName;
|
||||||
|
requestParam.variables.maintOrg = "b57f5cb612864627807e7a603aa190c8";
|
||||||
|
requestParam.variables.maintOrgName = "配网管理部";
|
||||||
|
requestParam.variables.personType = "bz";
|
||||||
|
requestParam.variables.receivePerson = item.pCode || '';
|
||||||
|
requestParam.variables.receivePersonName = item.pName || '';
|
||||||
|
successList.push({ id: hbsdList[0].eventId });
|
||||||
|
console.log('进入抢修班===');
|
||||||
|
autoTask_fun(requestParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// let flag = true;
|
||||||
|
// if (flag) {
|
||||||
|
// console.log('【日志】无班组满足派单条件,已派往抢修班');
|
||||||
|
// let type = "户表失电-嘉峪关";
|
||||||
|
// let orderID = JSON.stringify(successList);
|
||||||
|
// let time = mac.moment().format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
// let name = "";
|
||||||
|
// let state = "被派到抢修班";
|
||||||
|
// mac.localHostAxjos({
|
||||||
|
// url: "http://localhost:13313/MonitorServices/setDisposeLog",
|
||||||
|
// method: "POST",
|
||||||
|
// data: JSON.stringify({
|
||||||
|
// type,
|
||||||
|
// orderID,
|
||||||
|
// name,
|
||||||
|
// time,
|
||||||
|
// state,
|
||||||
|
// }), //必须是字符串格式
|
||||||
|
// }).then(re => {
|
||||||
|
// if (re.status == 200) {
|
||||||
|
// mac.exeTQueue();
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 自动播报
|
||||||
|
function audioFC(text) {
|
||||||
|
mac.audioPlay(text).then(response => {
|
||||||
|
if (response.status == 200) {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: text, time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "成功" })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: text, time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "失败" })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setAudioPlayLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: text, time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "异常" })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function autoTask_fun(requestParam) {
|
||||||
|
console.log('自动派单===========', requestParam)
|
||||||
|
BrowserAction(
|
||||||
|
'sgBrowerserJsAjax2',
|
||||||
|
"window." + callbackName1,
|
||||||
|
`http://21.77.244.194:18890/#/webview/1543953229739896`,
|
||||||
|
`http://21.77.244.194:18890/gdgl/active/service/order/saveAndSend`,
|
||||||
|
"POST",
|
||||||
|
`Content-Type:application/json;userId:${_this.userID};Access-Control-Allow-Credentials:true;Access-Control-Allow-Methods: GET, POST, OPTIONS,PUT,DELETE,OPTION;Access-Control-Allow-Origin:*`,
|
||||||
|
JSON.stringify(requestParam)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
function msgFC(request) {
|
||||||
|
mac.sendMessages(request).then(res4 => {
|
||||||
|
if (res4.status == 200) {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setSendMessageLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: request.content, time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "成功" })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setSendMessageLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: request.content, time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "失败" })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
mac.localHostAxjos({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setSendMessageLog",
|
||||||
|
method: "POST",
|
||||||
|
data: JSON.stringify({ type: request.content, time: mac.moment().format("YYYY-MM-DD HH:mm:ss"), status: "异常" })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,388 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<link rel="shortcut icon" href="./images/95598/logo.gif" type="image/x-icon" />
|
||||||
|
<link rel="stylesheet" href="./css/elementui.css" />
|
||||||
|
<link rel="stylesheet" href="./css/szhfn.css" />
|
||||||
|
<title>接单班组信息</title>
|
||||||
|
<script src="./js/jquery.js"></script>
|
||||||
|
<script src="./js/vue.js"></script>
|
||||||
|
<script src="./js/elementui.js"></script>
|
||||||
|
<script src="./js/moment.js"></script>
|
||||||
|
<script src="./js/dpage.min.js"></script>
|
||||||
|
<script src="./js/axios.js"></script>
|
||||||
|
<script src="/a_js/YPTAPI.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<el-table :data="allclassList" border height="945px">
|
||||||
|
<el-table-column label="接单单位名称" align="center" property="cName"></el-table-column>
|
||||||
|
<el-table-column label="接单时间" align="center" property="cTime"></el-table-column>
|
||||||
|
<el-table-column label="接单人姓名" align="center" property="pName"></el-table-column>
|
||||||
|
<el-table-column label="接单人工号" align="center" property="pCode"></el-table-column>
|
||||||
|
<el-table-column label="接单人手机号" align="center" property="wName"></el-table-column>
|
||||||
|
<el-table-column property="state" label="操作" width="160" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="primary" @click="viewBtnFC(scope.row)">查看</el-button>
|
||||||
|
<el-button size="mini" type="warning" @click="editBtnFC(scope.row)">修改</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 修改 -->
|
||||||
|
<el-dialog :visible.sync="editStatus" title="修改" :append-to-body="true" :before-close="edithandleClose">
|
||||||
|
<el-form :model="editClassForm" ref="editClassForm" label-width="110px">
|
||||||
|
<el-form-item label="接单单位名称" prop="cName">
|
||||||
|
<el-input v-model="editClassForm.cName" placeholder="请输入接单单位名称" disabled></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="是否接单" prop="isSetcTime">
|
||||||
|
<el-switch is-range v-model="editClassForm.isSetcTime" activate-color="#13ce66" inactive-color="#ff4949"
|
||||||
|
@change="isSetcTimeOnChange"></el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- <el-form-item label="接单时间" prop="cTime" v-show="editClassForm.isSetcTime">
|
||||||
|
<el-time-picker
|
||||||
|
is-range
|
||||||
|
v-model="editClassForm.cTime"
|
||||||
|
start-placeholder="开始时间"
|
||||||
|
end-placeholder="结束时间"
|
||||||
|
format="HH:ss:mm"
|
||||||
|
placeholder="选择时间范围"
|
||||||
|
@change="cTimeOnChange"
|
||||||
|
></el-time-picker>
|
||||||
|
</el-form-item> -->
|
||||||
|
|
||||||
|
<el-form-item label="接单时间" prop="cTime" v-show="editClassForm.isSetcTime">
|
||||||
|
<!-- <el-input v-model="editClassForm.cTime" placeholder="请输入当前班组接单时间,如果有多个请用、隔开(例:周一、周六、周日)"></el-input>
|
||||||
|
-->
|
||||||
|
<el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选
|
||||||
|
</el-checkbox>
|
||||||
|
<el-checkbox-group v-model="selectedDays">
|
||||||
|
<el-checkbox v-for="day in weekOptions" :key="day.value" :label="day.value">{{ day.label }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="接单人姓名" prop="pName">
|
||||||
|
<el-input v-model="editClassForm.pName" placeholder="请输入接单人姓名"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="接单人账号" prop="pCode">
|
||||||
|
<el-input v-model="editClassForm.pCode" placeholder="请输入接单人账号"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="接单人手机号" prop="wName">
|
||||||
|
<el-input v-model="editClassForm.wName" placeholder="请输入接单人手机号"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="editClassFC()" size="small" style="background: #018c87; color: #fff">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
<!-- 查看 -->
|
||||||
|
<el-dialog :visible.sync="viewStatus" title="查看" :append-to-body="true" :before-close="viewhandleClose">
|
||||||
|
<el-form :model="editClassForm" ref="editClassForm" label-width="110px">
|
||||||
|
<el-form-item label="接单单位名称" prop="cName">
|
||||||
|
<el-input v-model="editClassForm.cName" placeholder="请输入接单单位名称" disabled></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="设置接单时间" prop="isSetcTime">
|
||||||
|
<el-switch is-range v-model="editClassForm.isSetcTime" activate-color="#13ce66" inactive-color="#ff4949"
|
||||||
|
disabled></el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="接单时间" prop="cTime" v-show="editClassForm.isSetcTime">
|
||||||
|
<!-- <el-input v-model="editClassForm.cTime" placeholder="请输入当前班组接单时间,如果有多个请用、隔开(例:周一、周六、周日)"></el-input>
|
||||||
|
-->
|
||||||
|
<el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange" disabled>全选
|
||||||
|
</el-checkbox>
|
||||||
|
<el-checkbox-group v-model="selectedDays" disabled>
|
||||||
|
<el-checkbox v-for="day in weekOptions" :key="day.value" :label="day.value">{{ day.label }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="接单人姓名" prop="pName">
|
||||||
|
<el-input v-model="editClassForm.pName" placeholder="请输入接单人姓名" disabled></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="接单人账号" prop="pCode">
|
||||||
|
<el-input v-model="editClassForm.pCode" placeholder="请输入接单人账号" disabled></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="接单人手机号" prop="wName">
|
||||||
|
<el-input v-model="editClassForm.wName" placeholder="请输入接单人手机号" disabled></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
var mac = new Vue({
|
||||||
|
el: "#app",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 修改接单班组
|
||||||
|
editClassForm: {
|
||||||
|
orgId: "",
|
||||||
|
cName: "",
|
||||||
|
isSetcTime: false,
|
||||||
|
cTime: "",
|
||||||
|
scope: "",
|
||||||
|
pName: "",
|
||||||
|
pCode: "",
|
||||||
|
type: "",
|
||||||
|
wName: "",
|
||||||
|
},
|
||||||
|
classList: [],
|
||||||
|
allclassList: [],
|
||||||
|
disabled: true,
|
||||||
|
editStatus: false,
|
||||||
|
viewStatus: false,
|
||||||
|
labelText: "",
|
||||||
|
editlabelText: "",
|
||||||
|
placeholder: "",
|
||||||
|
formInfo: {},
|
||||||
|
checkAll: false,
|
||||||
|
isIndeterminate: false,
|
||||||
|
selectedDays: [],
|
||||||
|
weekOptions: [
|
||||||
|
{ label: '周一', value: '周一' },
|
||||||
|
{ label: '周二', value: '周二' },
|
||||||
|
{ label: '周三', value: '周三' },
|
||||||
|
{ label: '周四', value: '周四' },
|
||||||
|
{ label: '周五', value: '周五' },
|
||||||
|
{ label: '周六', value: '周六' },
|
||||||
|
{ label: '周日', value: '周日' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
selectedDays(newVal) {
|
||||||
|
const len = this.weekOptions.length;
|
||||||
|
if (newVal.length === 0) {
|
||||||
|
this.checkAll = false;
|
||||||
|
this.isIndeterminate = false;
|
||||||
|
} else if (newVal.lengtht === len) {
|
||||||
|
this.checkAll = true;
|
||||||
|
this.isIndeterminate = false;
|
||||||
|
} else {
|
||||||
|
this.checkAll = false;
|
||||||
|
this.isIndeterminate = true;
|
||||||
|
}
|
||||||
|
this.editClassForm.cTime = newVal.join(',')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.setStorage(localStorage.tGfUser)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setStorage(obj) {
|
||||||
|
// console.log(obj);
|
||||||
|
const mac = this;
|
||||||
|
sessionStorage.setItem("tGfUser", obj);
|
||||||
|
const tGfUser = JSON.parse(sessionStorage.getItem("tGfUser"));
|
||||||
|
mac.formInfo = {
|
||||||
|
cityCode: tGfUser.orgNo, //机构码
|
||||||
|
cityName: tGfUser.orgName, //机构名称 比如 国网嘉峪关供电公司
|
||||||
|
userNameIV: tGfUser.name, //大四区登录的人名
|
||||||
|
userCodeIV: tGfUser.id, //大四区登录账号
|
||||||
|
};
|
||||||
|
mac.zdpdFc({ name: "户表失电-嘉峪关" });
|
||||||
|
},
|
||||||
|
// 自动派单配置图标点击弹出配置弹出框
|
||||||
|
zdpdFc(x) {
|
||||||
|
// 区县级表头名称
|
||||||
|
if (x.name == "95598抢修") {
|
||||||
|
this.labelText = "当前接单单位管辖的所有地址名称";
|
||||||
|
this.editlabelText = "地址名称";
|
||||||
|
this.placeholder = "请输入地址名称";
|
||||||
|
} else {
|
||||||
|
this.labelText = "当前接单单位管辖的所有配变名称";
|
||||||
|
this.editlabelText = "配变名称";
|
||||||
|
this.placeholder = "请输入配变名称";
|
||||||
|
}
|
||||||
|
this.editClassForm.type = x.name;
|
||||||
|
// this.getUrl(x.name);
|
||||||
|
this.gethngdsList(x.name)
|
||||||
|
},
|
||||||
|
// 抓取浏览器地址
|
||||||
|
// getUrl() {
|
||||||
|
// window.getAllUrlCallBack = (urls) => {
|
||||||
|
// var urlArr = urls.split(";");
|
||||||
|
// let hasPage = false;
|
||||||
|
// let hasPage1 = false;
|
||||||
|
// let home = null;
|
||||||
|
// urlArr.forEach((item) => {
|
||||||
|
// if (item.indexOf("http://21.77.244.194:18890/") !== -1) {
|
||||||
|
// hasPage = true;
|
||||||
|
// home = item;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// if (hasPage) {
|
||||||
|
// mac.gethngdsList("户表失电", home);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// dpage.dPageGetUrl(true, "window.getAllUrlCallBack");
|
||||||
|
// },
|
||||||
|
// 获取大IV中班组信息
|
||||||
|
gethngdsList(name) {
|
||||||
|
const mac = this;
|
||||||
|
axios.post(`http://21.77.244.194:18890/system/organization/queryOrgBylevel/${mac.formInfo.cityCode}/bz`, '', {
|
||||||
|
baseurl: 'http://21.77.244.194:18890/#/webview/1543953229739896',
|
||||||
|
headers: {
|
||||||
|
'Accept': '*/*',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Userid': `${mac.formInfo.userCodeIV}`
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
if (res.status == '200' && res.data.msg == 'success' && res.data.orgs.length) {
|
||||||
|
let list = res.data.orgs.forEach((item) => {
|
||||||
|
mac.classList.push({
|
||||||
|
orgId: item.orgId,
|
||||||
|
type: "",
|
||||||
|
cName: item.orgName,
|
||||||
|
scope: "",
|
||||||
|
pName: "",
|
||||||
|
pCode: "",
|
||||||
|
wName: "",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(mac.classList)
|
||||||
|
mac.getClassList(name);
|
||||||
|
mac.$message({
|
||||||
|
message: "接单班组信息获取成功!",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).catch(error => {
|
||||||
|
mac.$message({
|
||||||
|
message: "接单班组信息获取失败!",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
// 查询接单班组
|
||||||
|
getClassList(name) {
|
||||||
|
$.ajax({
|
||||||
|
url: "http://localhost:13313/MonitorServices/getClassList",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
crossDomain: true,
|
||||||
|
data: JSON.stringify({ type: name }),
|
||||||
|
contentType: "application/json", //指定中容格式
|
||||||
|
success: (res) => {
|
||||||
|
//括号里的data是服务器返回的数据
|
||||||
|
if (res.status == 200) {
|
||||||
|
if (res.data.length > 0) {
|
||||||
|
res.data.forEach((item) => {
|
||||||
|
item.status = false; //按钮状态
|
||||||
|
});
|
||||||
|
mac.allclassList = res.data;
|
||||||
|
} else {
|
||||||
|
let arrList = [];
|
||||||
|
mac.classList.forEach((item) => {
|
||||||
|
if (!arrList.some((e) => e.orgId == item.orgId)) {
|
||||||
|
arrList.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
arrList.forEach((x) => {
|
||||||
|
x.type = name;
|
||||||
|
mac.setClassList(x);
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
this.getClassList(name);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 存储接单班组
|
||||||
|
setClassList(val) {
|
||||||
|
$.ajax({
|
||||||
|
url: "http://localhost:13313/MonitorServices/setClassList",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
crossDomain: true,
|
||||||
|
data: JSON.stringify(val), //必须是字符串格式
|
||||||
|
contentType: "application/json",
|
||||||
|
success: (res) => { },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
handleCheckAllChange(val) {
|
||||||
|
this.selectedDays = val ? this.weekOptions.map(item => item.value) : [];
|
||||||
|
this.isIndeterminate = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 修改
|
||||||
|
editBtnFC(e) {
|
||||||
|
this.editStatus = true;
|
||||||
|
e.isSetcTime = e.isSetcTime == "1" ? true : false;
|
||||||
|
this.selectedDays = e.cTime == '' || e.cTime == null ? [] : e.cTime.split(',');
|
||||||
|
this.editClassForm = JSON.parse(JSON.stringify(e));
|
||||||
|
// 时间格式化
|
||||||
|
if (e.cTime && typeof e.cTime === "string" && e.cTime.includes("~")) {
|
||||||
|
const timeParts = e.cTime.split("~");
|
||||||
|
this.editClassForm.cTime = [moment().format("YYYY-MM-DD") + " " + timeParts[0], moment().format("YYYY-MM-DD") + " " + timeParts[1]];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 查看
|
||||||
|
viewBtnFC(e) {
|
||||||
|
this.viewStatus = true;
|
||||||
|
e.isSetcTime = e.isSetcTime == "1" ? true : false;
|
||||||
|
this.selectedDays = e.cTime == '' || e.cTime == null ? [] : e.cTime.split(',');
|
||||||
|
this.editClassForm = JSON.parse(JSON.stringify(e));
|
||||||
|
// 时间格式化
|
||||||
|
if (e.cTime && typeof e.cTime === "string" && e.cTime.includes("~")) {
|
||||||
|
const timeParts = e.cTime.split("~");
|
||||||
|
this.editClassForm.cTime = [moment().format("YYYY-MM-DD") + " " + timeParts[0], moment().format("YYYY-MM-DD") + " " + timeParts[1]];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
edithandleClose() {
|
||||||
|
this.editStatus = false;
|
||||||
|
},
|
||||||
|
viewhandleClose() {
|
||||||
|
this.viewStatus = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
isSetcTimeOnChange(e) {
|
||||||
|
this.editClassForm.isSetcTime = e;
|
||||||
|
if (e == false) {
|
||||||
|
this.editClassForm.cTime = "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 修改后保存按钮
|
||||||
|
editClassFC() {
|
||||||
|
const formData = { ...this.editClassForm };
|
||||||
|
// if (Array.isArray(formData.cTime)) {
|
||||||
|
// formData.cTime = moment(formData.cTime[0]).format("HH:mm:ss") + "~" + moment(formData.cTime[1]).format("HH:mm:ss");
|
||||||
|
// }
|
||||||
|
|
||||||
|
console.log(this.selectedDays)
|
||||||
|
$.ajax({
|
||||||
|
// url: "http://localhost:13313/MonitorServices/editClassList",
|
||||||
|
url: "http://localhost:13313/MonitorServices/editClassList",
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
crossDomain: true,
|
||||||
|
data: JSON.stringify(formData), //必须是字符串格式
|
||||||
|
contentType: "application/json",
|
||||||
|
success: (res) => {
|
||||||
|
if (res.status == 200) {
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "修改成功!",
|
||||||
|
});
|
||||||
|
this.editStatus = false;
|
||||||
|
mac.getClassList(this.editClassForm.type);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# Collection Flow
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
- Source page: `D:\desk\智能体资料\大四区报告监测项\户表失电-嘉峪关\index.html`
|
||||||
|
- Rule assets (scheduled workflow source-of-truth):
|
||||||
|
- `D:/desk/智能体资料/大四区报告监测项/户表失电-嘉峪关_业务监测配置.txt`
|
||||||
|
- `D:/desk/智能体资料/大四区报告监测项/户表失电-嘉峪关_自动处理配置.txt`
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
The page focuses on class-list and auto-processing configuration (`assets/scene-snapshot/index.html` is configuration-only). The monitoring package combines outage-event collection, service-order enrichment, historical pending comparison, and downstream auto-processing context from the desk rule source-of-truth scripts.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- Current platform session and user context
|
||||||
|
- Current org context from the outage platform
|
||||||
|
- Marketing-system token context used by downstream enrichment flows
|
||||||
|
- Browser-visible class-list configuration
|
||||||
|
- Local monitor-log and dispose-log context from localhost services
|
||||||
|
- The current outage and service-order query windows
|
||||||
|
|
||||||
|
## First-pass Collection Steps
|
||||||
|
|
||||||
|
1. Open or attach to the outage configuration page.
|
||||||
|
2. Verify required platform-session, org, and token context is available.
|
||||||
|
3. Read the scheduled workflow rule scripts from desk source-of-truth to understand outage-event, service-order, historical comparison, and auto-processing semantics.
|
||||||
|
4. Trigger the deterministic outage collector through BrowserAction / browser-side request execution.
|
||||||
|
5. Query current outage events from the outage source.
|
||||||
|
6. Query related service-order states from the active-service order source.
|
||||||
|
7. Normalize source results into `pending`, `audit`, `processed`, `pending_ids`, and `new_pending_ids` using packaged runtime collector logic while preserving the `consNo` vs `eventId` identity mismatch note.
|
||||||
|
8. Compare with local monitor/dispose logs only as downstream context.
|
||||||
|
9. Return a structured monitor snapshot before downstream audio reminder or auto-processing side effects.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- BrowserAction or equivalent browser-side request execution
|
||||||
|
- Platform-visible session, org, and user context
|
||||||
|
- Optional marketing token context for downstream enrichment / dispatch flows
|
||||||
|
- Upstream outage endpoints under `http://21.77.244.194:18890/outage/dhsd/*`
|
||||||
|
- Upstream service-order endpoints under `http://21.77.244.194:18890/gdgl/active/service/order/*`
|
||||||
|
- Localhost services under `http://localhost:13313/MonitorServices/*`
|
||||||
|
- Localhost config services used by the source configuration page
|
||||||
|
|
||||||
|
## State Semantics
|
||||||
|
|
||||||
|
- Success: outage events are collected, service-order states are collected, and the snapshot is assembled with `success` status.
|
||||||
|
- Partial result: outage events are collected but order-state enrichment, historical comparison, local logging, downstream reminder / auto-processing side effects, or `consNo`→`eventId` identity crosswalk quality are incomplete.
|
||||||
|
- Empty result: a valid outage query returns zero relevant outage events for the chosen window.
|
||||||
|
- Blocked/error: login failure, missing context, token failure, interception failure, request failure, permission failure, or parse failure.
|
||||||
|
- Blocked/error must not be reported as empty data.
|
||||||
|
- Historical monitor logs and dispose logs are downstream comparison context, not the primary upstream business data source.
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# Data Quality
|
||||||
|
|
||||||
|
## Complete Result
|
||||||
|
|
||||||
|
A complete result means the outage-event source and the related service-order source are both available for the chosen windows, historical comparison is usable, and the monitor snapshot contains aligned values for:
|
||||||
|
|
||||||
|
- `pending`
|
||||||
|
- `audit`
|
||||||
|
- `processed`
|
||||||
|
- `pending_ids`
|
||||||
|
- `new_pending_ids`
|
||||||
|
|
||||||
|
## Snapshot Rules
|
||||||
|
|
||||||
|
The packaged first-pass snapshot uses:
|
||||||
|
|
||||||
|
- outage-event rows as the primary source for `pending` and `pending_ids`
|
||||||
|
- service-order rows to derive `audit` and `processed`
|
||||||
|
- historical monitor/dispose logs only to derive `new_pending_ids`
|
||||||
|
|
||||||
|
If the package later expands to more status buckets, update the contract before surfacing them as first-pass counters.
|
||||||
|
|
||||||
|
## Partial Rules
|
||||||
|
|
||||||
|
- If outage events are collected but service-order enrichment fails, set `status` to `partial`.
|
||||||
|
- If outage events and service-order states are collected but monitor-log or dispose-log parsing/comparison fails, set `status` to `partial`.
|
||||||
|
- If snapshot assembly succeeds but monitor-log write, monitor-data write, dispose-log write, or audio-log write fails, keep the snapshot and set `status` to `partial`.
|
||||||
|
- If pending-id comparison is unavailable, do not claim full completeness.
|
||||||
|
- Do not report the run as fully complete when only outage rows are present without usable comparison context.
|
||||||
|
|
||||||
|
## Common Weak Areas
|
||||||
|
|
||||||
|
- Missing platform session, org, or marketing token context
|
||||||
|
- Outage response parse failure
|
||||||
|
- Service-order response parse failure
|
||||||
|
- Historical dispose-log parse failure
|
||||||
|
- Local `MonitorServices` failure after snapshot assembly
|
||||||
|
- Audio reminder or auto-processing side effects failing after collection
|
||||||
|
|
||||||
|
## Empty vs Failure
|
||||||
|
|
||||||
|
- A valid outage request with zero relevant outage events is empty data.
|
||||||
|
- Login failure, blocked page, missing context, token failure, request failure, interception failure, permission failure, or parse failure must be surfaced as failure or partial, not empty.
|
||||||
|
|
||||||
|
## Dependency Warnings
|
||||||
|
|
||||||
|
- Localhost service availability affects snapshot completeness.
|
||||||
|
- Historical comparison quality depends on prior monitor/dispose log integrity.
|
||||||
|
- Audio reminder or auto-processing side effects must never replace the underlying snapshot result.
|
||||||
@@ -0,0 +1,344 @@
|
|||||||
|
const SOURCE_GROUPS = {
|
||||||
|
outage_events: "http://21.77.244.194:18890/outage/dhsd/dhsdList",
|
||||||
|
service_orders: "http://21.77.244.194:18890/gdgl/active/service/order/list"
|
||||||
|
};
|
||||||
|
|
||||||
|
const LOCAL_SERVICE_ENDPOINTS = [
|
||||||
|
"http://localhost:13313/MonitorServices/getMonitorLog",
|
||||||
|
"http://localhost:13313/MonitorServices/setMonitorData",
|
||||||
|
"http://localhost:13313/MonitorServices/setMonitorLog",
|
||||||
|
"http://localhost:13313/MonitorServices/getDisposeLog",
|
||||||
|
"http://localhost:13313/MonitorServices/setDisposeLog",
|
||||||
|
"http://localhost:13313/MonitorServices/setAudioPlayLog"
|
||||||
|
];
|
||||||
|
|
||||||
|
const WORKFLOW_RULE_SOURCES = [
|
||||||
|
"D:/desk/智能体资料/大四区报告监测项/户表失电-嘉峪关_业务监测配置.txt",
|
||||||
|
"D:/desk/智能体资料/大四区报告监测项/户表失电-嘉峪关_自动处理配置.txt"
|
||||||
|
];
|
||||||
|
|
||||||
|
const CONFIG_BASE_PAGE = "assets/scene-snapshot/index.html";
|
||||||
|
|
||||||
|
const IDENTITY_MODEL = {
|
||||||
|
pending_identity: "consNo",
|
||||||
|
dispose_dedupe_identity: "eventId",
|
||||||
|
status: "implementation intent exists but not rigorous / buggy"
|
||||||
|
};
|
||||||
|
|
||||||
|
function asArray(value) {
|
||||||
|
return Array.isArray(value) ? value : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeId(value) {
|
||||||
|
if (value === null || value === undefined || value === "") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function uniq(values) {
|
||||||
|
return Array.from(new Set(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
function looksLikeJsonString(value) {
|
||||||
|
if (typeof value !== "string") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const trimmed = value.trim();
|
||||||
|
return trimmed.startsWith("[") || trimmed.startsWith("{") || trimmed.startsWith("\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseLooseJson(value, depth = 0) {
|
||||||
|
if (depth > 4 || value === null || value === undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value !== "string") {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimmed = value.trim();
|
||||||
|
if (!trimmed) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(trimmed);
|
||||||
|
return parseLooseJson(parsed, depth + 1);
|
||||||
|
} catch {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function classifyServiceOrders(serviceOrders = []) {
|
||||||
|
const auditOrders = [];
|
||||||
|
const processedOrders = [];
|
||||||
|
const unknownStatusLabels = [];
|
||||||
|
|
||||||
|
asArray(serviceOrders).forEach((item) => {
|
||||||
|
const statusLabel = normalizeId(item && item.gdztmc);
|
||||||
|
if (statusLabel === "待审核") {
|
||||||
|
auditOrders.push(item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (statusLabel === "已归档") {
|
||||||
|
processedOrders.push(item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (statusLabel) {
|
||||||
|
unknownStatusLabels.push(statusLabel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
auditOrders,
|
||||||
|
processedOrders,
|
||||||
|
unknownStatusLabels: uniq(unknownStatusLabels)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildOutageContext(outageEvents = []) {
|
||||||
|
const pendingIds = [];
|
||||||
|
const eventIds = [];
|
||||||
|
const eventIdsByConsNo = {};
|
||||||
|
|
||||||
|
asArray(outageEvents).forEach((item) => {
|
||||||
|
const consNo = normalizeId(item && item.consNo);
|
||||||
|
const eventId = normalizeId(item && item.eventId);
|
||||||
|
|
||||||
|
if (consNo) {
|
||||||
|
pendingIds.push(consNo);
|
||||||
|
if (!eventIdsByConsNo[consNo]) {
|
||||||
|
eventIdsByConsNo[consNo] = [];
|
||||||
|
}
|
||||||
|
if (eventId) {
|
||||||
|
eventIdsByConsNo[consNo].push(eventId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventId) {
|
||||||
|
eventIds.push(eventId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(eventIdsByConsNo).forEach((consNo) => {
|
||||||
|
eventIdsByConsNo[consNo] = uniq(eventIdsByConsNo[consNo]);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
pendingIds: uniq(pendingIds),
|
||||||
|
eventIds: uniq(eventIds),
|
||||||
|
eventIdsByConsNo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractMonitorPendingIds(monitorLogs = []) {
|
||||||
|
const ids = [];
|
||||||
|
let malformed = false;
|
||||||
|
|
||||||
|
asArray(monitorLogs).forEach((item) => {
|
||||||
|
const pendingIds = asArray(item && item.pending_ids)
|
||||||
|
.map(normalizeId)
|
||||||
|
.filter(Boolean);
|
||||||
|
if (pendingIds.length > 0) {
|
||||||
|
ids.push(...pendingIds);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rawPendingList = item && item.pendingList;
|
||||||
|
const pendingList = parseLooseJson(rawPendingList);
|
||||||
|
if (Array.isArray(pendingList)) {
|
||||||
|
pendingList
|
||||||
|
.map(normalizeId)
|
||||||
|
.filter(Boolean)
|
||||||
|
.forEach((id) => ids.push(id));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (looksLikeJsonString(rawPendingList)) {
|
||||||
|
malformed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
ids: uniq(ids),
|
||||||
|
malformed
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractDisposeEventIds(disposeLogs = []) {
|
||||||
|
const ids = [];
|
||||||
|
let malformed = false;
|
||||||
|
|
||||||
|
asArray(disposeLogs).forEach((item) => {
|
||||||
|
const rawOrderPayload = item && item.orderID;
|
||||||
|
const orderPayload = parseLooseJson(rawOrderPayload);
|
||||||
|
if (Array.isArray(orderPayload)) {
|
||||||
|
orderPayload.forEach((entry) => {
|
||||||
|
const eventId = normalizeId(entry && (entry.eventId || entry.id || entry.orderID));
|
||||||
|
if (eventId) {
|
||||||
|
ids.push(eventId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (entry && typeof entry === "object") {
|
||||||
|
malformed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const scalarEntry = normalizeId(entry);
|
||||||
|
if (scalarEntry) {
|
||||||
|
ids.push(scalarEntry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rawLooksJson = looksLikeJsonString(rawOrderPayload);
|
||||||
|
if (rawLooksJson && orderPayload === rawOrderPayload) {
|
||||||
|
malformed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const scalarId = normalizeId(orderPayload);
|
||||||
|
if (scalarId && (!rawLooksJson || orderPayload !== rawOrderPayload)) {
|
||||||
|
ids.push(scalarId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawLooksJson) {
|
||||||
|
malformed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
ids: uniq(ids),
|
||||||
|
malformed
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function determineStatus({ blocked, hasData, partialReasons }) {
|
||||||
|
if (blocked) {
|
||||||
|
return "blocked";
|
||||||
|
}
|
||||||
|
if (partialReasons.length > 0) {
|
||||||
|
return "partial";
|
||||||
|
}
|
||||||
|
if (!hasData) {
|
||||||
|
return "empty";
|
||||||
|
}
|
||||||
|
return "success";
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectOutageEvents(input = {}) {
|
||||||
|
const blockedReason = normalizeId(input.blocked_reason);
|
||||||
|
const outageEvents = asArray(input.outage_events);
|
||||||
|
const serviceOrders = asArray(input.service_orders);
|
||||||
|
const monitorLogs = asArray(input.monitor_logs || input.monitor_log);
|
||||||
|
const disposeLogs = asArray(input.dispose_logs || input.dispose_log);
|
||||||
|
const localWriteFailures = asArray(input.local_write_failures)
|
||||||
|
.map(normalizeId)
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
const partialReasons = [];
|
||||||
|
|
||||||
|
const outageContext = buildOutageContext(outageEvents);
|
||||||
|
const { auditOrders, processedOrders, unknownStatusLabels } = classifyServiceOrders(serviceOrders);
|
||||||
|
|
||||||
|
if (unknownStatusLabels.length > 0) {
|
||||||
|
partialReasons.push(`service_order_status_unclassified:${unknownStatusLabels.join(",")}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let monitorPendingIds = [];
|
||||||
|
let disposedEventIds = [];
|
||||||
|
|
||||||
|
if (outageContext.pendingIds.length > 0) {
|
||||||
|
if (monitorLogs.length === 0) {
|
||||||
|
partialReasons.push("monitor_log_unavailable");
|
||||||
|
} else {
|
||||||
|
const extractedMonitor = extractMonitorPendingIds(monitorLogs);
|
||||||
|
monitorPendingIds = extractedMonitor.ids;
|
||||||
|
if (extractedMonitor.malformed) {
|
||||||
|
partialReasons.push("monitor_log_parse_failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disposeLogs.length === 0) {
|
||||||
|
partialReasons.push("dispose_log_unavailable");
|
||||||
|
} else {
|
||||||
|
const extractedDispose = extractDisposeEventIds(disposeLogs);
|
||||||
|
disposedEventIds = extractedDispose.ids;
|
||||||
|
if (extractedDispose.malformed) {
|
||||||
|
partialReasons.push("dispose_log_parse_failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outageContext.pendingIds.length > 0 && outageContext.eventIds.length === 0) {
|
||||||
|
partialReasons.push("event_identity_missing_for_pending");
|
||||||
|
}
|
||||||
|
|
||||||
|
const ambiguousIdentityConsNos = outageContext.pendingIds.filter((consNo) => {
|
||||||
|
const relatedEventIds = asArray(outageContext.eventIdsByConsNo[consNo]);
|
||||||
|
return relatedEventIds.length > 1;
|
||||||
|
});
|
||||||
|
if (ambiguousIdentityConsNos.length > 0) {
|
||||||
|
partialReasons.push(`identity_crosswalk_ambiguous:${ambiguousIdentityConsNos.join(",")}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
localWriteFailures.forEach((failure) => {
|
||||||
|
partialReasons.push(`local_write_failed:${failure}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
const monitorSet = new Set(monitorPendingIds);
|
||||||
|
const disposedEventSet = new Set(disposedEventIds);
|
||||||
|
const newPendingIds = outageContext.pendingIds.filter((consNo) => {
|
||||||
|
const relatedEventIds = asArray(outageContext.eventIdsByConsNo[consNo]);
|
||||||
|
const unseenByMonitor = !monitorSet.has(consNo);
|
||||||
|
const unseenByDispose = relatedEventIds.length === 0
|
||||||
|
? true
|
||||||
|
: relatedEventIds.every((eventId) => !disposedEventSet.has(eventId));
|
||||||
|
return unseenByMonitor && unseenByDispose;
|
||||||
|
});
|
||||||
|
|
||||||
|
const hasData = outageEvents.length > 0;
|
||||||
|
const blocked = Boolean(input.blocked) || Boolean(blockedReason);
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: "monitor-snapshot",
|
||||||
|
scene: "jiayuguan-meter-outage",
|
||||||
|
time: input.time || "",
|
||||||
|
pending: outageContext.pendingIds.length,
|
||||||
|
audit: auditOrders.length,
|
||||||
|
processed: processedOrders.length,
|
||||||
|
pending_ids: outageContext.pendingIds,
|
||||||
|
new_pending_ids: uniq(newPendingIds),
|
||||||
|
status: determineStatus({
|
||||||
|
blocked,
|
||||||
|
hasData,
|
||||||
|
partialReasons
|
||||||
|
}),
|
||||||
|
partial_reasons: uniq(
|
||||||
|
blockedReason ? [...partialReasons, blockedReason] : partialReasons
|
||||||
|
),
|
||||||
|
evidence: {
|
||||||
|
workflow_rule_sources: WORKFLOW_RULE_SOURCES,
|
||||||
|
config_base_page: CONFIG_BASE_PAGE,
|
||||||
|
config_base_role: "configuration-only",
|
||||||
|
packaged_collector_role: "runtime-snapshot-collector"
|
||||||
|
},
|
||||||
|
identity_model: IDENTITY_MODEL
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
SOURCE_GROUPS,
|
||||||
|
LOCAL_SERVICE_ENDPOINTS,
|
||||||
|
WORKFLOW_RULE_SOURCES,
|
||||||
|
CONFIG_BASE_PAGE,
|
||||||
|
IDENTITY_MODEL,
|
||||||
|
classifyServiceOrders,
|
||||||
|
buildOutageContext,
|
||||||
|
extractMonitorPendingIds,
|
||||||
|
extractDisposeEventIds,
|
||||||
|
determineStatus,
|
||||||
|
collectOutageEvents
|
||||||
|
};
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
|
||||||
|
const {
|
||||||
|
classifyServiceOrders,
|
||||||
|
buildOutageContext,
|
||||||
|
extractMonitorPendingIds,
|
||||||
|
extractDisposeEventIds,
|
||||||
|
determineStatus,
|
||||||
|
collectOutageEvents
|
||||||
|
} = require('./collect_outage_events.js');
|
||||||
|
|
||||||
|
test('classifyServiceOrders buckets audit/processed and keeps unknown labels', () => {
|
||||||
|
const result = classifyServiceOrders([
|
||||||
|
{ gdztmc: '待审核' },
|
||||||
|
{ gdztmc: '已归档' },
|
||||||
|
{ gdztmc: '处理中' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert.equal(result.auditOrders.length, 1);
|
||||||
|
assert.equal(result.processedOrders.length, 1);
|
||||||
|
assert.deepEqual(result.unknownStatusLabels, ['处理中']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('buildOutageContext extracts consNo pending ids and event ids', () => {
|
||||||
|
const context = buildOutageContext([
|
||||||
|
{ consNo: 'C1', eventId: 'E1' },
|
||||||
|
{ consNo: 'C2', eventId: 'E2' },
|
||||||
|
{ consNo: 'C1', eventId: 'E1' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert.deepEqual(context.pendingIds, ['C1', 'C2']);
|
||||||
|
assert.deepEqual(context.eventIds, ['E1', 'E2']);
|
||||||
|
assert.deepEqual(context.eventIdsByConsNo, { C1: ['E1'], C2: ['E2'] });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('extractMonitorPendingIds parses pending_ids and nested pendingList', () => {
|
||||||
|
const logs = [
|
||||||
|
{ pending_ids: ['C1'] },
|
||||||
|
{ pendingList: JSON.stringify(['C2']) },
|
||||||
|
{ pendingList: JSON.stringify(JSON.stringify(['C3'])) }
|
||||||
|
];
|
||||||
|
|
||||||
|
assert.deepEqual(extractMonitorPendingIds(logs), { ids: ['C1', 'C2', 'C3'], malformed: false });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('extractDisposeEventIds parses nested orderID payloads', () => {
|
||||||
|
const logs = [
|
||||||
|
{ orderID: JSON.stringify([{ id: 'E1' }, { eventId: 'E2' }]) },
|
||||||
|
{ orderID: JSON.stringify(JSON.stringify([{ id: 'E3' }])) },
|
||||||
|
{ orderID: 'E4' }
|
||||||
|
];
|
||||||
|
|
||||||
|
assert.deepEqual(extractDisposeEventIds(logs), { ids: ['E1', 'E2', 'E3', 'E4'], malformed: false });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('extractors mark malformed payloads when JSON-like strings cannot be parsed', () => {
|
||||||
|
const monitor = extractMonitorPendingIds([{ pendingList: '{bad-json' }]);
|
||||||
|
const dispose = extractDisposeEventIds([{ orderID: '[{"id":"E1"}, {' }]);
|
||||||
|
|
||||||
|
assert.deepEqual(monitor, { ids: [], malformed: true });
|
||||||
|
assert.deepEqual(dispose, { ids: [], malformed: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('determineStatus follows blocked > partial > empty > success precedence', () => {
|
||||||
|
assert.equal(determineStatus({ blocked: true, hasData: true, partialReasons: [] }), 'blocked');
|
||||||
|
assert.equal(determineStatus({ blocked: false, hasData: true, partialReasons: ['x'] }), 'partial');
|
||||||
|
assert.equal(determineStatus({ blocked: false, hasData: false, partialReasons: [] }), 'empty');
|
||||||
|
assert.equal(determineStatus({ blocked: false, hasData: true, partialReasons: [] }), 'success');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('collectOutageEvents builds snapshot using outage and service-order inputs', () => {
|
||||||
|
const snapshot = collectOutageEvents({
|
||||||
|
time: '2026-04-08 10:00:00',
|
||||||
|
outage_events: [
|
||||||
|
{ consNo: 'C1', eventId: 'E1' },
|
||||||
|
{ consNo: 'C2', eventId: 'E2' }
|
||||||
|
],
|
||||||
|
service_orders: [
|
||||||
|
{ gdztmc: '待审核' },
|
||||||
|
{ gdztmc: '已归档' }
|
||||||
|
],
|
||||||
|
monitor_logs: [{ pendingList: JSON.stringify(['C1']) }],
|
||||||
|
dispose_logs: [{ orderID: JSON.stringify([{ id: 'E2' }]) }]
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(snapshot.scene, 'jiayuguan-meter-outage');
|
||||||
|
assert.equal(snapshot.pending, 2);
|
||||||
|
assert.equal(snapshot.audit, 1);
|
||||||
|
assert.equal(snapshot.processed, 1);
|
||||||
|
assert.deepEqual(snapshot.pending_ids, ['C1', 'C2']);
|
||||||
|
assert.deepEqual(snapshot.new_pending_ids, []);
|
||||||
|
assert.equal(snapshot.status, 'success');
|
||||||
|
assert.equal(snapshot.partial_reasons.length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('collectOutageEvents reports partial when comparison logs are missing', () => {
|
||||||
|
const snapshot = collectOutageEvents({
|
||||||
|
outage_events: [{ consNo: 'C1', eventId: 'E1' }],
|
||||||
|
service_orders: []
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(snapshot.status, 'partial');
|
||||||
|
assert.deepEqual(snapshot.partial_reasons.sort(), [
|
||||||
|
'dispose_log_unavailable',
|
||||||
|
'monitor_log_unavailable'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('collectOutageEvents reports partial when one consNo maps to multiple event ids', () => {
|
||||||
|
const snapshot = collectOutageEvents({
|
||||||
|
outage_events: [
|
||||||
|
{ consNo: 'C1', eventId: 'E1' },
|
||||||
|
{ consNo: 'C1', eventId: 'E2' }
|
||||||
|
],
|
||||||
|
monitor_logs: [{ pendingList: JSON.stringify([]) }],
|
||||||
|
dispose_logs: [{ orderID: JSON.stringify([]) }]
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(snapshot.status, 'partial');
|
||||||
|
assert.ok(snapshot.partial_reasons.includes('identity_crosswalk_ambiguous:C1'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('collectOutageEvents reports blocked when blocked reason exists', () => {
|
||||||
|
const snapshot = collectOutageEvents({
|
||||||
|
blocked_reason: 'missing_marketing_token',
|
||||||
|
outage_events: [{ consNo: 'C1', eventId: 'E1' }],
|
||||||
|
monitor_logs: [{ pendingList: '[]' }],
|
||||||
|
dispose_logs: [{ orderID: '[]' }]
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(snapshot.status, 'blocked');
|
||||||
|
assert.ok(snapshot.partial_reasons.includes('missing_marketing_token'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('collectOutageEvents reports empty for valid empty outage result', () => {
|
||||||
|
const snapshot = collectOutageEvents({
|
||||||
|
outage_events: []
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(snapshot.status, 'empty');
|
||||||
|
assert.equal(snapshot.pending, 0);
|
||||||
|
assert.deepEqual(snapshot.pending_ids, []);
|
||||||
|
assert.deepEqual(snapshot.new_pending_ids, []);
|
||||||
|
});
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
---
|
||||||
|
name: jinchang-business-environment-weekly-report
|
||||||
|
description: Use when the user wants to collect Jinchang business-environment meeting metrics and generate a weekly report artifact.
|
||||||
|
version: 0.1.0
|
||||||
|
author: sgclaw
|
||||||
|
tags:
|
||||||
|
- jinchang
|
||||||
|
- business-environment
|
||||||
|
- weekly-report
|
||||||
|
- browser
|
||||||
|
- report
|
||||||
|
---
|
||||||
|
|
||||||
|
# Jinchang Business Environment Weekly Report
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
- The user asks to collect weekly business-environment metrics for Jinchang.
|
||||||
|
- The user asks to generate a weekly meeting report artifact.
|
||||||
|
- The task needs a structured summary for downstream Word or Excel export.
|
||||||
|
- The task needs one report artifact assembled from multiple metric groups and multiple system queries.
|
||||||
|
|
||||||
|
Do not use this skill for:
|
||||||
|
|
||||||
|
- unrelated city reporting
|
||||||
|
- pure template editing without data collection
|
||||||
|
- claiming complete output when only some metric groups are available
|
||||||
|
- treating historical report entries as the primary source data
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Read the selected weekly range from the page.
|
||||||
|
2. Verify required system-session context is available.
|
||||||
|
3. Collect the required business-environment metric groups from the source systems.
|
||||||
|
4. Map the metrics into standard report sections.
|
||||||
|
5. Return the structured artifact before prose.
|
||||||
|
6. If some sections are unavailable or period alignment is inconsistent, mark the result as partial.
|
||||||
|
|
||||||
|
## Runtime Contract
|
||||||
|
|
||||||
|
- Prefer deterministic extraction before generic browser probing.
|
||||||
|
- Treat login failure, blocked pages, request failure, partial source availability, and empty data as separate outcomes.
|
||||||
|
- Structured sections are the primary output contract.
|
||||||
|
- Historical report lists and final document download are downstream artifacts, not the primary business data source.
|
||||||
|
- Localhost report-log and export services must not redefine upstream collection success.
|
||||||
|
|
||||||
|
## Partial-Failure Rule
|
||||||
|
|
||||||
|
- If some sections are collected and others fail, report `partial`.
|
||||||
|
- If weekly period alignment across metric groups is inconsistent, report `partial`.
|
||||||
|
- If final export or report-log writing fails after section collection succeeds, keep the artifact and report `partial`.
|
||||||
|
- Do not flatten section-level failures into a full success.
|
||||||
|
|
||||||
|
## Export Artifact
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "report-artifact",
|
||||||
|
"report_name": "jinchang-business-environment-weekly-report",
|
||||||
|
"period": "",
|
||||||
|
"columns": [],
|
||||||
|
"rows": [],
|
||||||
|
"sections": [
|
||||||
|
{
|
||||||
|
"name": "abnormal-transformer-monitoring",
|
||||||
|
"columns": ["unit", "transformer_name", "abnormal_type", "note", "handling"],
|
||||||
|
"rows": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "power-outage-monitoring",
|
||||||
|
"columns": ["unit", "station", "event_type", "count", "note"],
|
||||||
|
"rows": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "work-order-acceptance",
|
||||||
|
"columns": ["category", "current_period", "previous_period", "trend", "note"],
|
||||||
|
"rows": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dispatch-summary",
|
||||||
|
"columns": ["metric", "value", "note"],
|
||||||
|
"rows": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "ok",
|
||||||
|
"partial_reasons": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
Return:
|
||||||
|
|
||||||
|
- operation type
|
||||||
|
- region
|
||||||
|
- period
|
||||||
|
- section count
|
||||||
|
- complete or partial status
|
||||||
|
- missing sections
|
||||||
|
- period alignment issues
|
||||||
|
- downstream export/logging failures
|
||||||
|
- Export Artifact
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[skill]
|
||||||
|
name = "jinchang-business-environment-weekly-report"
|
||||||
|
description = "Use when the user wants to collect Jinchang business-environment meeting metrics and generate a weekly report artifact."
|
||||||
|
version = "0.1.0"
|
||||||
|
author = "sgclaw"
|
||||||
|
tags = ["jinchang", "business-environment", "weekly-report", "browser", "report"]
|
||||||
|
|
||||||
|
prompts = [
|
||||||
|
"For Jinchang weekly report collection, call jinchang-business-environment-weekly-report.collect_business_environment_metrics before generic browser probing.",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[tools]]
|
||||||
|
name = "collect_business_environment_metrics"
|
||||||
|
description = "Collect multi-section Jinchang weekly business-environment metrics and prepare the report artifact shell."
|
||||||
|
kind = "browser_script"
|
||||||
|
command = "scripts/collect_business_environment_metrics.js"
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,39 @@
|
|||||||
|
# Collection Flow
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
- Source scenario: `D:\desk\智能体资料\大四区报告监测项\国网金昌供电公司营商环境周例会报告\index.html`
|
||||||
|
- Entry page includes a weekly date-range selector, execution log area, and historical report list.
|
||||||
|
- The page orchestrates multiple source-system queries and then assembles one meeting report.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- Weekly date range selected from the page-level daterange control.
|
||||||
|
- Current platform session and cached tokens for the required upstream systems.
|
||||||
|
|
||||||
|
## First-pass Collection Steps
|
||||||
|
|
||||||
|
1. Open or attach to the source page.
|
||||||
|
2. Read the selected weekly range.
|
||||||
|
3. Verify required source-system session context is available.
|
||||||
|
4. Collect abnormal-transformer monitoring metrics.
|
||||||
|
5. Collect outage-monitoring metrics.
|
||||||
|
6. Collect work-order and dispatch metrics.
|
||||||
|
7. Map collected values into section-based report rows.
|
||||||
|
8. Return the section-based artifact before final document generation.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- Browser-visible page state
|
||||||
|
- Platform script integration such as `/a_js/YPTAPI.js`
|
||||||
|
- Multi-system session and token cache availability
|
||||||
|
- Localhost report services under `http://localhost:13313/ReportServices/*`
|
||||||
|
- Localhost export or surface services used by the final generated report
|
||||||
|
|
||||||
|
## State Semantics
|
||||||
|
|
||||||
|
- Success: required sections are available, mapped, and period-aligned.
|
||||||
|
- Partial result: some section groups are collected while others fail, or period alignment is inconsistent.
|
||||||
|
- Empty result: a valid query returns zero rows for a specific metric group.
|
||||||
|
- Blocked/error: login problems, missing cached sessions, page interception, request failure, or script failure.
|
||||||
|
- Blocked/error must not be misreported as empty data.
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Data Quality
|
||||||
|
|
||||||
|
## Complete Result
|
||||||
|
|
||||||
|
A complete result means the required metric groups for the selected period are all present, period-aligned, and can be placed into report sections.
|
||||||
|
|
||||||
|
## Core Section Groups
|
||||||
|
|
||||||
|
The first-pass package should preserve separate sections for:
|
||||||
|
|
||||||
|
- abnormal-transformer monitoring
|
||||||
|
- outage monitoring
|
||||||
|
- work-order acceptance and comparison
|
||||||
|
- dispatch or meeting summary indicators
|
||||||
|
|
||||||
|
## Partial Rules
|
||||||
|
|
||||||
|
- If one or more metric groups fail while others succeed, set `status` to `partial`.
|
||||||
|
- If one or more sections are built from a different weekly period than the selected range, set `status` to `partial`.
|
||||||
|
- If final export generation or report-log writing fails after section data is assembled, keep the artifact and record the downstream failure in `partial_reasons`.
|
||||||
|
- Do not claim a full weekly report when only part of the sections are available.
|
||||||
|
|
||||||
|
## Common Weak Areas
|
||||||
|
|
||||||
|
- Weekly period mismatch
|
||||||
|
- Section-level missing data
|
||||||
|
- Inconsistent metric grouping across sources
|
||||||
|
- Missing upstream token or session context
|
||||||
|
- Downstream document generation failure after successful collection
|
||||||
|
|
||||||
|
## Empty vs Failure
|
||||||
|
|
||||||
|
- A source returning no rows for the requested period can be empty data.
|
||||||
|
- Login failure, missing cached session, interception, export failure, or request failure must be reported explicitly and not treated as empty.
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
const SECTION_TEMPLATES = [
|
||||||
|
{
|
||||||
|
name: "abnormal-transformer-monitoring",
|
||||||
|
columns: ["unit", "transformer_name", "abnormal_type", "note", "handling"],
|
||||||
|
rows: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "power-outage-monitoring",
|
||||||
|
columns: ["unit", "station", "event_type", "count", "note"],
|
||||||
|
rows: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "work-order-acceptance",
|
||||||
|
columns: ["category", "current_period", "previous_period", "trend", "note"],
|
||||||
|
rows: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dispatch-summary",
|
||||||
|
columns: ["metric", "value", "note"],
|
||||||
|
rows: []
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
function collectBusinessEnvironmentMetrics(input = {}) {
|
||||||
|
return {
|
||||||
|
type: "report-artifact",
|
||||||
|
report_name: "jinchang-business-environment-weekly-report",
|
||||||
|
period: input.period || "",
|
||||||
|
columns: [],
|
||||||
|
rows: [],
|
||||||
|
sections: SECTION_TEMPLATES.map((section) => ({ ...section, rows: [] })),
|
||||||
|
status: "ok",
|
||||||
|
partial_reasons: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
SECTION_TEMPLATES,
|
||||||
|
collectBusinessEnvironmentMetrics
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user