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:
1 parent
6681b0c306
commit
63ab8b8fc9
13 files changed
+71
-28
No files matched your search
@@ -8,7 +8,7 @@ export const ticketSchema = {
|
||||
key: 'users.ticket',
|
||||
title: '工单中心',
|
||||
icon: 'fa fas fa-headset',
|
||||
description: '工单功能开关、工单号前缀、提交公告与提交表单(图片上传、关联订单、催单冷却)配置;部门、状态与预设回复在本页其余分页中维护。',
|
||||
description: '工单功能开关、工单号前缀、提交公告与提交表单(图片上传、关联订单、催单冷却、字数上限)配置;部门、状态与预设回复在本页其余分页中维护。',
|
||||
defaults: {
|
||||
ticket_s: true,
|
||||
ticket_num_prefix: 'T',
|
||||
@@ -18,6 +18,9 @@ export const ticketSchema = {
|
||||
ticket_attachment_max: 5,
|
||||
ticket_order_link_s: true,
|
||||
ticket_urge_interval: 15,
|
||||
ticket_title_max: 200,
|
||||
ticket_content_max: 5000,
|
||||
ticket_reply_max: 3000,
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
@@ -40,6 +43,9 @@ export const ticketSchema = {
|
||||
{ key: 'ticket_attachment_max', label: '单个工单图片上限', type: 'number', default: 5, min: 1, max: 9, help: '工单内容与每条回复各自可上传的图片数量上限' },
|
||||
{ key: 'ticket_order_link_s', label: '允许关联订单', type: 'switch', default: true, help: '开启后新建工单时可选择关联本人一个已支付订单;关闭后工单与订单完全解耦' },
|
||||
{ key: 'ticket_urge_interval', label: '催单冷却(分钟)', type: 'number', default: 15, min: 1, max: 1440, help: '同一工单两次催单之间的最小间隔' },
|
||||
{ key: 'ticket_title_max', label: '标题字数上限', type: 'number', default: 200, min: 10, max: 200, help: '工单标题最多可输入的字数(前台提交与后台代客提交共用)' },
|
||||
{ key: 'ticket_content_max', label: '问题描述字数上限', type: 'number', default: 5000, min: 100, max: 16000, help: '新建工单时问题描述最多可输入的字数(前台提交与后台代客提交共用)' },
|
||||
{ key: 'ticket_reply_max', label: '回复字数上限', type: 'number', default: 3000, min: 100, max: 16000, help: '用户与客服每条回复(含后台内部备注)最多可输入的字数' },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -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, '&')
|
||||
@@ -359,6 +365,7 @@
|
||||
settings: settings,
|
||||
attachmentEnabled: attachmentEnabled,
|
||||
attachmentMax: attachmentMax,
|
||||
lengthMax: lengthMax,
|
||||
escapeHtml: escapeHtml,
|
||||
notyf: notyf,
|
||||
request: request,
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
Reference in new issue
Block a user