148 lines
8.0 KiB
PHP
148 lines
8.0 KiB
PHP
<?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'; ?>
|