fix(report): align the report modal with the reference theme 1:1
- read preset reasons from the real source (ban_preset_reason via UserRuntime::ban_settings); the previous injection read a nonexistent report.categories key, so backend reasons never showed - rebuild the modal on the reference markup contract: edit-header warning header, reason chips toggling the reference .active class (focus color), other-reason textarea, violation link, description, but-average modal-buts footer - add image evidence upload gated by user_report_img_s: new /report/upload-image route reusing the comment upload handler with its own permission, preview/remove UI, up to 3 images appended to the report content - render the backend report notice (user_report_desc, sanitized HTML) inside the modal - widen the dialog to the reference 600px desktop geometry and share the form-upload preview styles with the order review modal - extend the report contract test accordingly
This commit is contained in:
1 parent
913958820c
commit
7a80297a56
7 files changed
+329
-91
No files matched your search
+45
-10
@@ -7189,6 +7189,41 @@ body.aksrt-modal-runtime-open {
|
|||||||
transition: opacity 0.15s ease;
|
transition: opacity 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- 举报弹窗(参考主题报告弹窗几何 1:1)----
|
||||||
|
宽度对齐参考主题 Bootstrap 默认模态(>=768px 600px),圆角/底色走
|
||||||
|
--main-radius / --main-bg-color;移动端仍由 --bottom 底部抽屉接管。 */
|
||||||
|
.aksrt-report-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog {
|
||||||
|
width: min(600px, calc(100vw - 32px));
|
||||||
|
border-radius: var(--main-radius, 8px);
|
||||||
|
background: var(--main-bg-color, #fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* edit-header:参考主题弹窗头(关闭钮靠右,红色警示徽标 + 标题居左)。 */
|
||||||
|
.aksrt-report-modal .edit-header {
|
||||||
|
position: relative;
|
||||||
|
padding-right: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aksrt-report-modal .edit-header .close {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
float: none;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
background: none;
|
||||||
|
border: 0;
|
||||||
|
padding: 2px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 原因徽章行:与参考主题一致,徽章可换行且间距走 mr6/mb6 工具类。 */
|
||||||
|
.aksrt-report-modal .form-but-radio .badg {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- order review modal content ---- */
|
/* ---- order review modal content ---- */
|
||||||
.order-comment-from .shop-score-box {
|
.order-comment-from .shop-score-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -7253,14 +7288,14 @@ body.aksrt-modal-runtime-open {
|
|||||||
color: var(--color-ink, #111);
|
color: var(--color-ink, #111);
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview .add,
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .add,
|
||||||
.order-comment-from .form-upload .preview .preview-item {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .preview-item {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 80px;
|
height: 80px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
@@ -7271,8 +7306,8 @@ body.aksrt-modal-runtime-open {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview .add::before,
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .add::before,
|
||||||
.order-comment-from .form-upload .preview .add::after {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .add::after {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
@@ -7281,24 +7316,24 @@ body.aksrt-modal-runtime-open {
|
|||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview .add::before {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .add::before {
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview .add::after {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .add::after {
|
||||||
width: 2px;
|
width: 2px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview .preview-item img {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .preview-item img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview .preview-item .remove {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .preview-item .remove {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
right: 2px;
|
right: 2px;
|
||||||
@@ -7313,7 +7348,7 @@ body.aksrt-modal-runtime-open {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .hide {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .hide {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -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;--skeleton-base: var(--surface-2);--skeleton-shine: var(--surface-1);--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);--content-max: var(--container);--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;Line 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;--skeleton-base: var(--surface-2);--skeleton-shine: var(--surface-1);--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);--content-max: var(--container);--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;Line truncated
|
||||||
@@ -272,6 +272,41 @@ body.aksrt-modal-runtime-open {
|
|||||||
transition: opacity 0.15s ease;
|
transition: opacity 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- 举报弹窗(参考主题报告弹窗几何 1:1)----
|
||||||
|
宽度对齐参考主题 Bootstrap 默认模态(>=768px 600px),圆角/底色走
|
||||||
|
--main-radius / --main-bg-color;移动端仍由 --bottom 底部抽屉接管。 */
|
||||||
|
.aksrt-report-modal:not(.aksrt-modal-runtime--bottom) .aksrt-modal-runtime__dialog {
|
||||||
|
width: min(600px, calc(100vw - 32px));
|
||||||
|
border-radius: var(--main-radius, 8px);
|
||||||
|
background: var(--main-bg-color, #fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* edit-header:参考主题弹窗头(关闭钮靠右,红色警示徽标 + 标题居左)。 */
|
||||||
|
.aksrt-report-modal .edit-header {
|
||||||
|
position: relative;
|
||||||
|
padding-right: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aksrt-report-modal .edit-header .close {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
float: none;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
background: none;
|
||||||
|
border: 0;
|
||||||
|
padding: 2px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 原因徽章行:与参考主题一致,徽章可换行且间距走 mr6/mb6 工具类。 */
|
||||||
|
.aksrt-report-modal .form-but-radio .badg {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- order review modal content ---- */
|
/* ---- order review modal content ---- */
|
||||||
.order-comment-from .shop-score-box {
|
.order-comment-from .shop-score-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -336,14 +371,14 @@ body.aksrt-modal-runtime-open {
|
|||||||
color: var(--color-ink, #111);
|
color: var(--color-ink, #111);
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview .add,
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .add,
|
||||||
.order-comment-from .form-upload .preview .preview-item {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .preview-item {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 80px;
|
height: 80px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
@@ -354,8 +389,8 @@ body.aksrt-modal-runtime-open {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview .add::before,
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .add::before,
|
||||||
.order-comment-from .form-upload .preview .add::after {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .add::after {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
@@ -364,24 +399,24 @@ body.aksrt-modal-runtime-open {
|
|||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview .add::before {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .add::before {
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview .add::after {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .add::after {
|
||||||
width: 2px;
|
width: 2px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview .preview-item img {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .preview-item img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .preview .preview-item .remove {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .preview .preview-item .remove {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
right: 2px;
|
right: 2px;
|
||||||
@@ -396,7 +431,7 @@ body.aksrt-modal-runtime-open {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.order-comment-from .form-upload .hide {
|
:is(.order-comment-from, .aksrt-report-modal) .form-upload .hide {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+181
-66
@@ -1,9 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* AKSRT Report — 前台统一举报弹窗
|
* AKSRT Report — 前台统一举报弹窗
|
||||||
*
|
*
|
||||||
* 监听 [data-aksrt-report] 点击,弹出对齐参考主题格式的举报弹窗:
|
* 监听 [data-aksrt-report] 点击,弹出对齐参考主题的举报弹窗(像素级同构):
|
||||||
* 红色警示头 + 举报原因徽章(含“其它原因”)+ 违规链接 + 详细描述 + 取消/确认提交。
|
* edit-header 红色警示头 + 举报原因徽章(active 状态走 .active.badg 焦点色)
|
||||||
* 提交走 REST /aksrt/v1/report/submit(user/comment/post 三类目标统一入口)。
|
* + 违规链接 + 详细描述 + 图片举证(后台开启 user_report_img_s 时)
|
||||||
|
* + 举报说明(后台 user_report_desc,支持 HTML)+ but-average modal-buts 底栏。
|
||||||
|
* 提交走 REST /aksrt/v1/report/submit(user/comment/post 三类目标统一入口),
|
||||||
|
* 举证图片走 /aksrt/v1/report/upload-image(最多 3 张,URL 拼入举报内容)。
|
||||||
*
|
*
|
||||||
* @package AKSRT
|
* @package AKSRT
|
||||||
*/
|
*/
|
||||||
@@ -24,27 +27,41 @@
|
|||||||
comment: '举报评论',
|
comment: '举报评论',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var MAX_IMAGES = 3;
|
||||||
|
|
||||||
function getReportCategories() {
|
function getReportCategories() {
|
||||||
// 预置原因:后台“用户&互动 → 禁封/举报”配置(aksrtData.reportCategories)。
|
// 预置原因:后台“用户&互动 → 禁封/举报 → 预置原因”(ban_preset_reason,
|
||||||
|
// 由 UserRuntime::ban_settings 解析,aksrtData.reportCategories 注入)。
|
||||||
var list = window.aksrtData && window.aksrtData.reportCategories;
|
var list = window.aksrtData && window.aksrtData.reportCategories;
|
||||||
if (Array.isArray(list)) {
|
if (Array.isArray(list)) {
|
||||||
var items = list
|
var items = list
|
||||||
.map(function (cat) {
|
.map(function (cat) {
|
||||||
return {
|
return {
|
||||||
slug: String((cat && (cat.slug || cat.value)) || ''),
|
slug: String((cat && (cat.slug || cat.value)) || ''),
|
||||||
label: String((cat && (cat.label || cat.name)) || ''),
|
name: String((cat && (cat.name || cat.label || cat.t)) || ''),
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter(function (cat) { return cat.slug !== '' && cat.label !== ''; });
|
.filter(function (cat) { return cat.slug !== '' && cat.name !== ''; });
|
||||||
if (items.length) return items;
|
if (items.length) return items;
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
{ slug: 'spam', label: '垃圾信息' },
|
{ slug: 'spam', name: '垃圾信息' },
|
||||||
{ slug: 'abuse', label: '人身攻击' },
|
{ slug: 'abuse', name: '人身攻击' },
|
||||||
{ slug: 'copyright', label: '版权投诉' },
|
{ slug: 'copyright', name: '版权投诉' },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reportDescHtml() {
|
||||||
|
// 举报说明:后台富文本(服务端已 wp_kses_post),直接注入。
|
||||||
|
var d = window.aksrtData && window.aksrtData.report;
|
||||||
|
return (d && typeof d.desc === 'string') ? d.desc : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function imgUploadEnabled() {
|
||||||
|
var d = window.aksrtData && window.aksrtData.report;
|
||||||
|
return !!(d && d.imgEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
function escapeHtml(value) {
|
function escapeHtml(value) {
|
||||||
return String(value == null ? '' : value)
|
return String(value == null ? '' : value)
|
||||||
.replace(/&/g, '&')
|
.replace(/&/g, '&')
|
||||||
@@ -60,35 +77,35 @@
|
|||||||
|
|
||||||
var html = '';
|
var html = '';
|
||||||
|
|
||||||
// 弹窗头:参考主题红色警示样式。
|
// 弹窗头:参考主题 edit-header 同构(关闭钮 + 红色警示徽标 + 标题)。
|
||||||
html += '<div class="flex jsb ac mb10">';
|
html += '<div class="mb10 edit-header touch">';
|
||||||
html += '<b class="flex ac c-red em12"><span class="toggle-radius mr10 c-red"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i></span>' + escapeHtml(title) + '</b>';
|
html += '<button type="button" class="close" data-aksrt-modal-close aria-label="关闭"><i class="fa fa-times" aria-hidden="true"></i></button>';
|
||||||
html += '<button type="button" class="aksrt-modal-runtime__close" data-aksrt-modal-close aria-label="关闭">×</button>';
|
html += '<b class="flex ac c-red"><span class="toggle-radius mr10 c-red"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i></span>' + escapeHtml(title) + '</b>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
html += '<form class="aksrt-report-form">';
|
html += '<form class="aksrt-report-form dependency-box">';
|
||||||
html += '<div class="scroll-y mini-scrollbar max-vh7">';
|
html += '<div class="scroll-y mini-scrollbar max-vh7">';
|
||||||
|
html += '<div class="mt10 mb20">';
|
||||||
|
|
||||||
// 被举报对象(头像 + 名称),由服务端渲染进 data-aksrt-report。
|
// 被举报对象(头像 + 名称),由服务端渲染进 data-aksrt-report。
|
||||||
if (data.target_avatar || data.target_name) {
|
if (data.target_avatar || data.target_name) {
|
||||||
html += '<div class="flex ac mb10">';
|
html += '<div class="flex ac mb6">';
|
||||||
if (data.target_avatar) {
|
if (data.target_avatar) {
|
||||||
html += '<img class="avatar-mini mr6" src="' + escapeHtml(data.target_avatar) + '" alt="">';
|
html += '<img class="avatar-mini mr6" src="' + escapeHtml(data.target_avatar) + '" alt="">';
|
||||||
}
|
}
|
||||||
html += '<b>' + escapeHtml(data.target_name || '') + '</b>';
|
html += '<b>' + escapeHtml(data.target_name || '') + '</b>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 举报原因(徽章单选,含“其它原因”)。
|
|
||||||
html += '<div class="mb20">';
|
|
||||||
html += '<div class="em09 muted-2-color mb6">举报原因</div>';
|
|
||||||
html += '<div class="aksrt-report-reasons">';
|
|
||||||
categories.forEach(function (cat) {
|
|
||||||
html += '<button type="button" class="mr6 mb6 badg p2-10 pointer" data-report-reason="' + escapeHtml(cat.slug) + '">' + escapeHtml(cat.label) + '</button>';
|
|
||||||
});
|
|
||||||
html += '<button type="button" class="mr6 mb6 badg p2-10 pointer" data-report-reason="other">其它原因</button>';
|
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += '<div class="aksrt-report-other mt6" hidden>';
|
|
||||||
|
// 举报原因(徽章单选,active 走参考主题焦点色;含“其它原因”展开自定义文本)。
|
||||||
|
html += '<div class="form-radio mb20 form-but-radio">';
|
||||||
|
html += '<div class="em09 muted-2-color mb6">举报原因</div>';
|
||||||
|
categories.forEach(function (cat) {
|
||||||
|
html += '<span class="mr6 mb6 badg p2-10 pointer" data-aksrt-report-reason="' + escapeHtml(cat.name) + '" data-reason-slug="' + escapeHtml(cat.slug) + '">' + escapeHtml(cat.name) + '</span>';
|
||||||
|
});
|
||||||
|
html += '<span class="mr6 mb6 badg p2-10 pointer" data-aksrt-report-reason="other">其它原因</span>';
|
||||||
|
html += '<div class="aksrt-report-other mb20" style="display: none;">';
|
||||||
html += '<textarea class="form-control" name="reason_other" rows="2" placeholder="请填写举报原因"></textarea>';
|
html += '<textarea class="form-control" name="reason_other" rows="2" placeholder="请填写举报原因"></textarea>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
@@ -96,15 +113,32 @@
|
|||||||
// 违规链接。
|
// 违规链接。
|
||||||
html += '<div class="mb20">';
|
html += '<div class="mb20">';
|
||||||
html += '<div class="em09 muted-2-color mb6">违规链接</div>';
|
html += '<div class="em09 muted-2-color mb6">违规链接</div>';
|
||||||
html += '<input type="url" class="form-control" name="report_url" placeholder="请输入违规链接(选填)">';
|
html += '<input type="text" class="form-control" name="report_url" placeholder="请输入违规链接">';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
// 详细描述。
|
// 详细描述。
|
||||||
html += '<div class="mb20">';
|
html += '<div class="mb20">';
|
||||||
html += '<div class="em09 muted-2-color mb6">详细描述</div>';
|
html += '<div class="em09 muted-2-color mb6">详细描述</div>';
|
||||||
html += '<textarea class="form-control" name="report_desc" rows="3" placeholder="请详细描述违规事项"></textarea>';
|
html += '<textarea class="form-control" name="report_desc" rows="2" placeholder="请详细描述违规事项"></textarea>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
|
// 图片举证(后台 user_report_img_s 开启时渲染,最多 3 张)。
|
||||||
|
if (imgUploadEnabled()) {
|
||||||
|
html += '<div class="form-upload mb10">';
|
||||||
|
html += '<div class="em09 muted-2-color mb6">添加图片举证</div>';
|
||||||
|
html += '<div class="preview">';
|
||||||
|
html += '<div class="add" data-aksrt-report-add role="button" aria-label="添加图片举证"></div>';
|
||||||
|
html += '</div>';
|
||||||
|
html += '<input class="hide" type="file" accept="image/gif,image/jpeg,image/jpg,image/png" data-aksrt-report-file>';
|
||||||
|
html += '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 举报说明(后台 user_report_desc,支持 HTML)。
|
||||||
|
var desc = reportDescHtml();
|
||||||
|
if (desc) {
|
||||||
|
html += '<div class="em09 padding-h10 muted-box mb10">' + desc + '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|
||||||
// 底栏:参考主题 but-average modal-buts 双按钮。
|
// 底栏:参考主题 but-average modal-buts 双按钮。
|
||||||
@@ -118,11 +152,67 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectedReason(shell) {
|
function selectedReason(shell) {
|
||||||
var active = shell.querySelector('[data-report-reason].is-active');
|
var active = shell.querySelector('[data-aksrt-report-reason].active');
|
||||||
return active ? active.getAttribute('data-report-reason') : '';
|
if (!active) return { label: '', slug: '' };
|
||||||
|
return {
|
||||||
|
label: active.getAttribute('data-aksrt-report-reason') || '',
|
||||||
|
slug: active.getAttribute('data-reason-slug') || '',
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitReport(session, data, shell) {
|
function collectImages(shell) {
|
||||||
|
return Array.prototype.map.call(
|
||||||
|
shell.querySelectorAll('.preview .preview-item img'),
|
||||||
|
function (img) { return img.getAttribute('src') || ''; }
|
||||||
|
).filter(function (url) { return url !== ''; });
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadImage(shell, file) {
|
||||||
|
var preview = shell.querySelector('.form-upload .preview');
|
||||||
|
if (!preview) return Promise.resolve();
|
||||||
|
|
||||||
|
var existing = shell.querySelectorAll('.preview .preview-item').length;
|
||||||
|
if (existing + collectImages(shell).length >= MAX_IMAGES) {
|
||||||
|
notyf('最多上传 ' + MAX_IMAGES + ' 张图片', 'danger');
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
var body = new FormData();
|
||||||
|
body.append('image', file);
|
||||||
|
|
||||||
|
return window.fetch(API_ROOT + '/report/upload-image', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'X-WP-Nonce': NONCE },
|
||||||
|
body: body,
|
||||||
|
})
|
||||||
|
.then(function (res) { return res.json(); })
|
||||||
|
.then(function (result) {
|
||||||
|
var url = result && result.success && result.data && result.data.url;
|
||||||
|
if (!url) {
|
||||||
|
notyf((result && result.message) || '图片上传失败', 'danger');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var item = document.createElement('div');
|
||||||
|
item.className = 'preview-item';
|
||||||
|
var img = document.createElement('img');
|
||||||
|
img.src = url;
|
||||||
|
img.alt = '';
|
||||||
|
var remove = document.createElement('button');
|
||||||
|
remove.type = 'button';
|
||||||
|
remove.className = 'remove';
|
||||||
|
remove.setAttribute('aria-label', '删除图片');
|
||||||
|
remove.innerHTML = '×';
|
||||||
|
remove.addEventListener('click', function () { item.remove(); });
|
||||||
|
item.appendChild(img);
|
||||||
|
item.appendChild(remove);
|
||||||
|
preview.insertBefore(item, preview.querySelector('.add'));
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
notyf('图片上传失败,请重试', 'danger');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitReport(data, shell) {
|
||||||
var form = shell.querySelector('.aksrt-report-form');
|
var form = shell.querySelector('.aksrt-report-form');
|
||||||
if (!form) return;
|
if (!form) return;
|
||||||
|
|
||||||
@@ -131,33 +221,31 @@
|
|||||||
var otherInput = form.querySelector('[name="reason_other"]');
|
var otherInput = form.querySelector('[name="reason_other"]');
|
||||||
var urlInput = form.querySelector('[name="report_url"]');
|
var urlInput = form.querySelector('[name="report_url"]');
|
||||||
|
|
||||||
var slug = selectedReason(shell);
|
var selected = selectedReason(shell);
|
||||||
var reason = (descInput && descInput.value || '').trim();
|
|
||||||
var other = (otherInput && otherInput.value || '').trim();
|
var other = (otherInput && otherInput.value || '').trim();
|
||||||
|
|
||||||
if (!slug && !reason) {
|
if (!selected.label && !other) {
|
||||||
notyf('请选择或输入举报原因', 'danger');
|
notyf('请选择或输入举报原因', 'danger');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// “其它原因”时以自定义文本为举报原因。
|
// “其它原因”以自定义文本为举报原因;预置徽章取徽章文案(参考主题同语义)。
|
||||||
if (slug === 'other') {
|
var reason = selected.label === 'other' || !selected.label ? other : selected.label;
|
||||||
slug = '';
|
var slug = selected.label && selected.label !== 'other' ? selected.slug : '';
|
||||||
reason = other || reason;
|
|
||||||
}
|
|
||||||
if (!reason) {
|
if (!reason) {
|
||||||
// 徽章已选但没有描述时,将徽章文案作为举报原因(参考主题同款语义)。
|
notyf('请填写举报原因', 'danger');
|
||||||
var activeBtn = shell.querySelector('[data-report-reason].is-active');
|
return;
|
||||||
reason = activeBtn ? (activeBtn.textContent || '').trim() : '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var link = (urlInput && urlInput.value || '').trim();
|
var link = (urlInput && urlInput.value || '').trim();
|
||||||
if (link) {
|
if (link) {
|
||||||
reason += (reason ? '\n' : '') + '违规链接:' + link;
|
reason += (reason ? '\n' : '') + '违规链接:' + link;
|
||||||
}
|
}
|
||||||
|
var images = collectImages(shell);
|
||||||
if (!reason) {
|
if (images.length) {
|
||||||
notyf('请选择或输入举报原因', 'danger');
|
reason += '\n图片举证:';
|
||||||
return;
|
images.forEach(function (url) { reason += '\n' + url; });
|
||||||
}
|
}
|
||||||
|
|
||||||
submitBtn.disabled = true;
|
submitBtn.disabled = true;
|
||||||
@@ -196,6 +284,48 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bindReportModal(shell) {
|
||||||
|
shell.addEventListener('click', function (event) {
|
||||||
|
// 原因徽章:单选 active(参考主题 .active.badg 焦点色),其它原因展开文本框。
|
||||||
|
// 参考主题行为:重复点击已选徽章保持选中(先全清再激活),不做反选。
|
||||||
|
var chip = event.target.closest('[data-aksrt-report-reason]');
|
||||||
|
if (chip) {
|
||||||
|
event.preventDefault();
|
||||||
|
shell.querySelectorAll('[data-aksrt-report-reason].active').forEach(function (el) {
|
||||||
|
el.classList.remove('active');
|
||||||
|
});
|
||||||
|
chip.classList.add('active');
|
||||||
|
var otherBox = shell.querySelector('.aksrt-report-other');
|
||||||
|
if (otherBox) otherBox.style.display = chip.getAttribute('data-aksrt-report-reason') === 'other' ? '' : 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片举证:点击加号或预览补位触发文件选择。
|
||||||
|
var addBtn = event.target.closest('[data-aksrt-report-add]');
|
||||||
|
if (addBtn) {
|
||||||
|
event.preventDefault();
|
||||||
|
var fileInput = shell.querySelector('[data-aksrt-report-file]');
|
||||||
|
if (fileInput) fileInput.click();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var submitBtn = event.target.closest('[data-aksrt-report-submit]');
|
||||||
|
if (submitBtn) {
|
||||||
|
event.preventDefault();
|
||||||
|
submitReport(shell.getAttribute('data-aksrt-report-target') ? JSON.parse(shell.getAttribute('data-aksrt-report-target')) : {}, shell);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
shell.addEventListener('change', function (event) {
|
||||||
|
var fileInput = event.target.closest('[data-aksrt-report-file]');
|
||||||
|
if (!fileInput || !fileInput.files || !fileInput.files.length) return;
|
||||||
|
Array.prototype.forEach.call(fileInput.files, function (file) {
|
||||||
|
uploadImage(shell, file);
|
||||||
|
});
|
||||||
|
fileInput.value = '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function openReportModal(data) {
|
function openReportModal(data) {
|
||||||
if (!window.AksrtModalRuntime || typeof window.AksrtModalRuntime.open !== 'function') {
|
if (!window.AksrtModalRuntime || typeof window.AksrtModalRuntime.open !== 'function') {
|
||||||
notyf('举报组件加载失败,请刷新页面后重试', 'danger');
|
notyf('举报组件加载失败,请刷新页面后重试', 'danger');
|
||||||
@@ -204,30 +334,15 @@
|
|||||||
|
|
||||||
var shell = window.AksrtModalRuntime.open({
|
var shell = window.AksrtModalRuntime.open({
|
||||||
html: buildReportModalHtml(data),
|
html: buildReportModalHtml(data),
|
||||||
className: 'aksrt-report-modal modal-mini',
|
className: 'aksrt-report-modal',
|
||||||
kind: 'report',
|
kind: 'report',
|
||||||
mobileBottom: true,
|
mobileBottom: true,
|
||||||
});
|
});
|
||||||
|
shell.setAttribute('data-aksrt-report-target', JSON.stringify({
|
||||||
shell.addEventListener('click', function (event) {
|
target_type: data.target_type,
|
||||||
var chip = event.target.closest('[data-report-reason]');
|
target_id: data.target_id,
|
||||||
if (chip) {
|
}));
|
||||||
event.preventDefault();
|
bindReportModal(shell);
|
||||||
var wasActive = chip.classList.contains('is-active');
|
|
||||||
shell.querySelectorAll('[data-report-reason].is-active').forEach(function (el) {
|
|
||||||
el.classList.remove('is-active');
|
|
||||||
});
|
|
||||||
if (!wasActive) chip.classList.add('is-active');
|
|
||||||
var otherBox = shell.querySelector('.aksrt-report-other');
|
|
||||||
if (otherBox) otherBox.hidden = chip.getAttribute('data-report-reason') !== 'other' || wasActive;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var submitBtn = event.target.closest('[data-aksrt-report-submit]');
|
|
||||||
if (submitBtn) {
|
|
||||||
event.preventDefault();
|
|
||||||
submitReport({ target_type: data.target_type, target_id: data.target_id }, data, shell);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function initReportButtons() {
|
function initReportButtons() {
|
||||||
|
|||||||
@@ -57,6 +57,20 @@ class UserController extends ControllerBase {
|
|||||||
'permission_callback' => [$this, 'check_comment_image_upload_permission'],
|
'permission_callback' => [$this, 'check_comment_image_upload_permission'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Report evidence image upload (logged-in users; the report image setting gates the entry).
|
||||||
|
// Reuses the comment upload handler — the permission boundary differs only.
|
||||||
|
register_rest_route(self::API_NAMESPACE, '/report/upload-image', [
|
||||||
|
'methods' => 'POST',
|
||||||
|
'callback' => [$this, 'rest_upload_comment_image'],
|
||||||
|
'permission_callback' => static function (): bool {
|
||||||
|
if (!is_user_logged_in() || !class_exists('\AKSRT\Settings\UserRuntime')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$report = \AKSRT\Settings\UserRuntime::report_settings();
|
||||||
|
return !empty($report['enabled']) && !empty($report['img_enabled']);
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
// Notification settings
|
// Notification settings
|
||||||
register_rest_route(self::API_NAMESPACE, '/settings/notifications', [
|
register_rest_route(self::API_NAMESPACE, '/settings/notifications', [
|
||||||
'methods' => ['GET', 'POST'],
|
'methods' => ['GET', 'POST'],
|
||||||
|
|||||||
@@ -487,13 +487,24 @@ trait ScriptsPart1c {
|
|||||||
'restUrl' => esc_url_raw(rest_url('aksrt/v1')),
|
'restUrl' => esc_url_raw(rest_url('aksrt/v1')),
|
||||||
// Alias used by modal-auth / follow / report (same value as restUrl).
|
// Alias used by modal-auth / follow / report (same value as restUrl).
|
||||||
'apiUrl' => esc_url_raw(rest_url('aksrt/v1')),
|
'apiUrl' => esc_url_raw(rest_url('aksrt/v1')),
|
||||||
// 举报弹窗预置原因(report.js 徽章选择数据源)。
|
// 举报弹窗数据(report.js):预置原因读取后台“禁封/举报”的 ban_preset_reason
|
||||||
|
// (UserRuntime::ban_settings,参考主题 _pz('ban_preset_reason') 同源),
|
||||||
|
// 图片举证开关与举报说明读取 user_report_img_s / user_report_desc。
|
||||||
'reportCategories' => (function () {
|
'reportCategories' => (function () {
|
||||||
if (!class_exists('\AKSRT\Settings\Settings')) {
|
if (!class_exists('\AKSRT\Settings\UserRuntime')) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
$report = \AKSRT\Settings\Settings::get_user_identity_settings()['report'] ?? [];
|
return \AKSRT\Settings\UserRuntime::ban_settings()['reasons'] ?? [];
|
||||||
return is_array($report['categories'] ?? null) ? array_values($report['categories']) : [];
|
})(),
|
||||||
|
'report' => (function () {
|
||||||
|
if (!class_exists('\AKSRT\Settings\UserRuntime')) {
|
||||||
|
return ['imgEnabled' => false, 'desc' => ''];
|
||||||
|
}
|
||||||
|
$report = \AKSRT\Settings\UserRuntime::report_settings();
|
||||||
|
return [
|
||||||
|
'imgEnabled' => !empty($report['img_enabled']),
|
||||||
|
'desc' => (string) ($report['desc'] ?? ''),
|
||||||
|
];
|
||||||
})(),
|
})(),
|
||||||
'stickyEnabled' => class_exists('\AKSRT\Settings\Settings') ? !empty(\AKSRT\Settings\Settings::get_post_list_style_settings()['sticky_s']) : true,
|
'stickyEnabled' => class_exists('\AKSRT\Settings\Settings') ? !empty(\AKSRT\Settings\Settings::get_post_list_style_settings()['sticky_s']) : true,
|
||||||
'stickyPages' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_post_list_style_settings()['sticky_s'] : ['home', 'cat'],
|
'stickyPages' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_post_list_style_settings()['sticky_s'] : ['home', 'cat'],
|
||||||
|
|||||||
@@ -169,6 +169,34 @@ test('native ban page mirrors the reference theme layout', () => {
|
|||||||
assert.ok(!tickets.includes('name="action_taken"'), 'report process form should be status-only like the reference theme')
|
assert.ok(!tickets.includes('name="action_taken"'), 'report process form should be status-only like the reference theme')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('report modal mirrors the reference theme: preset reasons, image evidence, notice, geometry', () => {
|
||||||
|
const scripts = read('src/Core/ScriptsPart1c.php')
|
||||||
|
// 预置原因真实数据源是 ban_preset_reason(UserRuntime::ban_settings),
|
||||||
|
// 不再读取 report_settings 中不存在的 categories 键(短路已修)。
|
||||||
|
assert.match(scripts, /UserRuntime::ban_settings\(\)\['reasons'\]/)
|
||||||
|
assert.ok(!scripts.includes("$report['categories']"), 'dead report.categories source must be removed')
|
||||||
|
// 图片举证开关与举报说明随 aksrtData 注入。
|
||||||
|
assert.match(scripts, /imgEnabled/)
|
||||||
|
assert.match(scripts, /report_settings\(\)/)
|
||||||
|
|
||||||
|
const reportJs = read('assets/js/report.js')
|
||||||
|
// Zibll 同构标记:edit-header 警示头、原因徽章 active 焦点色、其它原因、
|
||||||
|
// 图片举证入口(后台开启时)、举报说明注入、but-average modal-buts 底栏。
|
||||||
|
for (const part of ['edit-header', 'toggle-radius mr10 c-red', 'data-aksrt-report-reason', 'form-but-radio', '其它原因', '违规链接', '详细描述', '添加图片举证', 'but-average modal-buts']) {
|
||||||
|
assert.ok(reportJs.includes(part), `report.js missing reference-theme part: ${part}`)
|
||||||
|
}
|
||||||
|
assert.match(reportJs, /report\/upload-image/)
|
||||||
|
assert.ok(!reportJs.includes('is-active'), 'chips must toggle the reference .active class, not a custom one')
|
||||||
|
|
||||||
|
// 举报图片上传端点存在,复用评论上传回调、独立权限(登录 + 举报 + 图片开关)。
|
||||||
|
assert.match(userController, /'\/report\/upload-image'/)
|
||||||
|
|
||||||
|
// 几何 1:1:桌面端 600px(参考主题 Bootstrap 默认模态宽)。
|
||||||
|
const css = read('assets/css/frontend/modal-runtime.css')
|
||||||
|
assert.match(css, /\.aksrt-report-modal:not\(\.aksrt-modal-runtime--bottom\) \.aksrt-modal-runtime__dialog/)
|
||||||
|
assert.match(css, /600px/)
|
||||||
|
})
|
||||||
|
|
||||||
test('comments expose a report entry for other users when reporting is enabled', () => {
|
test('comments expose a report entry for other users when reporting is enabled', () => {
|
||||||
// 举报位于“回复”右侧三点下拉菜单内(参考主题同位置),载荷走 wp_json_encode。
|
// 举报位于“回复”右侧三点下拉菜单内(参考主题同位置),载荷走 wp_json_encode。
|
||||||
assert.match(commentItem, /data-aksrt-report="/)
|
assert.match(commentItem, /data-aksrt-report="/)
|
||||||
|
|||||||
Reference in new issue
Block a user