{"id":57,"date":"2026-06-03T18:45:27","date_gmt":"2026-06-03T18:45:27","guid":{"rendered":"https:\/\/akku.cozyfluffy.com\/index.php\/pkt-sales-dashboard\/"},"modified":"2026-06-03T18:45:27","modified_gmt":"2026-06-03T18:45:27","slug":"pkt-sales-dashboard","status":"publish","type":"page","link":"https:\/\/akku.cozyfluffy.com\/index.php\/pkt-sales-dashboard\/","title":{"rendered":"PKT\u9500\u552e\u6570\u636e\u4eea\u8868\u677f"},"content":{"rendered":"<div class=\"pkt-dashboard-inline-bundle\"><style id=\"pkt-dashboard-inline-css\">:root {\n  --bg: #f8fbff;\n  --panel: rgba(255, 255, 255, 0.82);\n  --panel-strong: #ffffff;\n  --text: #101827;\n  --muted: #667085;\n  --line: #dbe5f1;\n  --blue: #2563eb;\n  --indigo: #4f46e5;\n  --green: #16a34a;\n  --orange: #f97316;\n  --purple: #9333ea;\n  --red: #dc2626;\n  --shadow: 0 18px 45px rgba(29, 78, 216, 0.12);\n}\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  margin: 0;\n  color: var(--text);\n  font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n  background: linear-gradient(135deg, #eff6ff 0%, #e0e7ff 100%);\n}\n\nbutton,\ninput,\nselect {\n  font: inherit;\n}\n\nbutton {\n  cursor: pointer;\n}\n\n.screen {\n  min-height: 100vh;\n}\n\n.center-screen {\n  display: grid;\n  min-height: 100vh;\n  place-items: center;\n  padding: 24px;\n}\n\n.hero {\n  width: min(820px, 100%);\n  text-align: center;\n}\n\n.hero h1 {\n  margin: 0 0 24px;\n  font-size: clamp(38px, 4.3vw, 48px);\n  font-weight: 700;\n  letter-spacing: 0;\n  line-height: 1;\n}\n\n.hero p {\n  margin: 0 auto 24px;\n  max-width: 760px;\n  color: #526071;\n  font-size: 20px;\n}\n\n.hero .primary-btn {\n  min-height: 48px;\n  border-radius: 6px;\n  padding: 12px 32px;\n  font-size: 18px;\n}\n\n.primary-btn,\n.secondary-btn,\n.ghost-btn,\n.danger-btn {\n  min-height: 40px;\n  border-radius: 8px;\n  border: 1px solid transparent;\n  padding: 10px 16px;\n  font-weight: 650;\n  transition: transform 0.16s ease, box-shadow 0.16s ease, background 0.16s ease;\n}\n\n.primary-btn {\n  background: #0f172a;\n  color: #fff;\n  box-shadow: 0 8px 22px rgba(15, 23, 42, 0.18);\n}\n\n.primary-btn:hover,\n.secondary-btn:hover,\n.ghost-btn:hover,\n.danger-btn:hover {\n  transform: translateY(-1px);\n}\n\n.secondary-btn {\n  background: #fff;\n  color: #172554;\n  border-color: var(--line);\n}\n\n.ghost-btn {\n  background: rgba(255, 255, 255, 0.62);\n  color: #1f2937;\n  border-color: rgba(148, 163, 184, 0.38);\n}\n\n.danger-btn {\n  background: #fff1f2;\n  color: #be123c;\n  border-color: #fecdd3;\n}\n\n.hint {\n  margin-top: 18px;\n  color: #748196;\n  font-size: 14px;\n}\n\n.auth-card {\n  width: min(440px, 100%);\n  border: 1px solid rgba(203, 213, 225, 0.9);\n  border-radius: 8px;\n  background: var(--panel-strong);\n  box-shadow: var(--shadow);\n}\n\n.auth-head {\n  padding: 28px 28px 10px;\n  text-align: center;\n}\n\n.auth-head h1 {\n  margin: 0 0 8px;\n  font-size: 25px;\n  font-weight: 800;\n}\n\n.auth-head p {\n  margin: 0;\n  color: var(--muted);\n}\n\n.tabs {\n  display: grid;\n  grid-template-columns: repeat(2, 1fr);\n  gap: 4px;\n  margin: 18px 28px 0;\n  padding: 4px;\n  border-radius: 8px;\n  background: #f1f5f9;\n}\n\n.tab-btn {\n  border: 0;\n  border-radius: 7px;\n  background: transparent;\n  padding: 8px 10px;\n  color: #475569;\n  font-weight: 650;\n}\n\n.tab-btn.active {\n  background: #fff;\n  color: #0f172a;\n  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);\n}\n\n.form {\n  display: grid;\n  gap: 16px;\n  padding: 22px 28px 28px;\n}\n\n.field {\n  display: grid;\n  gap: 8px;\n}\n\n.field label {\n  font-size: 14px;\n  font-weight: 650;\n}\n\n.field input,\n.field select {\n  width: 100%;\n  min-height: 42px;\n  border: 1px solid #cbd5e1;\n  border-radius: 8px;\n  padding: 8px 11px;\n  background: #fff;\n}\n\n.app-shell {\n  min-height: 100vh;\n  padding: 24px;\n  background: linear-gradient(135deg, #eff6ff 0%, #eef2ff 50%, #faf5ff 100%);\n}\n\n.dashboard {\n  max-width: 1280px;\n  margin: 0 auto;\n}\n\n.topbar {\n  display: flex;\n  align-items: flex-start;\n  justify-content: space-between;\n  gap: 18px;\n  min-height: 72px;\n  margin-bottom: 24px;\n}\n\n.brand {\n  display: flex;\n  align-items: flex-start;\n  gap: 16px;\n  min-width: 0;\n}\n\n.logo-wrap {\n  display: flex;\n  height: 68px;\n  width: 150px;\n  align-items: center;\n  justify-content: center;\n  overflow: hidden;\n  border: 1px solid #d6dde8;\n  border-radius: 8px;\n  background: #fff;\n  box-shadow: 0 10px 22px rgba(30, 64, 175, 0.1);\n}\n\n.logo-wrap img {\n  max-height: 56px;\n  width: auto;\n  max-width: 130px;\n}\n\n.brand h1 {\n  margin: 0;\n  font-size: clamp(30px, 4vw, 42px);\n  font-weight: 800;\n  line-height: 68px;\n  letter-spacing: 0;\n  background: linear-gradient(90deg, #2563eb, #9333ea);\n  -webkit-background-clip: text;\n  background-clip: text;\n  color: transparent;\n}\n\n.user-menu {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: flex-end;\n  gap: 8px;\n}\n\n.nav-tabs {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 8px;\n  margin-bottom: 22px;\n}\n\n.nav-tabs button {\n  border: 1px solid rgba(148, 163, 184, 0.45);\n  border-radius: 8px;\n  background: rgba(255, 255, 255, 0.68);\n  color: #334155;\n  padding: 10px 13px;\n  font-weight: 650;\n}\n\n.nav-tabs button.active {\n  background: #0f172a;\n  color: #fff;\n  border-color: #0f172a;\n}\n\n.nav-tabs button[data-accent=\"overview\"].active {\n  background: #3b82f6;\n  border-color: #3b82f6;\n}\n\n.nav-tabs button[data-accent=\"input\"].active {\n  background: #22c55e;\n  border-color: #22c55e;\n}\n\n.nav-tabs button[data-accent=\"targets\"].active {\n  background: #f97316;\n  border-color: #f97316;\n}\n\n.nav-tabs button[data-accent=\"overall\"].active {\n  background: #a855f7;\n  border-color: #a855f7;\n}\n\n.nav-tabs button[data-accent=\"salesperson\"].active {\n  background: #ec4899;\n  border-color: #ec4899;\n}\n\n.nav-tabs button[data-accent=\"tools\"].active {\n  background: #6366f1;\n  border-color: #6366f1;\n}\n\n.grid {\n  display: grid;\n  gap: 16px;\n}\n\n.metrics {\n  grid-template-columns: repeat(4, minmax(0, 1fr));\n}\n\n.two-col {\n  grid-template-columns: minmax(0, 1.2fr) minmax(320px, 0.8fr);\n}\n\n.three-col {\n  grid-template-columns: repeat(3, minmax(0, 1fr));\n}\n\n.card {\n  border: 1px solid rgba(203, 213, 225, 0.72);\n  border-radius: 8px;\n  background: var(--panel);\n  box-shadow: var(--shadow);\n  backdrop-filter: blur(12px);\n}\n\n.card-head {\n  display: flex;\n  align-items: flex-start;\n  justify-content: space-between;\n  gap: 12px;\n  padding: 18px 18px 8px;\n}\n\n.card h2,\n.card h3 {\n  margin: 0;\n  font-size: 17px;\n  font-weight: 800;\n}\n\n.card p {\n  margin: 4px 0 0;\n  color: var(--muted);\n  font-size: 14px;\n}\n\n.card-body {\n  padding: 16px 18px 18px;\n}\n\n.section-panel {\n  overflow: hidden;\n}\n\n.section-title-bar {\n  padding: 16px 24px;\n  color: #fff;\n}\n\n.section-title-bar h2 {\n  margin: 0;\n  font-size: 18px;\n  font-weight: 800;\n}\n\n.section-title-bar p {\n  margin: 4px 0 0;\n  color: rgba(255, 255, 255, 0.86);\n  font-size: 14px;\n}\n\n.bar-green {\n  background: linear-gradient(90deg, #22c55e, #10b981);\n}\n\n.bar-orange {\n  background: linear-gradient(90deg, #f97316, #ef4444);\n}\n\n.bar-pink {\n  background: linear-gradient(90deg, #ec4899, #a855f7);\n}\n\n.bar-indigo {\n  background: linear-gradient(90deg, #6366f1, #a855f7);\n}\n\n.metric-value {\n  margin-top: 10px;\n  font-size: 30px;\n  font-weight: 800;\n}\n\n.delta {\n  display: inline-flex;\n  align-items: center;\n  margin-top: 8px;\n  border-radius: 999px;\n  padding: 4px 9px;\n  font-size: 12px;\n  font-weight: 700;\n}\n\n.delta.up {\n  background: #dcfce7;\n  color: #166534;\n}\n\n.delta.down {\n  background: #fee2e2;\n  color: #991b1b;\n}\n\n.blue-card {\n  background: linear-gradient(135deg, #eff6ff, #dbeafe);\n  border-color: #bfdbfe;\n}\n\n.green-card {\n  background: linear-gradient(135deg, #f0fdf4, #dcfce7);\n  border-color: #bbf7d0;\n}\n\n.orange-card {\n  background: linear-gradient(135deg, #fff7ed, #ffedd5);\n  border-color: #fed7aa;\n}\n\n.purple-card {\n  background: linear-gradient(135deg, #faf5ff, #f3e8ff);\n  border-color: #e9d5ff;\n}\n\n.month-panel {\n  margin-bottom: 28px;\n  background: rgba(255, 255, 255, 0.94);\n  box-shadow: 0 18px 34px rgba(15, 23, 42, 0.14);\n}\n\n.month-panel-head {\n  padding: 24px 28px 6px;\n}\n\n.month-panel-head h2 {\n  font-size: 28px;\n}\n\n.month-panel-head p {\n  margin-top: 12px;\n  color: #64748b;\n  font-size: 21px;\n}\n\n.month-cards {\n  display: grid;\n  grid-template-columns: repeat(5, minmax(0, 1fr));\n  gap: 26px;\n  padding: 20px 0 12px;\n}\n\n.month-card,\n.annual-card {\n  min-height: 210px;\n  border: 1px solid rgba(191, 219, 254, 0.85);\n  border-radius: 8px;\n  padding: 28px;\n  box-shadow: 0 7px 16px rgba(15, 23, 42, 0.12);\n}\n\n.month-card-top,\n.annual-card {\n  display: flex;\n  justify-content: space-between;\n  gap: 16px;\n}\n\n.month-card h3,\n.annual-card h3 {\n  margin: 0 0 10px;\n  font-size: 21px;\n  font-weight: 600;\n}\n\n.month-value {\n  color: #1e3a8a;\n  font-size: 38px;\n  font-weight: 800;\n  line-height: 1.1;\n}\n\n.round-icon {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  width: 58px;\n  height: 58px;\n  flex: 0 0 58px;\n  border-radius: 50%;\n  background: #3b82f6;\n  color: #fff;\n  font-size: 28px;\n  font-weight: 800;\n}\n\n.month-green .round-icon,\n.annual-green .round-icon {\n  background: #10b981;\n}\n\n.month-amber .round-icon,\n.annual-amber .round-icon {\n  background: #f59e0b;\n}\n\n.month-purple .round-icon,\n.month-violet .round-icon,\n.annual-purple .round-icon {\n  background: #a855f7;\n}\n\n.month-blue,\n.annual-blue {\n  background: linear-gradient(135deg, #eff6ff, #dbeafe);\n  color: #2563eb;\n}\n\n.month-green,\n.annual-green {\n  background: linear-gradient(135deg, #ecfdf5, #d1fae5);\n  color: #047857;\n  border-color: #a7f3d0;\n}\n\n.month-violet {\n  background: linear-gradient(135deg, #faf5ff, #f3e8ff);\n  color: #6b21a8;\n  border-color: #e9d5ff;\n}\n\n.month-amber,\n.annual-amber {\n  background: linear-gradient(135deg, #fffbeb, #fef3c7);\n  color: #c2410c;\n  border-color: #fde68a;\n}\n\n.month-purple,\n.annual-purple {\n  background: linear-gradient(135deg, #faf5ff, #f3e8ff);\n  color: #7e22ce;\n  border-color: #e9d5ff;\n}\n\n.revenue-line {\n  display: flex;\n  justify-content: space-between;\n  gap: 16px;\n  margin-top: 22px;\n  border-top: 1px solid rgba(37, 99, 235, 0.18);\n  padding-top: 16px;\n  font-size: 18px;\n}\n\n.target-row {\n  display: grid;\n  grid-template-columns: 1fr 1fr;\n  margin-top: 16px;\n  color: #2563eb;\n  font-size: 18px;\n  line-height: 1.22;\n}\n\n.target-row strong {\n  color: #ef4444;\n}\n\n.progress-track {\n  height: 12px;\n  margin-top: 12px;\n  overflow: hidden;\n  border-radius: 999px;\n  background: #bfdbfe;\n}\n\n.progress-track i {\n  display: block;\n  height: 100%;\n  border-radius: inherit;\n  background: #3b82f6;\n}\n\n.annual-grid {\n  display: grid;\n  grid-template-columns: repeat(4, minmax(0, 1fr));\n  gap: 28px;\n  margin-bottom: 30px;\n}\n\n.annual-card {\n  min-height: 200px;\n  align-items: flex-start;\n}\n\n.annual-value {\n  margin-top: 34px;\n  font-size: 40px;\n  font-weight: 800;\n  line-height: 1;\n}\n\n.annual-card p {\n  margin: 10px 0 0;\n  color: currentColor;\n  font-size: 17px;\n}\n\n.trend-grid {\n  display: grid;\n  grid-template-columns: repeat(2, minmax(0, 1fr));\n  gap: 28px;\n  margin-bottom: 28px;\n}\n\n.chart-card {\n  overflow: hidden;\n  border-radius: 8px;\n  background: #fff;\n  box-shadow: 0 14px 30px rgba(15, 23, 42, 0.13);\n}\n\n.chart-title {\n  min-height: 128px;\n  padding: 28px 36px;\n  color: #fff;\n}\n\n.chart-title h2 {\n  margin: 0;\n  font-size: 34px;\n  font-weight: 800;\n}\n\n.chart-title p {\n  margin: 6px 0 0;\n  color: rgba(255, 255, 255, 0.92);\n  font-size: 23px;\n  font-weight: 600;\n}\n\n.chart-blue .chart-title {\n  background: linear-gradient(135deg, #3b82f6, #06b6d4);\n}\n\n.chart-green .chart-title {\n  background: linear-gradient(135deg, #10b981, #14b8a6);\n}\n\n.chart-orange .chart-title {\n  background: linear-gradient(135deg, #f59e0b, #f97316);\n}\n\n.chart-pink .chart-title {\n  background: linear-gradient(135deg, #a855f7, #ec4899);\n}\n\n.chart-stage {\n  padding: 26px 36px 22px;\n}\n\n.svg-chart {\n  width: 100%;\n  min-height: 300px;\n  overflow: visible;\n  color: #334155;\n  font-size: 18px;\n  font-weight: 600;\n}\n\n.svg-chart text {\n  fill: currentColor;\n}\n\n.svg-chart .green-text {\n  fill: #22c55e;\n  font-weight: 800;\n}\n\n.chart {\n  display: grid;\n  align-items: end;\n  min-height: 290px;\n  grid-template-columns: repeat(6, 1fr);\n  gap: 10px;\n  border-bottom: 1px solid #ccd6e4;\n  padding: 14px 6px 0;\n}\n\n.bar-group {\n  display: grid;\n  align-items: end;\n  height: 260px;\n  gap: 5px;\n  grid-template-columns: repeat(3, 1fr);\n}\n\n.bar {\n  min-height: 5px;\n  border-radius: 6px 6px 0 0;\n  background: var(--blue);\n}\n\n.bar.pi {\n  background: var(--orange);\n}\n\n.bar.ci {\n  background: var(--green);\n}\n\n.bar.revenue {\n  background: linear-gradient(180deg, #6366f1, #2563eb);\n}\n\n.chart-label {\n  margin-top: 8px;\n  color: #64748b;\n  font-size: 12px;\n  text-align: center;\n}\n\n.legend {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 12px;\n  margin-top: 14px;\n  color: #475569;\n  font-size: 13px;\n}\n\n.legend span {\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n}\n\n.dot {\n  width: 10px;\n  height: 10px;\n  border-radius: 50%;\n  background: var(--blue);\n}\n\n.dot.orange {\n  background: var(--orange);\n}\n\n.dot.green {\n  background: var(--green);\n}\n\n.dot.purple {\n  background: var(--purple);\n}\n\n.table-wrap {\n  overflow-x: auto;\n}\n\n.detail-table-wrap {\n  border: 1px solid #e2e8f0;\n  border-radius: 8px;\n  background: #fff;\n}\n\ntable {\n  width: 100%;\n  border-collapse: collapse;\n  min-width: 780px;\n}\n\nth,\ntd {\n  border-bottom: 1px solid #e2e8f0;\n  padding: 11px 10px;\n  text-align: left;\n  white-space: nowrap;\n}\n\nth {\n  color: #475569;\n  font-size: 13px;\n  font-weight: 800;\n  background: rgba(248, 250, 252, 0.72);\n}\n\n.details-layout {\n  grid-template-columns: minmax(0, 3fr) minmax(360px, 2fr);\n}\n\n.detail-record-table {\n  min-width: 1850px;\n}\n\n.salesperson-record-table {\n  min-width: 1100px;\n}\n\n.weekly-record-table {\n  min-width: 920px;\n}\n\n.weekly-total-row {\n  margin: 22px 0;\n}\n\n.weekly-actions {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 12px;\n}\n\n.detail-record-table th {\n  color: #64748b;\n  font-size: 15px;\n  line-height: 1.45;\n  vertical-align: bottom;\n  white-space: normal;\n}\n\n.detail-record-table td {\n  height: 70px;\n  font-size: 16px;\n}\n\n.record-actions {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n}\n\n.icon-btn {\n  min-height: 34px;\n  border: 1px solid transparent;\n  border-radius: 6px;\n  padding: 6px 9px;\n  background: #fff;\n  font-size: 13px;\n  font-weight: 750;\n}\n\n.icon-btn.edit {\n  color: #2563eb;\n  border-color: #bfdbfe;\n}\n\n.icon-btn.delete {\n  color: #dc2626;\n  border-color: #fecaca;\n}\n\n.detail-message {\n  margin-bottom: 12px;\n  text-align: left;\n}\n\n.modal-backdrop {\n  position: fixed;\n  inset: 0;\n  z-index: 100000;\n  display: grid;\n  place-items: start center;\n  overflow-y: auto;\n  padding: 42px 18px;\n  background: rgba(15, 23, 42, 0.74);\n}\n\n.edit-dialog {\n  width: min(560px, 100%);\n  border-radius: 8px;\n  background: #fff;\n  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.32);\n}\n\n.dialog-head {\n  display: flex;\n  align-items: flex-start;\n  justify-content: space-between;\n  gap: 14px;\n  border-bottom: 1px solid #e5e7eb;\n  padding: 18px 20px 14px;\n}\n\n.dialog-head h2 {\n  margin: 0;\n  font-size: 20px;\n}\n\n.dialog-head p {\n  margin: 4px 0 0;\n  color: #64748b;\n  font-size: 13px;\n}\n\n.dialog-close {\n  border: 0;\n  background: transparent;\n  color: #64748b;\n  font-size: 28px;\n  line-height: 1;\n}\n\n.dialog-grid {\n  display: grid;\n  grid-template-columns: repeat(3, minmax(0, 1fr));\n  gap: 16px;\n  padding: 18px 20px;\n}\n\n.dialog-grid .field {\n  align-content: start;\n}\n\n.dialog-grid .field label {\n  min-height: 42px;\n  color: #111827;\n  font-size: 14px;\n  line-height: 1.45;\n}\n\n.dialog-grid input:disabled {\n  background: #f8fafc;\n  color: #94a3b8;\n}\n\n.dialog-actions {\n  display: flex;\n  justify-content: flex-end;\n  gap: 10px;\n  border-top: 1px solid #e5e7eb;\n  padding: 14px 20px 18px;\n}\n\n.target-total-stack {\n  display: grid;\n  gap: 14px;\n  margin-bottom: 18px;\n}\n\n.target-total-row {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 20px;\n  min-height: 58px;\n  border: 1px solid;\n  border-radius: 8px;\n  padding: 16px 18px;\n  font-size: 20px;\n}\n\n.target-total-row strong,\n.target-total-row span {\n  font-size: 20px;\n  font-weight: 800;\n}\n\n.target-total-row.green {\n  border-color: #86efac;\n  background: #dcfce7;\n  color: #166534;\n}\n\n.target-total-row.blue {\n  border-color: #bfdbfe;\n  background: #dbeafe;\n  color: #1d4ed8;\n}\n\n.target-total-row.orange {\n  border-color: #fed7aa;\n  background: #ffedd5;\n  color: #c2410c;\n}\n\n.target-form {\n  display: grid;\n  gap: 18px;\n}\n\n.target-edit-table {\n  min-width: 920px;\n  border: 1px solid #e2e8f0;\n}\n\n.target-edit-table th,\n.target-edit-table td {\n  padding: 11px 14px;\n}\n\n.target-edit-table th {\n  font-size: 17px;\n}\n\n.target-edit-table td:first-child {\n  width: 140px;\n  color: #0f172a;\n  font-size: 18px;\n  font-weight: 650;\n}\n\n.target-input {\n  width: 100%;\n  min-height: 44px;\n  border: 1px solid #cbd5e1;\n  border-radius: 8px;\n  padding: 8px 12px;\n  background: #fff;\n  color: #111827;\n  font-size: 18px;\n}\n\n.target-input.green {\n  border-color: #bbf7d0;\n}\n\n.target-input.blue {\n  border-color: #bfdbfe;\n}\n\n.target-input.orange {\n  border-color: #fed7aa;\n}\n\n.target-save-btn {\n  width: 100%;\n  min-height: 52px;\n  font-size: 18px;\n}\n\n.target-save-btn:disabled {\n  cursor: wait;\n  opacity: 0.72;\n}\n\n.save-message {\n  color: #166534;\n  font-size: 14px;\n  font-weight: 700;\n  text-align: center;\n}\n\n.tools-grid {\n  grid-template-columns: repeat(3, minmax(0, 1fr));\n}\n\n.tool-card {\n  min-height: 132px;\n}\n\n.tool-card .card-body {\n  display: grid;\n  gap: 14px;\n}\n\n.form-grid {\n  grid-template-columns: repeat(4, minmax(0, 1fr));\n}\n\n.data-entry-form {\n  gap: 20px;\n}\n\n.data-entry-form .field label {\n  min-height: 30px;\n  color: #111827;\n  font-size: 15px;\n  font-weight: 800;\n}\n\n.data-entry-form input,\n.data-entry-form select {\n  min-height: 48px;\n  font-size: 17px;\n}\n\n.data-entry-form input:disabled {\n  background: #f8fafc;\n  color: #94a3b8;\n}\n\n.span-2 {\n  grid-column: span 2;\n}\n\n.full {\n  grid-column: 1 \/ -1;\n}\n\n.hidden {\n  display: none !important;\n}\n\n@media (max-width: 980px) {\n  .metrics,\n  .two-col,\n  .details-layout,\n  .three-col,\n  .tools-grid,\n  .month-cards,\n  .annual-grid,\n  .trend-grid,\n  .form-grid {\n    grid-template-columns: 1fr 1fr;\n  }\n\n  .details-layout,\n  .dialog-grid {\n    grid-template-columns: 1fr;\n  }\n\n  .span-2 {\n    grid-column: span 1;\n  }\n\n  .topbar {\n    flex-direction: column;\n  }\n\n  .user-menu {\n    justify-content: flex-start;\n  }\n}\n\n@media (max-width: 640px) {\n  .app-shell {\n    padding: 16px;\n  }\n\n  .hero p {\n    font-size: 17px;\n  }\n\n  .brand {\n    flex-direction: column;\n    gap: 10px;\n  }\n\n  .brand h1 {\n    line-height: 1.16;\n    font-size: 31px;\n    text-align: center;\n  }\n\n  .logo-wrap {\n    display: none;\n  }\n\n  .metrics,\n  .two-col,\n  .three-col,\n  .tools-grid,\n  .month-cards,\n  .annual-grid,\n  .trend-grid,\n  .form-grid {\n    grid-template-columns: 1fr;\n  }\n\n  .month-card,\n  .annual-card {\n    min-height: 160px;\n    padding: 22px;\n  }\n\n  .chart-title {\n    min-height: 110px;\n    padding: 22px;\n  }\n\n  .chart-title h2 {\n    font-size: 27px;\n  }\n\n  .chart-title p {\n    font-size: 17px;\n  }\n\n  .chart-stage {\n    padding: 18px 14px;\n  }\n\n  .chart {\n    gap: 5px;\n  }\n}\n<\/style><div class=\"pkt-dashboard-host\"><div id=\"pkt-dashboard-app\"><\/div><\/div><script id=\"pkt-dashboard-config\">window.PKT_DASHBOARD = {\"restUrl\":\"https:\/\/akku.cozyfluffy.com\/?rest_route=\/pkt-dashboard\/v1\/\",\"nonce\":\"779fe4f75b\",\"isLoggedIn\":false,\"loginUrl\":\"https:\/\/akku.cozyfluffy.com\/wp-login.php?redirect_to=https%3A%2F%2Fakku.cozyfluffy.com%2Findex.php%2Fpkt-sales-dashboard%2F\",\"currentUser\":\"\"};<\/script><script id=\"pkt-dashboard-inline-js\">const wpConfig = window.PKT_DASHBOARD || null;\n\nconst state = {\n  view: wpConfig && wpConfig.isLoggedIn ? \"dashboard\" : \"landing\",\n  authTab: \"signin\",\n  activeTab: \"overview\",\n  user: \"rayye@pkt.local\",\n  sales: [\n    { month: \"2026-01\", inquiries: 128, pktInquiries: 54, pktGolfInquiries: 36, idealakkuInquiries: 38, pi: 47, ci: 24, pktCi: 11, pktGolfCi: 6, idealakkuCi: 7, revenue: 46200, conversionRevenue: 9200, currentMonthInquiryCustomers: 12, pastInquiryCustomers: 7, golfCartInquiryCustomers: 4, pktRvInquiryCustomers: 5, pktBoatInquiryCustomers: 1, iaInquiryCustomers: 2 },\n    { month: \"2026-02\", inquiries: 142, pktInquiries: 63, pktGolfInquiries: 41, idealakkuInquiries: 38, pi: 52, ci: 29, pktCi: 13, pktGolfCi: 8, idealakkuCi: 8, revenue: 51840, conversionRevenue: 11200, currentMonthInquiryCustomers: 15, pastInquiryCustomers: 8, golfCartInquiryCustomers: 5, pktRvInquiryCustomers: 6, pktBoatInquiryCustomers: 2, iaInquiryCustomers: 2 },\n    { month: \"2026-03\", inquiries: 166, pktInquiries: 71, pktGolfInquiries: 48, idealakkuInquiries: 47, pi: 61, ci: 33, pktCi: 15, pktGolfCi: 9, idealakkuCi: 9, revenue: 67250, conversionRevenue: 14500, currentMonthInquiryCustomers: 18, pastInquiryCustomers: 9, golfCartInquiryCustomers: 6, pktRvInquiryCustomers: 7, pktBoatInquiryCustomers: 2, iaInquiryCustomers: 3 },\n    { month: \"2026-04\", inquiries: 154, pktInquiries: 66, pktGolfInquiries: 44, idealakkuInquiries: 44, pi: 58, ci: 31, pktCi: 14, pktGolfCi: 8, idealakkuCi: 9, revenue: 63890, conversionRevenue: 13100, currentMonthInquiryCustomers: 17, pastInquiryCustomers: 10, golfCartInquiryCustomers: 5, pktRvInquiryCustomers: 7, pktBoatInquiryCustomers: 2, iaInquiryCustomers: 3 },\n    { month: \"2026-05\", inquiries: 183, pktInquiries: 82, pktGolfInquiries: 52, idealakkuInquiries: 49, pi: 70, ci: 39, pktCi: 18, pktGolfCi: 11, idealakkuCi: 10, revenue: 78640, conversionRevenue: 16800, currentMonthInquiryCustomers: 22, pastInquiryCustomers: 11, golfCartInquiryCustomers: 8, pktRvInquiryCustomers: 8, pktBoatInquiryCustomers: 3, iaInquiryCustomers: 3 },\n    { month: \"2026-06\", inquiries: 196, pktInquiries: 91, pktGolfInquiries: 56, idealakkuInquiries: 49, pi: 76, ci: 43, pktCi: 20, pktGolfCi: 12, idealakkuCi: 11, revenue: 84520, conversionRevenue: 18100, currentMonthInquiryCustomers: 24, pastInquiryCustomers: 12, golfCartInquiryCustomers: 9, pktRvInquiryCustomers: 9, pktBoatInquiryCustomers: 3, iaInquiryCustomers: 3 }\n  ],\n  salespeople: [\n    { name: \"Nora\", active: 62, passive: 38, current: 12, past: 7 },\n    { name: \"Ryan\", active: 54, passive: 31, current: 10, past: 6 },\n    { name: \"Eva\", active: 44, passive: 28, current: 8, past: 5 },\n    { name: \"Mia\", active: 36, passive: 24, current: 6, past: 4 }\n  ],\n  targets: [\n    { month: \"2026-01\", base: 150000, balanced: 0, stretch: 0 },\n    { month: \"2026-02\", base: 170000, balanced: 0, stretch: 0 },\n    { month: \"2026-03\", base: 170000, balanced: 0, stretch: 0 },\n    { month: \"2026-04\", base: 180000, balanced: 0, stretch: 0 },\n    { month: \"2026-05\", base: 180000, balanced: 0, stretch: 0 },\n    { month: \"2026-06\", base: 200000, balanced: 0, stretch: 0 },\n    { month: \"2026-07\", base: 180000, balanced: 0, stretch: 0 },\n    { month: \"2026-08\", base: 120000, balanced: 0, stretch: 0 },\n    { month: \"2026-09\", base: 123000, balanced: 0, stretch: 0 },\n    { month: \"2026-10\", base: 160000, balanced: 0, stretch: 0 },\n    { month: \"2026-11\", base: 180000, balanced: 0, stretch: 0 },\n    { month: \"2026-12\", base: 150000, balanced: 0, stretch: 0 }\n  ],\n  targetSaving: false,\n  targetSaveMessage: \"\",\n  editingSalesMonth: null,\n  salesEditMessage: \"\",\n  salespersonRows: [],\n  weekly: [],\n  editingSalespersonKey: null,\n  salespersonEditMessage: \"\",\n  editingWeeklyKey: null,\n  weeklyEditMessage: \"\"\n};\n\nconst tabs = [\n  [\"overview\", \"\u6982\u89c8\", \"overview\"],\n  [\"input\", \"\u6570\u636e\u5f55\u5165\", \"input\"],\n  [\"targets\", \"\u76ee\u6807\u8bbe\u5b9a\", \"targets\"],\n  [\"overall-details\", \"\u6574\u4f53\u8be6\u7ec6\u6570\u636e\", \"overall\"],\n  [\"salesperson-details\", \"\u4e2a\u4eba\u8be6\u7ec6\u6570\u636e\", \"salesperson\"],\n  [\"tools\", \"\u6570\u636e\u7ba1\u7406\u5de5\u5177\", \"tools\"]\n];\n\nconst app = document.getElementById(\"pkt-dashboard-app\") || document.getElementById(\"app\");\n\nconst oldOverviewSeries = [\n  { label: \"01\u6708\", revenue: 92000, target: 150000, completion: 61.4, inquiries: 16, pktRv: 7, pktGolf: 2, ia: 7, currentNew: 1, pastNew: 0, conversionRate: 6, pi: 64, ciPktRv: 37, ciPktGolf: 0, ciIa: 8 },\n  { label: \"02\u6708\", revenue: 320000, target: 170000, completion: 187.5, inquiries: 24, pktRv: 9, pktGolf: 3, ia: 12, currentNew: 6, pastNew: 3, conversionRate: 12.5, pi: 111, ciPktRv: 93, ciPktGolf: 14, ciIa: 28 },\n  { label: \"03\u6708\", revenue: 267000, target: 170000, completion: 157.2, inquiries: 18, pktRv: 13, pktGolf: 0, ia: 5, currentNew: 2, pastNew: 2, conversionRate: 0, pi: 140, ciPktRv: 126, ciPktGolf: 0, ciIa: 24 },\n  { label: \"04\u6708\", revenue: 33000, target: 180000, completion: 18.3, inquiries: 0, pktRv: 0, pktGolf: 0, ia: 0, currentNew: 0, pastNew: 0, conversionRate: 0, pi: 24, ciPktRv: 12, ciPktGolf: 0, ciIa: 0 },\n  { label: \"05\u6708\", revenue: 0, target: 180000, completion: 0, inquiries: 0, pktRv: 0, pktGolf: 0, ia: 0, currentNew: 0, pastNew: 0, conversionRate: 0, pi: 0, ciPktRv: 0, ciPktGolf: 0, ciIa: 0 },\n  { label: \"06\u6708\", revenue: 0, target: 200000, completion: 0, inquiries: 0, pktRv: 0, pktGolf: 0, ia: 0, currentNew: 0, pastNew: 0, conversionRate: 0, pi: 0, ciPktRv: 0, ciPktGolf: 0, ciIa: 0 }\n];\n\nconst oldOverviewTotals = {\n  yearRevenue: 2229063.9,\n  totalInquiries: 360,\n  totalPi: 1171,\n  totalCi: 1176,\n  monthlyTarget: 200000,\n  monthLabel: \"2026\u5e746\u6708\"\n};\n\nfunction money(value) {\n  return value.toLocaleString(\"de-DE\", { style: \"currency\", currency: \"EUR\" });\n}\n\nfunction pct(value) {\n  return `${value.toFixed(1)}%`;\n}\n\nfunction totals() {\n  const rows = state.sales;\n  return rows.reduce(\n    (acc, row) => {\n      acc.revenue += row.revenue;\n      acc.inquiries += row.inquiries;\n      acc.pi += row.pi;\n      acc.ci += row.ci;\n      acc.customers += row.currentMonthInquiryCustomers + row.pastInquiryCustomers;\n      return acc;\n    },\n    { revenue: 0, inquiries: 0, pi: 0, ci: 0, customers: 0 }\n  );\n}\n\nfunction latest() {\n  return state.sales[state.sales.length - 1];\n}\n\nfunction previous() {\n  return state.sales[state.sales.length - 2] || latest();\n}\n\nfunction ensureTargetRows() {\n  const defaults = [\n    { month: \"2026-01\", base: 150000, balanced: 0, stretch: 0 },\n    { month: \"2026-02\", base: 170000, balanced: 0, stretch: 0 },\n    { month: \"2026-03\", base: 170000, balanced: 0, stretch: 0 },\n    { month: \"2026-04\", base: 180000, balanced: 0, stretch: 0 },\n    { month: \"2026-05\", base: 180000, balanced: 0, stretch: 0 },\n    { month: \"2026-06\", base: 200000, balanced: 0, stretch: 0 },\n    { month: \"2026-07\", base: 180000, balanced: 0, stretch: 0 },\n    { month: \"2026-08\", base: 120000, balanced: 0, stretch: 0 },\n    { month: \"2026-09\", base: 123000, balanced: 0, stretch: 0 },\n    { month: \"2026-10\", base: 160000, balanced: 0, stretch: 0 },\n    { month: \"2026-11\", base: 180000, balanced: 0, stretch: 0 },\n    { month: \"2026-12\", base: 150000, balanced: 0, stretch: 0 }\n  ];\n  const rowsByMonth = new Map(defaults.map((target) => [target.month, { ...target }]));\n  state.targets.forEach((target) => {\n    if (!target.month) return;\n    rowsByMonth.set(target.month, {\n      month: target.month,\n      base: Number(target.base) || 0,\n      balanced: Number(target.balanced) || 0,\n      stretch: Number(target.stretch) || 0\n    });\n  });\n  state.targets = Array.from(rowsByMonth.values()).sort((a, b) => a.month.localeCompare(b.month));\n  return state.targets;\n}\n\nfunction numberFromForm(form, name) {\n  return Math.max(0, Number(form.get(name)) || 0);\n}\n\nfunction setView(view) {\n  state.view = view;\n  render();\n}\n\nfunction handleLoginClick() {\n  if (wpConfig && !wpConfig.isLoggedIn) {\n    window.location.href = wpConfig.loginUrl;\n    return;\n  }\n  setView(\"auth\");\n}\n\nfunction setTab(tab) {\n  state.activeTab = tab;\n  render();\n}\n\nfunction landing() {\n  return `\n    <main class=\"screen center-screen\">\n      <section class=\"hero\">\n        <h1>PKT\u9500\u552e\u6570\u636e\u4eea\u8868\u677f<\/h1>\n        <p>\u4e13\u4e1a\u7684\u9500\u552e\u6570\u636e\u7ba1\u7406\u5e73\u53f0\uff0c\u5e2e\u52a9\u60a8\u8ddf\u8e2a\u8be2\u76d8\u3001PI\u3001CI\u548c\u8425\u6536\u6570\u636e<\/p>\n        <button class=\"primary-btn\" onclick=\"handleLoginClick()\">\u7acb\u5373\u767b\u5f55<\/button>\n        <div class=\"hint\">\u8fd8\u6ca1\u6709\u8d26\u6237\uff1f\u70b9\u51fb\u767b\u5f55\u9875\u9762\u7684\u6ce8\u518c\u9009\u9879\u5361\u521b\u5efa\u65b0\u8d26\u6237<\/div>\n      <\/section>\n    <\/main>\n  `;\n}\n\nfunction auth() {\n  const signin = state.authTab === \"signin\";\n  return `\n    <main class=\"screen center-screen\">\n      <section class=\"auth-card\">\n        <div class=\"auth-head\">\n          <h1>PKT\u9500\u552e\u6570\u636e\u4eea\u8868\u677f<\/h1>\n          <p>\u767b\u5f55\u6216\u6ce8\u518c\u4ee5\u8bbf\u95ee\u60a8\u7684\u9500\u552e\u6570\u636e<\/p>\n        <\/div>\n        <div class=\"tabs\">\n          <button class=\"tab-btn ${signin ? \"active\" : \"\"}\" onclick=\"state.authTab='signin';render()\">\u767b\u5f55<\/button>\n          <button class=\"tab-btn ${!signin ? \"active\" : \"\"}\" onclick=\"state.authTab='signup';render()\">\u6ce8\u518c<\/button>\n        <\/div>\n        <form class=\"form\" onsubmit=\"event.preventDefault(); wpConfig ? window.location.href = wpConfig.loginUrl : setView('dashboard')\">\n          ${signin ? \"\" : `<div class=\"field\"><label>\u7528\u6237\u540d<\/label><input placeholder=\"\u8bf7\u8f93\u5165\u7528\u6237\u540d\" value=\"rayye\" \/><\/div>`}\n          <div class=\"field\"><label>\u90ae\u7bb1\u5730\u5740<\/label><input type=\"email\" placeholder=\"\u8bf7\u8f93\u5165\u90ae\u7bb1\u5730\u5740\" value=\"${signin ? \"rayye@pkt.local\" : \"\"}\" \/><\/div>\n          <div class=\"field\"><label>\u5bc6\u7801<\/label><input type=\"password\" placeholder=\"${signin ? \"\u8bf7\u8f93\u5165\u5bc6\u7801\" : \"\u8bf7\u8f93\u5165\u5bc6\u7801\uff08\u81f3\u5c116\u4f4d\uff09\"}\" value=\"123456\" \/><\/div>\n          <button class=\"primary-btn\" type=\"submit\">${signin ? \"\u767b\u5f55\" : \"\u6ce8\u518c\"}<\/button>\n        <\/form>\n      <\/section>\n    <\/main>\n  `;\n}\n\nfunction shell(content) {\n  return `\n    <main class=\"screen app-shell\">\n      <section class=\"dashboard\">\n        <header class=\"topbar\">\n          <div class=\"brand\">\n            <button class=\"logo-wrap\" onclick=\"setTab('overview')\" title=\"\u8fd4\u56de\u6982\u89c8\u9875\u9762\">\n              <img decoding=\"async\" src=\".\/logo.png\" alt=\"Perfektium Logo\" \/>\n            <\/button>\n            <h1>PKT\u9500\u552e\u6570\u636e\u4eea\u8868\u677f<\/h1>\n          <\/div>\n          <div class=\"user-menu\">\n            <button class=\"ghost-btn\">\u56e2\u961f\u8d26\u53f7\u7ba1\u7406<\/button>\n            <button class=\"ghost-btn\">\u66f4\u6539\u5bc6\u7801<\/button>\n            <button class=\"secondary-btn\" onclick=\"setView('landing')\">\u9000\u51fa\u767b\u5f55<\/button>\n          <\/div>\n        <\/header>\n        <nav class=\"nav-tabs\">\n          ${tabs.map(([key, label, accent]) => `<button data-accent=\"${accent}\" class=\"${state.activeTab === key ? \"active\" : \"\"}\" onclick=\"setTab('${key}')\">${label}<\/button>`).join(\"\")}\n        <\/nav>\n        ${content}\n      <\/section>\n    <\/main>\n  `;\n}\n\nfunction metricCards() {\n  const total = totals();\n  const now = latest();\n  const prev = previous();\n  const conversion = total.inquiries ? (total.ci \/ total.inquiries) * 100 : 0;\n  const revenueChange = prev.revenue ? ((now.revenue - prev.revenue) \/ prev.revenue) * 100 : 0;\n  return `\n    <section class=\"grid metrics\">\n      ${metric(\"\u672c\u6708\u7d2f\u8ba1\u8425\u6536\", money(now.revenue), `${revenueChange >= 0 ? \"\u4e0a\u5347\" : \"\u4e0b\u964d\"} ${Math.abs(revenueChange).toFixed(1)}%`, \"blue-card\", revenueChange >= 0)}\n      ${metric(\"\u672c\u6708\u7d2f\u8ba1\u8be2\u76d8\", now.inquiries, `\u603b\u8be2\u76d8 ${total.inquiries}`, \"green-card\", true)}\n      ${metric(\"\u672c\u6708\u7d2f\u8ba1PI\", now.pi, `PI\u603b\u6570 ${total.pi}`, \"orange-card\", true)}\n      ${metric(\"\u672c\u6708\u7d2f\u8ba1CI\", now.ci, `\u8be2\u76d8\u8f6c\u5316\u7387 ${pct(conversion)}`, \"purple-card\", true)}\n    <\/section>\n  `;\n}\n\nfunction metric(title, value, detail, cls, up) {\n  return `\n    <article class=\"card ${cls}\">\n      <div class=\"card-head\"><h3>${title}<\/h3><\/div>\n      <div class=\"card-body\">\n        <div class=\"metric-value\">${value}<\/div>\n        <span class=\"delta ${up ? \"up\" : \"down\"}\">${detail}<\/span>\n      <\/div>\n    <\/article>\n  `;\n}\n\nfunction overview() {\n  return `\n    ${currentMonthDataBlock()}\n    ${annualSummaryBlock()}\n    ${trendChartsBlock()}\n    <section class=\"grid two-col\" style=\"margin-top:16px\">\n      <article class=\"card\">\n        <div class=\"card-head\"><div><h2>\u5feb\u6377\u5165\u53e3<\/h2><p>\u6e90\u7ad9\u6982\u89c8\u9875\u4e2d\u7684\u5e38\u7528\u64cd\u4f5c<\/p><\/div><\/div>\n        <div class=\"card-body grid\" style=\"grid-template-columns:1fr 1fr;gap:12px\">\n          <button class=\"secondary-btn\" onclick=\"setView('history')\">\u67e5\u770b\u5386\u53f2\u6570\u636e (\u5f80\u5e74)<\/button>\n          <button class=\"secondary-btn\" onclick=\"setView('weekly')\">\u5f55\u5165\u5468\u5ea6\u5ba2\u6237\u6570\u636e<\/button>\n        <\/div>\n      <\/article>\n      <article class=\"card\">\n        <div class=\"card-head\"><div><h2>\u65b0\u5ba2\u6237\u6570\u91cf\u7edf\u8ba1<\/h2><p>\u6309\u5468\/\u6708\u663e\u793a\u84dd\u8272\u3001\u7d2b\u8272\u3001\u7ea2\u8272\u5ba2\u6237\u6570\u91cf<\/p><\/div><\/div>\n        <div class=\"card-body\">${weeklyCustomerPreview()}<\/div>\n      <\/article>\n    <\/section>\n    <section class=\"grid two-col\" style=\"margin-top:16px\">\n      <article class=\"card\">\n        <div class=\"card-head\">\n          <div><h2>\u5e74\u8d8b\u52bf\u56fe\u8868<\/h2><p>2026\u5e74\u6708\u5ea6\u8be2\u76d8\u3001PI\u3001CI\u8d70\u52bf<\/p><\/div>\n        <\/div>\n        <div class=\"card-body\">${barChart()}<\/div>\n      <\/article>\n      <article class=\"card\">\n        <div class=\"card-head\">\n          <div><h2>\u5e74\u5ea6\u8425\u6536\u76ee\u6807\u5bf9\u6bd4<\/h2><p>\u5b9e\u9645\u8425\u6536\u4e0e\u4e09\u4e2a\u76ee\u6807\u5c42\u7ea7\u5bf9\u6bd4<\/p><\/div>\n        <\/div>\n        <div class=\"card-body\">${revenueTargetChart()}<\/div>\n      <\/article>\n    <\/section>\n    <section class=\"grid two-col\" style=\"margin-top:16px\">\n      <article class=\"card\">\n        <div class=\"card-head\"><div><h2>\u672c\u6708\u6570\u636e<\/h2><p>\u672c\u6708\u7684\u9500\u552e\u6570\u636e\u6982\u89c8<\/p><\/div><\/div>\n        <div class=\"card-body\">${summaryTable([latest()])}<\/div>\n      <\/article>\n      <article class=\"card\">\n        <div class=\"card-head\"><div><h2>\u65b0\u5ba2\u6237\u6570\u91cf\u8d8b\u52bf<\/h2><p>\u6309\u6708\u663e\u793a\u65b0\u5ba2\u6237\u6765\u6e90\u53ca\u603b\u6570<\/p><\/div><\/div>\n        <div class=\"card-body\">${customerSummary()}<\/div>\n      <\/article>\n    <\/section>\n    <section class=\"card\" style=\"margin-top:16px\">\n      <div class=\"card-head\"><div><h2>\u5916\u90e8\u5de5\u5177\u94fe\u63a5<\/h2><\/div><\/div>\n      <div class=\"card-body grid tools-grid\">${externalTools()}<\/div>\n    <\/section>\n  `;\n}\n\nfunction currentMonthDataBlock() {\n  const current = oldOverviewSeries[oldOverviewSeries.length - 1];\n  return `\n    <section class=\"card month-panel\">\n      <div class=\"card-head month-panel-head\">\n        <div>\n          <h2>\u672c\u6708\u6570\u636e<\/h2>\n          <p>${oldOverviewTotals.monthLabel} \u7684\u9500\u552e\u6570\u636e<\/p>\n        <\/div>\n      <\/div>\n      <div class=\"card-body\">\n        <div class=\"month-cards\">\n          ${monthlyMetricCard({\n            className: \"month-blue\",\n            title: \"\u672c\u6708\u7d2f\u8ba1\u8425\u6536\",\n            value: money(current.revenue),\n            icon: \"\u20ac\",\n            details: `\n              <div class=\"revenue-line\"><span>\u8f6c\u6362\u7ec4\u8425\u6536<\/span><strong>${money(0).replace(\"\u20ac\", \"\").trim()} \u20ac<\/strong><\/div>\n              <div class=\"target-row\"><span>\u5f53\u6708\u76ee\u6807:<br>${money(oldOverviewTotals.monthlyTarget).replace(\"\u20ac\", \"\").trim()} \u20ac<\/span><strong>\u5b8c\u6210\u7387:<br>0.0%<\/strong><\/div>\n              <div class=\"progress-track\"><i style=\"width:0%\"><\/i><\/div>\n            `\n          })}\n          ${monthlyMetricCard({ className: \"month-green\", title: \"\u672c\u6708\u7d2f\u8ba1\u8be2\u76d8\", value: current.inquiries, icon: \"\u2709\" })}\n          ${monthlyMetricCard({ className: \"month-violet\", title: \"\u672c\u6708\u8be2\u76d8\u8f6c\u5316\u7387\", value: \"0.0%\", icon: \"\u2197\" })}\n          ${monthlyMetricCard({ className: \"month-amber\", title: \"\u672c\u6708\u7d2f\u8ba1PI\", value: current.pi, icon: \"\u25a4\" })}\n          ${monthlyMetricCard({ className: \"month-purple\", title: \"\u672c\u6708\u7d2f\u8ba1CI\", value: current.ciPktRv + current.ciPktGolf + current.ciIa, icon: \"\u25c7\" })}\n        <\/div>\n      <\/div>\n    <\/section>\n  `;\n}\n\nfunction monthlyMetricCard({ className, title, value, icon, details = \"\" }) {\n  return `\n    <article class=\"month-card ${className}\">\n      <div class=\"month-card-top\">\n        <div>\n          <h3>${title}<\/h3>\n          <div class=\"month-value\">${value}<\/div>\n        <\/div>\n        <span class=\"round-icon\">${icon}<\/span>\n      <\/div>\n      ${details}\n    <\/article>\n  `;\n}\n\nfunction annualSummaryBlock() {\n  return `\n    <section class=\"annual-grid\">\n      ${annualCard(\"annual-blue\", \"\u5f53\u5e74\u7d2f\u8ba1\u8425\u6536\", money(oldOverviewTotals.yearRevenue), \"0% \u76f8\u6bd4\u4e0a\u6708\", \"\u20ac\")}\n      ${annualCard(\"annual-green\", \"\u603b\u8be2\u76d8\u6570\", oldOverviewTotals.totalInquiries.toLocaleString(), \"\u7d2f\u8ba1\u8be2\u76d8\u603b\u6570\", \"\u2709\")}\n      ${annualCard(\"annual-amber\", \"\u603bPI\u6570\u91cf\", oldOverviewTotals.totalPi.toLocaleString(), \"\u7d2f\u8ba1PI\u603b\u6570\", \"\u25a4\")}\n      ${annualCard(\"annual-purple\", \"\u603bCI\u6570\u91cf\", oldOverviewTotals.totalCi.toLocaleString(), \"\u7d2f\u8ba1CI\u603b\u6570\", \"\u25c7\")}\n    <\/section>\n  `;\n}\n\nfunction annualCard(className, title, value, caption, icon) {\n  return `\n    <article class=\"annual-card ${className}\">\n      <div>\n        <h3>${title}<\/h3>\n        <div class=\"annual-value\">${value}<\/div>\n        <p>${caption}<\/p>\n      <\/div>\n      <span class=\"round-icon\">${icon}<\/span>\n    <\/article>\n  `;\n}\n\nfunction trendChartsBlock() {\n  return `\n    <section class=\"trend-grid\">\n      ${chartCard(\"chart-blue\", \"\u8425\u6536\u8d8b\u52bf\u4e0e\u76ee\u6807\", \"\u76ee\u6807\u548c\u5b9e\u9645\u8425\u6536\u8d8b\u52bf\", revenueTrendChart())}\n      ${chartCard(\"chart-green\", \"\u8be2\u76d8\u6570\u91cf\u8d8b\u52bf\", \"\u6309\u6708\u663e\u793a\u8be2\u76d8\u6570\u91cf\u548c\u65b0\u5ba2\u6237\u6570\u91cf\u53d8\u5316 - \u67f1\u72b6\u56fe\u4e3a\u8be2\u76d8\u6570\u91cf\uff0c\u66f2\u7ebf\u4e3a\u65b0\u5ba2\u6237\u8f6c\u5316\", inquiryTrendChart())}\n      ${chartCard(\"chart-orange\", \"PI\u6570\u91cf\u8d8b\u52bf\", \"\u6309\u6708\u663e\u793aPI\u6570\u91cf\u53d8\u5316\", piTrendChart())}\n      ${chartCard(\"chart-pink\", \"CI\u6570\u91cf\u8d8b\u52bf\", \"\u6309\u6708\u663e\u793aCI\u6570\u91cf\u53d8\u5316 - PKT\u623f\u8f66\u3001PKT\u7403\u8f66\u3001IA\", ciTrendChart())}\n    <\/section>\n  `;\n}\n\nfunction chartCard(className, title, subtitle, chart) {\n  return `\n    <article class=\"chart-card ${className}\">\n      <div class=\"chart-title\">\n        <h2>${title}<\/h2>\n        <p>${subtitle}<\/p>\n      <\/div>\n      <div class=\"chart-stage\">${chart}<\/div>\n    <\/article>\n  `;\n}\n\nfunction linePoints(values, max, width = 620, height = 260, left = 52, top = 24) {\n  const step = width \/ (values.length - 1);\n  return values.map((value, index) => {\n    const x = left + index * step;\n    const y = top + height - (value \/ max) * height;\n    return [x, y];\n  });\n}\n\nfunction pathFrom(points) {\n  return points.map(([x, y], index) => `${index === 0 ? \"M\" : \"L\"}${x.toFixed(1)} ${y.toFixed(1)}`).join(\" \");\n}\n\nfunction svgGrid(maxLabel = \"320k\", color = \"#dbeafe\") {\n  return `\n    <g class=\"grid-lines\">\n      ${[0, 1, 2, 3, 4].map((i) => `<line x1=\"52\" y1=\"${24 + i * 65}\" x2=\"672\" y2=\"${24 + i * 65}\" stroke=\"${color}\" stroke-dasharray=\"4 4\"\/>`).join(\"\")}\n      ${oldOverviewSeries.map((_, i) => `<line x1=\"${52 + i * 124}\" y1=\"24\" x2=\"${52 + i * 124}\" y2=\"284\" stroke=\"${color}\" stroke-dasharray=\"4 4\"\/>`).join(\"\")}\n      <text x=\"12\" y=\"30\">${maxLabel}<\/text><text x=\"20\" y=\"96\">240k<\/text><text x=\"20\" y=\"160\">160k<\/text><text x=\"28\" y=\"224\">80k<\/text><text x=\"36\" y=\"288\">0k<\/text>\n    <\/g>\n  `;\n}\n\nfunction revenueTrendChart() {\n  const max = 330000;\n  const target = linePoints(oldOverviewSeries.map((item) => item.target), max);\n  const revenue = linePoints(oldOverviewSeries.map((item) => item.revenue), max);\n  const completion = linePoints(oldOverviewSeries.map((item) => item.completion * 1000), max);\n  return `\n    <svg class=\"svg-chart\" viewBox=\"0 0 730 360\" role=\"img\" aria-label=\"\u8425\u6536\u8d8b\u52bf\u4e0e\u76ee\u6807\">\n      ${svgGrid(\"320k\")}\n      <path d=\"${pathFrom(target)}\" fill=\"none\" stroke=\"#a3a3a3\" stroke-width=\"4\"\/>\n      <path d=\"${pathFrom(revenue)}\" fill=\"none\" stroke=\"#3b82f6\" stroke-width=\"5\"\/>\n      <path d=\"${pathFrom(completion)}\" fill=\"none\" stroke=\"#22c55e\" stroke-width=\"4\" stroke-dasharray=\"5 5\"\/>\n      ${revenue.map(([x, y]) => `<circle cx=\"${x}\" cy=\"${y}\" r=\"7\" fill=\"#3b82f6\"\/>`).join(\"\")}\n      ${target.map(([x, y]) => `<circle cx=\"${x}\" cy=\"${y}\" r=\"7\" fill=\"#a3a3a3\"\/>`).join(\"\")}\n      ${oldOverviewSeries.map((item, i) => `<text x=\"${52 + i * 124}\" y=\"310\" text-anchor=\"middle\">${item.label}<\/text><text class=\"green-text\" x=\"${52 + i * 124}\" y=\"340\" text-anchor=\"middle\">${item.completion.toFixed(1)}%<\/text>`).join(\"\")}\n      <g class=\"chart-legend\"><text x=\"250\" y=\"14\" fill=\"#999\">\u25cf \u76ee\u6807\u8425\u6536<\/text><text x=\"365\" y=\"14\" fill=\"#3b82f6\">\u25cf \u5b9e\u9645\u8425\u6536<\/text><text x=\"490\" y=\"14\" fill=\"#22c55e\">\u25cf \u5b8c\u6210\u7387<\/text><\/g>\n    <\/svg>\n  `;\n}\n\nfunction inquiryTrendChart() {\n  const max = 24;\n  const barW = 72;\n  const chartTop = 28;\n  const chartH = 260;\n  const currentNew = linePoints(oldOverviewSeries.map((item) => item.currentNew * 2), max, 620, 250, 52, 34);\n  const pastNew = linePoints(oldOverviewSeries.map((item) => item.pastNew * 2), max, 620, 250, 52, 34);\n  const conversion = linePoints(oldOverviewSeries.map((item) => item.conversionRate * 1.8), max, 620, 250, 52, 34);\n  return `\n    <svg class=\"svg-chart\" viewBox=\"0 0 730 360\" role=\"img\" aria-label=\"\u8be2\u76d8\u6570\u91cf\u8d8b\u52bf\">\n      ${svgGrid(\"24\", \"#d1fae5\").replaceAll(\"240k\", \"18\").replaceAll(\"160k\", \"12\").replaceAll(\"80k\", \"6\").replaceAll(\"0k\", \"0\")}\n      ${oldOverviewSeries.map((item, i) => {\n        const x = 52 + i * 124 - barW \/ 2;\n        const iaH = (item.ia \/ max) * chartH;\n        const golfH = (item.pktGolf \/ max) * chartH;\n        const rvH = (item.pktRv \/ max) * chartH;\n        let y = chartTop + chartH;\n        y -= rvH;\n        const rv = `<rect x=\"${x}\" y=\"${y}\" width=\"${barW}\" height=\"${rvH}\" fill=\"#10b981\"\/>`;\n        y -= golfH;\n        const golf = `<rect x=\"${x}\" y=\"${y}\" width=\"${barW}\" height=\"${golfH}\" fill=\"#f59e0b\"\/>`;\n        y -= iaH;\n        const ia = `<rect x=\"${x}\" y=\"${y}\" width=\"${barW}\" height=\"${iaH}\" fill=\"#2563eb\" rx=\"4\"\/>`;\n        return rv + golf + ia + `<text x=\"${52 + i * 124}\" y=\"316\" text-anchor=\"middle\">${item.label}<\/text>`;\n      }).join(\"\")}\n      <path d=\"${pathFrom(currentNew)}\" fill=\"none\" stroke=\"#ec4899\" stroke-width=\"4\"\/>\n      <path d=\"${pathFrom(pastNew)}\" fill=\"none\" stroke=\"#06b6d4\" stroke-width=\"4\"\/>\n      <path d=\"${pathFrom(conversion)}\" fill=\"none\" stroke=\"#f97316\" stroke-width=\"4\" stroke-dasharray=\"6 6\"\/>\n      <text x=\"130\" y=\"344\" fill=\"#10b981\">\u25a0 PKT\u623f\u8f66<\/text><text x=\"245\" y=\"344\" fill=\"#f59e0b\">\u25a0 PKT\u7403\u8f66<\/text><text x=\"360\" y=\"344\" fill=\"#2563eb\">\u25a0 IA<\/text><text x=\"450\" y=\"344\" fill=\"#ec4899\">- \u5f53\u6708\u8be2\u76d8\u8f6c\u5316\u65b0\u5ba2\u6237<\/text>\n    <\/svg>\n  `;\n}\n\nfunction piTrendChart() {\n  const max = 140;\n  return simpleBarChart(oldOverviewSeries.map((item) => item.pi), max, \"#f59e0b\", [\"140\", \"105\", \"70\", \"35\", \"0\"]);\n}\n\nfunction ciTrendChart() {\n  const max = 160;\n  const chartTop = 28;\n  const chartH = 260;\n  const barW = 80;\n  return `\n    <svg class=\"svg-chart\" viewBox=\"0 0 730 360\" role=\"img\" aria-label=\"CI\u6570\u91cf\u8d8b\u52bf\">\n      ${svgGrid(\"160\", \"#f3e8ff\").replaceAll(\"240k\", \"120\").replaceAll(\"160k\", \"80\").replaceAll(\"80k\", \"40\").replaceAll(\"0k\", \"0\")}\n      ${oldOverviewSeries.map((item, i) => {\n        const x = 52 + i * 124 - barW \/ 2;\n        const iaH = (item.ciIa \/ max) * chartH;\n        const golfH = (item.ciPktGolf \/ max) * chartH;\n        const rvH = (item.ciPktRv \/ max) * chartH;\n        let y = chartTop + chartH;\n        y -= rvH;\n        const rv = `<rect x=\"${x}\" y=\"${y}\" width=\"${barW}\" height=\"${rvH}\" fill=\"#8b5cf6\"\/>`;\n        y -= golfH;\n        const golf = `<rect x=\"${x}\" y=\"${y}\" width=\"${barW}\" height=\"${golfH}\" fill=\"#fb923c\"\/>`;\n        y -= iaH;\n        const ia = `<rect x=\"${x}\" y=\"${y}\" width=\"${barW}\" height=\"${iaH}\" fill=\"#60a5fa\" rx=\"4\"\/>`;\n        return rv + golf + ia + `<text x=\"${52 + i * 124}\" y=\"316\" text-anchor=\"middle\">${item.label}<\/text>`;\n      }).join(\"\")}\n      <text x=\"250\" y=\"344\" fill=\"#8b5cf6\">\u25a0 PKT\u623f\u8f66<\/text><text x=\"365\" y=\"344\" fill=\"#fb923c\">\u25a0 PKT\u7403\u8f66<\/text><text x=\"480\" y=\"344\" fill=\"#60a5fa\">\u25a0 IA<\/text>\n    <\/svg>\n  `;\n}\n\nfunction simpleBarChart(values, max, color, labels) {\n  const chartTop = 28;\n  const chartH = 260;\n  const barW = 86;\n  return `\n    <svg class=\"svg-chart\" viewBox=\"0 0 730 360\" role=\"img\" aria-label=\"PI\u6570\u91cf\u8d8b\u52bf\">\n      <g class=\"grid-lines\">\n        ${[0, 1, 2, 3, 4].map((i) => `<line x1=\"52\" y1=\"${chartTop + i * 65}\" x2=\"672\" y2=\"${chartTop + i * 65}\" stroke=\"#fde68a\" stroke-dasharray=\"4 4\"\/><text x=\"12\" y=\"${chartTop + i * 65 + 5}\">${labels[i]}<\/text>`).join(\"\")}\n        ${oldOverviewSeries.map((_, i) => `<line x1=\"${52 + i * 124}\" y1=\"${chartTop}\" x2=\"${52 + i * 124}\" y2=\"${chartTop + chartH}\" stroke=\"#fde68a\" stroke-dasharray=\"4 4\"\/>`).join(\"\")}\n      <\/g>\n      ${values.map((value, i) => {\n        const h = (value \/ max) * chartH;\n        const x = 52 + i * 124 - barW \/ 2;\n        const y = chartTop + chartH - h;\n        return `<rect x=\"${x}\" y=\"${y}\" width=\"${barW}\" height=\"${h}\" fill=\"${color}\" rx=\"5\"\/><text x=\"${52 + i * 124}\" y=\"316\" text-anchor=\"middle\">${oldOverviewSeries[i].label}<\/text>`;\n      }).join(\"\")}\n    <\/svg>\n  `;\n}\n\nfunction weeklyCustomerPreview() {\n  return `\n    <div class=\"grid\" style=\"gap:12px\">\n      ${miniStat(\"\u84dd\u8272\u5ba2\u6237\", 42)}\n      ${miniStat(\"\u7d2b\u8272\u5ba2\u6237\", 18)}\n      ${miniStat(\"\u7ea2\u8272\u5ba2\u6237\", 7)}\n    <\/div>\n  `;\n}\n\nfunction barChart() {\n  const max = Math.max(...state.sales.flatMap((row) => [row.inquiries, row.pi, row.ci]));\n  return `\n    <div class=\"chart\">\n      ${state.sales.map((row) => `\n        <div>\n          <div class=\"bar-group\">\n            <div class=\"bar\" style=\"height:${(row.inquiries \/ max) * 100}%\"><\/div>\n            <div class=\"bar pi\" style=\"height:${(row.pi \/ max) * 100}%\"><\/div>\n            <div class=\"bar ci\" style=\"height:${(row.ci \/ max) * 100}%\"><\/div>\n          <\/div>\n          <div class=\"chart-label\">${row.month.slice(5)}\u6708<\/div>\n        <\/div>\n      `).join(\"\")}\n    <\/div>\n    <div class=\"legend\"><span><i class=\"dot\"><\/i>\u8be2\u76d8<\/span><span><i class=\"dot orange\"><\/i>PI<\/span><span><i class=\"dot green\"><\/i>CI<\/span><\/div>\n  `;\n}\n\nfunction revenueTargetChart() {\n  const max = Math.max(...state.targets.map((t) => t.stretch), ...state.sales.map((s) => s.revenue));\n  return `\n    <div class=\"chart\">\n      ${state.sales.map((row, index) => {\n        const target = state.targets[index];\n        return `\n          <div>\n            <div class=\"bar-group\">\n              <div class=\"bar revenue\" style=\"height:${(row.revenue \/ max) * 100}%\"><\/div>\n              <div class=\"bar pi\" style=\"height:${(target.balanced \/ max) * 100}%\"><\/div>\n              <div class=\"bar ci\" style=\"height:${(target.stretch \/ max) * 100}%\"><\/div>\n            <\/div>\n            <div class=\"chart-label\">${row.month.slice(5)}\u6708<\/div>\n          <\/div>\n        `;\n      }).join(\"\")}\n    <\/div>\n    <div class=\"legend\"><span><i class=\"dot\"><\/i>\u5b9e\u9645\u8425\u6536<\/span><span><i class=\"dot orange\"><\/i>\u5e73\u8861\u76ee\u6807<\/span><span><i class=\"dot green\"><\/i>\u51b2\u523a\u76ee\u6807<\/span><\/div>\n  `;\n}\n\nfunction customerSummary() {\n  const row = latest();\n  const current = row.golfCartInquiryCustomers + row.pktRvInquiryCustomers + row.pktBoatInquiryCustomers + row.iaInquiryCustomers;\n  const total = current + row.pastInquiryCustomers;\n  return `\n    <div class=\"grid\" style=\"gap:12px\">\n      ${miniStat(\"\u5f53\u6708\u8be2\u76d8\u8f6c\u5316\", current)}\n      ${miniStat(\"\u8fc7\u5f80\u8be2\u76d8\u8f6c\u5316\", row.pastInquiryCustomers)}\n      ${miniStat(\"\u65b0\u5ba2\u6237\u603b\u6570\", total)}\n      ${miniStat(\"\u8f6c\u6362\u7ec4\u8425\u6536\", money(row.conversionRevenue))}\n    <\/div>\n  `;\n}\n\nfunction miniStat(label, value) {\n  return `<div class=\"card\" style=\"box-shadow:none\"><div class=\"card-body\"><p>${label}<\/p><div class=\"metric-value\" style=\"font-size:24px\">${value}<\/div><\/div><\/div>`;\n}\n\nfunction summaryTable(rows = state.sales) {\n  return `\n    <div class=\"table-wrap\">\n      <table>\n        <thead>\n          <tr><th>\u6708\u4efd<\/th><th>\u603b\u8be2\u76d8<\/th><th>PKT\u623f\u8f66\u8be2\u76d8<\/th><th>PKT\u7403\u8f66\u8be2\u76d8<\/th><th>Idealakku\u8be2\u76d8<\/th><th>PI<\/th><th>CI<\/th><th>\u6708\u5ea6\u8425\u6536<\/th><th>\u65b0\u5ba2\u6237\u603b\u6570<\/th><\/tr>\n        <\/thead>\n        <tbody>\n          ${rows.map((row) => `<tr><td>${row.month}<\/td><td>${row.inquiries}<\/td><td>${row.pktInquiries}<\/td><td>${row.pktGolfInquiries}<\/td><td>${row.idealakkuInquiries}<\/td><td>${row.pi}<\/td><td>${row.ci}<\/td><td>${money(row.revenue)}<\/td><td>${row.currentMonthInquiryCustomers + row.pastInquiryCustomers}<\/td><\/tr>`).join(\"\")}\n        <\/tbody>\n      <\/table>\n    <\/div>\n  `;\n}\n\nfunction salesDate(row) {\n  if (row.createdAt) return row.createdAt.slice(0, 10).replaceAll(\"-\", \"\/\");\n  const [year, month] = row.month.split(\"-\");\n  return `${year}\/${Number(month)}\/1`;\n}\n\nfunction salesRecordTable() {\n  const rows = [...state.sales].sort((a, b) => a.month.localeCompare(b.month));\n  return `\n    <div class=\"table-wrap detail-table-wrap\">\n      <table class=\"detail-record-table\">\n        <thead>\n          <tr>\n            <th>\u6708\u4efd<\/th>\n            <th>\u603b\u8be2\u76d8<\/th>\n            <th>PKT\u623f\u8f66\u8be2\u76d8<\/th>\n            <th>PKT\u7403\u8f66\u8be2\u76d8<\/th>\n            <th>Idealakku\u8be2\u76d8<\/th>\n            <th>PI\u6570\u91cf<\/th>\n            <th>CI\u6570\u91cf<\/th>\n            <th>PKT\u623f\u8f66CI<\/th>\n            <th>PKT\u7403\u8f66CI<\/th>\n            <th>Idealakku CI<\/th>\n            <th>\u6708\u5ea6\u8425\u6536<\/th>\n            <th>\u8f6c\u6362\u7ec4\u8425\u6536<\/th>\n            <th>\u5f53\u6708\u8be2\u76d8\u8f6c\u5316<\/th>\n            <th>\u8fc7\u5f80\u8be2\u76d8\u8f6c\u5316<\/th>\n            <th>\u65b0\u5ba2\u6237\u603b\u6570<\/th>\n            <th>\u7403\u8f66\u7535\u6c60\u8be2\u76d8\u8f6c\u5316<\/th>\n            <th>PKT\u623f\u8f66\u7535\u6c60\u8be2\u76d8\u8f6c\u5316<\/th>\n            <th>PKT\u8239\u8236\u7535\u6c60\u8be2\u76d8\u8f6c\u5316<\/th>\n            <th>IA\u8be2\u76d8\u8f6c\u5316<\/th>\n            <th>\u5f53\u6708\u8be2\u76d8\u8f6c\u5316\u7ec6\u5206\u603b\u548c<\/th>\n            <th>\u521b\u5efa\u65f6\u95f4<\/th>\n            <th>\u64cd\u4f5c<\/th>\n          <\/tr>\n        <\/thead>\n        <tbody>\n          ${rows.map((row) => {\n            const currentBreakdown = row.golfCartInquiryCustomers + row.pktRvInquiryCustomers + row.pktBoatInquiryCustomers + row.iaInquiryCustomers;\n            const newTotal = row.currentMonthInquiryCustomers + row.pastInquiryCustomers;\n            return `\n              <tr>\n                <td>${row.month}<\/td>\n                <td>${row.inquiries}<\/td>\n                <td>${row.pktInquiries}<\/td>\n                <td>${row.pktGolfInquiries}<\/td>\n                <td>${row.idealakkuInquiries}<\/td>\n                <td>${row.pi}<\/td>\n                <td><strong>${row.ci}<\/strong><\/td>\n                <td>${row.pktCi}<\/td>\n                <td>${row.pktGolfCi}<\/td>\n                <td>${row.idealakkuCi}<\/td>\n                <td>${money(row.revenue)}<\/td>\n                <td>${money(row.conversionRevenue)}<\/td>\n                <td>${row.currentMonthInquiryCustomers}<\/td>\n                <td>${row.pastInquiryCustomers}<\/td>\n                <td><strong>${newTotal}<\/strong><\/td>\n                <td>${row.golfCartInquiryCustomers}<\/td>\n                <td>${row.pktRvInquiryCustomers}<\/td>\n                <td>${row.pktBoatInquiryCustomers}<\/td>\n                <td>${row.iaInquiryCustomers}<\/td>\n                <td><strong>${currentBreakdown}<\/strong><\/td>\n                <td>${salesDate(row)}<\/td>\n                <td>\n                  <div class=\"record-actions\">\n                    <button class=\"icon-btn edit\" type=\"button\" onclick=\"openSalesEdit('${row.month}')\" title=\"\u7f16\u8f91\">\u7f16\u8f91<\/button>\n                    <button class=\"icon-btn delete\" type=\"button\" onclick=\"deleteSalesRecord('${row.month}')\" title=\"\u5220\u9664\">\u5220\u9664<\/button>\n                  <\/div>\n                <\/td>\n              <\/tr>\n            `;\n          }).join(\"\")}\n        <\/tbody>\n      <\/table>\n    <\/div>\n  `;\n}\n\nfunction salesEditField(name, label, value, disabled = false) {\n  return `\n    <div class=\"field\">\n      <label>${label}<\/label>\n      <input name=\"${disabled ? \"\" : name}\" data-field=\"${name}\" type=\"number\" min=\"0\" step=\"0.01\" value=\"${value ?? 0}\" ${disabled ? \"disabled\" : \"\"}>\n    <\/div>\n  `;\n}\n\nfunction salesEditModal(row) {\n  if (!row) return \"\";\n  const currentBreakdown = row.golfCartInquiryCustomers + row.pktRvInquiryCustomers + row.pktBoatInquiryCustomers + row.iaInquiryCustomers;\n  const totalCustomers = row.currentMonthInquiryCustomers + row.pastInquiryCustomers;\n  const label = row.month.replace(\"-\", \"\u5e74\") + \"\u6708\";\n  return `\n    <div class=\"modal-backdrop\" onclick=\"closeSalesEdit(event)\">\n      <form class=\"edit-dialog\" onsubmit=\"saveSales(event)\" oninput=\"refreshSalesEditTotals(this)\">\n        <div class=\"dialog-head\">\n          <div>\n            <h2>\u4fee\u6539 ${label} \u7684\u9500\u552e\u6570\u636e<\/h2>\n            <p>\u4fdd\u5b58\u540e\u4f1a\u66f4\u65b0\u6570\u636e\u5e93\u548c\u4eea\u8868\u76d8\u56fe\u8868<\/p>\n          <\/div>\n          <button class=\"dialog-close\" type=\"button\" onclick=\"closeSalesEdit()\">\u00d7<\/button>\n        <\/div>\n        <input type=\"hidden\" name=\"month\" value=\"${row.month}\">\n        <div class=\"dialog-grid\">\n          ${salesEditField(\"pktInquiries\", \"PKT\u623f\u8f66\u8be2\u76d8\u6570\u91cf\", row.pktInquiries)}\n          ${salesEditField(\"pktGolfInquiries\", \"PKT\u7403\u8f66\u8be2\u76d8\u6570\u91cf\", row.pktGolfInquiries)}\n          ${salesEditField(\"idealakkuInquiries\", \"Idealakku\u8be2\u76d8\u6570\u91cf\", row.idealakkuInquiries)}\n          ${salesEditField(\"inquiries\", \"\u603b\u8be2\u76d8\u6570\u91cf\uff08\u81ea\u52a8\u8ba1\u7b97\uff09\", row.inquiries, true)}\n          ${salesEditField(\"pi\", \"PI\u6570\u91cf\", row.pi)}\n          ${salesEditField(\"ci\", \"\u603bCI\u6570\u91cf\uff08\u81ea\u52a8\u8ba1\u7b97\uff09\", row.ci, true)}\n          ${salesEditField(\"pktCi\", \"PKT\u623f\u8f66CI\u6570\u91cf\", row.pktCi)}\n          ${salesEditField(\"pktGolfCi\", \"PKT\u7403\u8f66CI\u6570\u91cf\", row.pktGolfCi)}\n          ${salesEditField(\"idealakkuCi\", \"Idealakku CI\u6570\u91cf\", row.idealakkuCi)}\n          ${salesEditField(\"revenue\", \"\u6708\u5ea6\u8425\u6536 (\u20ac)\", row.revenue)}\n          ${salesEditField(\"conversionRevenue\", \"\u8f6c\u6362\u7ec4\u8425\u6536 (\u20ac)\", row.conversionRevenue)}\n          ${salesEditField(\"currentMonthInquiryCustomers\", \"\u5f53\u6708\u8be2\u76d8\u8f6c\u5316\uff08\u81ea\u52a8\u8ba1\u7b97\uff09\", currentBreakdown, true)}\n          ${salesEditField(\"pastInquiryCustomers\", \"\u8fc7\u5f80\u8be2\u76d8\u8f6c\u5316\", row.pastInquiryCustomers)}\n          ${salesEditField(\"totalCustomers\", \"\u65b0\u5ba2\u6237\u603b\u6570\uff08\u81ea\u52a8\u8ba1\u7b97\uff09\", totalCustomers, true)}\n          ${salesEditField(\"golfCartInquiryCustomers\", \"\u5f53\u6708\u7403\u8f66\u7535\u6c60\u8be2\u76d8\u8f6c\u5316\", row.golfCartInquiryCustomers)}\n          ${salesEditField(\"pktRvInquiryCustomers\", \"\u5f53\u6708PKT\u623f\u8f66\u7535\u6c60\u8be2\u76d8\u8f6c\u5316\", row.pktRvInquiryCustomers)}\n          ${salesEditField(\"pktBoatInquiryCustomers\", \"\u5f53\u6708PKT\u8239\u8236\u7535\u6c60\u8be2\u76d8\u8f6c\u5316\", row.pktBoatInquiryCustomers)}\n          ${salesEditField(\"iaInquiryCustomers\", \"\u5f53\u6708IA\u8be2\u76d8\u8f6c\u5316\", row.iaInquiryCustomers)}\n        <\/div>\n        <div class=\"dialog-actions\">\n          <button class=\"secondary-btn\" type=\"button\" onclick=\"closeSalesEdit()\">\u53d6\u6d88<\/button>\n          <button class=\"primary-btn\" type=\"submit\">\u4fdd\u5b58\u66f4\u6539<\/button>\n        <\/div>\n      <\/form>\n    <\/div>\n  `;\n}\n\nfunction openSalesEdit(month) {\n  state.editingSalesMonth = month;\n  state.salesEditMessage = \"\";\n  render();\n}\n\nfunction closeSalesEdit(event) {\n  if (event && event.target !== event.currentTarget) return;\n  state.editingSalesMonth = null;\n  render();\n}\n\nfunction readDialogNumber(form, field) {\n  const input = form.querySelector(`[data-field=\"${field}\"]`);\n  return Number(input?.value || 0);\n}\n\nfunction writeDialogNumber(form, field, value) {\n  const input = form.querySelector(`[data-field=\"${field}\"]`);\n  if (input) input.value = String(value);\n}\n\nfunction refreshSalesEditTotals(form) {\n  const inquiries = readDialogNumber(form, \"pktInquiries\") + readDialogNumber(form, \"pktGolfInquiries\") + readDialogNumber(form, \"idealakkuInquiries\");\n  const ci = readDialogNumber(form, \"pktCi\") + readDialogNumber(form, \"pktGolfCi\") + readDialogNumber(form, \"idealakkuCi\");\n  const current = readDialogNumber(form, \"golfCartInquiryCustomers\") + readDialogNumber(form, \"pktRvInquiryCustomers\") + readDialogNumber(form, \"pktBoatInquiryCustomers\") + readDialogNumber(form, \"iaInquiryCustomers\");\n  const totalCustomers = current + readDialogNumber(form, \"pastInquiryCustomers\");\n  writeDialogNumber(form, \"inquiries\", inquiries);\n  writeDialogNumber(form, \"ci\", ci);\n  writeDialogNumber(form, \"currentMonthInquiryCustomers\", current);\n  writeDialogNumber(form, \"totalCustomers\", totalCustomers);\n}\n\nfunction refreshEntryTotals(form) {\n  const year = form.querySelector('[data-field=\"year\"]')?.value || \"2026\";\n  const monthPart = form.querySelector('[data-field=\"monthPart\"]')?.value || \"01\";\n  const monthInput = form.querySelector('[data-field=\"month\"]');\n  if (monthInput) monthInput.value = `${year}-${monthPart}`;\n\n  const inquiries = readDialogNumber(form, \"pktInquiries\") + readDialogNumber(form, \"pktGolfInquiries\") + readDialogNumber(form, \"idealakkuInquiries\");\n  const ci = readDialogNumber(form, \"pktCi\") + readDialogNumber(form, \"pktGolfCi\") + readDialogNumber(form, \"idealakkuCi\");\n  const current = readDialogNumber(form, \"golfCartInquiryCustomers\") + readDialogNumber(form, \"pktRvInquiryCustomers\") + readDialogNumber(form, \"pktBoatInquiryCustomers\") + readDialogNumber(form, \"iaInquiryCustomers\");\n  const totalCustomers = current + readDialogNumber(form, \"pastInquiryCustomers\");\n  writeDialogNumber(form, \"inquiries\", inquiries);\n  writeDialogNumber(form, \"ci\", ci);\n  writeDialogNumber(form, \"currentMonthInquiryCustomers\", current);\n  writeDialogNumber(form, \"currentMonthInquiryBreakdownTotal\", current);\n  writeDialogNumber(form, \"totalCustomers\", totalCustomers);\n}\n\nfunction deleteSalesRecord(month) {\n  if (!window.confirm(`\u786e\u5b9a\u5220\u9664 ${month} \u7684\u9500\u552e\u6570\u636e\u5417\uff1f`)) return;\n  state.sales = state.sales.filter((row) => row.month !== month);\n  state.editingSalesMonth = null;\n  state.salesEditMessage = `${month} \u9500\u552e\u6570\u636e\u5df2\u5220\u9664\u3002`;\n  deleteRemoteSales(month);\n  render();\n}\n\nasync function deleteRemoteSales(month) {\n  if (!wpConfig || !wpConfig.isLoggedIn) return;\n  try {\n    await fetch(`${wpConfig.restUrl}sales\/${month}&_method=DELETE`, {\n      method: \"POST\",\n      headers: { \"X-WP-Nonce\": wpConfig.nonce },\n      credentials: \"same-origin\"\n    });\n  } catch (error) {\n    console.error(\"Unable to delete sales data\", error);\n  }\n}\n\nfunction entry() {\n  const currentYear = \"2026\";\n  const currentMonth = \"07\";\n  return `\n    <article class=\"card section-panel\">\n      <div class=\"section-title-bar bar-green\"><h2>\u5f55\u5165\u9500\u552e\u6570\u636e<\/h2><p>\u8bf7\u8f93\u5165\u6708\u5ea6\u9500\u552e\u6570\u636e\uff0c\u5305\u62ec\u8be2\u76d8\u6570\u91cf\u3001PI\u6570\u91cf\u3001CI\u6570\u91cf\u548c\u5f53\u6708\u8425\u6536<\/p><\/div>\n      <form class=\"card-body grid form-grid data-entry-form\" onsubmit=\"saveSales(event)\" oninput=\"refreshEntryTotals(this)\" onchange=\"refreshEntryTotals(this)\">\n        <input type=\"hidden\" name=\"month\" data-field=\"month\" value=\"${currentYear}-${currentMonth}\">\n        ${selectField(\"year\", \"\u5e74\u4efd\", [\"2026\", \"2025\", \"2024\"], currentYear)}\n        ${selectField(\"monthPart\", \"\u6708\u4efd\", [\n          [\"01\", \"1\u6708\"],\n          [\"02\", \"2\u6708\"],\n          [\"03\", \"3\u6708\"],\n          [\"04\", \"4\u6708\"],\n          [\"05\", \"5\u6708\"],\n          [\"06\", \"6\u6708\"],\n          [\"07\", \"7\u6708\"],\n          [\"08\", \"8\u6708\"],\n          [\"09\", \"9\u6708\"],\n          [\"10\", \"10\u6708\"],\n          [\"11\", \"11\u6708\"],\n          [\"12\", \"12\u6708\"]\n        ], currentMonth)}\n        ${entryField(\"inquiries\", \"\u603b\u8be2\u76d8\u6570\u91cf\uff08\u81ea\u52a8\u8ba1\u7b97\uff09\", 0, true)}\n        ${entryField(\"pktInquiries\", \"PKT\u623f\u8f66\u8be2\u76d8\u6570\u91cf\", 0)}\n        ${entryField(\"pktGolfInquiries\", \"PKT\u7403\u8f66\u8be2\u76d8\u6570\u91cf\", 0)}\n        ${entryField(\"idealakkuInquiries\", \"Idealakku\u8be2\u76d8\u6570\u91cf\", 0)}\n        ${entryField(\"pi\", \"PI\u6570\u91cf\", 0, false, \"span-2\")}\n        ${entryField(\"ci\", \"\u603bCI\u6570\u91cf\uff08\u81ea\u52a8\u8ba1\u7b97\uff09\", 0, true, \"span-2\")}\n        ${entryField(\"pktCi\", \"PKT\u623f\u8f66CI\u6570\u91cf\", 0)}\n        ${entryField(\"pktGolfCi\", \"PKT\u7403\u8f66CI\u6570\u91cf\", 0)}\n        ${entryField(\"idealakkuCi\", \"Idealakku CI\u6570\u91cf\", 0)}\n        ${entryField(\"revenue\", \"\u5f53\u6708\u8425\u6536 (\u20ac)\", 0, false, \"full\")}\n        ${entryField(\"currentMonthInquiryCustomers\", \"\u5f53\u6708\u8be2\u76d8\u8f6c\u5316\uff08\u81ea\u52a8\u8ba1\u7b97\uff09\", 0, true)}\n        ${entryField(\"pastInquiryCustomers\", \"\u8fc7\u5f80\u8be2\u76d8\u8f6c\u5316\", 0)}\n        ${entryField(\"totalCustomers\", \"\u65b0\u5ba2\u6237\u603b\u6570\uff08\u81ea\u52a8\u8ba1\u7b97\uff09\", 0, true)}\n        ${entryField(\"golfCartInquiryCustomers\", \"\u5f53\u6708\u7403\u8f66\u7535\u6c60\u8be2\u76d8\u8f6c\u5316\", 0)}\n        ${entryField(\"pktRvInquiryCustomers\", \"\u5f53\u6708PKT\u623f\u8f66\u7535\u6c60\u8be2\u76d8\u8f6c\u5316\", 0)}\n        ${entryField(\"pktBoatInquiryCustomers\", \"\u5f53\u6708PKT\u8239\u8236\u7535\u6c60\u8be2\u76d8\u8f6c\u5316\", 0)}\n        ${entryField(\"iaInquiryCustomers\", \"\u5f53\u6708IA\u8be2\u76d8\u8f6c\u5316\", 0)}\n        ${entryField(\"currentMonthInquiryBreakdownTotal\", \"\u5f53\u6708\u8be2\u76d8\u8f6c\u5316\u7ec6\u5206\u603b\u548c\uff08\u81ea\u52a8\u8ba1\u7b97\uff09\", 0, true)}\n        ${entryField(\"conversionRevenue\", \"\u8f6c\u6362\u7ec4\u8425\u6536 (\u20ac)\", 0, false, \"full\")}\n        <div class=\"full\"><button class=\"primary-btn target-save-btn\" type=\"submit\">\u4fdd\u5b58\u6570\u636e<\/button><\/div>\n      <\/form>\n    <\/article>\n  `;\n}\n\nfunction input(name, label, type, value) {\n  return `<div class=\"field\"><label>${label}<\/label><input name=\"${name}\" type=\"${type}\" value=\"${value}\" min=\"0\" \/><\/div>`;\n}\n\nfunction entryField(name, label, value, disabled = false, extraClass = \"\") {\n  return `\n    <div class=\"field ${extraClass}\">\n      <label>${label}<\/label>\n      <input name=\"${disabled ? \"\" : name}\" data-field=\"${name}\" type=\"number\" min=\"0\" step=\"0.01\" value=\"${value ?? 0}\" ${disabled ? \"disabled\" : \"\"}>\n    <\/div>\n  `;\n}\n\nfunction selectField(name, label, options, value) {\n  const items = options.map((option) => Array.isArray(option) ? option : [option, option]);\n  return `\n    <div class=\"field span-2\">\n      <label>${label}<\/label>\n      <select name=\"${name}\" data-field=\"${name}\">\n        ${items.map(([key, labelText]) => `<option value=\"${key}\" ${key === value ? \"selected\" : \"\"}>${labelText}<\/option>`).join(\"\")}\n      <\/select>\n    <\/div>\n  `;\n}\n\nfunction normalizeSalesRow(raw) {\n  const row = { ...raw };\n  if (!row.month && raw.year && raw.monthPart) {\n    row.month = `${raw.year}-${String(raw.monthPart).padStart(2, \"0\")}`;\n  }\n  const numericKeys = [\n    \"inquiries\",\n    \"pktInquiries\",\n    \"pktGolfInquiries\",\n    \"idealakkuInquiries\",\n    \"pi\",\n    \"ci\",\n    \"pktCi\",\n    \"pktGolfCi\",\n    \"idealakkuCi\",\n    \"revenue\",\n    \"conversionRevenue\",\n    \"currentMonthInquiryCustomers\",\n    \"pastInquiryCustomers\",\n    \"golfCartInquiryCustomers\",\n    \"pktRvInquiryCustomers\",\n    \"pktBoatInquiryCustomers\",\n    \"iaInquiryCustomers\"\n  ];\n  numericKeys.forEach((key) => {\n    row[key] = Number(row[key] || 0);\n  });\n\n  const hasInquiryBreakdown = [\"pktInquiries\", \"pktGolfInquiries\", \"idealakkuInquiries\"].some((key) => Object.prototype.hasOwnProperty.call(raw, key));\n  if (!Object.prototype.hasOwnProperty.call(raw, \"inquiries\") && hasInquiryBreakdown) {\n    row.inquiries = row.pktInquiries + row.pktGolfInquiries + row.idealakkuInquiries;\n  }\n\n  const hasCiBreakdown = [\"pktCi\", \"pktGolfCi\", \"idealakkuCi\"].some((key) => Object.prototype.hasOwnProperty.call(raw, key));\n  if (hasCiBreakdown) {\n    row.ci = row.pktCi + row.pktGolfCi + row.idealakkuCi;\n  } else {\n    row.pktCi = Math.round(row.ci * 0.45);\n    row.pktGolfCi = Math.round(row.ci * 0.28);\n    row.idealakkuCi = row.ci - row.pktCi - row.pktGolfCi;\n  }\n\n  const hasConversionBreakdown = [\"golfCartInquiryCustomers\", \"pktRvInquiryCustomers\", \"pktBoatInquiryCustomers\", \"iaInquiryCustomers\"].some((key) => Object.prototype.hasOwnProperty.call(raw, key));\n  if (!Object.prototype.hasOwnProperty.call(raw, \"currentMonthInquiryCustomers\") && hasConversionBreakdown) {\n    row.currentMonthInquiryCustomers = row.golfCartInquiryCustomers + row.pktRvInquiryCustomers + row.pktBoatInquiryCustomers + row.iaInquiryCustomers;\n  }\n\n  return row;\n}\n\nasync function saveSales(event) {\n  event.preventDefault();\n  const form = new FormData(event.target);\n  const row = normalizeSalesRow(Object.fromEntries(form.entries()));\n  const index = state.sales.findIndex((item) => item.month === row.month);\n  if (index >= 0) state.sales[index] = { ...state.sales[index], ...row };\n  else state.sales.push(row);\n  state.sales.sort((a, b) => a.month.localeCompare(b.month));\n  const saved = await saveRemoteSales(row);\n  state.activeTab = \"overall-details\";\n  state.editingSalesMonth = null;\n  state.salesEditMessage = saved ? \"\u9500\u552e\u6570\u636e\u5df2\u4fdd\u5b58\u3002\" : \"\u4fdd\u5b58\u5931\u8d25\uff0c\u8bf7\u5237\u65b0\u540e\u91cd\u8bd5\u3002\";\n  render();\n}\n\nasync function saveRemoteSales(row) {\n  if (!wpConfig || !wpConfig.isLoggedIn) return true;\n  try {\n    const response = await fetch(`${wpConfig.restUrl}sales`, {\n      method: \"POST\",\n      headers: {\n        \"content-type\": \"application\/json\",\n        \"X-WP-Nonce\": wpConfig.nonce\n      },\n      credentials: \"same-origin\",\n      body: JSON.stringify(row)\n    });\n    if (!response.ok) throw new Error(`Save failed: ${response.status}`);\n    return true;\n  } catch (error) {\n    console.error(\"Unable to save sales data\", error);\n    return false;\n  }\n}\n\nfunction salespersonDetails() {\n  const max = Math.max(...state.salespeople.map((person) => person.active + person.passive));\n  return `\n    <section class=\"grid two-col\">\n      <article class=\"card section-panel\">\n        <div class=\"section-title-bar bar-pink\"><h2>\u5f55\u5165\u4e1a\u52a1\u5458\u6570\u636e<\/h2><p>\u8bf7\u8f93\u5165\u5404\u4e1a\u52a1\u5458\u7684\u8be2\u76d8\u548c\u8f6c\u5316\u6570\u636e<\/p><\/div>\n        <div class=\"card-body\">${salespersonTable()}<\/div>\n      <\/article>\n      <article class=\"card\">\n        <div class=\"card-head\"><div><h2>\u4e1a\u52a1\u5458\u8be2\u76d8\u548c\u8f6c\u5316\u60c5\u51b5<\/h2><p>\u5404\u4e1a\u52a1\u5458\u7684\u8be2\u76d8\u6570\u91cf\u548c\u5ba2\u6237\u8f6c\u5316\u60c5\u51b5<\/p><\/div><\/div>\n        <div class=\"card-body\">\n          <div class=\"chart\" style=\"grid-template-columns:repeat(${state.salespeople.length},1fr)\">\n            ${state.salespeople.map((person) => `<div><div class=\"bar-group\" style=\"grid-template-columns:1fr 1fr\"><div class=\"bar\" style=\"height:${((person.active + person.passive) \/ max) * 100}%\"><\/div><div class=\"bar ci\" style=\"height:${((person.current + person.past) \/ max) * 100}%\"><\/div><\/div><div class=\"chart-label\">${person.name}<\/div><\/div>`).join(\"\")}\n          <\/div>\n          <div class=\"legend\"><span><i class=\"dot\"><\/i>\u8be2\u76d8<\/span><span><i class=\"dot green\"><\/i>\u8f6c\u5316\u5ba2\u6237<\/span><\/div>\n        <\/div>\n      <\/article>\n    <\/section>\n  `;\n}\n\nfunction salespersonTable() {\n  return `\n    <div class=\"table-wrap\">\n      <table>\n        <thead><tr><th>\u4e1a\u52a1\u5458<\/th><th>\u4e3b\u52a8\u8be2\u76d8<\/th><th>\u88ab\u52a8\u8be2\u76d8<\/th><th>\u5f53\u6708\u8f6c\u5316<\/th><th>\u8fc7\u5f80\u8f6c\u5316<\/th><th>\u8f6c\u5316\u7387<\/th><\/tr><\/thead>\n        <tbody>\n          ${state.salespeople.map((p) => {\n            const inquiries = p.active + p.passive;\n            const conversions = p.current + p.past;\n            return `<tr><td>${p.name}<\/td><td>${p.active}<\/td><td>${p.passive}<\/td><td>${p.current}<\/td><td>${p.past}<\/td><td>${pct((conversions \/ inquiries) * 100)}<\/td><\/tr>`;\n          }).join(\"\")}\n        <\/tbody>\n      <\/table>\n    <\/div>\n  `;\n}\n\nfunction htmlText(value) {\n  return String(value ?? \"\").replace(\/[&<>\"']\/g, (char) => ({\n    \"&\": \"&amp;\",\n    \"<\": \"&lt;\",\n    \">\": \"&gt;\",\n    '\"': \"&quot;\",\n    \"'\": \"&#39;\"\n  }[char]));\n}\n\nfunction salespersonKey(row) {\n  return encodeURIComponent(`${row.month || \"\"}|${row.name || \"\"}`);\n}\n\nfunction decodeSalespersonKey(key) {\n  const [month, ...nameParts] = decodeURIComponent(key || \"\").split(\"|\");\n  return { month, name: nameParts.join(\"|\") };\n}\n\nfunction sameSalesperson(row, target) {\n  return row.month === target.month && row.name === target.name;\n}\n\nfunction salespersonDetailRows() {\n  const rows = Array.isArray(state.salespersonRows) && state.salespersonRows.length\n    ? state.salespersonRows\n    : state.salespeople.map((person) => ({ month: \"2026-06\", ...person }));\n  return [...rows].sort((a, b) => (a.month || \"\").localeCompare(b.month || \"\") || (a.name || \"\").localeCompare(b.name || \"\"));\n}\n\nfunction aggregateSalespeopleClient(rows) {\n  const people = new Map();\n  rows.forEach((row) => {\n    const name = row.name || \"\";\n    if (!name) return;\n    if (!people.has(name)) people.set(name, { name, active: 0, passive: 0, current: 0, past: 0 });\n    const person = people.get(name);\n    person.active += Number(row.active || 0);\n    person.passive += Number(row.passive || 0);\n    person.current += Number(row.current || 0);\n    person.past += Number(row.past || 0);\n  });\n  return [...people.values()].sort((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction applySalespersonRows(rows, people = null) {\n  state.salespersonRows = [...rows].sort((a, b) => (a.month || \"\").localeCompare(b.month || \"\") || (a.name || \"\").localeCompare(b.name || \"\"));\n  state.salespeople = people || aggregateSalespeopleClient(state.salespersonRows);\n}\n\nfunction upsertSalespersonRow(rows, row, original) {\n  const filtered = rows.filter((item) => !sameSalesperson(item, original) && !sameSalesperson(item, row));\n  return [...filtered, row];\n}\n\nfunction salespersonDetails() {\n  const rows = salespersonDetailRows();\n  const max = Math.max(1, ...state.salespeople.map((person) => person.active + person.passive));\n  const editing = state.editingSalespersonKey ? rows.find((row) => sameSalesperson(row, decodeSalespersonKey(state.editingSalespersonKey))) : null;\n  return `\n    <section class=\"grid details-layout\">\n      <article class=\"card section-panel\">\n        <div class=\"section-title-bar bar-pink\"><h2>\u4e2a\u4eba\u8be6\u7ec6\u6570\u636e<\/h2><p>\u6309\u6708\u4efd\u67e5\u770b\u3001\u7f16\u8f91\u548c\u5220\u9664\u4e1a\u52a1\u5458\u8be2\u76d8\u4e0e\u8f6c\u5316\u6570\u636e<\/p><\/div>\n        <div class=\"card-body\">\n          ${state.salespersonEditMessage ? `<div class=\"save-message detail-message\">${state.salespersonEditMessage}<\/div>` : \"\"}\n          ${salespersonTable(rows)}\n        <\/div>\n      <\/article>\n      <article class=\"card\">\n        <div class=\"card-head\"><div><h2>\u4e1a\u52a1\u5458\u8be2\u76d8\u548c\u8f6c\u5316\u60c5\u51b5<\/h2><p>\u5404\u4e1a\u52a1\u5458\u7684\u8be2\u76d8\u6570\u91cf\u548c\u5ba2\u6237\u8f6c\u5316\u60c5\u51b5<\/p><\/div><\/div>\n        <div class=\"card-body\">\n          <div class=\"chart\" style=\"grid-template-columns:repeat(${Math.max(1, state.salespeople.length)},1fr)\">\n            ${state.salespeople.map((person) => `<div><div class=\"bar-group\" style=\"grid-template-columns:1fr 1fr\"><div class=\"bar\" style=\"height:${((person.active + person.passive) \/ max) * 100}%\"><\/div><div class=\"bar ci\" style=\"height:${((person.current + person.past) \/ max) * 100}%\"><\/div><\/div><div class=\"chart-label\">${htmlText(person.name)}<\/div><\/div>`).join(\"\")}\n          <\/div>\n          <div class=\"legend\"><span><i class=\"dot\"><\/i>\u8be2\u76d8<\/span><span><i class=\"dot green\"><\/i>\u8f6c\u5316\u5ba2\u6237<\/span><\/div>\n        <\/div>\n      <\/article>\n    <\/section>\n    ${salespersonEditModal(editing)}\n  `;\n}\n\nfunction salespersonTable(rows = salespersonDetailRows()) {\n  return `\n    <div class=\"table-wrap detail-table-wrap\">\n      <table class=\"salesperson-record-table\">\n        <thead>\n          <tr>\n            <th>\u6708\u4efd<\/th>\n            <th>\u4e1a\u52a1\u5458<\/th>\n            <th>\u4e3b\u52a8\u8be2\u76d8<\/th>\n            <th>\u88ab\u52a8\u8be2\u76d8<\/th>\n            <th>\u603b\u8be2\u76d8<\/th>\n            <th>\u5f53\u6708\u8f6c\u5316<\/th>\n            <th>\u8fc7\u5f80\u8f6c\u5316<\/th>\n            <th>\u603b\u8f6c\u5316<\/th>\n            <th>\u8f6c\u5316\u7387<\/th>\n            <th>\u521b\u5efa\u65f6\u95f4<\/th>\n            <th>\u64cd\u4f5c<\/th>\n          <\/tr>\n        <\/thead>\n        <tbody>\n          ${rows.map((row) => {\n            const inquiries = Number(row.active || 0) + Number(row.passive || 0);\n            const conversions = Number(row.current || 0) + Number(row.past || 0);\n            const key = salespersonKey(row);\n            return `\n              <tr>\n                <td>${htmlText(row.month)}<\/td>\n                <td><strong>${htmlText(row.name)}<\/strong><\/td>\n                <td>${row.active}<\/td>\n                <td>${row.passive}<\/td>\n                <td><strong>${inquiries}<\/strong><\/td>\n                <td>${row.current}<\/td>\n                <td>${row.past}<\/td>\n                <td><strong>${conversions}<\/strong><\/td>\n                <td>${inquiries ? pct((conversions \/ inquiries) * 100) : \"0.0%\"}<\/td>\n                <td>${row.createdAt ? htmlText(row.createdAt.slice(0, 10).replaceAll(\"-\", \"\/\")) : \"-\"}<\/td>\n                <td>\n                  <div class=\"record-actions\">\n                    <button class=\"icon-btn edit\" type=\"button\" onclick=\"openSalespersonEdit('${key}')\" title=\"\u7f16\u8f91\">\u7f16\u8f91<\/button>\n                    <button class=\"icon-btn delete\" type=\"button\" onclick=\"deleteSalespersonRecord('${key}')\" title=\"\u5220\u9664\">\u5220\u9664<\/button>\n                  <\/div>\n                <\/td>\n              <\/tr>\n            `;\n          }).join(\"\")}\n        <\/tbody>\n      <\/table>\n    <\/div>\n  `;\n}\n\nfunction salespersonEditField(name, label, value, disabled = false) {\n  return `\n    <div class=\"field\">\n      <label>${label}<\/label>\n      <input name=\"${disabled ? \"\" : name}\" data-field=\"${name}\" type=\"number\" min=\"0\" step=\"1\" value=\"${Number(value || 0)}\" ${disabled ? \"disabled\" : \"\"}>\n    <\/div>\n  `;\n}\n\nfunction salespersonEditModal(row) {\n  if (!row) return \"\";\n  const inquiries = Number(row.active || 0) + Number(row.passive || 0);\n  const conversions = Number(row.current || 0) + Number(row.past || 0);\n  const key = salespersonKey(row);\n  return `\n    <div class=\"modal-backdrop\" onclick=\"closeSalespersonEdit(event)\">\n      <form class=\"edit-dialog\" onsubmit=\"saveSalesperson(event)\" oninput=\"refreshSalespersonEditTotals(this)\">\n        <div class=\"dialog-head\">\n          <div>\n            <h2>\u4fee\u6539 ${htmlText(row.month)} ${htmlText(row.name)} \u7684\u4e1a\u52a1\u5458\u6570\u636e<\/h2>\n            <p>\u4fdd\u5b58\u540e\u4f1a\u66f4\u65b0\u6570\u636e\u5e93\u3001\u4e2a\u4eba\u660e\u7ec6\u8868\u548c\u4e1a\u52a1\u5458\u6c47\u603b\u56fe<\/p>\n          <\/div>\n          <button class=\"dialog-close\" type=\"button\" onclick=\"closeSalespersonEdit()\">\u00d7<\/button>\n        <\/div>\n        <input type=\"hidden\" name=\"originalKey\" value=\"${key}\">\n        <div class=\"dialog-grid\">\n          <div class=\"field\">\n            <label>\u6708\u4efd<\/label>\n            <input name=\"month\" type=\"month\" value=\"${htmlText(row.month)}\">\n          <\/div>\n          <div class=\"field\">\n            <label>\u4e1a\u52a1\u5458<\/label>\n            <input name=\"name\" type=\"text\" value=\"${htmlText(row.name)}\">\n          <\/div>\n          ${salespersonEditField(\"active\", \"\u4e3b\u52a8\u8be2\u76d8\", row.active)}\n          ${salespersonEditField(\"passive\", \"\u88ab\u52a8\u8be2\u76d8\", row.passive)}\n          ${salespersonEditField(\"totalInquiries\", \"\u603b\u8be2\u76d8\uff08\u81ea\u52a8\u8ba1\u7b97\uff09\", inquiries, true)}\n          ${salespersonEditField(\"current\", \"\u5f53\u6708\u8f6c\u5316\", row.current)}\n          ${salespersonEditField(\"past\", \"\u8fc7\u5f80\u8f6c\u5316\", row.past)}\n          ${salespersonEditField(\"totalConversions\", \"\u603b\u8f6c\u5316\uff08\u81ea\u52a8\u8ba1\u7b97\uff09\", conversions, true)}\n          ${salespersonEditField(\"conversionRate\", \"\u8f6c\u5316\u7387 %\uff08\u81ea\u52a8\u8ba1\u7b97\uff09\", inquiries ? ((conversions \/ inquiries) * 100).toFixed(1) : 0, true)}\n        <\/div>\n        <div class=\"dialog-actions\">\n          <button class=\"secondary-btn\" type=\"button\" onclick=\"closeSalespersonEdit()\">\u53d6\u6d88<\/button>\n          <button class=\"primary-btn\" type=\"submit\">\u4fdd\u5b58\u66f4\u6539<\/button>\n        <\/div>\n      <\/form>\n    <\/div>\n  `;\n}\n\nfunction openSalespersonEdit(key) {\n  state.editingSalespersonKey = key;\n  state.salespersonEditMessage = \"\";\n  render();\n}\n\nfunction closeSalespersonEdit(event) {\n  if (event && event.target !== event.currentTarget) return;\n  state.editingSalespersonKey = null;\n  render();\n}\n\nfunction refreshSalespersonEditTotals(form) {\n  const inquiries = readDialogNumber(form, \"active\") + readDialogNumber(form, \"passive\");\n  const conversions = readDialogNumber(form, \"current\") + readDialogNumber(form, \"past\");\n  writeDialogNumber(form, \"totalInquiries\", inquiries);\n  writeDialogNumber(form, \"totalConversions\", conversions);\n  writeDialogNumber(form, \"conversionRate\", inquiries ? ((conversions \/ inquiries) * 100).toFixed(1) : 0);\n}\n\nfunction normalizeSalespersonRow(raw) {\n  return {\n    month: String(raw.month || \"\").slice(0, 7),\n    name: String(raw.name || \"\").trim(),\n    active: Number(raw.active || 0),\n    passive: Number(raw.passive || 0),\n    current: Number(raw.current || 0),\n    past: Number(raw.past || 0)\n  };\n}\n\nasync function saveSalesperson(event) {\n  event.preventDefault();\n  const form = new FormData(event.target);\n  const row = normalizeSalespersonRow(Object.fromEntries(form.entries()));\n  const original = decodeSalespersonKey(form.get(\"originalKey\"));\n  if (!row.month || !row.name) {\n    state.salespersonEditMessage = \"\u6708\u4efd\u548c\u4e1a\u52a1\u5458\u4e0d\u80fd\u4e3a\u7a7a\u3002\";\n    render();\n    return;\n  }\n  const remote = await saveRemoteSalesperson(row, original);\n  if (remote === false) {\n    state.salespersonEditMessage = \"\u4fdd\u5b58\u5931\u8d25\uff0c\u8bf7\u5237\u65b0\u540e\u91cd\u8bd5\u3002\";\n    render();\n    return;\n  }\n  const rows = remote && Array.isArray(remote.salespersonRows)\n    ? remote.salespersonRows\n    : upsertSalespersonRow(salespersonDetailRows(), row, original);\n  applySalespersonRows(rows, remote && Array.isArray(remote.salespeople) ? remote.salespeople : null);\n  state.editingSalespersonKey = null;\n  state.salespersonEditMessage = \"\u4e1a\u52a1\u5458\u6570\u636e\u5df2\u4fdd\u5b58\u3002\";\n  render();\n}\n\nasync function saveRemoteSalesperson(row, original) {\n  if (!wpConfig || !wpConfig.isLoggedIn) return null;\n  try {\n    const response = await fetch(`${wpConfig.restUrl}salesperson`, {\n      method: \"POST\",\n      headers: {\n        \"content-type\": \"application\/json\",\n        \"X-WP-Nonce\": wpConfig.nonce\n      },\n      credentials: \"same-origin\",\n      body: JSON.stringify({ ...row, originalMonth: original.month, originalName: original.name })\n    });\n    if (!response.ok) throw new Error(`Save failed: ${response.status}`);\n    return await response.json();\n  } catch (error) {\n    console.error(\"Unable to save salesperson data\", error);\n    return false;\n  }\n}\n\nasync function deleteSalespersonRecord(key) {\n  const target = decodeSalespersonKey(key);\n  if (!window.confirm(`\u786e\u5b9a\u5220\u9664 ${target.month} ${target.name} \u7684\u4e1a\u52a1\u5458\u6570\u636e\u5417\uff1f`)) return;\n  const remote = await deleteRemoteSalesperson(target);\n  if (remote === false) {\n    state.salespersonEditMessage = \"\u5220\u9664\u5931\u8d25\uff0c\u8bf7\u5237\u65b0\u540e\u91cd\u8bd5\u3002\";\n    render();\n    return;\n  }\n  const rows = remote && Array.isArray(remote.salespersonRows)\n    ? remote.salespersonRows\n    : salespersonDetailRows().filter((row) => !sameSalesperson(row, target));\n  applySalespersonRows(rows, remote && Array.isArray(remote.salespeople) ? remote.salespeople : null);\n  state.editingSalespersonKey = null;\n  state.salespersonEditMessage = `${target.month} ${target.name} \u7684\u4e1a\u52a1\u5458\u6570\u636e\u5df2\u5220\u9664\u3002`;\n  render();\n}\n\nasync function deleteRemoteSalesperson(target) {\n  if (!wpConfig || !wpConfig.isLoggedIn) return null;\n  try {\n    const response = await fetch(`${wpConfig.restUrl}salesperson\/delete`, {\n      method: \"POST\",\n      headers: {\n        \"content-type\": \"application\/json\",\n        \"X-WP-Nonce\": wpConfig.nonce\n      },\n      credentials: \"same-origin\",\n      body: JSON.stringify(target)\n    });\n    if (!response.ok) throw new Error(`Delete failed: ${response.status}`);\n    return await response.json();\n  } catch (error) {\n    console.error(\"Unable to delete salesperson data\", error);\n    return false;\n  }\n}\n\nfunction targets() {\n  const rows = ensureTargetRows();\n  const base = rows.reduce((sum, row) => sum + row.base, 0);\n  const balanced = rows.reduce((sum, row) => sum + row.balanced, 0);\n  const stretch = rows.reduce((sum, row) => sum + row.stretch, 0);\n  return `\n    <article class=\"card section-panel\" style=\"margin-top:16px\">\n      <div class=\"section-title-bar bar-orange\"><h2>\u8bbe\u5b9a\u9500\u552e\u76ee\u6807\uff08\u5168\u5e7412\u4e2a\u6708\uff09<\/h2><p>\u6279\u91cf\u8bbe\u7f6e\u6bcf\u6708\u9500\u552e\u76ee\u6807\uff0c\u66f4\u65b9\u4fbf\u7ba1\u7406\u5e74\u5ea6\u76ee\u6807<\/p><\/div>\n      <div class=\"card-body\">\n        <div class=\"target-total-stack\">\n          ${targetTotal(\"green\", \"\u5e74\u5ea6\u4fdd\u5e95\u76ee\u6807\u603b\u989d\", base)}\n          ${targetTotal(\"blue\", \"\u5e74\u5ea6\u5e73\u8861\u76ee\u6807\u603b\u989d\", balanced)}\n          ${targetTotal(\"orange\", \"\u5e74\u5ea6\u51b2\u523a\u76ee\u6807\u603b\u989d\", stretch)}\n        <\/div>\n        <form class=\"target-form\" onsubmit=\"saveTargets(event)\">\n          ${targetTable(rows)}\n          <button class=\"primary-btn target-save-btn\" type=\"submit\" ${state.targetSaving ? \"disabled\" : \"\"}>\n            ${state.targetSaving ? \"\u4fdd\u5b58\u4e2d...\" : \"\u4fdd\u5b58\u5168\u90e8\u76ee\u6807\"}\n          <\/button>\n          ${state.targetSaveMessage ? `<div class=\"save-message\">${state.targetSaveMessage}<\/div>` : \"\"}\n        <\/form>\n      <\/div>\n    <\/article>\n  `;\n}\n\nfunction targetTotal(tone, label, value) {\n  return `\n    <div class=\"target-total-row ${tone}\">\n      <strong>${label}<\/strong>\n      <span>${money(value).replace(\"\u20ac\", \"\").trim()} \u20ac<\/span>\n    <\/div>\n  `;\n}\n\nfunction targetTable(rows = ensureTargetRows()) {\n  return `\n    <div class=\"table-wrap\">\n      <table class=\"target-edit-table\">\n        <thead><tr><th>\u6708\u4efd<\/th><th>\u4fdd\u5e95\u76ee\u6807 (\u20ac)<\/th><th>\u5e73\u8861\u76ee\u6807 (\u20ac)<\/th><th>\u51b2\u523a\u76ee\u6807 (\u20ac)<\/th><\/tr><\/thead>\n        <tbody>\n          ${rows.map((target) => {\n            return `\n              <tr>\n                <td>${target.month}<\/td>\n                <td><input class=\"target-input green\" name=\"base-${target.month}\" type=\"number\" min=\"0\" step=\"1\" value=\"${target.base}\"><\/td>\n                <td><input class=\"target-input blue\" name=\"balanced-${target.month}\" type=\"number\" min=\"0\" step=\"1\" value=\"${target.balanced}\"><\/td>\n                <td><input class=\"target-input orange\" name=\"stretch-${target.month}\" type=\"number\" min=\"0\" step=\"1\" value=\"${target.stretch}\"><\/td>\n              <\/tr>\n            `;\n          }).join(\"\")}\n        <\/tbody>\n      <\/table>\n    <\/div>\n  `;\n}\n\nasync function saveTargets(event) {\n  event.preventDefault();\n  const form = new FormData(event.target);\n  const rows = ensureTargetRows().map((target) => ({\n    month: target.month,\n    base: numberFromForm(form, `base-${target.month}`),\n    balanced: numberFromForm(form, `balanced-${target.month}`),\n    stretch: numberFromForm(form, `stretch-${target.month}`)\n  }));\n\n  state.targets = rows;\n  state.targetSaving = true;\n  state.targetSaveMessage = \"\";\n  render();\n\n  if (!wpConfig || !wpConfig.isLoggedIn) {\n    state.targetSaving = false;\n    state.targetSaveMessage = \"\u5df2\u4fdd\u5b58\u5728\u5f53\u524d\u9875\u9762\u3002\";\n    render();\n    return;\n  }\n\n  try {\n    const response = await fetch(`${wpConfig.restUrl}targets`, {\n      method: \"POST\",\n      headers: {\n        \"Content-Type\": \"application\/json\",\n        \"X-WP-Nonce\": wpConfig.nonce\n      },\n      credentials: \"same-origin\",\n      body: JSON.stringify({ targets: rows })\n    });\n    if (!response.ok) throw new Error(`Save failed: ${response.status}`);\n    const data = await response.json();\n    if (Array.isArray(data.targets) && data.targets.length) state.targets = data.targets;\n    state.targetSaveMessage = \"\u76ee\u6807\u5df2\u4fdd\u5b58\u3002\";\n  } catch (error) {\n    console.error(\"Unable to save targets\", error);\n    state.targetSaveMessage = \"\u4fdd\u5b58\u5931\u8d25\uff0c\u8bf7\u5237\u65b0\u540e\u91cd\u8bd5\u3002\";\n  } finally {\n    state.targetSaving = false;\n    render();\n  }\n}\n\nfunction history() {\n  return `\n    ${shell(`\n      <article class=\"card\">\n        <div class=\"card-head\">\n          <div><h2>\u5386\u53f2\u6570\u636e<\/h2><p>\u5404\u6708\u4efd\u9500\u552e\u6570\u636e\u660e\u7ec6<\/p><\/div>\n          <div class=\"user-menu\">\n            <button class=\"secondary-btn\" onclick=\"setView('dashboard')\">\u8fd4\u56de\u4eea\u8868\u76d8<\/button>\n            <button class=\"secondary-btn\" onclick=\"downloadJson()\">\u5bfc\u51fa\u6570\u636e<\/button>\n          <\/div>\n        <\/div>\n        <div class=\"card-body\">${summaryTable()}<\/div>\n      <\/article>\n    `)}\n  `;\n}\n\nfunction tools() {\n  const items = [\n    [\"\u5bfc\u51fa\u6570\u636e\", \"\u5c06\u60a8\u7684\u9500\u552e\u6570\u636e\u548c\u76ee\u6807\u5bfc\u51fa\u4e3aJSON\u6587\u4ef6\", \"downloadJson()\", \"\u5bfc\u51fa\u6570\u636e\"],\n    [\"\u5bfc\u5165\u6570\u636e\", \"\u4eceJSON\u6587\u4ef6\u5bfc\u5165\u9500\u552e\u6570\u636e\u548c\u76ee\u6807\", \"\", \"\u9009\u62e9JSON\u6587\u4ef6\"],\n    [\"PDF\u62a5\u544a\u751f\u6210\", \"\u751f\u6210\u5305\u542b\u6240\u6709\u9500\u552e\u6570\u636e\u3001\u56fe\u8868\u5206\u6790\u548c\u76ee\u6807\u7684PDF\u62a5\u544a\", \"window.print()\", \"\u751f\u6210PDF\u62a5\u544a\"]\n  ];\n  return `\n    <section class=\"card section-panel\">\n      <div class=\"section-title-bar bar-indigo\"><h2>\u6570\u636e\u7ba1\u7406\u5de5\u5177<\/h2><p>\u5bfc\u51fa\/\u5bfc\u5165\u6570\u636e\u548c\u751f\u6210PDF\u62a5\u544a<\/p><\/div>\n      <div class=\"card-body grid tools-grid\">\n        ${items.map(([title, desc, action, btn]) => `\n          <article class=\"card tool-card\" style=\"box-shadow:none\">\n            <div class=\"card-head\"><div><h2>${title}<\/h2><p>${desc}<\/p><\/div><\/div>\n            <div class=\"card-body\">\n              ${title === \"\u5bfc\u5165\u6570\u636e\" ? `<input type=\"file\" accept=\"application\/json\" onchange=\"importJson(event)\" \/>` : `<button class=\"secondary-btn\" onclick=\"${action}\">${btn}<\/button>`}\n            <\/div>\n          <\/article>\n        `).join(\"\")}\n      <\/div>\n    <\/section>\n  `;\n}\n\nfunction externalTools() {\n  const links = [\n    [\"\u53d1\u7968\u7cfb\u7edf\", \"\u8bbf\u95ee\u5916\u90e8\u53d1\u7968\u7ba1\u7406\u7cfb\u7edf\", \"https:\/\/akku.cozyfluffy.com\/\", \"\u6253\u5f00\u53d1\u7968\u7cfb\u7edf\"],\n    [\"\u8be2\u76d8\u767b\u8bb0\u8868\", \"\u8bbf\u95ee\u8be2\u76d8\u7b49\u7ea7\u5206\u7c7b\u8868\u683c\", \"https:\/\/docs.google.com\/\", \"\u6253\u5f00\u8be2\u76d8\u767b\u8bb0\u8868\"],\n    [\"\u5fb7\u4ed3\u65e5\u5e38\u5de5\u4f5c\u8868\", \"\u8bbf\u95ee\u5fb7\u4ed3\u65e5\u5e38\u5de5\u4f5c\u7ba1\u7406\u8868\u683c\", \"https:\/\/docs.google.com\/\", \"\u6253\u5f00\u5fb7\u4ed3\u5de5\u4f5c\u8868\"],\n    [\"\u552e\u540e\u670d\u52a1\u7cfb\u7edf\", \"\u8bbf\u95ee\u552e\u540e\u670d\u52a1\u652f\u6301\u7cfb\u7edf\", \"https:\/\/akku.cozyfluffy.com\/\", \"\u6253\u5f00\u552e\u540e\u7cfb\u7edf\"],\n    [\"\u5c0f\u6ee1\u5ba2\u6237\u7ba1\u7406\u7cfb\u7edf\", \"\u8bbf\u95ee\u5c0f\u6ee1\u5ba2\u6237\u7ba1\u7406\/CRM\u7cfb\u7edf\", \"https:\/\/akku.cozyfluffy.com\/\", \"\u6253\u5f00\u5c0f\u6ee1CRM\"],\n    [\"PKT\u6587\u6863\u4e2d\u5fc3\", \"\u8bbf\u95eePKT\u6587\u6863\u4e2d\u5fc3\", \"https:\/\/akku.cozyfluffy.com\/\", \"\u6253\u5f00PKT\u6587\u6863\u4e2d\u5fc3\"],\n    [\"\u7f51\u5546\u6d41\u91cf\u67e5\u8be2\u7cfb\u7edf\", \"\u5168\u7403\u4e3b\u6d41\u7f51\u5546\u5e73\u53f0\u6d41\u91cf\u4e00\u952e\u67e5\u8be2\uff08SEMrush\uff09\", \"https:\/\/akku.cozyfluffy.com\/\", \"\u6253\u5f00\u6d41\u91cf\u67e5\u8be2\u7cfb\u7edf\"],\n    [\"\u7535\u6c60\u552e\u540e\u5904\u7406\u4e91\u5e73\u53f0\", \"\u8bbf\u95ee\u7535\u6c60\u552e\u540e\u5904\u7406\u4e91\u5e73\u53f0\u7cfb\u7edf\", \"https:\/\/akku.cozyfluffy.com\/\", \"\u6253\u5f00\u7535\u6c60\u552e\u540e\u5e73\u53f0\"]\n  ];\n  return links.map(([title, desc, url, label]) => `\n    <article class=\"card tool-card\" style=\"box-shadow:none\">\n      <div class=\"card-head\"><div><h2>${title}<\/h2><p>${desc}<\/p><\/div><\/div>\n      <div class=\"card-body\"><button class=\"secondary-btn\" onclick=\"openTool('${url}')\">${label}<\/button><\/div>\n    <\/article>\n  `).join(\"\");\n}\n\nfunction overallDetails() {\n  return `\n    <section class=\"grid two-col details-layout\">\n      <article class=\"card\">\n        <div class=\"card-head\"><div><h2>\u67e5\u770b\u6240\u6709\u9500\u552e\u6570\u636e\u8bb0\u5f55<\/h2><p>\u53ef\u4ee5\u7f16\u8f91\u6216\u5220\u9664\u6bcf\u4e2a\u6708\u7684\u9500\u552e\u6570\u636e<\/p><\/div><\/div>\n        <div class=\"card-body\">\n          ${state.salesEditMessage ? `<div class=\"save-message detail-message\">${state.salesEditMessage}<\/div>` : \"\"}\n          ${salesRecordTable()}\n        <\/div>\n      <\/article>\n      <article class=\"card\">\n        <div class=\"card-head\"><div><h2>\u5e74\u5ea6\u8425\u6536\u5bf9\u6bd4<\/h2><p>\u5f53\u5e74vs\u4e0a\u4e00\u5e74\u8425\u6536\u5bf9\u6bd4<\/p><\/div><\/div>\n        <div class=\"card-body\">${revenueTargetChart()}<\/div>\n      <\/article>\n    <\/section>\n    ${state.editingSalesMonth ? salesEditModal(state.sales.find((row) => row.month === state.editingSalesMonth)) : \"\"}\n  `;\n}\n\nfunction weeklyEntry() {\n  return shell(`\n    <article class=\"card section-panel\">\n      <div class=\"section-title-bar bar-indigo\"><h2>2026\u5e74\u5468\u5ea6\u5ba2\u6237\u6570\u636e\u5f55\u5165<\/h2><p>\u6309\u5468\u8bb0\u5f55\u5404\u4e1a\u52a1\u5458\u7684\u84dd\u8272\u3001\u7d2b\u8272\u3001\u7ea2\u8272\u5ba2\u6237\u6570\u91cf<\/p><\/div>\n      <div class=\"card-body\">\n        <button class=\"secondary-btn\" onclick=\"setView('dashboard')\" style=\"margin-bottom:16px\">\u8fd4\u56de\u4eea\u8868\u76d8<\/button>\n        <div class=\"grid form-grid\">\n          ${input(\"salesperson_name\", \"\u4e1a\u52a1\u5458\", \"text\", \"Vincent\")}\n          ${input(\"week_number\", \"\u5468\u6570\", \"number\", \"1\")}\n          ${input(\"blue_customers\", \"\u84dd\u8272\u5ba2\u6237\", \"number\", \"0\")}\n          ${input(\"purple_customers\", \"\u7d2b\u8272\u5ba2\u6237\", \"number\", \"0\")}\n          ${input(\"red_customers\", \"\u7ea2\u8272\u5ba2\u6237\", \"number\", \"0\")}\n        <\/div>\n        <h3 style=\"margin-top:22px\">\u6708\u6570\u636e\u6c47\u603b<\/h3>\n        ${weeklyCustomerPreview()}\n      <\/div>\n    <\/article>\n  `);\n}\n\nfunction openTool(url) {\n  window.open(url, \"_blank\", \"noopener,noreferrer\");\n}\n\nfunction downloadJson() {\n  const blob = new Blob([JSON.stringify({ sales: state.sales, targets: state.targets }, null, 2)], { type: \"application\/json\" });\n  const url = URL.createObjectURL(blob);\n  const link = document.createElement(\"a\");\n  link.href = url;\n  link.download = \"pkt-sales-data.json\";\n  link.click();\n  URL.revokeObjectURL(url);\n}\n\nfunction importJson(event) {\n  const file = event.target.files[0];\n  if (!file) return;\n  const reader = new FileReader();\n  reader.onload = () => {\n    try {\n      const parsed = JSON.parse(reader.result);\n      if (Array.isArray(parsed.sales)) state.sales = parsed.sales;\n      if (Array.isArray(parsed.targets)) state.targets = parsed.targets;\n      state.activeTab = \"history\";\n      render();\n    } catch {\n      alert(\"\u5bfc\u5165\u5931\u8d25\uff0c\u8bf7\u68c0\u67e5\u6587\u4ef6\u683c\u5f0f\");\n    }\n  };\n  reader.readAsText(file);\n}\n\nfunction weeklyKey(row) {\n  return encodeURIComponent(`${row.year || \"\"}|${row.weekNumber || \"\"}|${row.salespersonName || \"\"}`);\n}\n\nfunction decodeWeeklyKey(key) {\n  const [year, weekNumber, ...nameParts] = decodeURIComponent(key || \"\").split(\"|\");\n  return { year: Number(year || 0), weekNumber: Number(weekNumber || 0), salespersonName: nameParts.join(\"|\") };\n}\n\nfunction sameWeekly(row, target) {\n  return Number(row.year) === Number(target.year) && Number(row.weekNumber) === Number(target.weekNumber) && row.salespersonName === target.salespersonName;\n}\n\nfunction weeklyRows() {\n  return [...(Array.isArray(state.weekly) ? state.weekly : [])].sort((a, b) => Number(a.year) - Number(b.year) || Number(a.weekNumber) - Number(b.weekNumber) || (a.salespersonName || \"\").localeCompare(b.salespersonName || \"\"));\n}\n\nfunction weeklyTotals(rows = weeklyRows()) {\n  return rows.reduce((sum, row) => {\n    sum.blue += Number(row.blueCustomers || 0);\n    sum.purple += Number(row.purpleCustomers || 0);\n    sum.red += Number(row.redCustomers || 0);\n    return sum;\n  }, { blue: 0, purple: 0, red: 0 });\n}\n\nfunction weeklyCustomerPreview() {\n  const total = weeklyTotals();\n  return `\n    <div class=\"grid\" style=\"gap:12px\">\n      ${miniStat(\"\u84dd\u8272\u5ba2\u6237\", total.blue)}\n      ${miniStat(\"\u7d2b\u8272\u5ba2\u6237\", total.purple)}\n      ${miniStat(\"\u7ea2\u8272\u5ba2\u6237\", total.red)}\n    <\/div>\n  `;\n}\n\nfunction weeklyFormField(name, label, value, type = \"number\") {\n  return `\n    <div class=\"field\">\n      <label>${label}<\/label>\n      <input name=\"${name}\" data-field=\"${name}\" type=\"${type}\" min=\"${type === \"number\" ? \"0\" : \"\"}\" step=\"1\" value=\"${htmlText(value ?? \"\")}\">\n    <\/div>\n  `;\n}\n\nfunction weeklyEntry() {\n  const rows = weeklyRows();\n  const editing = state.editingWeeklyKey ? rows.find((row) => sameWeekly(row, decodeWeeklyKey(state.editingWeeklyKey))) : null;\n  const current = editing || { salespersonName: \"\", year: 2026, weekNumber: 1, blueCustomers: 0, purpleCustomers: 0, redCustomers: 0 };\n  const totals = weeklyTotals(rows);\n  return shell(`\n    <article class=\"card section-panel\">\n      <div class=\"section-title-bar bar-indigo\"><h2>2026\u5e74\u5468\u5ea6\u5ba2\u6237\u6570\u636e\u5f55\u5165<\/h2><p>\u5f55\u5165\u5e76\u7ef4\u62a4\u6bcf\u5468\u84dd\u8272\u3001\u7d2b\u8272\u3001\u7ea2\u8272\u5ba2\u6237\u6570\u91cf<\/p><\/div>\n      <div class=\"card-body\">\n        <button class=\"secondary-btn\" onclick=\"setView('dashboard')\">\u8fd4\u56de\u4eea\u8868\u76d8<\/button>\n        ${state.weeklyEditMessage ? `<div class=\"save-message detail-message\">${state.weeklyEditMessage}<\/div>` : \"\"}\n        <form class=\"grid form-grid data-entry-form weekly-entry-form\" onsubmit=\"saveWeekly(event)\">\n          <input type=\"hidden\" name=\"originalKey\" value=\"${editing ? weeklyKey(editing) : \"\"}\">\n          ${weeklyFormField(\"salespersonName\", \"\u4e1a\u52a1\u5458\", current.salespersonName, \"text\")}\n          ${weeklyFormField(\"year\", \"\u5e74\u4efd\", current.year)}\n          ${weeklyFormField(\"weekNumber\", \"\u5468\u6570\", current.weekNumber)}\n          ${weeklyFormField(\"blueCustomers\", \"\u84dd\u8272\u5ba2\u6237\", current.blueCustomers)}\n          ${weeklyFormField(\"purpleCustomers\", \"\u7d2b\u8272\u5ba2\u6237\", current.purpleCustomers)}\n          ${weeklyFormField(\"redCustomers\", \"\u7ea2\u8272\u5ba2\u6237\", current.redCustomers)}\n          <div class=\"full weekly-actions\">\n            <button class=\"primary-btn target-save-btn\" type=\"submit\">${editing ? \"\u4fdd\u5b58\u5468\u5ea6\u8bb0\u5f55\" : \"\u65b0\u589e\u5468\u5ea6\u8bb0\u5f55\"}<\/button>\n            ${editing ? `<button class=\"secondary-btn\" type=\"button\" onclick=\"cancelWeeklyEdit()\">\u53d6\u6d88\u7f16\u8f91<\/button>` : \"\"}\n          <\/div>\n        <\/form>\n        <div class=\"grid three-col weekly-total-row\">\n          ${miniStat(\"\u84dd\u8272\u5ba2\u6237\u603b\u6570\", totals.blue)}\n          ${miniStat(\"\u7d2b\u8272\u5ba2\u6237\u603b\u6570\", totals.purple)}\n          ${miniStat(\"\u7ea2\u8272\u5ba2\u6237\u603b\u6570\", totals.red)}\n        <\/div>\n        ${weeklyRecordTable(rows)}\n      <\/div>\n    <\/article>\n  `);\n}\n\nfunction weeklyRecordTable(rows = weeklyRows()) {\n  return `\n    <div class=\"table-wrap detail-table-wrap\">\n      <table class=\"weekly-record-table\">\n        <thead>\n          <tr>\n            <th>\u5e74\u4efd<\/th>\n            <th>\u5468\u6570<\/th>\n            <th>\u4e1a\u52a1\u5458<\/th>\n            <th>\u84dd\u8272\u5ba2\u6237<\/th>\n            <th>\u7d2b\u8272\u5ba2\u6237<\/th>\n            <th>\u7ea2\u8272\u5ba2\u6237<\/th>\n            <th>\u5408\u8ba1<\/th>\n            <th>\u64cd\u4f5c<\/th>\n          <\/tr>\n        <\/thead>\n        <tbody>\n          ${rows.map((row) => {\n            const total = Number(row.blueCustomers || 0) + Number(row.purpleCustomers || 0) + Number(row.redCustomers || 0);\n            const key = weeklyKey(row);\n            return `\n              <tr>\n                <td>${row.year}<\/td>\n                <td>${row.weekNumber}<\/td>\n                <td><strong>${htmlText(row.salespersonName)}<\/strong><\/td>\n                <td>${row.blueCustomers}<\/td>\n                <td>${row.purpleCustomers}<\/td>\n                <td>${row.redCustomers}<\/td>\n                <td><strong>${total}<\/strong><\/td>\n                <td>\n                  <div class=\"record-actions\">\n                    <button class=\"icon-btn edit\" type=\"button\" onclick=\"editWeeklyRecord('${key}')\" title=\"\u7f16\u8f91\">\u7f16\u8f91<\/button>\n                    <button class=\"icon-btn delete\" type=\"button\" onclick=\"deleteWeeklyRecord('${key}')\" title=\"\u5220\u9664\">\u5220\u9664<\/button>\n                  <\/div>\n                <\/td>\n              <\/tr>\n            `;\n          }).join(\"\")}\n        <\/tbody>\n      <\/table>\n    <\/div>\n  `;\n}\n\nfunction normalizeWeeklyRow(raw) {\n  return {\n    salespersonName: String(raw.salespersonName || \"\").trim(),\n    year: Number(raw.year || 0),\n    weekNumber: Number(raw.weekNumber || 0),\n    blueCustomers: Number(raw.blueCustomers || 0),\n    purpleCustomers: Number(raw.purpleCustomers || 0),\n    redCustomers: Number(raw.redCustomers || 0)\n  };\n}\n\nfunction editWeeklyRecord(key) {\n  state.editingWeeklyKey = key;\n  state.weeklyEditMessage = \"\";\n  render();\n}\n\nfunction cancelWeeklyEdit() {\n  state.editingWeeklyKey = null;\n  state.weeklyEditMessage = \"\";\n  render();\n}\n\nfunction upsertWeeklyRow(rows, row, original) {\n  const filtered = rows.filter((item) => !sameWeekly(item, original) && !sameWeekly(item, row));\n  return [...filtered, row];\n}\n\nasync function saveWeekly(event) {\n  event.preventDefault();\n  const form = new FormData(event.target);\n  const row = normalizeWeeklyRow(Object.fromEntries(form.entries()));\n  const original = decodeWeeklyKey(form.get(\"originalKey\"));\n  if (!row.salespersonName || !row.year || !row.weekNumber) {\n    state.weeklyEditMessage = \"\u4e1a\u52a1\u5458\u3001\u5e74\u4efd\u548c\u5468\u6570\u4e0d\u80fd\u4e3a\u7a7a\u3002\";\n    render();\n    return;\n  }\n  const remote = await saveRemoteWeekly(row, original);\n  if (remote === false) {\n    state.weeklyEditMessage = \"\u4fdd\u5b58\u5931\u8d25\uff0c\u8bf7\u5237\u65b0\u540e\u91cd\u8bd5\u3002\";\n    render();\n    return;\n  }\n  state.weekly = remote && Array.isArray(remote.weekly) ? remote.weekly : upsertWeeklyRow(weeklyRows(), row, original);\n  state.editingWeeklyKey = null;\n  state.weeklyEditMessage = \"\u5468\u5ea6\u5ba2\u6237\u6570\u636e\u5df2\u4fdd\u5b58\u3002\";\n  render();\n}\n\nasync function saveRemoteWeekly(row, original) {\n  if (!wpConfig || !wpConfig.isLoggedIn) return null;\n  try {\n    const response = await fetch(`${wpConfig.restUrl}weekly`, {\n      method: \"POST\",\n      headers: {\n        \"content-type\": \"application\/json\",\n        \"X-WP-Nonce\": wpConfig.nonce\n      },\n      credentials: \"same-origin\",\n      body: JSON.stringify({ ...row, originalYear: original.year, originalWeekNumber: original.weekNumber, originalSalespersonName: original.salespersonName })\n    });\n    if (!response.ok) throw new Error(`Save failed: ${response.status}`);\n    return await response.json();\n  } catch (error) {\n    console.error(\"Unable to save weekly customer data\", error);\n    return false;\n  }\n}\n\nasync function deleteWeeklyRecord(key) {\n  const target = decodeWeeklyKey(key);\n  if (!window.confirm(`\u786e\u5b9a\u5220\u9664 ${target.year} \u5e74\u7b2c ${target.weekNumber} \u5468 ${target.salespersonName} \u7684\u5468\u5ea6\u5ba2\u6237\u6570\u636e\u5417\uff1f`)) return;\n  const remote = await deleteRemoteWeekly(target);\n  if (remote === false) {\n    state.weeklyEditMessage = \"\u5220\u9664\u5931\u8d25\uff0c\u8bf7\u5237\u65b0\u540e\u91cd\u8bd5\u3002\";\n    render();\n    return;\n  }\n  state.weekly = remote && Array.isArray(remote.weekly) ? remote.weekly : weeklyRows().filter((row) => !sameWeekly(row, target));\n  state.editingWeeklyKey = null;\n  state.weeklyEditMessage = \"\u5468\u5ea6\u5ba2\u6237\u6570\u636e\u5df2\u5220\u9664\u3002\";\n  render();\n}\n\nasync function deleteRemoteWeekly(target) {\n  if (!wpConfig || !wpConfig.isLoggedIn) return null;\n  try {\n    const response = await fetch(`${wpConfig.restUrl}weekly\/delete`, {\n      method: \"POST\",\n      headers: {\n        \"content-type\": \"application\/json\",\n        \"X-WP-Nonce\": wpConfig.nonce\n      },\n      credentials: \"same-origin\",\n      body: JSON.stringify(target)\n    });\n    if (!response.ok) throw new Error(`Delete failed: ${response.status}`);\n    return await response.json();\n  } catch (error) {\n    console.error(\"Unable to delete weekly customer data\", error);\n    return false;\n  }\n}\n\nfunction dashboard() {\n  const content = {\n    overview,\n    input: entry,\n    targets,\n    \"overall-details\": overallDetails,\n    \"salesperson-details\": salespersonDetails,\n    tools\n  }[state.activeTab]();\n  return shell(content);\n}\n\nfunction render() {\n  if (!app) {\n    console.error(\"PKT dashboard mount element was not found.\");\n    return;\n  }\n  app.innerHTML = state.view === \"landing\" ? landing() : state.view === \"auth\" ? auth() : state.view === \"history\" ? history() : state.view === \"weekly\" ? weeklyEntry() : dashboard();\n}\n\nrender();\n\nasync function loadRemoteData() {\n  if (!wpConfig || !wpConfig.isLoggedIn) return;\n  try {\n    const response = await fetch(`${wpConfig.restUrl}dataset`, {\n      headers: { \"X-WP-Nonce\": wpConfig.nonce },\n      credentials: \"same-origin\"\n    });\n    if (!response.ok) return;\n    const data = await response.json();\n    if (Array.isArray(data.sales) && data.sales.length) state.sales = data.sales;\n    if (Array.isArray(data.targets) && data.targets.length) state.targets = data.targets;\n    if (Array.isArray(data.salespeople) && data.salespeople.length) state.salespeople = data.salespeople;\n    if (Array.isArray(data.salespersonRows)) state.salespersonRows = data.salespersonRows;\n    if (Array.isArray(data.weekly)) state.weekly = data.weekly;\n    render();\n  } catch (error) {\n    console.error(\"Unable to load dashboard data\", error);\n  }\n}\n\nloadRemoteData();\n<\/script><\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-57","page","type-page","status-publish","hentry"],"blocksy_meta":[],"_links":{"self":[{"href":"https:\/\/akku.cozyfluffy.com\/index.php\/wp-json\/wp\/v2\/pages\/57","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/akku.cozyfluffy.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/akku.cozyfluffy.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/akku.cozyfluffy.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/akku.cozyfluffy.com\/index.php\/wp-json\/wp\/v2\/comments?post=57"}],"version-history":[{"count":0,"href":"https:\/\/akku.cozyfluffy.com\/index.php\/wp-json\/wp\/v2\/pages\/57\/revisions"}],"wp:attachment":[{"href":"https:\/\/akku.cozyfluffy.com\/index.php\/wp-json\/wp\/v2\/media?parent=57"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}