feat(tickets): make ticket title/content/reply length limits configurable

Add ticket_title_max / ticket_content_max / ticket_reply_max to the
users/ticket schema (PHP + SPA) with clamped TicketSettings readers.
All write paths (front REST, admin REST, note REST, native admin page)
and front-end maxlength/counters now read the configured limits.
Remove the hardcoded TICKET_CONTENT_MAX constant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Fable 5 committed 2026-10-27 23:06:28 +08:00
1 parent 6681b0c306
commit 63ab8b8fc9
13 files changed
+71 -28

No files matched your search

+7
View File
@@ -35,6 +35,12 @@
return parseInt(settings().attachmentMax, 10) || 5;
}
/** 字数上限(后台「工单中心 → 提交设置」配置,PHP 侧已夹取边界)。 */
function lengthMax(kind) {
var defaults = { title: 200, content: 5000, reply: 3000 };
return parseInt(settings()[kind + 'Max'], 10) || defaults[kind];
}
function escapeHtml(value) {
return String(value === null || value === undefined ? '' : value)
.replace(/&/g, '&amp;')
@@ -359,6 +365,7 @@
settings: settings,
attachmentEnabled: attachmentEnabled,
attachmentMax: attachmentMax,
lengthMax: lengthMax,
escapeHtml: escapeHtml,
notyf: notyf,
request: request,
+7 -6
View File
@@ -22,6 +22,7 @@
var settings = core.settings;
var attachmentEnabled = core.attachmentEnabled;
var attachmentMax = core.attachmentMax;
var lengthMax = core.lengthMax;
var escapeHtml = core.escapeHtml;
var notyf = core.notyf;
var request = core.request;
@@ -448,11 +449,11 @@
+ attachTrayHtml()
+ '<div class="aksrt-ticket-composer__input">'
+ '<label class="screen-reader-text" for="' + fieldId + '">回复内容</label>'
+ '<textarea id="' + fieldId + '" name="reply" rows="2" maxlength="3000"'
+ '<textarea id="' + fieldId + '" name="reply" rows="2" maxlength="' + lengthMax('reply') + '"'
+ ' placeholder="补充说明或回复客服…"></textarea></div>'
+ '<div class="aksrt-ticket-composer__bar">'
+ '<span class="aksrt-ticket-composer__hint">Ctrl + Enter 发送</span>'
+ '<span class="aksrt-ticket-counter" data-aksrt-ticket-counter="reply">0 / 3000</span>'
+ '<span class="aksrt-ticket-counter" data-aksrt-ticket-counter="reply">0 / ' + lengthMax('reply') + '</span>'
+ '<button type="submit" class="btn-primary" data-aksrt-ticket-submit>' + icon('fa-paper-plane') + '发送</button>'
+ '</div></form>';
}
@@ -642,8 +643,8 @@
html += field(
'<label for="aksrt-ticket-f-title">工单标题<em aria-hidden="true">*</em></label>',
'<input id="aksrt-ticket-f-title" type="text" name="title" maxlength="200" autocomplete="off" placeholder="一句话概括问题,如:支付成功但会员未开通">',
'<span class="aksrt-ticket-counter" data-aksrt-ticket-counter="title">0 / 200</span>'
'<input id="aksrt-ticket-f-title" type="text" name="title" maxlength="' + lengthMax('title') + '" autocomplete="off" placeholder="一句话概括问题,如:支付成功但会员未开通">',
'<span class="aksrt-ticket-counter" data-aksrt-ticket-counter="title">0 / ' + lengthMax('title') + '</span>'
);
html += '<fieldset class="aksrt-ticket-field aksrt-ticket-types" data-aksrt-ticket-types>'
@@ -667,8 +668,8 @@
html += field(
'<label for="aksrt-ticket-f-content">问题描述<em aria-hidden="true">*</em></label>',
'<textarea id="aksrt-ticket-f-content" name="content" rows="5" maxlength="5000" placeholder="请描述问题现象、发生时间、操作步骤等,信息越完整处理越快"></textarea>',
'<span class="aksrt-ticket-counter" data-aksrt-ticket-counter="content">0 / 5000</span>'
'<textarea id="aksrt-ticket-f-content" name="content" rows="5" maxlength="' + lengthMax('content') + '" placeholder="请描述问题现象、发生时间、操作步骤等,信息越完整处理越快"></textarea>',
'<span class="aksrt-ticket-counter" data-aksrt-ticket-counter="content">0 / ' + lengthMax('content') + '</span>'
);
if (attachmentEnabled()) {