- aksrt_ticket gains urge_count / last_urge_time (schema 3.1.0) - cooldown moves from transient to an atomic conditional UPDATE - urge inserts a system reply rendered as a centered notice (not quotable) - admin list badge + info card row for urge count / last time - new ticket_urge_admin mail event via aksrt_ticket_urged Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
180 lines
6.9 KiB
PHP
180 lines
6.9 KiB
PHP
<?php
|
|
/**
|
|
* Ticket (工单) tables.
|
|
*
|
|
* 6 张表取代旧的 aksrt_order_aftersale:工单不再绑定订单退款流程,
|
|
* 标题 + 部门 + 描述为必填,关联订单为可选项。
|
|
*
|
|
* @package AKSRT
|
|
*/
|
|
|
|
namespace AKSRT\Core;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
trait DBMigratorTicket {
|
|
|
|
private static function migrate_ticket_tables(string $prefix, string $charset_collate): void {
|
|
$ticket = "CREATE TABLE {$prefix}aksrt_ticket (
|
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
ticket_num VARCHAR(32) NOT NULL,
|
|
user_id BIGINT UNSIGNED NOT NULL,
|
|
title VARCHAR(200) NOT NULL,
|
|
ticket_type_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
|
content TEXT NOT NULL,
|
|
status VARCHAR(24) NOT NULL DEFAULT 'pending',
|
|
order_number VARCHAR(32) NOT NULL DEFAULT '',
|
|
attachment LONGTEXT DEFAULT NULL,
|
|
last_reply_time DATETIME DEFAULT NULL,
|
|
post_time DATETIME NOT NULL,
|
|
notes TEXT DEFAULT NULL,
|
|
admin_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
|
last_reply_admin_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
|
post_admin_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
|
urge_count INT UNSIGNED NOT NULL DEFAULT 0,
|
|
last_urge_time DATETIME DEFAULT NULL,
|
|
created_at DATETIME NOT NULL,
|
|
updated_at DATETIME DEFAULT NULL,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uniq_ticket_num (ticket_num),
|
|
KEY idx_user_created (user_id, created_at),
|
|
KEY idx_status_created (status, created_at),
|
|
KEY idx_type_status (ticket_type_id, status),
|
|
KEY idx_order (order_number)
|
|
) ENGINE=InnoDB {$charset_collate};";
|
|
dbDelta($ticket);
|
|
|
|
$reply = "CREATE TABLE {$prefix}aksrt_ticket_reply (
|
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
ticket_id BIGINT UNSIGNED NOT NULL,
|
|
author_type VARCHAR(16) NOT NULL DEFAULT 'user',
|
|
author_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
|
content TEXT NOT NULL,
|
|
attachment LONGTEXT DEFAULT NULL,
|
|
quote_reply_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
|
created_at DATETIME NOT NULL,
|
|
PRIMARY KEY (id),
|
|
KEY idx_ticket_created (ticket_id, created_at),
|
|
KEY idx_quote (quote_reply_id)
|
|
) ENGINE=InnoDB {$charset_collate};";
|
|
dbDelta($reply);
|
|
|
|
// status_key 是工单上 aksrt_ticket.status 的外延键:管理员改状态名只动 name,
|
|
// 存量工单的 status 不受影响。默认状态(is_default)不可改删。
|
|
$status = "CREATE TABLE {$prefix}aksrt_ticket_status (
|
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
status_key VARCHAR(24) NOT NULL,
|
|
name VARCHAR(60) NOT NULL,
|
|
color VARCHAR(20) NOT NULL DEFAULT '#6b7280',
|
|
is_closed TINYINT(1) NOT NULL DEFAULT 0,
|
|
is_default TINYINT(1) NOT NULL DEFAULT 0,
|
|
sort_order INT NOT NULL DEFAULT 0,
|
|
created_at DATETIME NOT NULL,
|
|
updated_at DATETIME DEFAULT NULL,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uniq_status_key (status_key)
|
|
) ENGINE=InnoDB {$charset_collate};";
|
|
dbDelta($status);
|
|
|
|
$type = "CREATE TABLE {$prefix}aksrt_ticket_type (
|
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
name VARCHAR(120) NOT NULL,
|
|
description TEXT DEFAULT NULL,
|
|
admin_ids LONGTEXT DEFAULT NULL,
|
|
sort_order INT NOT NULL DEFAULT 0,
|
|
created_at DATETIME NOT NULL,
|
|
updated_at DATETIME DEFAULT NULL,
|
|
PRIMARY KEY (id)
|
|
) ENGINE=InnoDB {$charset_collate};";
|
|
dbDelta($type);
|
|
|
|
$prereply = "CREATE TABLE {$prefix}aksrt_ticket_prereply (
|
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
content TEXT NOT NULL,
|
|
sort_order INT NOT NULL DEFAULT 0,
|
|
created_at DATETIME NOT NULL,
|
|
PRIMARY KEY (id)
|
|
) ENGINE=InnoDB {$charset_collate};";
|
|
dbDelta($prereply);
|
|
|
|
$note = "CREATE TABLE {$prefix}aksrt_ticket_note (
|
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
ticket_id BIGINT UNSIGNED NOT NULL,
|
|
admin_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
|
content TEXT NOT NULL,
|
|
created_at DATETIME NOT NULL,
|
|
PRIMARY KEY (id),
|
|
KEY idx_ticket_created (ticket_id, created_at)
|
|
) ENGINE=InnoDB {$charset_collate};";
|
|
dbDelta($note);
|
|
|
|
self::seed_ticket_statuses($prefix);
|
|
self::seed_ticket_types($prefix);
|
|
}
|
|
|
|
/**
|
|
* 工单状态 seeds:按 status_key 幂等补齐,不覆盖管理员已改过的名称与颜色。
|
|
* 「待接单」标记 is_default,后台拒绝改删。
|
|
*
|
|
* @return void
|
|
*/
|
|
private static function seed_ticket_statuses(string $prefix): void {
|
|
global $wpdb;
|
|
$table = $prefix . 'aksrt_ticket_status';
|
|
$now = current_time('mysql');
|
|
$seeds = [
|
|
['pending', '待接单', '#f59e0b', 0, 1],
|
|
['handling', '处理中', '#8b5cf6', 0, 0],
|
|
['user_replied', '待回复', '#3b82f6', 0, 0],
|
|
['admin_replied', '已回复', '#10b981', 0, 0],
|
|
['closed', '已关闭', '#6b7280', 1, 0],
|
|
];
|
|
|
|
$exists = $wpdb->get_col("SELECT status_key FROM {$table}"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL
|
|
if (!is_array($exists)) {
|
|
$exists = [];
|
|
}
|
|
|
|
$sort = 0;
|
|
foreach ($seeds as [$key, $label, $color, $is_closed, $is_default]) {
|
|
if (in_array($key, $exists, true)) {
|
|
continue;
|
|
}
|
|
$wpdb->insert($table, [
|
|
'status_key' => $key,
|
|
'name' => $label,
|
|
'color' => $color,
|
|
'is_closed' => $is_closed,
|
|
'is_default' => $is_default,
|
|
'sort_order' => $sort++,
|
|
'created_at' => $now,
|
|
], ['%s', '%s', '%s', '%d', '%d', '%d', '%s']);
|
|
}
|
|
}
|
|
|
|
/** 工单部门 seeds:按 name 幂等补齐。 */
|
|
private static function seed_ticket_types(string $prefix): void {
|
|
global $wpdb;
|
|
$table = $prefix . 'aksrt_ticket_type';
|
|
$now = current_time('mysql');
|
|
$seeds = ['技术支持', '账号问题', '财务问题', '产品建议', '其他'];
|
|
|
|
$exists = $wpdb->get_col("SELECT name FROM {$table}"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL
|
|
if (!is_array($exists)) {
|
|
$exists = [];
|
|
}
|
|
|
|
$sort = 0;
|
|
foreach ($seeds as $label) {
|
|
if (in_array($label, $exists, true)) {
|
|
continue;
|
|
}
|
|
$wpdb->insert($table, [
|
|
'name' => $label,
|
|
'sort_order' => $sort++,
|
|
'created_at' => $now,
|
|
], ['%s', '%d', '%s']);
|
|
}
|
|
}
|
|
}
|