import io
p='排班工具.html'
s=io.open(p,encoding='utf-8').read()

anchor = "  function copyTsv() {"
code = r'''  /* ---------- 任务 Excel 导入 / 模板 ---------- */
  /* 列固定：地点(必填) | 周几(周一~周日,顿号分隔) | 时段(全天/上午/下午) | 人数 | 工作量(高/中/低) | 任意天数(每天/是) | 备注 */
  var XLS_HEAD = ['地点', '周几', '时段', '人数', '工作量', '任意天数', '备注'];
  function xlsTemplate() {
    var rows = [
      ['科技支行', '周一', '全天', 2, '中', '', '楼下实施'],
      ['清泰支行', '周三', '全天', 2, '高', '', 'PC16+打印机12+A3/A4扫描仪'],
      ['临平崇贤', '周三', '全天', 1, '中', '', '经济开发区'],
      ['青山湖、临安', '周三、周五', '全天', 1, '中', '是', '两天里挑一天'],
      ['瓜沥支行', '周二、周三、周四、周五', '上午', 1, '中', '', '半天，5-6台PC']
    ];
    var html = '<html xmlns:x="urn:schemas-microsoft-com:office:excel"><head><meta charset="utf-8">'
      + '<style>td,th{border:1px solid #999;padding:4px 8px;font-family:微软雅黑;font-size:11pt;mso-number-format:"\@"}'
      + 'th{background:#DCEBFB;font-weight:600}</style></head><body>'
      + '<table><thead><tr><th>' + XLS_HEAD.join('</th><th>') + '</th></tr></thead><tbody>'
      + rows.map(function (r) {
        return '<tr>' + r.map(function (c) { return '<td>' + String(c == null ? '' : c) + '</td>'; }).join('') + '</tr>';
      }).join('')
      + '</tbody></table>'
      + '<table style="margin-top:10px"><tbody>'
      + '<tr><td style="border:0">说明</td><td style="border:0">地点可写多个，用顿号或逗号分隔；写机构名关键词即可，工具会自动匹配全名。</td></tr>'
      + '<tr><td style="border:0">说明</td><td style="border:0">周几写“周一”到“周日”，多个用顿号分隔；也可以只写“下周”表示全周。</td></tr>'
      + '<tr><td style="border:0">说明</td><td style="border:0">任意天数填“是”= 弹性任务，只在所选几天里挑一天排。</td></tr>'
      + '<tr><td style="border:0">说明</td><td style="border:0">导入只新增任务，不会动人员、辖区、固定轮班。</td></tr>'
      + '</tbody></table></body></html>';
    download('排班任务导入模板.xls', html, 'application/vnd.ms-excel');
    toast('模板已下载，填好再点「导入任务 Excel」');
  }

  function parseWeekDays(txt) {
    var map = { '一': 0, '二': 1, '三': 2, '四': 3, '五': 4, '六': 5, '日': 6, '天': 6, '七': 6 };
    var out = [], t = String(txt || '');
    if (!t.trim()) return [0, 1, 2, 3, 4];
    if (/下周|本周|全周|每周|每天/.test(t) && !/周[一二三四五六日天七]/.test(t)) return [0, 1, 2, 3, 4, 5, 6];
    t.split(/[、,，\/\s]+/).forEach(function (x) {
      var m = String(x).match(/周?([一二三四五六日天七])/);
      if (m && map[m[1]] != null) { if (out.indexOf(map[m[1]]) < 0) out.push(map[m[1]]); }
    });
    return out.length ? out : [0, 1, 2, 3, 4];
  }
  function parseSlot(txt) {
    var t = String(txt || '');
    if (/上午|AM|am|上午半天/.test(t)) return 'am';
    if (/下午|PM|pm/.test(t)) return 'pm';
    if (/半天/.test(t)) return 'am';
    return 'all';
  }
  function parseWork(txt) {
    var t = String(txt || '');
    if (/高|H|high/i.test(t)) return 'high';
    if (/低|L|low/i.test(t)) return 'low';
    return 'mid';
  }
  function matchOrgs(keyword) {
    var kws = String(keyword || '').split(/[、,，\/]+/).map(function (x) { return x.trim(); }).filter(Boolean);
    var out = [], miss = [];
    kws.forEach(function (kw) {
      var hit = null;
      for (var i = 0; i < state.orgs.length; i++) {
        var o = state.orgs[i];
        if (o.n === kw || o.c === kw) { hit = o; break; }
      }
      if (!hit) {
        for (var j = 0; j < state.orgs.length; j++) {
          if (state.orgs[j].n.indexOf(kw) >= 0) { hit = state.orgs[j]; break; }
        }
      }
      if (hit) { if (!out.some(function (x) { return x.c === hit.c; })) out.push(hit); }
      else miss.push(kw);
    });
    return { hit: out, miss: miss };
  }
  /* 从 HTML 表格里扒出行（本工具导出的模板/回填表就是 HTML 表） */
  function importXls(file) {
    if (!file) return;
    var fr = new FileReader();
    fr.onload = function () {
      var html = String(fr.result || '');
      var bad = '';
      if (!/<table/i.test(html)) { bad = '这不是本工具导出的表格（真 .xlsx 请另存为「网页 .xls」或 CSV 再导入）'; }
      if (bad) return toast(bad);
      var box = document.createElement('div');
      box.innerHTML = html;
      var table = box.querySelector('table');
      var trs = table ? table.querySelectorAll('tr') : [];
      var added = 0, updated = 0, skipped = [];
      for (var i = 0; i < trs.length; i++) {
        var tds = trs[i].querySelectorAll('td,th');
        if (tds.length < 2) continue;
        var c = [];
        for (var k = 0; k < tds.length; k++) c.push(String(tds[k].textContent || '').trim());
        if (i === 0 && /地点/.test(c[0])) continue;
        if (/^说明$/.test(c[0])) continue;
        var loc = c[0];
        if (!loc) continue;
        var mt = matchOrgs(loc);
        if (!mt.hit.length) { skipped.push(loc); continue; }
        var days = parseWeekDays(c[1]);
        var slot = parseSlot(c[2]);
        var need = Math.max(1, Math.min(10, parseInt(c[3], 10) || 1));
        var work = parseWork(c[4]);
        var flex = /^(是|y|Y|yes|YES|true)$/.test(String(c[5] || '').trim());
        mt.hit.forEach(function (og) {
          if (flex) {
            var wd = days.filter(function (d) { return d <= 4; });
            if (!wd.length) wd = [0, 1, 2, 3, 4];
            var dup0 = null;
            state.plans.forEach(function (p) { if (p.orgCode === og.c && p.flex && p.slot === slot) dup0 = p; });
            if (dup0) { dup0.need = need; dup0.cands = wd; dup0.work = work; updated++; }
            else {
              state.plans.push({ id: 'pl' + Date.now() + '_fx_' + state.plans.length,
                orgCode: og.c, orgName: og.n, area: og.r2, flex: true, cands: wd, day: wd[0],
                slot: slot, need: need, work: work });
              added++;
            }
            return;
          }
          days.forEach(function (d) {
            var dup = null;
            state.plans.forEach(function (p) {
              if (p.orgCode === og.c && p.day === d && p.slot === slot && !p.flex) dup = p;
            });
            if (dup) { dup.need = need; dup.work = work; updated++; }
            else {
              state.plans.push({ id: 'pl' + Date.now() + '_' + d + '_' + state.plans.length,
                orgCode: og.c, orgName: og.n, area: og.r2, day: d, slot: slot, need: need, work: work });
              added++;
            }
          });
        });
      }
      save(); renderPlans(); renderResult();
      var msg = '导入完成：新增 ' + added + ' 条' + (updated ? '，更新 ' + updated + ' 条' : '');
      if (skipped.length) msg += '；认不出的地点 ' + skipped.length + ' 个：' + skipped.slice(0, 5).join('、');
      toast(msg);
    };
    fr.readAsText(file, 'utf-8');
  }

'''
assert anchor in s
s = s.replace(anchor, code + anchor, 1)

old = "    $('btnExportXls').addEventListener('click', exportXls);"
new = """    $('btnExportXls').addEventListener('click', exportXls);
    $('btnXlsTpl').addEventListener('click', xlsTemplate);
    $('btnXlsImport').addEventListener('click', function () { $('fileXls').click(); });
    $('fileXls').addEventListener('change', function () {
      importXls(this.files && this.files[0]);
      this.value = '';
    });"""
assert old in s
s = s.replace(old, new, 1)
io.open(p,'w',encoding='utf-8').write(s)
print('ok')
