@aiyiran/myclaw 1.1.166 → 1.1.167
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>作品扫描 - __SESSIONS_COUNT__ sessions</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { box-sizing: border-box; }
|
|
9
|
+
body {
|
|
10
|
+
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif;
|
|
11
|
+
background: linear-gradient(135deg, #f5f7fa 0%, #e9ecf3 100%);
|
|
12
|
+
margin: 0; padding: 24px; min-height: 100vh; color: #2d3748;
|
|
13
|
+
}
|
|
14
|
+
.container { max-width: 1200px; margin: 0 auto; }
|
|
15
|
+
.header {
|
|
16
|
+
background: linear-gradient(135deg, #667eea, #764ba2);
|
|
17
|
+
color: white; padding: 30px; border-radius: 16px; margin-bottom: 24px;
|
|
18
|
+
box-shadow: 0 10px 30px rgba(102,126,234,0.3);
|
|
19
|
+
}
|
|
20
|
+
.header h1 { margin: 0 0 8px 0; font-size: 1.8em; }
|
|
21
|
+
.header p { margin: 0; opacity: 0.9; }
|
|
22
|
+
.summary-bar { display: flex; gap: 16px; margin-top: 16px; flex-wrap: wrap; }
|
|
23
|
+
.summary-bar .stat {
|
|
24
|
+
background: rgba(255,255,255,0.2); padding: 8px 16px; border-radius: 8px;
|
|
25
|
+
backdrop-filter: blur(10px);
|
|
26
|
+
}
|
|
27
|
+
.stat strong { font-size: 1.3em; margin-right: 6px; }
|
|
28
|
+
.legend { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; }
|
|
29
|
+
.legend-item { padding: 4px 12px; border-radius: 6px; font-size: 0.85em; font-weight: 500; }
|
|
30
|
+
table {
|
|
31
|
+
width: 100%; background: white; border-radius: 12px; overflow: hidden;
|
|
32
|
+
border-collapse: collapse; box-shadow: 0 4px 20px rgba(0,0,0,0.08);
|
|
33
|
+
}
|
|
34
|
+
th {
|
|
35
|
+
background: #f7fafc; padding: 14px 12px; text-align: left;
|
|
36
|
+
font-weight: 600; color: #4a5568; border-bottom: 2px solid #e2e8f0;
|
|
37
|
+
font-size: 0.9em;
|
|
38
|
+
}
|
|
39
|
+
td { padding: 10px 12px; border-bottom: 1px solid rgba(0,0,0,0.05); font-size: 0.92em; }
|
|
40
|
+
tr:hover { filter: brightness(0.96); }
|
|
41
|
+
.num { text-align: right; font-variant-numeric: tabular-nums; }
|
|
42
|
+
.link {
|
|
43
|
+
color: #667eea; text-decoration: none; font-weight: 500;
|
|
44
|
+
padding: 4px 10px; border-radius: 6px; background: rgba(255,255,255,0.6);
|
|
45
|
+
transition: all 0.2s; display: inline-block;
|
|
46
|
+
}
|
|
47
|
+
.link:hover { background: #667eea; color: white; transform: translateY(-1px); }
|
|
48
|
+
.footer { text-align: center; margin-top: 24px; color: #718096; font-size: 0.85em; }
|
|
49
|
+
.export-bar {
|
|
50
|
+
position: sticky; bottom: 20px; margin-top: 20px;
|
|
51
|
+
background: white; border-radius: 12px; padding: 16px 24px;
|
|
52
|
+
box-shadow: 0 4px 20px rgba(0,0,0,0.12);
|
|
53
|
+
display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
|
|
54
|
+
}
|
|
55
|
+
.export-bar .count { font-weight: 600; color: #667eea; }
|
|
56
|
+
.btn {
|
|
57
|
+
background: #667eea; color: white; border: none; padding: 8px 20px;
|
|
58
|
+
border-radius: 8px; font-size: 0.95em; cursor: pointer; transition: all 0.2s;
|
|
59
|
+
}
|
|
60
|
+
.btn:hover { background: #5a67d8; transform: translateY(-1px); }
|
|
61
|
+
.btn:disabled { background: #cbd5e0; cursor: not-allowed; transform: none; }
|
|
62
|
+
input[type=checkbox] { width: 18px; height: 18px; cursor: pointer; }
|
|
63
|
+
.work-input {
|
|
64
|
+
width: 100%; max-width: 180px; padding: 4px 8px; border: 1px solid #e2e8f0;
|
|
65
|
+
border-radius: 6px; font-size: 0.85em; background: rgba(255,255,255,0.7);
|
|
66
|
+
}
|
|
67
|
+
.work-input:focus { outline: none; border-color: #667eea; box-shadow: 0 0 0 2px rgba(102,126,234,0.2); }
|
|
68
|
+
.work-input.saved { border-color: #48bb78; }
|
|
69
|
+
</style>
|
|
70
|
+
</head>
|
|
71
|
+
<body>
|
|
72
|
+
<div class="container">
|
|
73
|
+
<div class="header">
|
|
74
|
+
<h1>📋 作品扫描</h1>
|
|
75
|
+
<p>Generated by chat-history-extractor</p>
|
|
76
|
+
<div class="summary-bar">
|
|
77
|
+
<div class="stat"><strong>__SESSIONS_COUNT__</strong> sessions</div>
|
|
78
|
+
<div class="stat"><strong>__TOTAL_PAIRS__</strong> conversation pairs</div>
|
|
79
|
+
<div class="stat"><strong>host:</strong> __HOST__</div>
|
|
80
|
+
</div>
|
|
81
|
+
<div class="legend">__LEGEND__</div>
|
|
82
|
+
</div>
|
|
83
|
+
<table>
|
|
84
|
+
<thead>
|
|
85
|
+
<tr>
|
|
86
|
+
<th><input type="checkbox" id="checkAll"></th>
|
|
87
|
+
<th class="num">#</th>
|
|
88
|
+
<th>workspace</th>
|
|
89
|
+
<th>会话名</th>
|
|
90
|
+
<th class="num">对话数</th>
|
|
91
|
+
<th>起始时间</th>
|
|
92
|
+
<th>最后更新</th>
|
|
93
|
+
<th>作品链接</th>
|
|
94
|
+
<th>对话链接</th>
|
|
95
|
+
</tr>
|
|
96
|
+
</thead>
|
|
97
|
+
<tbody>__ROWS__
|
|
98
|
+
</tbody>
|
|
99
|
+
</table>
|
|
100
|
+
<div class="export-bar">
|
|
101
|
+
<span>已选择 <span class="count" id="selectedCount">0</span> 个会话</span>
|
|
102
|
+
<button class="btn" id="exportBtn" disabled>导出所选数据</button>
|
|
103
|
+
<span style="color:#a0aec0;font-size:0.85em;">勾选后点击导出,复制到剪贴板</span>
|
|
104
|
+
</div>
|
|
105
|
+
<p class="footer">提示:相同颜色 = 同一项目。作品链接会自动保存到浏览器,刷新不丢失。</p>
|
|
106
|
+
<script>
|
|
107
|
+
var STORAGE_KEY = '___STORAGE_KEY___';
|
|
108
|
+
|
|
109
|
+
// --- Restore state on load ---
|
|
110
|
+
function loadState() {
|
|
111
|
+
try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}'); }
|
|
112
|
+
catch(e) { return {}; }
|
|
113
|
+
}
|
|
114
|
+
function saveState(state) {
|
|
115
|
+
try { localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); }
|
|
116
|
+
catch(e) {}
|
|
117
|
+
}
|
|
118
|
+
var state = loadState();
|
|
119
|
+
|
|
120
|
+
// --- Checkbox: restore + persist ---
|
|
121
|
+
document.querySelectorAll('.row-check').forEach(function(cb) {
|
|
122
|
+
var sk = cb.dataset.session;
|
|
123
|
+
// restore checked
|
|
124
|
+
if (state[sk] && state[sk].checked) cb.checked = true;
|
|
125
|
+
// restore work_url
|
|
126
|
+
var input = cb.closest('tr').querySelector('.work-input');
|
|
127
|
+
if (input) {
|
|
128
|
+
if (state[sk] && state[sk].work) {
|
|
129
|
+
input.value = state[sk].work;
|
|
130
|
+
input.classList.add('saved');
|
|
131
|
+
}
|
|
132
|
+
// persist on edit
|
|
133
|
+
input.addEventListener('input', function() {
|
|
134
|
+
if (!state[sk]) state[sk] = {};
|
|
135
|
+
state[sk].work = input.value;
|
|
136
|
+
saveState(state);
|
|
137
|
+
input.classList.add('saved');
|
|
138
|
+
});
|
|
139
|
+
input.addEventListener('blur', function() {
|
|
140
|
+
input.classList.remove('saved');
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// persist checkbox
|
|
144
|
+
cb.addEventListener('change', function() {
|
|
145
|
+
if (!state[sk]) state[sk] = {};
|
|
146
|
+
state[sk].checked = cb.checked;
|
|
147
|
+
saveState(state);
|
|
148
|
+
updateCount();
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// --- Check all ---
|
|
153
|
+
var checkAll = document.getElementById('checkAll');
|
|
154
|
+
// restore checkAll based on all checked
|
|
155
|
+
function syncCheckAll() {
|
|
156
|
+
var cbs = document.querySelectorAll('.row-check');
|
|
157
|
+
var allChecked = Array.from(cbs).every(function(c) { return c.checked; });
|
|
158
|
+
checkAll.checked = cbs.length > 0 && allChecked;
|
|
159
|
+
}
|
|
160
|
+
checkAll.addEventListener('change', function() {
|
|
161
|
+
document.querySelectorAll('.row-check').forEach(function(cb) {
|
|
162
|
+
cb.checked = checkAll.checked;
|
|
163
|
+
var sk = cb.dataset.session;
|
|
164
|
+
if (!state[sk]) state[sk] = {};
|
|
165
|
+
state[sk].checked = cb.checked;
|
|
166
|
+
});
|
|
167
|
+
saveState(state);
|
|
168
|
+
updateCount();
|
|
169
|
+
});
|
|
170
|
+
syncCheckAll();
|
|
171
|
+
|
|
172
|
+
function updateCount() {
|
|
173
|
+
var checked = document.querySelectorAll('.row-check:checked');
|
|
174
|
+
document.getElementById('selectedCount').textContent = checked.length;
|
|
175
|
+
document.getElementById('exportBtn').disabled = checked.length === 0;
|
|
176
|
+
}
|
|
177
|
+
updateCount();
|
|
178
|
+
|
|
179
|
+
// --- Export: copy text to clipboard ---
|
|
180
|
+
document.getElementById('exportBtn').addEventListener('click', function() {
|
|
181
|
+
var checked = document.querySelectorAll('.row-check:checked');
|
|
182
|
+
var lines = [];
|
|
183
|
+
checked.forEach(function(cb, idx) {
|
|
184
|
+
var tr = cb.closest('tr');
|
|
185
|
+
var linkEl = tr.querySelector('.link');
|
|
186
|
+
var workEl = tr.querySelector('.work-input');
|
|
187
|
+
var workUrl = workEl ? workEl.value.trim() : '';
|
|
188
|
+
lines.push('编号' + (idx + 1) + ':');
|
|
189
|
+
lines.push('workspace名:' + cb.dataset.agent);
|
|
190
|
+
lines.push('session名:' + cb.dataset.name);
|
|
191
|
+
lines.push('对话链接:' + (linkEl ? linkEl.href : ''));
|
|
192
|
+
lines.push('作品链接:' + (workUrl || '暂无'));
|
|
193
|
+
lines.push('');
|
|
194
|
+
});
|
|
195
|
+
var text = lines.join('\n');
|
|
196
|
+
var ta = document.createElement('textarea');
|
|
197
|
+
ta.value = text;
|
|
198
|
+
ta.style.position = 'fixed';
|
|
199
|
+
ta.style.left = '-9999px';
|
|
200
|
+
document.body.appendChild(ta);
|
|
201
|
+
ta.select();
|
|
202
|
+
try {
|
|
203
|
+
document.execCommand('copy');
|
|
204
|
+
var btn = document.getElementById('exportBtn');
|
|
205
|
+
btn.textContent = '✅ 已复制 ' + checked.length + ' 条到剪贴板';
|
|
206
|
+
btn.style.background = '#48bb78';
|
|
207
|
+
setTimeout(function() {
|
|
208
|
+
btn.textContent = '导出所选数据';
|
|
209
|
+
btn.style.background = '';
|
|
210
|
+
}, 2000);
|
|
211
|
+
} catch(e) {
|
|
212
|
+
alert('复制失败,请手动复制:\n\n' + text);
|
|
213
|
+
}
|
|
214
|
+
document.body.removeChild(ta);
|
|
215
|
+
});
|
|
216
|
+
</script>
|
|
217
|
+
</div>
|
|
218
|
+
</body>
|
|
219
|
+
</html>
|