feat(admin): upgrade invite code management with dialogs

Replace standalone add and export views with accessible dialogs, refine list interactions, and remove obsolete paths and unused counts. Fix filtered totals and reject oversized imports without truncation, with regression coverage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Fable 5 committed 2026-10-30 18:53:01 +08:00
1 parent 1cd19434d1
commit a6776ffe0a
8 files changed
+884 -400

No files matched your search

+101 -46
View File
@@ -1,49 +1,104 @@
/*
* 邀请码管理(users.php?page=aksrt_invite_codes)页面专属样式。
*
* 共享外壳/卡片/表格/徽标由 native-ui.css 承载;这里只留列表排序箭头、
* 添加/导出表单的行布局与按钮组切换、复制提示 toast 等本页独有交互样式。
* 仅在 users_page_aksrt_invite_codes 入队,规则限定在 .aksrt-inv-page 下。
*/
/* 邀请码原生运营页;外壳、表格与表单令牌沿用 native-ui.css。 */
.aksrt-inv-page [hidden] { display: none !important; }
.aksrt-inv-page .aksrt-native-header__actions .button { display: inline-flex; align-items: center; gap: 5px; }
.aksrt-inv-page .aksrt-native-header__actions .dashicons { margin: 0; font-size: 17px; line-height: 20px; }
.aksrt-inv-toolbar .subsubsub { margin: 0; padding: 0; box-shadow: none; }
.aksrt-inv-toolbar .aksrt-native-filters { margin: 0; }
.aksrt-inv-filter-summary { display: flex; flex-wrap: wrap; gap: 8px 16px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--an-border-soft); overflow-wrap: anywhere; }
.aksrt-inv-selection { color: var(--an-text-2); font-size: 12px; font-variant-numeric: tabular-nums; }
/* 排序箭头:默认弱化,悬停加强。 */
.aksrt-inv-page .orderby-but { position: relative; display: inline-block; margin-left: 4px; }
.aksrt-inv-page .orderby-but > a { opacity: .4; position: absolute; transform: translateY(-3px); transition: .3s; }
.aksrt-inv-page .orderby-but > a + a { transform: translateY(6px); }
.aksrt-inv-page .orderby-but:hover a { opacity: .6; }
.aksrt-inv-page .orderby-but > a:hover { opacity: 1; }
.aksrt-inv-page .aksrt-inv-table { min-width: 1000px; table-layout: fixed; }
.aksrt-inv-table .column-code { width: 21%; }
.aksrt-inv-table .column-rewards { width: 14%; }
.aksrt-inv-table .column-created_at,
.aksrt-inv-table .column-updated_at { width: 16%; }
.aksrt-inv-table .column-used_count { width: 13%; }
.aksrt-inv-table .column-remark { width: 20%; }
.aksrt-inv-page .aksrt-inv-table td { vertical-align: middle; overflow-wrap: anywhere; }
.aksrt-inv-table .orderby-but { display: inline-flex; align-items: center; gap: 3px; color: var(--an-text-2); text-decoration: none; }
.aksrt-inv-table .orderby-but .dashicons { width: 14px; height: 14px; font-size: 14px; opacity: .35; }
.aksrt-inv-table .orderby-but:hover,
.aksrt-inv-table .orderby-but.is-active { color: var(--an-primary); }
.aksrt-inv-table .orderby-but.is-active .dashicons { opacity: 1; }
.aksrt-inv-code { display: inline-flex; align-items: center; gap: 5px; max-width: 100%; padding: 5px 7px; color: var(--an-text); background: var(--an-bg-soft); border: 1px solid transparent; border-radius: 5px; text-align: left; font-size: 13px; overflow-wrap: anywhere; cursor: pointer; }
.aksrt-inv-code .dashicons { flex: none; width: 14px; height: 14px; color: var(--an-muted); font-size: 14px; }
.aksrt-inv-code:hover { color: var(--an-primary); background: var(--an-primary-soft); border-color: var(--an-primary); }
.aksrt-inv-date { font-variant-numeric: tabular-nums; font-size: 12px; }
.aksrt-inv-user { margin-top: 4px; font-size: 12px; }
.aksrt-inv-table tr.is-selected > td,
.aksrt-inv-table tr.is-selected > th { background: var(--an-primary-soft); }
.aksrt-inv-page .aksrt-inv-code:focus-visible,
.aksrt-inv-page .aksrt-inv-dialog__close:focus-visible { outline: 2px solid var(--an-primary); outline-offset: 2px; }
/* 复制邀请码:指针反馈。 */
.aksrt-inv-page .aksrt-inv-code { cursor: pointer; }
html.aksrt-inv-modal-open { overflow: hidden; }
.aksrt-inv-dialog { width: min(680px, calc(100vw - 32px)); max-width: none; max-height: calc(100vh - 64px); max-height: calc(100dvh - 64px); margin: auto; padding: 0; overflow: hidden; color: var(--an-text-2); background: var(--an-card); border: 0; border-radius: var(--an-radius); box-shadow: 0 16px 64px rgba(15, 23, 42, .2); }
.aksrt-inv-dialog::backdrop { background: rgba(15, 23, 42, .45); }
#aksrt-inv-export { width: min(560px, calc(100vw - 32px)); }
.aksrt-inv-dialog__frame { display: flex; flex-direction: column; max-height: inherit; margin: 0; }
.aksrt-inv-dialog__head { display: flex; flex: none; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 20px 24px 18px; border-bottom: 1px solid var(--an-border-soft); }
.aksrt-inv-dialog .aksrt-inv-dialog__head h2 { margin: 0; padding: 0; color: var(--an-text); font-size: 18px; font-weight: 600; line-height: 1.5; }
.aksrt-inv-dialog__head p { margin: 5px 0 0; font-size: 12px; line-height: 1.7; }
.aksrt-inv-dialog__close { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 30px; height: 30px; padding: 0; color: var(--an-text-2); background: transparent; border: 0; border-radius: 6px; cursor: pointer; }
.aksrt-inv-dialog__close:hover { color: var(--an-text); background: var(--an-bg-soft); }
.aksrt-inv-dialog__body { min-height: 0; padding: 20px 24px 24px; overflow-y: auto; overscroll-behavior: contain; }
.aksrt-inv-dialog__foot { display: flex; flex: none; justify-content: flex-end; gap: 8px; padding: 16px 24px; border-top: 1px solid var(--an-border-soft); background: var(--an-card); }
.aksrt-inv-dialog .aksrt-native-form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.aksrt-inv-dialog .aksrt-native-field { min-width: 0; }
.aksrt-inv-dialog .aksrt-native-field > input,
.aksrt-inv-dialog .aksrt-native-field > textarea { width: 100%; max-width: 100%; }
.aksrt-inv-dialog textarea { resize: vertical; }
.aksrt-inv-pane { min-width: 0; margin: 0; padding: 0; border: 0; }
.aksrt-inv-modes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; margin: 0 0 22px; padding: 4px; background: var(--an-bg-soft); border: 0; border-radius: var(--an-radius-sm); }
.aksrt-inv-modes label { position: relative; cursor: pointer; }
.aksrt-inv-modes input { position: absolute; width: 1px; height: 1px; margin: -1px; opacity: 0; clip-path: inset(50%); }
.aksrt-inv-modes span { display: block; padding: 9px 12px; border: 1px solid transparent; border-radius: 6px; text-align: center; }
.aksrt-inv-modes input:checked + span { color: var(--an-primary); background: var(--an-card); border-color: var(--an-primary); font-weight: 600; }
.aksrt-inv-modes input:focus-visible + span { outline: 2px solid var(--an-primary); outline-offset: 2px; }
.aksrt-inv-rewards { min-width: 0; margin: 22px 0; padding: 18px; border: 1px solid var(--an-border); border-radius: var(--an-radius-sm); }
.aksrt-inv-rewards > legend,
.aksrt-inv-options > legend { padding: 0 5px; color: var(--an-text); font-weight: 600; }
.aksrt-inv-hint { margin: -2px 0 14px; font-size: 12px; line-height: 1.7; }
.aksrt-inv-dialog .aksrt-inv-reward-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.aksrt-inv-vip { margin: 16px 0 0; padding: 0; border: 0; }
.aksrt-inv-vip legend { margin-bottom: 8px; padding: 0; font-weight: 600; }
.aksrt-inv-radios { display: flex; flex-wrap: wrap; gap: 12px 18px; }
.aksrt-inv-radios label { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.aksrt-inv-radios input { margin: 0; }
.aksrt-inv-vip-time { max-width: 200px; margin-top: 14px; }
.aksrt-inv-advanced { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.aksrt-inv-advanced input { margin: 0; }
.aksrt-inv-length { margin-top: 12px; }
.aksrt-inv-dialog .aksrt-inv-length input { max-width: 160px; }
.aksrt-inv-separator { margin-top: 16px; }
.aksrt-inv-dialog .aksrt-inv-separator input { max-width: 100px; }
.aksrt-inv-help { margin-top: 20px; padding-top: 14px; border-top: 1px solid var(--an-border-soft); line-height: 1.8; }
.aksrt-inv-help summary { color: var(--an-primary); cursor: pointer; }
.aksrt-inv-help p { font-size: 12px; }
.aksrt-inv-help pre { padding: 12px; overflow: auto; font-size: 12px; background: var(--an-bg-soft); border-radius: 6px; }
.aksrt-inv-options { min-width: 0; margin: 0 0 22px; padding: 0; border: 0; }
.aksrt-inv-options > legend { margin-bottom: 12px; padding: 0; }
.aksrt-inv-formats { display: grid; gap: 10px; }
.aksrt-inv-formats label { display: flex; align-items: flex-start; gap: 10px; padding: 13px 14px; border: 1px solid var(--an-border); border-radius: var(--an-radius-sm); cursor: pointer; }
.aksrt-inv-formats label:has(input:checked) { background: var(--an-primary-soft); border-color: var(--an-primary); }
.aksrt-inv-formats input { flex: none; margin: 3px 0 0; }
.aksrt-inv-formats strong { display: block; color: var(--an-text); font-weight: 600; }
.aksrt-inv-formats small { display: block; margin-top: 5px; font-size: 12px; line-height: 1.7; }
.aksrt-inv-page .aksrt-inv-export-note { margin: 20px 0 0; padding: 12px 14px; font-size: 12px; line-height: 1.8; }
.aksrt-inv-toast { position: fixed; z-index: 100100; top: 48px; left: 50%; max-width: calc(100vw - 48px); padding: 10px 18px; transform: translateX(-50%); color: #fff; background: #1f2329; border-radius: var(--an-radius-sm); box-shadow: var(--an-shadow); opacity: 0; pointer-events: none; }
.aksrt-inv-toast.is-visible { opacity: 1; }
/* 三视图切换链接(列表 / 添加 / 导出):贴合页头下方。 */
.aksrt-inv-page .aksrt-inv-switch-views { margin: -8px 0 12px; display: flex; flex-wrap: wrap; gap: 6px; }
.aksrt-inv-page .aksrt-inv-switch-views .page-title-action { display: inline-flex; align-items: center; gap: 4px; }
/* 选项字段布局:左标题右控件,行间分隔线。 */
.aksrt-inv-page .aksrt-inv-field { display: flex; align-items: flex-start; padding: 14px 0; border-bottom: 1px solid var(--an-border-soft); }
.aksrt-inv-page .aksrt-inv-field:last-child { border-bottom: 0; }
.aksrt-inv-page .aksrt-inv-field > label { flex: 0 0 170px; color: var(--an-text); font-weight: 600; padding-top: 4px; }
.aksrt-inv-page .aksrt-inv-field > .aksrt-inv-control { flex: 1; min-width: 0; }
.aksrt-inv-page .aksrt-inv-field .description { display: block; margin-top: 4px; }
/* 添加方式按钮组(二选一)。 */
.aksrt-inv-page .aksrt-inv-btnset label { display: inline-block; margin-right: -1px; padding: 4px 14px; color: var(--an-text-2); background: #fff; border: 1px solid var(--an-border); cursor: pointer; }
.aksrt-inv-page .aksrt-inv-btnset label:first-child { border-radius: var(--an-radius-sm) 0 0 var(--an-radius-sm); }
.aksrt-inv-page .aksrt-inv-btnset label:last-child { border-radius: 0 var(--an-radius-sm) var(--an-radius-sm) 0; }
.aksrt-inv-page .aksrt-inv-btnset input { display: none; }
.aksrt-inv-page .aksrt-inv-btnset label.on { color: #fff; background: var(--an-primary); border-color: var(--an-primary); }
/* 开关式复选 / 奖励字段行 / 单位后缀。 */
.aksrt-inv-page .aksrt-inv-switch { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.aksrt-inv-page .aksrt-inv-switch input { margin: 0; }
.aksrt-inv-page .aksrt-inv-rewards { display: flex; flex-wrap: wrap; gap: 12px; }
.aksrt-inv-page .aksrt-inv-radios { margin-top: 8px; }
.aksrt-inv-page .aksrt-inv-radios label + label { margin-left: 12px; font-weight: 400; }
.aksrt-inv-page .aksrt-inv-viptime { margin-top: 8px; }
.aksrt-inv-page .aksrt-inv-mini { width: 80px; }
.aksrt-inv-page .aksrt-inv-unit { margin-left: 4px; color: var(--an-muted); }
.aksrt-inv-page .aksrt-inv-textarea { resize: both; }
/* 复制成功悬浮提示。 */
.aksrt-inv-toast { position: fixed; top: 42px; left: 50%; transform: translateX(-50%); display: none; padding: 8px 22px; color: #fff; font-size: 13px; background: rgba(0, 0, 0, .75); border-radius: 4px; z-index: 100100; }
@media (max-width: 600px) {
.aksrt-inv-page .aksrt-native-header__actions { width: 100%; }
.aksrt-inv-page .aksrt-native-header__actions .button { flex: 1; justify-content: center; }
.aksrt-inv-toolbar .aksrt-native-filters { width: 100%; }
.aksrt-inv-toolbar input[type="search"] { flex: 1; width: 0; min-width: 0; }
.aksrt-inv-dialog { max-height: calc(100dvh - 24px); }
.aksrt-inv-dialog__head,
.aksrt-inv-dialog__body,
.aksrt-inv-dialog__foot { padding-left: 16px; padding-right: 16px; }
.aksrt-inv-dialog .aksrt-native-form-grid { grid-template-columns: 1fr; }
.aksrt-inv-rewards { padding: 12px; }
.aksrt-inv-dialog .aksrt-inv-reward-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.aksrt-inv-radios { gap: 12px; }
.aksrt-inv-dialog__foot .button { flex: 1; }
}