Initial rrweb SGrobot skill package

This commit is contained in:
2026-06-24 09:45:48 +08:00
commit 27a0ebe1d7
17 changed files with 1554 additions and 0 deletions

25
examples/basic-trace.json Normal file
View File

@@ -0,0 +1,25 @@
{
"id": "expense-approval",
"name": "费用审批",
"description": "打开审批页,填写意见并点击同意。",
"startUrl": "https://oa.example.test/expense/123",
"steps": [
{
"type": "assertText",
"text": "费用审批",
"label": "确认在审批页"
},
{
"type": "fill",
"selector": "textarea[name='comment']",
"value": "同意",
"label": "填写审批意见"
},
{
"type": "click",
"selector": "button[data-action='approve']",
"label": "点击同意",
"risk": "write"
}
]
}

View File

@@ -0,0 +1,210 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="data:," />
<title>客户回访工单登记</title>
<style>
:root {
color-scheme: light;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: #eef2f6;
color: #1f2937;
}
body {
margin: 0;
padding: 32px;
}
main {
max-width: 920px;
margin: 0 auto;
background: #ffffff;
border: 1px solid #d7dee8;
border-radius: 8px;
box-shadow: 0 12px 34px rgba(31, 41, 55, 0.08);
}
header {
padding: 24px 28px;
border-bottom: 1px solid #e3e8ef;
}
h1 {
margin: 0 0 8px;
font-size: 24px;
}
.meta {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
padding: 20px 28px;
background: #f8fafc;
border-bottom: 1px solid #e3e8ef;
}
.meta div,
label {
font-size: 14px;
}
.meta strong {
display: block;
margin-top: 4px;
font-size: 16px;
}
form {
padding: 24px 28px 28px;
}
.field {
margin-bottom: 18px;
}
select,
textarea {
width: 100%;
box-sizing: border-box;
margin-top: 8px;
border: 1px solid #cbd5e1;
border-radius: 6px;
padding: 10px 12px;
font: inherit;
}
textarea {
min-height: 96px;
resize: vertical;
}
.actions {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 24px;
}
button {
border: 0;
border-radius: 6px;
padding: 10px 18px;
font: inherit;
cursor: pointer;
}
button.secondary {
background: #e5e7eb;
color: #111827;
}
button.primary {
background: #166534;
color: #ffffff;
}
#status {
margin-top: 16px;
color: #166534;
font-weight: 600;
}
</style>
</head>
<body>
<main>
<header>
<h1>客户回访工单登记</h1>
<p>低压故障抢修完成后,客服需要登记一次客户回访结果。</p>
</header>
<section class="meta" aria-label="工单概要">
<div>工单编号<strong>GD-20260612-0421</strong></div>
<div>客户姓名<strong>李女士</strong></div>
<div>回访任务<strong>待处理</strong></div>
</section>
<form id="callback-form">
<div class="field">
<label for="result">回访结果</label>
<select id="result" name="callbackResult" data-trace="callback-result">
<option value="">请选择</option>
<option value="satisfied">客户满意,问题已解决</option>
<option value="follow-up">仍需跟进</option>
<option value="unreachable">暂未接通</option>
</select>
</div>
<div class="field">
<label for="remark">回访备注</label>
<textarea id="remark" name="remark" data-trace="callback-remark" placeholder="请输入回访备注"></textarea>
</div>
<div class="actions">
<button type="button" class="secondary" data-action="cancel">取消</button>
<button type="submit" class="primary" data-action="save-draft">保存草稿</button>
</div>
<div id="status" role="status" aria-live="polite"></div>
</form>
</main>
<script>
window.__semanticTrace = {
id: "customer-callback-draft",
name: "客户回访工单登记",
description: "客服打开待回访工单,选择客户满意,填写回访备注,并保存草稿。",
startUrl: window.location.href,
steps: [
{ type: "assertText", text: "客户回访工单登记", label: "确认进入客户回访工单页面" }
]
};
const trace = window.__semanticTrace.steps;
function selectorFor(node) {
if (node.dataset && node.dataset.trace) {
return `[data-trace="${node.dataset.trace}"]`;
}
if (node.dataset && node.dataset.action) {
return `[data-action="${node.dataset.action}"]`;
}
if (node.id) {
return `#${node.id}`;
}
return node.tagName.toLowerCase();
}
document.querySelector("select").addEventListener("change", (event) => {
trace.push({
type: "select",
selector: selectorFor(event.target),
value: event.target.value,
label: "选择回访结果"
});
});
document.querySelector("textarea").addEventListener("change", (event) => {
trace.push({
type: "fill",
selector: selectorFor(event.target),
value: event.target.value,
label: "填写回访备注"
});
});
document.getElementById("callback-form").addEventListener("submit", (event) => {
event.preventDefault();
trace.push({
type: "click",
selector: '[data-action="save-draft"]',
label: "点击保存草稿",
risk: "write"
});
document.getElementById("status").textContent = "草稿已保存,等待班长复核。";
});
</script>
</body>
</html>

View File

@@ -0,0 +1,31 @@
{
"id": "customer-callback-draft",
"name": "客户回访工单登记",
"description": "客服打开待回访工单,选择客户满意,填写回访备注,并保存草稿。",
"startUrl": "http://127.0.0.1:4187/customer-callback.html",
"steps": [
{
"type": "assertText",
"text": "客户回访工单登记",
"label": "确认进入客户回访工单页面"
},
{
"type": "select",
"selector": "[data-trace=\"callback-result\"]",
"value": "satisfied",
"label": "选择回访结果"
},
{
"type": "fill",
"selector": "[data-trace=\"callback-remark\"]",
"value": "已电话回访客户,现场供电恢复正常,客户确认满意。",
"label": "填写回访备注"
},
{
"type": "click",
"selector": "[data-action=\"save-draft\"]",
"label": "点击保存草稿",
"risk": "write"
}
]
}