feat(after-sale): 支持撤销售后工单并接入人机验证

This commit is contained in:
kate522 committed 2026-10-07 09:20:59 +08:00
1 parent 918ca371be
commit 8023e2e472
14 files changed
+427 -82

No files matched your search

@@ -85,6 +85,8 @@ export const permissionsSchemas = {
{ label: '每日签到', value: 'signin' },
{ label: '前台投稿', value: 'front_submit' },
{ label: '打赏用户', value: 'tip_user' },
{ label: '申请售后', value: 'after_sale_apply' },
{ label: '撤销售后', value: 'after_sale_cancel' },
],
},
],
+89 -10
View File
@@ -6496,7 +6496,8 @@ body.aksrt-modal-runtime-open {
底色走 --main-radius / --main-bg-color;移动端由 --bottom 底部抽屉接管。 */
.aksrt-after-sale-apply-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog,
.aksrt-after-sale-detail-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog,
.aksrt-after-sale-expired-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog {
.aksrt-after-sale-expired-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog,
.aksrt-after-sale-withdraw-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog {
width: min(400px, calc(100vw - 32px));
border-radius: var(--main-radius, 8px);
background: var(--main-bg-color, #fff);
@@ -6504,7 +6505,8 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .aksrt-modal-runtime__skeleton,
.aksrt-after-sale-detail-modal .aksrt-modal-runtime__skeleton,
.aksrt-after-sale-expired-modal .aksrt-modal-runtime__skeleton {
.aksrt-after-sale-expired-modal .aksrt-modal-runtime__skeleton,
.aksrt-after-sale-withdraw-modal .aksrt-modal-runtime__skeleton {
padding: 24px 18px;
}
@@ -6513,9 +6515,13 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .modal-colorful-header,
.aksrt-after-sale-detail-modal .modal-colorful-header,
.aksrt-after-sale-expired-modal .modal-colorful-header,
.aksrt-after-sale-withdraw-modal .modal-colorful-header,
.aksrt-order-detail-modal .modal-colorful-header,
.aksrt-after-sale-apply-modal .colorful-bg,
.aksrt-after-sale-detail-modal .colorful-bg,
.aksrt-after-sale-expired-modal .colorful-bg {
.aksrt-after-sale-expired-modal .colorful-bg,
.aksrt-after-sale-withdraw-modal .colorful-bg,
.aksrt-order-detail-modal .colorful-bg {
position: relative;
overflow: hidden;
color: var(--this-color);
@@ -6525,7 +6531,9 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .modal-colorful-header,
.aksrt-after-sale-detail-modal .modal-colorful-header,
.aksrt-after-sale-expired-modal .modal-colorful-header {
.aksrt-after-sale-expired-modal .modal-colorful-header,
.aksrt-after-sale-withdraw-modal .modal-colorful-header,
.aksrt-order-detail-modal .modal-colorful-header {
position: absolute;
top: 0;
right: 0;
@@ -6539,13 +6547,17 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .modal-colorful-header + *,
.aksrt-after-sale-detail-modal .modal-colorful-header + *,
.aksrt-after-sale-expired-modal .modal-colorful-header + * {
.aksrt-after-sale-expired-modal .modal-colorful-header + *,
.aksrt-after-sale-withdraw-modal .modal-colorful-header + *,
.aksrt-order-detail-modal .modal-colorful-header + * {
margin-top: 120px;
}
.aksrt-after-sale-apply-modal .modal-colorful-header > .close,
.aksrt-after-sale-detail-modal .modal-colorful-header > .close,
.aksrt-after-sale-expired-modal .modal-colorful-header > .close {
.aksrt-after-sale-expired-modal .modal-colorful-header > .close,
.aksrt-after-sale-withdraw-modal .modal-colorful-header > .close,
.aksrt-order-detail-modal .modal-colorful-header > .close {
position: absolute;
top: 10px;
right: 10px;
@@ -6562,8 +6574,14 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-detail-modal .colorful-bg > .colorful-make::before,
.aksrt-after-sale-detail-modal .colorful-bg > .colorful-make::after,
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make,
.aksrt-after-sale-withdraw-modal .colorful-bg > .colorful-make,
.aksrt-order-detail-modal .colorful-bg > .colorful-make,
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make::before,
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make::after {
.aksrt-after-sale-withdraw-modal .colorful-bg > .colorful-make::before,
.aksrt-order-detail-modal .colorful-bg > .colorful-make::before,
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make::after,
.aksrt-after-sale-withdraw-modal .colorful-bg > .colorful-make::after,
.aksrt-order-detail-modal .colorful-bg > .colorful-make::after {
position: absolute;
color: var(--this-color);
background: var(--this-bg);
@@ -6573,7 +6591,9 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .colorful-bg > .colorful-make,
.aksrt-after-sale-detail-modal .colorful-bg > .colorful-make,
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make {
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make,
.aksrt-after-sale-withdraw-modal .colorful-bg > .colorful-make,
.aksrt-order-detail-modal .colorful-bg > .colorful-make {
top: 60%;
bottom: 0;
width: 323px;
@@ -6583,7 +6603,9 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .colorful-bg > .colorful-make::before,
.aksrt-after-sale-detail-modal .colorful-bg > .colorful-make::before,
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make::before {
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make::before,
.aksrt-after-sale-withdraw-modal .colorful-bg > .colorful-make::before,
.aksrt-order-detail-modal .colorful-bg > .colorful-make::before {
top: -325px;
right: -558px;
bottom: 0;
@@ -6595,7 +6617,9 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .colorful-bg > .colorful-make::after,
.aksrt-after-sale-detail-modal .colorful-bg > .colorful-make::after,
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make::after {
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make::after,
.aksrt-after-sale-withdraw-modal .colorful-bg > .colorful-make::after,
.aksrt-order-detail-modal .colorful-bg > .colorful-make::after {
top: -170px;
bottom: 0;
left: -262px;
@@ -6669,6 +6693,61 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-status.is-rejected,
.aksrt-after-sale-status.is-cancelled { color: var(--color-error, #ef4444); }
/* 状态行右侧单元格:状态徽章 + 「撤销售后」入口(仅待审核工单渲染)。 */
.aksrt-after-sale-detail__statusCell { display: inline-flex; align-items: center; gap: 10px; }
.aksrt-after-sale-withdraw { display: inline-flex; align-items: center; gap: 3px; padding: 0; border: 0; background: transparent; color: var(--modal-danger, #ef4444); font-size: 12px; font-weight: 600; line-height: 1.4; cursor: pointer; transition: color .15s ease; }
.aksrt-after-sale-withdraw .fa { font-size: 12px; }
.aksrt-after-sale-withdraw:hover { color: color-mix(in srgb, var(--modal-danger) 78%, var(--modal-ink)); }
/* 售后提示弹窗(撤销售后确认)正文。 */
.aksrt-after-sale-withdraw__body { margin-bottom: 16px; color: var(--color-ink-2, #4e5358); line-height: 1.7; }
/* 售后弹窗底部按钮:全宽平铺贴底(负 margin 抵消 __content 内边距)+ 分隔线,
子按钮去独立背景/边框/圆角(文字色区分主次),覆盖上方全局按钮网格的胶囊观感;
仅在售后弹窗家族生效,其他 runtime 弹窗仍走全局网格样式。 */
.aksrt-after-sale-apply-modal .but-average.modal-buts,
.aksrt-after-sale-detail-modal .but-average.modal-buts,
.aksrt-after-sale-expired-modal .but-average.modal-buts,
.aksrt-after-sale-withdraw-modal .but-average.modal-buts {
gap: 0;
margin: 16px -18px -16px;
padding: 12px 18px;
border-top: 1px solid var(--modal-line-soft, rgba(50, 50, 50, 0.06));
background: var(--main-bg-color, #fff);
}
.aksrt-after-sale-apply-modal .but-average.modal-buts > .but,
.aksrt-after-sale-detail-modal .but-average.modal-buts > .but,
.aksrt-after-sale-expired-modal .but-average.modal-buts > .but,
.aksrt-after-sale-withdraw-modal .but-average.modal-buts > .but {
min-height: 38px;
border: 0;
border-radius: 0;
box-shadow: none;
background: transparent;
color: var(--modal-muted, #777);
font-weight: 600;
cursor: pointer;
--this-bg: transparent;
--this-border: transparent;
--this-shadow: none;
}
.aksrt-after-sale-apply-modal .but-average.modal-buts > .but.c-blue,
.aksrt-after-sale-detail-modal .but-average.modal-buts > .but.c-blue,
.aksrt-after-sale-expired-modal .but-average.modal-buts > .but.c-blue,
.aksrt-after-sale-withdraw-modal .but-average.modal-buts > .but.c-blue {
background: transparent;
border: 0;
color: var(--modal-primary, #f04494);
}
/* 单按钮 footer 占满整行(全局网格是 1fr 1fr,单按钮会只占一半)。 */
.aksrt-after-sale-apply-modal .but-average.modal-buts > .but:only-child,
.aksrt-after-sale-detail-modal .but-average.modal-buts > .but:only-child,
.aksrt-after-sale-expired-modal .but-average.modal-buts > .but:only-child,
.aksrt-after-sale-withdraw-modal .but-average.modal-buts > .but:only-child { grid-column: 1 / -1; }
/* source: assets/css/frontend/notyf.css */
/**
* legacy-compatible frontend notifications.
+1 -1
View File
@@ -1 +1 @@
:root{--color-primary: #f04494;--color-primary-hover: #e0307e;--color-primary-active: #c9206d;--color-primary-soft: rgba(240, 68, 148, .1);--color-primary-softer: rgba(240, 68, 148, .05);--color-on-primary: #FFFFFF;--color-ink: #333333;--color-ink-2: #4e5358;--color-ink-3: #777777;--color-ink-4: #999999;--surface-page: #f5f6f7;--surface-1: #FFFFFF;--surface-2: #eeeeee;--surface-3: #e9ecef;--surface-4: #f8f8f8;--color-line: rgba(50, 50, 50, .06);--color-line-soft: rgba(0, 0, 0, .03);--color-line-stronger: rgba(50, 50, 50, .12);--color-success: #10B981;--color-warning: #F59E0B;--color-error: #EF4444;--color-info: #3B82F6;--color-accent: #18a058;--color-accent-soft: rgba(24, 160, 88, .12);--color-accent-shadow: rgba(24, 160, 88, .28);--font-display: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;--font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;--font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;--font-mono: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;--text-xs: .75rem;--text-sm: .875rem;--text-base: .875rem;--text-md: 1.125rem;--text-lg: 1.25rem;--text-xl: 1.5rem;--text-2xl: 1.875rem;--text-3xl: 2.25rem;--text-4xl: 3rem;--text-5xl: 3.75rem;--leading-tight: 1.2;--leading-snug: 1.4;--leading-normal: 1.6;--leading-relaxed: 1.6;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--space-5: 20px;--space-6: 24px;--space-7: 32px;--space-8: 40px;--space-9: 48px;--space-10: 64px;--space-11: 80px;--space-12: 96px;--radius-xs: 3px;--radius-sm: 4px;--radius: 8px;--radius-lg: 8px;--radius-xl: 12px;--radius-2xl: 16px;--radius-pill: 100px;--radius-avatar: 50%;--shadow-xs: 0 1px 2px rgba(0, 0, 0, .03);--shadow-sm: 0 0 10px rgba(116, 116, 116, .08);--shadow: 0 0 10px rgba(116, 116, 116, .12);--shadow-lg: 0 12px 32px rgba(18, 18, 18, .1);--shadow-drawer: 0 18px 60px rgba(0, 0, 0, .2);--nav-height: 60px;--container: 1200px;--container-wide: 1440px;--container-read: 760px;--container-page: 880px;--sidebar-width: 311px;--content-gap: 24px;--section-gap: 24px;--sidebar-bp: 992px;--ease: cubic-bezier(.4, 0, .2, 1);--ease-out: cubic-bezier(.16, 1, .3, 1);--ease-spring: cubic-bezier(.34, 1.56, .64, 1);--dur-fast: .15s;--dur: .25s;--dur-slow: .4s;--focus-ring: 0 0 2px 3px rgba(253, 83, 161, .4);--z-dropdown: 100;--z-sticky: 200;--z-fixed: 300;--z-overlay: 400;--z-modal: 500;--z-popover: 600;--z-toast: 700;--z-tooltip: 800;--radius-btn: 4px;--btn-sm-h: 28px;--btn-md-h: 34px;--btn-lg-h: 44px;--card-padding: 15px;--card-padding-sm: 10px;--card-gap: 16px;--card-gap-lg: 20px;--color-primary-light: var(--color-primary-soft);--color-surface: var(--surface-1);--color-line-strong: var(--color-line);--color-bg-hover: var(--surface-2);--color-border-light: var(--color-line-soft);--color-fill: var(--surface-2);--color-warning-bg: #fffbe6;--color-warning-text: #ad6800;--text-secondary: var(--color-ink-3);--text-tertiary: var(--color-ink-4);--surface-active: var(--surface-2);--surface-card: var(--surface-1);--surface-hover: var(--surface-2);--surface-secondary: var(--surface-2);--radius-code: var(--radius);--radius-full: 100px;--shadow-xl: 0 0 10px rgba(116, 116, 116, .12);--space-16: 64px;--z-floating: 900;--transition-fast: .15s ease;--transition-base: .25s ease;--header-bg: var(--blur-bg);--header-color: var(--color-ink-2);--footer-bg: var(--surface-1);--footer-color: var(--color-ink-4);--blur-bg: rgba(255, 255, 255, .8);--float-btn-bg: rgba(200, 200, 200, .4);--font-heading: var(--font-ui);--radius-card: var(--radius);--radius-md: var(--radius);--color-primary-50: var(--color-primary-soft);--color-primary-dark: var(--color-primary-active);--shadow-md: var(--shadow);--mini-radius: calc(var(--radius) / 1.4);--aksrt-avatar-size-xs: 24px;--aksrt-avatar-size-sm: 32px;--aksrt-avatar-size: 40px;--aksrt-avatar-size-lg: 56px;--aksrt-avatar-size-xl: 80px;--aksrt-card-thumb-scale: 56.25%;--aksrt-rose: #f43f5e;--aksrt-rose-soft: rgba(244, 63, 94, .12);--aksrt-blue: #3b82f6;--aksrt-blue-soft: rgba(59, 130, 246, .12);--aksrt-green: #10b981;--aksrt-green-soft: rgba(16, 185, 129, .12);--aksrt-orange: #f97316;--aksrt-orange-soft:rgba(249, 115, 22, .12);--aksrt-purple: #8b5cf6;--aksrt-purple-soft:rgba(139, 92, 246, .12);--aksrt-cyan: #06b6d4;--aksrt-cyan-soft: rgba(6, 182, 212, .12);--aksrt-yellow: #eab308;--aksrt-yellow-soft:rgba(234, 179, 8, .12);--aksrt-red: #ef4444;--aksrt-red-soft: rgba(239, 68, 68, .12);--aksrt-teal: #14b8a6;--aksrt-teal-soft: rgba(20, 184, 166, .12);--aksrt-indigo: #6366f1;--aksrt-indigo-soft:rgba(99, 102, 241, .12);--aksrt-pink: #ec4899;--aksrt-pink-soft: rgba(236, 72, 153, .12);--aksrt-vip-gold-1: #f6d365;--aksrt-vip-gold-2: #fda085;--aksrt-grad-sunset-1: #f093fb;--aksrt-grad-sunset-2: #f5576c;--aksrt-graLine truncated
:root{--color-primary: #f04494;--color-primary-hover: #e0307e;--color-primary-active: #c9206d;--color-primary-soft: rgba(240, 68, 148, .1);--color-primary-softer: rgba(240, 68, 148, .05);--color-on-primary: #FFFFFF;--color-ink: #333333;--color-ink-2: #4e5358;--color-ink-3: #777777;--color-ink-4: #999999;--surface-page: #f5f6f7;--surface-1: #FFFFFF;--surface-2: #eeeeee;--surface-3: #e9ecef;--surface-4: #f8f8f8;--color-line: rgba(50, 50, 50, .06);--color-line-soft: rgba(0, 0, 0, .03);--color-line-stronger: rgba(50, 50, 50, .12);--color-success: #10B981;--color-warning: #F59E0B;--color-error: #EF4444;--color-info: #3B82F6;--color-accent: #18a058;--color-accent-soft: rgba(24, 160, 88, .12);--color-accent-shadow: rgba(24, 160, 88, .28);--font-display: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;--font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;--font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;--font-mono: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;--text-xs: .75rem;--text-sm: .875rem;--text-base: .875rem;--text-md: 1.125rem;--text-lg: 1.25rem;--text-xl: 1.5rem;--text-2xl: 1.875rem;--text-3xl: 2.25rem;--text-4xl: 3rem;--text-5xl: 3.75rem;--leading-tight: 1.2;--leading-snug: 1.4;--leading-normal: 1.6;--leading-relaxed: 1.6;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--space-5: 20px;--space-6: 24px;--space-7: 32px;--space-8: 40px;--space-9: 48px;--space-10: 64px;--space-11: 80px;--space-12: 96px;--radius-xs: 3px;--radius-sm: 4px;--radius: 8px;--radius-lg: 8px;--radius-xl: 12px;--radius-2xl: 16px;--radius-pill: 100px;--radius-avatar: 50%;--shadow-xs: 0 1px 2px rgba(0, 0, 0, .03);--shadow-sm: 0 0 10px rgba(116, 116, 116, .08);--shadow: 0 0 10px rgba(116, 116, 116, .12);--shadow-lg: 0 12px 32px rgba(18, 18, 18, .1);--shadow-drawer: 0 18px 60px rgba(0, 0, 0, .2);--nav-height: 60px;--container: 1200px;--container-wide: 1440px;--container-read: 760px;--container-page: 880px;--sidebar-width: 311px;--content-gap: 24px;--section-gap: 24px;--sidebar-bp: 992px;--ease: cubic-bezier(.4, 0, .2, 1);--ease-out: cubic-bezier(.16, 1, .3, 1);--ease-spring: cubic-bezier(.34, 1.56, .64, 1);--dur-fast: .15s;--dur: .25s;--dur-slow: .4s;--focus-ring: 0 0 2px 3px rgba(253, 83, 161, .4);--z-dropdown: 100;--z-sticky: 200;--z-fixed: 300;--z-overlay: 400;--z-modal: 500;--z-popover: 600;--z-toast: 700;--z-tooltip: 800;--radius-btn: 4px;--btn-sm-h: 28px;--btn-md-h: 34px;--btn-lg-h: 44px;--card-padding: 15px;--card-padding-sm: 10px;--card-gap: 16px;--card-gap-lg: 20px;--color-primary-light: var(--color-primary-soft);--color-surface: var(--surface-1);--color-line-strong: var(--color-line);--color-bg-hover: var(--surface-2);--color-border-light: var(--color-line-soft);--color-fill: var(--surface-2);--color-warning-bg: #fffbe6;--color-warning-text: #ad6800;--text-secondary: var(--color-ink-3);--text-tertiary: var(--color-ink-4);--surface-active: var(--surface-2);--surface-card: var(--surface-1);--surface-hover: var(--surface-2);--surface-secondary: var(--surface-2);--radius-code: var(--radius);--radius-full: 100px;--shadow-xl: 0 0 10px rgba(116, 116, 116, .12);--space-16: 64px;--z-floating: 900;--transition-fast: .15s ease;--transition-base: .25s ease;--header-bg: var(--blur-bg);--header-color: var(--color-ink-2);--footer-bg: var(--surface-1);--footer-color: var(--color-ink-4);--blur-bg: rgba(255, 255, 255, .8);--float-btn-bg: rgba(200, 200, 200, .4);--font-heading: var(--font-ui);--radius-card: var(--radius);--radius-md: var(--radius);--color-primary-50: var(--color-primary-soft);--color-primary-dark: var(--color-primary-active);--shadow-md: var(--shadow);--mini-radius: calc(var(--radius) / 1.4);--aksrt-avatar-size-xs: 24px;--aksrt-avatar-size-sm: 32px;--aksrt-avatar-size: 40px;--aksrt-avatar-size-lg: 56px;--aksrt-avatar-size-xl: 80px;--aksrt-card-thumb-scale: 56.25%;--aksrt-rose: #f43f5e;--aksrt-rose-soft: rgba(244, 63, 94, .12);--aksrt-blue: #3b82f6;--aksrt-blue-soft: rgba(59, 130, 246, .12);--aksrt-green: #10b981;--aksrt-green-soft: rgba(16, 185, 129, .12);--aksrt-orange: #f97316;--aksrt-orange-soft:rgba(249, 115, 22, .12);--aksrt-purple: #8b5cf6;--aksrt-purple-soft:rgba(139, 92, 246, .12);--aksrt-cyan: #06b6d4;--aksrt-cyan-soft: rgba(6, 182, 212, .12);--aksrt-yellow: #eab308;--aksrt-yellow-soft:rgba(234, 179, 8, .12);--aksrt-red: #ef4444;--aksrt-red-soft: rgba(239, 68, 68, .12);--aksrt-teal: #14b8a6;--aksrt-teal-soft: rgba(20, 184, 166, .12);--aksrt-indigo: #6366f1;--aksrt-indigo-soft:rgba(99, 102, 241, .12);--aksrt-pink: #ec4899;--aksrt-pink-soft: rgba(236, 72, 153, .12);--aksrt-vip-gold-1: #f6d365;--aksrt-vip-gold-2: #fda085;--aksrt-grad-sunset-1: #f093fb;--aksrt-grad-sunset-2: #f5576c;--aksrt-graLine truncated
+70 -2
View File
@@ -619,7 +619,8 @@ body.aksrt-modal-runtime-open {
底色走 --main-radius / --main-bg-color;移动端由 --bottom 底部抽屉接管。 */
.aksrt-after-sale-apply-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog,
.aksrt-after-sale-detail-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog,
.aksrt-after-sale-expired-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog {
.aksrt-after-sale-expired-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog,
.aksrt-after-sale-withdraw-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog {
width: min(400px, calc(100vw - 32px));
border-radius: var(--main-radius, 8px);
background: var(--main-bg-color, #fff);
@@ -627,7 +628,8 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .aksrt-modal-runtime__skeleton,
.aksrt-after-sale-detail-modal .aksrt-modal-runtime__skeleton,
.aksrt-after-sale-expired-modal .aksrt-modal-runtime__skeleton {
.aksrt-after-sale-expired-modal .aksrt-modal-runtime__skeleton,
.aksrt-after-sale-withdraw-modal .aksrt-modal-runtime__skeleton {
padding: 24px 18px;
}
@@ -636,10 +638,12 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .modal-colorful-header,
.aksrt-after-sale-detail-modal .modal-colorful-header,
.aksrt-after-sale-expired-modal .modal-colorful-header,
.aksrt-after-sale-withdraw-modal .modal-colorful-header,
.aksrt-order-detail-modal .modal-colorful-header,
.aksrt-after-sale-apply-modal .colorful-bg,
.aksrt-after-sale-detail-modal .colorful-bg,
.aksrt-after-sale-expired-modal .colorful-bg,
.aksrt-after-sale-withdraw-modal .colorful-bg,
.aksrt-order-detail-modal .colorful-bg {
position: relative;
overflow: hidden;
@@ -651,6 +655,7 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .modal-colorful-header,
.aksrt-after-sale-detail-modal .modal-colorful-header,
.aksrt-after-sale-expired-modal .modal-colorful-header,
.aksrt-after-sale-withdraw-modal .modal-colorful-header,
.aksrt-order-detail-modal .modal-colorful-header {
position: absolute;
top: 0;
@@ -666,6 +671,7 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .modal-colorful-header + *,
.aksrt-after-sale-detail-modal .modal-colorful-header + *,
.aksrt-after-sale-expired-modal .modal-colorful-header + *,
.aksrt-after-sale-withdraw-modal .modal-colorful-header + *,
.aksrt-order-detail-modal .modal-colorful-header + * {
margin-top: 120px;
}
@@ -673,6 +679,7 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .modal-colorful-header > .close,
.aksrt-after-sale-detail-modal .modal-colorful-header > .close,
.aksrt-after-sale-expired-modal .modal-colorful-header > .close,
.aksrt-after-sale-withdraw-modal .modal-colorful-header > .close,
.aksrt-order-detail-modal .modal-colorful-header > .close {
position: absolute;
top: 10px;
@@ -690,10 +697,13 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-detail-modal .colorful-bg > .colorful-make::before,
.aksrt-after-sale-detail-modal .colorful-bg > .colorful-make::after,
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make,
.aksrt-after-sale-withdraw-modal .colorful-bg > .colorful-make,
.aksrt-order-detail-modal .colorful-bg > .colorful-make,
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make::before,
.aksrt-after-sale-withdraw-modal .colorful-bg > .colorful-make::before,
.aksrt-order-detail-modal .colorful-bg > .colorful-make::before,
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make::after,
.aksrt-after-sale-withdraw-modal .colorful-bg > .colorful-make::after,
.aksrt-order-detail-modal .colorful-bg > .colorful-make::after {
position: absolute;
color: var(--this-color);
@@ -705,6 +715,7 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .colorful-bg > .colorful-make,
.aksrt-after-sale-detail-modal .colorful-bg > .colorful-make,
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make,
.aksrt-after-sale-withdraw-modal .colorful-bg > .colorful-make,
.aksrt-order-detail-modal .colorful-bg > .colorful-make {
top: 60%;
bottom: 0;
@@ -716,6 +727,7 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .colorful-bg > .colorful-make::before,
.aksrt-after-sale-detail-modal .colorful-bg > .colorful-make::before,
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make::before,
.aksrt-after-sale-withdraw-modal .colorful-bg > .colorful-make::before,
.aksrt-order-detail-modal .colorful-bg > .colorful-make::before {
top: -325px;
right: -558px;
@@ -729,6 +741,7 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-apply-modal .colorful-bg > .colorful-make::after,
.aksrt-after-sale-detail-modal .colorful-bg > .colorful-make::after,
.aksrt-after-sale-expired-modal .colorful-bg > .colorful-make::after,
.aksrt-after-sale-withdraw-modal .colorful-bg > .colorful-make::after,
.aksrt-order-detail-modal .colorful-bg > .colorful-make::after {
top: -170px;
bottom: 0;
@@ -802,3 +815,58 @@ body.aksrt-modal-runtime-open {
.aksrt-after-sale-status.is-completed { color: var(--color-success, #10b981); }
.aksrt-after-sale-status.is-rejected,
.aksrt-after-sale-status.is-cancelled { color: var(--color-error, #ef4444); }
/* 状态行右侧单元格:状态徽章 + 「撤销售后」入口(仅待审核工单渲染)。 */
.aksrt-after-sale-detail__statusCell { display: inline-flex; align-items: center; gap: 10px; }
.aksrt-after-sale-withdraw { display: inline-flex; align-items: center; gap: 3px; padding: 0; border: 0; background: transparent; color: var(--modal-danger, #ef4444); font-size: 12px; font-weight: 600; line-height: 1.4; cursor: pointer; transition: color .15s ease; }
.aksrt-after-sale-withdraw .fa { font-size: 12px; }
.aksrt-after-sale-withdraw:hover { color: color-mix(in srgb, var(--modal-danger) 78%, var(--modal-ink)); }
/* 售后提示弹窗(撤销售后确认)正文。 */
.aksrt-after-sale-withdraw__body { margin-bottom: 16px; color: var(--color-ink-2, #4e5358); line-height: 1.7; }
/* 售后弹窗底部按钮:全宽平铺贴底(负 margin 抵消 __content 内边距)+ 分隔线,
子按钮去独立背景/边框/圆角(文字色区分主次),覆盖上方全局按钮网格的胶囊观感;
仅在售后弹窗家族生效,其他 runtime 弹窗仍走全局网格样式。 */
.aksrt-after-sale-apply-modal .but-average.modal-buts,
.aksrt-after-sale-detail-modal .but-average.modal-buts,
.aksrt-after-sale-expired-modal .but-average.modal-buts,
.aksrt-after-sale-withdraw-modal .but-average.modal-buts {
gap: 0;
margin: 16px -18px -16px;
padding: 12px 18px;
border-top: 1px solid var(--modal-line-soft, rgba(50, 50, 50, 0.06));
background: var(--main-bg-color, #fff);
}
.aksrt-after-sale-apply-modal .but-average.modal-buts > .but,
.aksrt-after-sale-detail-modal .but-average.modal-buts > .but,
.aksrt-after-sale-expired-modal .but-average.modal-buts > .but,
.aksrt-after-sale-withdraw-modal .but-average.modal-buts > .but {
min-height: 38px;
border: 0;
border-radius: 0;
box-shadow: none;
background: transparent;
color: var(--modal-muted, #777);
font-weight: 600;
cursor: pointer;
--this-bg: transparent;
--this-border: transparent;
--this-shadow: none;
}
.aksrt-after-sale-apply-modal .but-average.modal-buts > .but.c-blue,
.aksrt-after-sale-detail-modal .but-average.modal-buts > .but.c-blue,
.aksrt-after-sale-expired-modal .but-average.modal-buts > .but.c-blue,
.aksrt-after-sale-withdraw-modal .but-average.modal-buts > .but.c-blue {
background: transparent;
border: 0;
color: var(--modal-primary, #f04494);
}
/* 单按钮 footer 占满整行(全局网格是 1fr 1fr,单按钮会只占一半)。 */
.aksrt-after-sale-apply-modal .but-average.modal-buts > .but:only-child,
.aksrt-after-sale-detail-modal .but-average.modal-buts > .but:only-child,
.aksrt-after-sale-expired-modal .but-average.modal-buts > .but:only-child,
.aksrt-after-sale-withdraw-modal .but-average.modal-buts > .but:only-child { grid-column: 1 / -1; }
+4
View File
@@ -114,6 +114,10 @@
border-radius: var(--main-radius, 8px);
background: var(--main-bg-color, #fff);
}
/* 滚动发生在 dialog 本体(modal-runtime 的 overflow:auto),内容超高时右缘会露出
滚动栏;与售后/申诉弹窗口径一致:完全隐藏滚动条(含细滚动条),滚动行为不变。 */
.aksrt-order-detail-modal .aksrt-modal-runtime__dialog { -ms-overflow-style: none; scrollbar-width: none; }
.aksrt-order-detail-modal .aksrt-modal-runtime__dialog::-webkit-scrollbar { display: none; }
.aksrt-order-detail-modal .aksrt-modal-runtime__content { display: flex; flex-direction: column; gap: 18px; padding: 16px 18px 0; }
.aksrt-order-detail__skeleton { display: grid; gap: 12px; padding: 4px 0; }
+151 -34
View File
@@ -4,9 +4,12 @@
* 与「禁封/举报」链路同构(report.js / user-ban.js):
* - [data-aksrt-after-sale-apply] → 申请售后弹窗(超时效则改为超时效提示弹窗)
* - [data-aksrt-after-sale-detail] → 售后详细弹窗(可再次申请 / 不可再申请提示)
* - [data-aksrt-after-sale-withdraw] → 撤销售后二次确认弹窗(仅待审核工单),确认后 DELETE 工单
* 两个入口的 data-* 属性携带订单与售后状态载荷(同 report.js 的 data-aksrt-report),
* 点击即同步弹窗,不做前置请求(避免首次点击无反馈)。
* - 提交走 REST /aksrt/v1/orders/{order_number}/after-sale
* - 撤销走 DELETE 同端点(仅待审核工单,后端置为已取消)
* - 提交与撤销前先过人机验证(after_sale_apply / after_sale_cancel,场景未启用自动放行)
* - 举证图片走 /orders/{order_number}/after-sale/upload-image(复用评论图片上传校验)
*
* 按钮形态由订单视图模型的 after_sale 状态决定(UserOrders::after_sale_state):
@@ -178,8 +181,13 @@
html += '<div class="aksrt-after-sale-detail__statusRow">' +
'<span class="muted-2-color em09">售后状态</span>' +
'<span class="aksrt-after-sale-detail__statusCell">' +
'<span class="badg p2-10 aksrt-after-sale-status is-' + escapeHtml(status) + '">' + escapeHtml(STATUS_LABELS[status] || status) + '</span>' +
'</div>';
// 仅「待审核」可撤销(后端 cancel 仅放行 pending):入口随状态徽章渲染。
(status === 'pending'
? '<button type="button" class="aksrt-after-sale-withdraw" data-aksrt-after-sale-withdraw="' + escapeHtml((order && order.order_number) || '') + '">撤销售后<i class="fa fas fa-angle-right" aria-hidden="true"></i></button>'
: '') +
'</span></div>';
html += '<div class="aksrt-after-sale-detail__rows">';
html += detailRow('申请时间', String(latest.created_at || ''));
@@ -238,6 +246,19 @@
return html;
}
// 撤销售后二次确认弹窗:待审核工单入口点入,确认后 DELETE 售后工单。
function buildWithdrawHtml(orderNumber) {
var html = '<div class="aksrt-after-sale-withdraw-modal">';
html += colorfulHeader('撤销售后', 'fa-undo-alt');
html += '<div class="aksrt-after-sale-withdraw__body em09">撤销后本次售后申请将关闭,订单恢复为可再次申请售后的状态。确定撤销吗?</div>';
html += '<div class="but-average modal-buts">' +
'<button type="button" class="but" data-aksrt-modal-close>取消</button>' +
'<button type="button" class="but c-blue" data-aksrt-after-sale-withdraw-confirm="' + escapeHtml(orderNumber) + '">确认撤销</button>' +
'</div>';
html += '</div>';
return html;
}
function openModal(options) {
if (!window.AksrtModalRuntime || typeof window.AksrtModalRuntime.open !== 'function') {
notyf('售后组件加载失败,请刷新页面后重试', 'danger');
@@ -277,6 +298,15 @@
});
}
function openWithdraw(orderNumber) {
if (!orderNumber) return;
return openModal({
html: buildWithdrawHtml(orderNumber),
className: 'aksrt-after-sale-withdraw-modal',
kind: 'after-sale-withdraw',
});
}
/**
* 解析按钮 data-* 上的售后载荷(与举报链路 data-aksrt-report 同模式):
* 入口数据随列表一起渲染,点击即可同步弹窗,不做前置请求。
@@ -407,6 +437,22 @@
return parts.join('\n');
}
function clearToast(id) {
var toast = document.getElementById(id);
if (toast) toast.remove();
}
// 提交前的人机验证:场景未启用时无挂载点,run 直接 resolve {};
// 用户中途取消验证时 run resolve null,此时还原按钮并中止提交。
function runCaptcha(scene) {
if (!window.AKSRTCaptcha || typeof window.AKSRTCaptcha.run !== 'function') {
return Promise.resolve({});
}
return window.AKSRTCaptcha.run(scene).then(function (payload) {
return payload === null ? Promise.reject({ cancelled: true }) : (payload || {});
});
}
function submitApply(shell) {
var form = shell.querySelector('[data-aksrt-after-sale-order]');
var orderNumber = form ? form.getAttribute('data-aksrt-after-sale-order') : '';
@@ -427,41 +473,97 @@
if (submitBtn) submitBtn.disabled = true;
notyf('正在提交售后申请…', 'load', 3000, 'aksrt-after-sale-submit');
window.fetch(API_ROOT + '/orders/' + encodeURIComponent(orderNumber) + '/after-sale', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': NONCE,
},
body: JSON.stringify({
reason: composeReason(shell),
reason_label: selectedReasonLabel(shell),
materials: collectMaterials(shell),
description: reasonText,
images: collectImages(shell),
}),
})
.then(function (res) { return res.json(); })
.then(function (result) {
if (result && result.success) {
window.AksrtModalRuntime.close('submit');
notyf('售后申请已提交', 'success');
if (window.AKSRTOrderCenter && typeof window.AKSRTOrderCenter.refresh === 'function') {
window.AKSRTOrderCenter.refresh(orderNumber);
var restoreButton = function () {
if (submitBtn) submitBtn.disabled = false;
};
var sendApply = function (captchaPayload) {
window.fetch(API_ROOT + '/orders/' + encodeURIComponent(orderNumber) + '/after-sale', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': NONCE,
},
body: JSON.stringify(Object.assign({
reason: composeReason(shell),
reason_label: selectedReasonLabel(shell),
materials: collectMaterials(shell),
description: reasonText,
images: collectImages(shell),
}, captchaPayload)),
})
.then(function (res) { return res.json(); })
.then(function (result) {
if (result && result.success) {
window.AksrtModalRuntime.close('submit');
notyf('售后申请已提交', 'success');
if (window.AKSRTOrderCenter && typeof window.AKSRTOrderCenter.refresh === 'function') {
window.AKSRTOrderCenter.refresh(orderNumber);
}
} else {
restoreButton();
notyf((result && result.message) || '售后申请提交失败', 'danger');
}
} else {
if (submitBtn) submitBtn.disabled = false;
notyf((result && result.message) || '售后申请提交失败', 'danger');
}
})
.catch(function () {
restoreButton();
notyf('网络错误,请重试', 'danger');
})
.then(function () { clearToast('aksrt-after-sale-submit'); });
};
runCaptcha('after_sale_apply').then(sendApply).catch(function (error) {
restoreButton();
clearToast('aksrt-after-sale-submit');
if (error && error.cancelled) return;
notyf('人机验证失败,请重试', 'danger');
});
}
// 撤销售后:待审核工单置为已取消(DELETE 售后工单),成功后刷新订单列表与统计。
function submitWithdraw(shell, button) {
var orderNumber = button.getAttribute('data-aksrt-after-sale-withdraw-confirm') || '';
if (!orderNumber || button.disabled) return;
button.disabled = true;
notyf('正在撤销售后申请…', 'load', 3000, 'aksrt-after-sale-withdraw');
var restoreButton = function () {
button.disabled = false;
};
var sendWithdraw = function (captchaPayload) {
window.fetch(API_ROOT + '/orders/' + encodeURIComponent(orderNumber) + '/after-sale', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': NONCE,
},
body: JSON.stringify(captchaPayload || {}),
})
.catch(function () {
if (submitBtn) submitBtn.disabled = false;
notyf('网络错误,请重试', 'danger');
})
.then(function () {
var toast = document.getElementById('aksrt-after-sale-submit');
if (toast) toast.remove();
});
.then(function (res) { return res.json(); })
.then(function (result) {
if (result && result.success) {
window.AksrtModalRuntime.close('withdraw');
notyf('售后申请已撤销', 'success');
if (window.AKSRTOrderCenter && typeof window.AKSRTOrderCenter.refresh === 'function') {
window.AKSRTOrderCenter.refresh(orderNumber);
}
} else {
restoreButton();
notyf((result && result.message) || '撤销失败,请重试', 'danger');
}
})
.catch(function () {
restoreButton();
notyf('网络错误,请重试', 'danger');
})
.then(function () { clearToast('aksrt-after-sale-withdraw'); });
};
runCaptcha('after_sale_cancel').then(sendWithdraw).catch(function (error) {
restoreButton();
clearToast('aksrt-after-sale-withdraw');
if (error && error.cancelled) return;
notyf('人机验证失败,请重试', 'danger');
});
}
function bindShell(shell) {
@@ -509,6 +611,21 @@
var payload = parsePayload(reapplyBtn.getAttribute('data-aksrt-after-sale-payload'));
window.AksrtModalRuntime.close('replace');
openApplyFlow(payload);
return;
}
// 撤销售后:入口在售后详细弹窗状态行(仅待审核),点击先弹二次确认。
var withdrawBtn = event.target.closest('[data-aksrt-after-sale-withdraw]');
if (withdrawBtn) {
event.preventDefault();
openWithdraw(withdrawBtn.getAttribute('data-aksrt-after-sale-withdraw') || '');
return;
}
var withdrawConfirm = event.target.closest('[data-aksrt-after-sale-withdraw-confirm]');
if (withdrawConfirm) {
event.preventDefault();
submitWithdraw(shell, withdrawConfirm);
}
});
+1 -20
View File
@@ -237,7 +237,6 @@
}));
html += '<div class="aksrt-order-detail__after-sale-foot">';
html += '<button class="btn-ghost" type="button" data-aksrt-after-sale-detail="' + recordPayload + '">查看详细</button>';
if (asStatus === "pending") html += '<button class="btn-ghost" type="button" data-aksrt-after-sale-cancel="' + escapeHtml(order.order_number) + '">取消申请</button>';
html += "</div>";
html += "</li>";
});
@@ -662,25 +661,7 @@
state.detailReplacementSession = null;
};
state.onDocumentClick = function (event) {
var afterSaleCancel = closest(event.target, "[data-aksrt-after-sale-cancel]");
if (afterSaleCancel && !event.__aksrtAfterSaleCancelHandled) {
var afterSaleNumber = afterSaleCancel.getAttribute("data-aksrt-after-sale-cancel") || "";
if (activeDetail(state, afterSaleNumber)) {
event.__aksrtAfterSaleCancelHandled = true;
event.preventDefault();
afterSaleCancel.disabled = true;
request(orderPath(afterSaleNumber, "/after-sale"), undefined, "DELETE", window.AksrtRequest.createIdempotencyKey()).then(function () {
notyf("售后申请已取消", "success");
invalidateOrder(afterSaleNumber);
openDetail(state, afterSaleNumber);
refreshView(state);
}).catch(function (error) {
afterSaleCancel.disabled = false;
notyf(errorMessage(error, "取消申请失败"), "danger");
});
return;
}
}
// 取消/撤销售后已移入售后详细弹窗(order-after-sale.js 的「撤销售后」入口)。
if (!state.detailSession || window.AksrtModalRuntime.getActive() !== state.detailSession.shell) return;
var copy = closest(event.target, "[data-aksrt-order-copy]");
if (copy) {