Files
2026-08-14 10:55:06 +08:00

148 lines
8.0 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// 前台提交工单(须登录)。支持普通工单与「续期申请」(关联周期订单)。
require __DIR__ . '/includes/init.php';
requireLogin('ticket.php');
$user = currentUser();
$pageTitle = __('ticket_page.title');
$depts = db()->query('SELECT * FROM ' . tn('ticket_departments') . ' ORDER BY sort, id')->fetchAll();
if (empty($depts)) {
$depts = [['id' => 0, 'name' => __('ticket.meta_unspecified'), 'description' => '']];
}
// 当前用户可续期的订单(周期商品 + 已发货/已完成)
$renewOrders = db()->prepare(
'SELECT o.id, o.order_no, o.period_days, o.expires_at FROM ' . tn('orders') . ' o
WHERE o.user_id = ? AND o.period_days > 0 AND o.status IN ("shipped","completed") ORDER BY o.created_at DESC'
);
$renewOrders->execute([$user['id']]);
$renewOrders = $renewOrders->fetchAll();
$renewOrderId = (int) ($_GET['order_id'] ?? 0);
$msg = '';
$err = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
verifyCsrf();
$dept = (int) ($_POST['dept_id'] ?? 0);
$subject = trim($_POST['subject'] ?? '');
$message = trim($_POST['message'] ?? '');
$priority = (int) ($_POST['priority'] ?? 2);
$type = in_array($_POST['type'] ?? 'general', ['general', 'renewal'], true) ? $_POST['type'] : 'general';
$orderId = (int) ($_POST['order_id'] ?? 0);
if ($type === 'renewal') {
// 校验关联订单确实属于本人且可续期
$okOrder = false;
foreach ($renewOrders as $ro) {
if ((int) $ro['id'] === $orderId) { $okOrder = true; break; }
}
if (!$okOrder) {
$err = __('ticket_page.err_order_invalid');
} elseif ($subject === '') {
$subject = __('ticket_page.subject_renewal_prefix') . $orderId;
}
}
if ($subject === '') $err = __('ticket_page.err_subject_empty');
elseif (strlen($subject) > 160) $err = __('ticket_page.err_subject_long');
elseif ($message === '') $err = __('ticket_page.err_message_empty');
elseif (!in_array($priority, [1, 2, 3], true)) $err = __('ticket_page.err_priority_bad');
if ($err === '') {
db()->prepare(
'INSERT INTO ' . tn('tickets') .
' (user_id, dept_id, order_id, type, subject, message, priority, status, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,NOW(),NOW())'
)->execute([$user['id'], $dept, $type === 'renewal' ? $orderId : null, $type, $subject, $message, $priority, 'open']);
$tid = db()->lastInsertId();
// 通过 SMTP 通知处理人员(失败不影响工单入库)
$deptNameMap = [];
foreach ($depts as $d) { $deptNameMap[$d['id']] = $d['name']; }
$deptName = $deptNameMap[$dept] ?? __('ticket.meta_unspecified');
$cfg = smtpConfig();
if (!empty($cfg['notify_emails'])) {
$base = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http')
. '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost') . dirname($_SERVER['SCRIPT_NAME']);
$url = rtrim($base, '/') . '/admin/tickets.php?view=' . $tid;
$typeLabel = ticketTypeLabel($type);
$orderLine = $type === 'renewal'
? '<p><strong>类型:</strong>续期申请(关联订单 #' . $orderId . '</p>'
: '<p><strong>类型:strong>普通工单</p>';
$body = '<div style="font-family:sans-serif;max-width:560px;margin:auto">'
. '<h2 style="color:#1a73e8">[' . h(SITE_NAME) . '] 收到新工单 #' . $tid . '</h2>'
. '<p><strong>提交人:</strong>' . h($user['username']) . '' . h($user['email']) . '</p>'
. '<p><strong>部门:</strong>' . h($deptName) . '</p>'
. '<p><strong>优先级:</strong>' . ticketPriorityLabel($priority) . '</p>'
. $orderLine
. '<p><strong>标题:</strong>' . h($subject) . '</p>'
. '<div style="background:#f5f7fb;border-left:4px solid #1a73e8;padding:12px 16px;margin:10px 0;white-space:pre-wrap">' . h($message) . '</div>'
. '<p><a href="' . $url . '" style="background:#1a73e8;color:#fff;padding:10px 18px;border-radius:6px;text-decoration:none;display:inline-block">前往后台处理</a></p>'
. '</div>';
fnwSendMail($cfg['notify_emails'], '[' . SITE_NAME . '] 新工单 #' . $tid . ' ' . $subject, $body);
}
redirect('mytickets.php?ok=1');
}
}
require 'includes/header.php';
?>
<section class="section">
<h2 class="sec-title"><i class="fas fa-ticket-alt"></i> <?= __('ticket_page.title') ?></h2>
<p class="muted" style="margin-bottom:18px;"><?= __('ticket_page.desc_hint') ?></p>
<?php if ($err): ?><p class="form-err"><?= h($err) ?></p><?php endif; ?>
<div class="panel" style="max-width:680px;">
<form method="post" action="" class="grid-form">
<?= csrfField() ?>
<label><?= __('ticket.type_label', ['type' => ''])
?><select name="type" id="ticketType">
<option value="general" <?= $renewOrderId ? '' : 'selected' ?>><?= __('ticket_page.type_general') ?></option>
<?php if (!empty($renewOrders)): ?>
<option value="renewal" <?= $renewOrderId ? 'selected' : '' ?>><?= __('ticket_page.type_renewal') ?></option>
<?php endif; ?>
</select>
</label>
<label><?= __('ticket_page.select_dept') ?>
<select name="dept_id">
<?php foreach ($depts as $d): ?>
<option value="<?= (int) $d['id'] ?>"><?= h($d['name']) ?><?= $d['description'] ? '' . h($d['description']) . '' : '' ?></option>
<?php endforeach; ?>
</select>
</label>
<?php if (!empty($renewOrders)): ?>
<label class="span2"><?= __('ticket_page.related_order_label') ?>
<select name="order_id" id="ticketOrder">
<option value="0"><?= __('ticket_page.order_no_link') ?></option>
<?php foreach ($renewOrders as $ro): ?>
<option value="<?= (int) $ro['id'] ?>" <?= $renewOrderId === (int) $ro['id'] ? 'selected' : '' ?>>
#<?= (int) $ro['id'] ?> · <?= h($ro['order_no']) ?> · <?= __('ticket_page.renewal_period') ?> <?= periodLabel($ro['period_days']) ?> · <?= __('ticket_page.renewal_expire') ?> <?= expiryText($ro['expires_at']) ?>
</option>
<?php endforeach; ?>
</select>
</label>
<?php endif; ?>
<label class="span2"><?= __('ticket.subject') ?> *<input type="text" name="subject" id="ticketSubject" maxlength="160" value="<?= $renewOrderId ? __('ticket_page.subject_renewal_prefix') . $renewOrderId : '' ?>" placeholder="<?= __('ticket_page.subject_placeholder') ?>" required></label>
<label class="span2"><?= __('ticket.content') ?> *<textarea name="message" rows="6" placeholder="<?= __('ticket_page.message_placeholder') ?>" required></textarea></label>
<label><?= __('ticket.priority') ?>
<select name="priority">
<option value="1"><?= __('ticket.low') ?></option>
<option value="2" selected><?= __('ticket.normal') ?></option>
<option value="3"><?= __('ticket.high') ?></option>
</select>
</label>
<label><?= __('ticket_page.contact_email') ?>
<input type="text" value="<?= h($user['email']) ?>" readonly>
</label>
<div class="form-actions span2">
<button type="submit" class="btn btn-primary"><i class="fas fa-paper-plane"></i> <?= __('ticket_page.submit_btn') ?></button>
<a href="mytickets.php" class="btn btn-ghost"><?= __('ticket_page.view_my_tickets') ?></a>
</div>
</form>
</div>
</section>
<?php require 'includes/footer.php'; ?>