# -*- coding: utf-8 -*-
"""任免文件 ↔ 干部 人级关联（后台）
 1) 上传/替换前任免文件先选「本文件涉及哪几名干部」（默认带上已关联的人）
 2) 文件列表：标题用真实姓名、人数用关联人数、新增「人员」查看并直达审批表
 3) 顶部漏文提示：已导入审批表却没进任何任免文件的人
"""
import shutil, time

A = '/data/www/files/rmsys-app/backend/src/Rmsys.Api/wwwroot/admin.html'
shutil.copy2(A, A + '.bakL.' + time.strftime('%Y%m%d%H%M%S'))
s = open(A, encoding='utf-8').read()

# ---------- 1) 全局：漏文清单 ----------
old_g = "var DOC_Q='', DOC_STATUS='全部';"
if s.count(old_g) != 1:
    # 兼容其它写法：找 DOC_STATUS 定义
    import re
    m = re.search(r"var DOC_Q='[^']*'(,\s*DOC_STATUS='[^']*')?;", s)
    assert m, "DOC_Q 定义未找到"
    old_g = m.group(0)
s = s.replace(old_g, old_g + "\nvar DOCGAPS=[];   /* 有审批表但未进任何任免文件的干部 */", 1)

# ---------- 2) 选人弹窗 ----------
anchor = "function uploadDoc(k){"
assert s.count(anchor) == 1
picker = r'''/* 上传/替换任免文件前：选择本文件涉及的干部（默认勾上已关联的人） */
function pickDocCadres(deptKey, presetIds, cb){
  var list = cadresOf(deptKey);
  if(!list.length){ cb([]); return; }
  var preset = {};
  (presetIds || []).forEach(function(id){ preset[id] = 1; });
  var h = '<div class="modal-h"><h3>选择本文件涉及的干部</h3><div class="spacer"></div><button class="x" onclick="closeModal()">&times;</button></div>';
  h += '<div class="modal-b">';
  h += '<div class="sec-note">勾选后，系统会把这些干部与该任免文件建立对应关系：文件列表可按人查看、可直接跳到其任免审批表，并用于漏文校验。'
     + '取消勾选不会改动已上传的文件。</div>';
  h += '<div class="bar" style="margin:10px 0;"><button class="btn" onclick="docPickAll(1)">全选</button>'
     + '<button class="btn" onclick="docPickAll(0)">清空</button>'
     + '<span id="pickCnt" style="font-size:13px;color:var(--ink3);margin-left:6px;"></span></div>';
  h += '<div style="max-height:40vh;overflow:auto;border:1px solid var(--line);border-radius:8px;padding:10px;">';
  list.forEach(function(c){
    h += '<label style="display:flex;align-items:center;gap:8px;padding:6px 4px;border-bottom:1px dashed var(--line2);">'
       + '<input type="checkbox" class="dpick" value="' + c.id + '"' + (preset[c.id] ? ' checked' : '')
       + ' onchange="docPickCnt()">'
       + '<b style="min-width:70px;">' + esc(c.name) + '</b>'
       + '<span style="color:var(--ink3);font-size:12.5px;">' + (c.deptNull ? '未分配' : deptName(c.dept)) + '</span>'
       + '<span style="flex:1;color:var(--ink2);font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">'
       + esc(c.cur || '—') + (c.prop ? ('　拟任 ' + esc(c.prop)) : '') + '</span>'
       + '</label>';
  });
  h += '</div></div>';
  h += '<div class="modal-f"><div class="spacer"></div><button class="btn" onclick="closeModal()">取消</button>'
     + '<button class="btn pri" onclick="docPickOk()">下一步：选择文件</button></div>';
  window.__pickCb = cb;
  openModal(h, true);
  docPickCnt();
}
function docPickAll(on){
  document.querySelectorAll('.dpick').forEach(function(c){ c.checked = !!on; });
  docPickCnt();
}
function docPickCnt(){
  var n = document.querySelectorAll('.dpick:checked').length;
  var el = document.getElementById('pickCnt'); if(el) el.textContent = '已选 ' + n + ' 人';
}
function docPickOk(){
  var ids = [];
  document.querySelectorAll('.dpick:checked').forEach(function(c){ ids.push(+c.value); });
  var cb = window.__pickCb; window.__pickCb = null;
  closeModal();
  if(cb) cb(ids);
}

/* 查看某份任免文件涉及的人员，可直达其任免审批表 */
function docCadres(docId){
  var d = null; DOCS.forEach(function(x){ if(x.id === docId) d = x; });
  if(!d) return;
  var ids = d.cadreIds || [];
  var h = '<div class="modal-h"><h3>任免文件涉及人员 · ' + esc(d.no || d.id) + '</h3><div class="spacer"></div><button class="x" onclick="closeModal()">&times;</button></div>';
  h += '<div class="modal-b">';
  if(!ids.length){
    h += '<div class="empty">这份文件上传时未关联干部。可点「替换」重新上传并勾选涉及人员。</div>';
  } else {
    h += '<div class="sec-note">共 ' + ids.length + ' 人，与《任免审批表》按干部一一对应；点「审批表」可直接查看该同志的表。</div>';
    h += '<div class="tbl-wrap"><table class="grid slim" style="min-width:0;width:100%;table-layout:fixed;"><colgroup>'
       + '<col style="width:52px"><col style="width:88px"><col style="width:16%"><col><col style="width:96px"></colgroup>'
       + '<thead><tr><th>序号</th><th>姓名</th><th>处室</th><th>现任 → 拟任</th><th>操作</th></tr></thead><tbody>';
    ids.forEach(function(id, i){
      var c = null; CADRES.forEach(function(x){ if(x.id === id) c = x; });
      if(!c) return;
      h += '<tr><td>' + (i + 1) + '</td><td class="nm">' + esc(c.name) + '</td>'
         + '<td>' + (c.deptNull ? '—' : deptName(c.dept)) + '</td>'
         + '<td style="font-size:13px;">' + esc(c.cur || '—') + ' → ' + (c.prop ? esc(c.prop) : '免去现职') + '</td>'
         + '<td class="ops"><button class="opbtn pri" onclick="closeModal();previewCadre(' + c.id + ')">审批表</button></td></tr>';
    });
    h += '</tbody></table></div>';
  }
  h += '</div>';
  h += '<div class="modal-f"><div class="spacer"></div><button class="btn" onclick="closeModal()">关闭</button></div>';
  openModal(h, true);
}

''' + anchor
s = s.replace(anchor, picker, 1)

