sync2 vibe
This commit is contained in:
parent
fc2b7f762a
commit
232a6b4238
3 changed files with 76 additions and 4 deletions
|
|
@ -84,6 +84,17 @@ function startSSE() {
|
|||
refreshDetailIfOpen(tid);
|
||||
});
|
||||
|
||||
sseSource.addEventListener('intra_addfield',e=>{
|
||||
const d=JSON.parse(e.data);
|
||||
const item=allData.find((x)=>String(x.task.id)===String(d.task_id));
|
||||
if(item) item.task._addfield_status=d.value||null;
|
||||
if(d.by!==currentUser?.username){
|
||||
showToast(`🔗 ${d.by}: служ. статус → «${d.value||'—'}» #${taskNumFromId(d.task_id)}`,'info');
|
||||
}
|
||||
renderTable();
|
||||
refreshDetailIfOpen(d.task_id);
|
||||
});
|
||||
|
||||
sseSource.addEventListener('tasks_updated',e=>{
|
||||
const d=JSON.parse(e.data);
|
||||
const incomingVersion=Number(d.cache_version||0);
|
||||
|
|
|
|||
|
|
@ -455,9 +455,8 @@ function intraStatusBadge(task) {
|
|||
else if (lc.includes('ожидан') || lc.includes('hold')) cls = 'sb-intra-hold';
|
||||
return `<span class="status-badge ${cls}"><span class="dot"></span>${esc(name)}</span>`;
|
||||
}
|
||||
// ── IntraDesk additional field status badge ───────────────────────
|
||||
function intraAddfieldBadge(task) {
|
||||
const val = task._addfield_status;
|
||||
// ── IntraDesk additional field — badge helper ─────────────────────
|
||||
function _addfieldBadgeHtml(val) {
|
||||
if (!val) return '<span style="color:var(--text3);font-size:11px;">—</span>';
|
||||
const match = (typeof MARKS_CONFIG !== 'undefined' ? MARKS_CONFIG : [])
|
||||
.find((m) => m.label && m.label.toLowerCase() === val.toLowerCase());
|
||||
|
|
@ -467,6 +466,36 @@ function intraAddfieldBadge(task) {
|
|||
}
|
||||
return `<span class="status-badge sb-intra-other"><span class="dot"></span>${esc(val)}</span>`;
|
||||
}
|
||||
|
||||
// ── IntraDesk additional field — interactive picker ───────────────
|
||||
function intraAddfieldPickerHtml(task) {
|
||||
const tid = String(task.id);
|
||||
const val = task._addfield_status || null;
|
||||
const cfg = typeof MARKS_CONFIG !== 'undefined' ? MARKS_CONFIG : [];
|
||||
const items = cfg.map((m) => `
|
||||
<div class="isp-item ${val && val.toLowerCase()===m.label.toLowerCase()?'isp-active':''}"
|
||||
onclick="setIntraAddfield('${esc(tid)}','${esc(m.label)}',event)">
|
||||
<span class="isp-dot" style="background:${m.ispColor||m.colorDot||'#1677ff'};"></span>${esc(m.label)}
|
||||
</div>`).join('');
|
||||
const clearItem = `<div class="isp-item${!val?' isp-active':''}" onclick="setIntraAddfield('${esc(tid)}',null,event)">
|
||||
<span class="isp-dot" style="background:var(--text3);"></span><span style="color:var(--text3);">— очистить</span>
|
||||
</div>`;
|
||||
return `<div class="inline-status-picker" onmouseenter="ispShow(this)" onmouseleave="ispHide(this)">
|
||||
${_addfieldBadgeHtml(val)}
|
||||
<div class="isp-dropdown">
|
||||
<div class="isp-dropdown-inner">${items}${clearItem}</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
async function setIntraAddfield(taskId, value, e) {
|
||||
if (e) e.stopPropagation();
|
||||
const r = await apiPost(`/api/tasks/${taskId}/intra-addfield`, { value: value || null });
|
||||
if (!r?.ok) { showToast(`❌ ${r?.error || 'Ошибка'}`, 'warn'); return; }
|
||||
// Обновляем кеш локально до следующего SSE
|
||||
const item = allData.find((d) => String(d.task.id) === String(taskId));
|
||||
if (item) { item.task._addfield_status = value || null; renderTable(); }
|
||||
}
|
||||
// Who answered — ring class for avatar
|
||||
function whoAnsweredRing(lc){
|
||||
if(!lc) return 'ring-none';
|
||||
|
|
@ -756,7 +785,7 @@ function renderTable(keepPage){
|
|||
${sc('num') ?`<td><span class="task-num">#${num}</span>${unreadDot}</td>`:''}
|
||||
${sc('title') ?`<td><div class="task-title-main" title="${esc(task.name)}">${esc(task.name)}</div>${orgName?`<div class="task-title-sub">${esc(orgName)}</div>`:''}</td>`:''}
|
||||
${sc('intrastatus')?`<td>${intraStatusBadge(task)}</td>`:''}
|
||||
${sc('servstatus') ?`<td>${intraAddfieldBadge(task)}</td>`:''}
|
||||
${sc('servstatus') ?`<td onclick="event.stopPropagation()">${intraAddfieldPickerHtml(task)}</td>`:''}
|
||||
${sc('status') ?`<td onclick="event.stopPropagation()">${statusPickerHtml(tid)}</td>`:''}
|
||||
${sc('client') ?`<td><div class="client-info">
|
||||
<div class="client-avatar ${whoAnsweredRing(lastComment)}" style="background:${avatarColor(authorName)};color:#fff;">${avatarInitials(authorName)}</div>
|
||||
|
|
|
|||
32
server.js
32
server.js
|
|
@ -790,6 +790,38 @@ app.post('/api/marks', auth, (req, res) => {
|
|||
res.json({ ok: true });
|
||||
});
|
||||
|
||||
// ── IntraDesk additional field (direct set) ───────────────────────
|
||||
app.post('/api/tasks/:taskId/intra-addfield', auth, async (req, res) => {
|
||||
const taskId = String(req.params.taskId || '').trim();
|
||||
const { value } = req.body || {};
|
||||
const statusLabel = value ? String(value).trim() : null;
|
||||
if (!taskId) return res.status(400).json({ error: 'task_id required' });
|
||||
|
||||
const s = getSettings();
|
||||
if (!s.api_key) return res.status(400).json({ error: 'API ключ не задан' });
|
||||
|
||||
const cacheRow = db.prepare('SELECT data FROM tasks_cache WHERE id=1').get();
|
||||
const tasks = JSON.parse(cacheRow?.data || '[]');
|
||||
const task = tasks.find((t) => String(t.id) === taskId);
|
||||
if (!task) return res.status(404).json({ error: 'Задача не найдена в кеше' });
|
||||
|
||||
try {
|
||||
await refreshService.updateIntraAdditionalField(task.tasknumber, statusLabel, s.api_key);
|
||||
} catch (e) {
|
||||
console.error('[AddField] IntraDesk update error:', e.message);
|
||||
return res.status(502).json({ error: `Ошибка IntraDesk: ${e.message}` });
|
||||
}
|
||||
|
||||
// Обновляем значение в локальном кеше немедленно
|
||||
task._addfield_status = statusLabel;
|
||||
const now = new Date().toISOString();
|
||||
db.prepare('UPDATE tasks_cache SET data=?, updated_at=? WHERE id=1')
|
||||
.run(JSON.stringify(tasks), now);
|
||||
|
||||
sseBroadcast('intra_addfield', { task_id: taskId, value: statusLabel, by: req.user.username });
|
||||
res.json({ ok: true, value: statusLabel });
|
||||
});
|
||||
|
||||
// ── Notes ─────────────────────────────────────────────────────────
|
||||
app.get('/api/notes', auth, (req, res) => {
|
||||
const r = {};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue