' : $this->ticket_form_open('create', 0, 'aksrt-ticket-dialog__frame'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- echo '
';
+ echo $this->ticket_dialog_head('create', __('代客提交工单', 'aksrt'), __('为指定用户创建工单,创建后由你跟进,用户会收到通知。', 'aksrt')); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '
' . $this->ticket_feedback(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
if ($types === []) {
echo NativeUi::empty_state(__('尚未配置工单部门', 'aksrt'), __('请先添加部门,再为用户创建工单。', 'aksrt')); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
diff --git a/src/Admin/Native/UsersMenusTicketsDetail.php b/src/Admin/Native/UsersMenusTicketsDetail.php
index 193abce2..1e3211a4 100644
--- a/src/Admin/Native/UsersMenusTicketsDetail.php
+++ b/src/Admin/Native/UsersMenusTicketsDetail.php
@@ -1,5 +1,5 @@
ticket_page_url($context), false, 'dashicons-arrow-left-alt');
@@ -30,21 +32,26 @@ trait UsersMenusTicketsDetail {
$this->render_ticket_notice();
echo $this->ticket_feedback(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->render_ticket_detail_panel($ticket); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ echo $this->ticket_note_dialog((int) $ticket['id']); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
private function render_ticket_detail_panel(array $ticket): string {
$id = (int) $ticket['id'];
- $html = '
';
- $html .= $this->ticket_conversation($ticket, TicketRepository::get_instance()->replies($id));
- $html .= !empty($ticket['is_closed'])
+ $footer = !empty($ticket['is_closed'])
? '
' . esc_html__('工单已关闭,不能继续回复或变更处理信息;仍可添加内部备注。', 'aksrt') . '
'
: $this->ticket_reply_form($id);
+ $html = '
';
+ $html .= $this->ticket_conversation($ticket, TicketRepository::get_instance()->replies($id), $footer);
$html .= '
';
}
- /** 原始问题与回复同属一条时间线:用户在左、客服在右、系统事件居中。 */
- private function ticket_conversation(array $ticket, array $replies): string {
+ /**
+ * 会话卡片:头部、可滚动时间线与底部固定的回复框同属一个面板(IM 式布局),
+ * 卡片高度跟随视口,开屏即可看到回复框和发送按钮。
+ * 原始问题与回复同属一条时间线:用户在左、客服在右、系统事件居中。
+ */
+ private function ticket_conversation(array $ticket, array $replies, string $footer): string {
$html = '
';
$html .= '' . esc_html__('沟通记录', 'aksrt') . ' ' . esc_html(sprintf(__('%d 条记录', 'aksrt'), count($replies))) . '
';
if ($replies !== []) {
@@ -68,7 +75,7 @@ trait UsersMenusTicketsDetail {
}
$html .= $this->ticket_message($admin ? 'admin' : 'user', (int) $reply['author_id'], (string) $reply['author_name'], $admin ? __('客服', 'aksrt') : __('用户', 'aksrt'), (string) $reply['created_at'], (string) $reply['content'], (array) $reply['attachment'], $quote_html);
}
- return $html . '';
+ return $html . '
' . $footer . '';
}
private function ticket_message(string $variant, int $user_id, string $name, string $role, string $time, string $content, array $attachments, string $quote_html = ''): string {
@@ -92,19 +99,15 @@ trait UsersMenusTicketsDetail {
}
$tools .= '';
}
- return $this->ticket_composer('reply', $id, $field, __('回复用户', 'aksrt'), __('发送后用户将收到通知', 'aksrt'), __('填写回复内容…', 'aksrt'), 4, $tools, __('发送回复', 'aksrt'), true);
- }
-
- /** 输入框与工具栏合为一个整体:预设回复、字数与提交按钮同排。 */
- private function ticket_composer(string $action, int $id, string $field, string $label, string $hint, string $placeholder, int $rows, string $tools, string $submit, bool $primary): string {
$max = TicketSettings::reply_max();
- return $this->ticket_form_open($action, $id, 'aksrt-ticket-composer aksrt-ticket-composer--' . $action)
- . '
'
- . ($hint !== '' ? '' . esc_html($hint) . '' : '') . '
'
- . '
'
+ // 输入框与工具栏合为一个整体:预设回复、字数与发送按钮同排;Ctrl/⌘ + Enter 发送。
+ return $this->ticket_form_open('reply', $id, 'aksrt-ticket-composer')
+ . '
'
+ . '
'
. '
' . $tools
+ . '' . esc_html__('Ctrl + Enter 发送', 'aksrt') . ''
. '0 / ' . $max . ''
- . '
';
+ . '
';
}
private function ticket_info_card(array $ticket): string {
@@ -193,7 +196,10 @@ trait UsersMenusTicketsDetail {
return $options;
}
- /** 默认只展示最新 3 条备注,更早的收进原生
,避免历史备注撑满侧栏。 */
+ /**
+ * 备注卡片只展示记录与「添加备注」入口,输入在弹窗内完成,侧栏高度不随输入变化。
+ * 默认只展示最新 3 条备注,更早的收进原生 ,避免历史备注撑满侧栏。
+ */
private function ticket_notes_card(int $id): string {
$notes = TicketNoteService::for_ticket($id);
$visible = 3;
@@ -201,16 +207,32 @@ trait UsersMenusTicketsDetail {
if ($notes !== []) {
$html .= ' ' . count($notes) . '';
}
- $html .= ' ' . esc_html__('仅管理员可见,不会发送给用户。', 'aksrt') . '
';
- if ($notes !== []) {
- $older = array_slice($notes, 0, -$visible);
- $html .= '