# ---------- 3) 上传前先选人 ----------
old_up = """  ensureAuth().then(function(ok){
    if(!ok) return;
    uploadDialog({
      title:'上传任免文件 · '+label,
      sub:'上传本次会议该范围对应的任免文件（Word / PDF，含组织部文头与文号）。上传后版本自动累加，旧版本保留可追溯。',
      endpoint:'/api/admin/appointdocs/upload',
      extra:{ meetingId:m.id, deptId:(deptObj?deptObj.id:null) },
      downloadBase:'/api/admin/appointdocs/{id}/download',
      onDone:function(){ bootstrap(true,true); renderMaterials(); }
    });
  });"""
new_up = """  ensureAuth().then(function(ok){
    if(!ok) return;
    /* 先选人：把"这份文件写了哪些人"结构化记下来，才能和任免审批表对上 */
    var exist = docList().filter(function(x){ return x.dept === dept; })[0];
    pickDocCadres(dept, exist ? (exist.cadreIds || []) : [], function(ids){
      uploadDialog({
        title:'上传任免文件 · '+label,
        sub:'上传本次会议该范围对应的任免文件（Word / PDF，含组织部文头与文号）。已选择 '+ids.length+' 名涉及干部。上传后版本自动累加，旧版本保留可追溯。',
        endpoint:'/api/admin/appointdocs/upload',
        extra:{ meetingId:m.id, deptId:(deptObj?deptObj.id:null), cadreIds:ids.join(',') },
        downloadBase:'/api/admin/appointdocs/{id}/download',
        onDone:function(){ bootstrap(true,true); renderMaterials(); }
      });
    });
  });"""
assert s.count(old_up) == 1, "uploadDoc 调用未命中"
s = s.replace(old_up, new_up, 1)

# ---------- 4) 列表：真实标题 / 关联人数 / 人员入口 / 漏文提示 ----------
old_row = """      h+=opsCell([['预览','previewDoc(\\''+r.dept+'\\')','pri'],
                  ['替换','uploadDoc(\\''+r.dept+'\\')'],
                  ['删除','delDoc('+d.id+')','del']])
       + '<td>'+(i+1)+'</td><td>'+esc(docLabel(r.dept))+'</td>'
       + '<td class="nm">'+esc(docNameOf(d))+'</td><td>'+esc(d.no)+'</td>'
       + '<td>'+n+' 人</td><td>'+d.pages+' 页</td><td>'+esc(d.by)+'</td><td>'+esc(d.at)+'</td>'"""
new_row = """      var linked = (d.cadreIds || []).length;
      h+=opsCell([['预览','previewDoc(\\''+r.dept+'\\')','pri'],
                  ['人员','docCadres('+d.id+')'],
                  ['替换','uploadDoc(\\''+r.dept+'\\')'],
                  ['删除','delDoc('+d.id+')','del']])
       + '<td>'+(i+1)+'</td><td>'+esc(docLabel(r.dept))+'</td>'
       + '<td class="nm">'+esc(d.title || docNameOf(d))+'</td><td>'+esc(d.no)+'</td>'
       + '<td>'+(linked? (linked+' 人') : '<span style="color:#8E6F14;font-weight:700;">未关联</span>')+'</td>'
       + '<td>'+d.pages+' 页</td><td>'+esc(d.by)+'</td><td>'+esc(d.at)+'</td>'"""
assert s.count(old_row) == 1, "文件行未命中"
s = s.replace(old_row, new_row, 1)

# 漏文提示条（放在表格前）
old_tbl = """  h+='<div class="tbl-wrap"><table class="grid" style="min-width:1380px;"><thead><tr>'
   + '<th class="opcell">操作</th>'"""
new_tbl = """  if(DOCGAPS.length){
    h+='<div style="background:#FFF8E1;border:1px solid #F0D9A0;color:#6B4E00;padding:11px 14px;border-radius:8px;margin-bottom:12px;font-size:13px;line-height:1.9;">'
     + '<b>漏文提示：'+DOCGAPS.length+' 名干部已导入任免审批表，但未被任何任免文件涵盖</b>　'
     + DOCGAPS.map(function(g){ return '<a class="lnk" style="margin-left:6px;" onclick="previewCadre('+g.id+')">'+esc(g.name)+'</a>'; }).join('')
     + '</div>';
  }
  h+='<div class="tbl-wrap"><table class="grid" style="min-width:1380px;"><thead><tr>'
   + '<th class="opcell">操作</th>'"""
assert s.count(old_tbl) == 1, "表格开头未命中"
s = s.replace(old_tbl, new_tbl, 1)

# ---------- 5) bootstrap 接收 docGaps ----------
old_b = "      DOCS    = d.docs    || [];"
assert s.count(old_b) == 1
s = s.replace(old_b, old_b + "\n      DOCGAPS = d.docGaps || [];", 1)

open(A, 'w', encoding='utf-8').write(s)
print("✓ 后台：选人弹窗 + 真实标题/人数 + 人员查看 + 漏文提示")
