hesabixCore/webUI/src/components/InvoiceElements.vue

418 lines
9.9 KiB
Vue
Raw Normal View History

<template>
<div class="invoice-element" :class="elementType">
<div class="element-header">
<v-icon>{{ getElementIcon() }}</v-icon>
<span>{{ getElementTitle() }}</span>
</div>
<div class="element-content">
<!-- Business Info Element -->
<div v-if="elementType === 'business-info'" class="business-info">
<div class="info-row">
<span class="label">نام:</span>
<span class="value">{{ businessData.name || 'نام کسب‌وکار' }}</span>
</div>
<div class="info-row">
<span class="label">تلفن:</span>
<span class="value">{{ businessData.tel || 'تلفن کسب‌وکار' }}</span>
</div>
<div class="info-row">
<span class="label">آدرس:</span>
<span class="value">{{ businessData.address || 'آدرس کسب‌وکار' }}</span>
</div>
</div>
<!-- Customer Info Element -->
<div v-else-if="elementType === 'customer-info'" class="customer-info">
<div class="info-row">
<span class="label">نام:</span>
<span class="value">{{ customerData.name || 'نام مشتری' }}</span>
</div>
<div class="info-row">
<span class="label">موبایل:</span>
<span class="value">{{ customerData.mobile || 'موبایل مشتری' }}</span>
</div>
<div class="info-row">
<span class="label">آدرس:</span>
<span class="value">{{ customerData.address || 'آدرس مشتری' }}</span>
</div>
</div>
<!-- Invoice Header Element -->
<div v-else-if="elementType === 'invoice-header'" class="invoice-header">
<div class="header-row">
<div class="logo-section">
<div class="logo-placeholder">لوگو</div>
</div>
<div class="title-section">
<h2>صورتحساب فروش کالا و خدمات</h2>
</div>
<div class="info-section">
<div class="info-item">
<span class="label">تاریخ:</span>
<span class="value">{{ invoiceData.date || 'تاریخ فاکتور' }}</span>
</div>
<div class="info-item">
<span class="label">شماره:</span>
<span class="value">{{ invoiceData.code || 'شماره فاکتور' }}</span>
</div>
</div>
</div>
</div>
<!-- Items Table Element -->
<div v-else-if="elementType === 'items-table'" class="items-table">
<table class="invoice-table">
<thead>
<tr>
<th>ردیف</th>
<th>کالا/خدمات</th>
<th>شرح</th>
<th>تعداد</th>
<th>فی واحد</th>
<th>تخفیف</th>
<th>مالیات</th>
<th>مبلغ کل</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in sampleItems" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ item.name }}</td>
<td>{{ item.description }}</td>
<td>{{ item.quantity }}</td>
<td>{{ formatNumber(item.unitPrice) }}</td>
<td>{{ item.discount }}%</td>
<td>{{ formatNumber(item.tax) }}</td>
<td>{{ formatNumber(item.total) }}</td>
</tr>
</tbody>
</table>
</div>
<!-- Totals Section Element -->
<div v-else-if="elementType === 'totals-section'" class="totals-section">
<div class="totals-row">
<span class="label">جمع کل:</span>
<span class="value">{{ formatNumber(totalsData.subtotal) }}</span>
</div>
<div class="totals-row">
<span class="label">تخفیف:</span>
<span class="value">{{ formatNumber(totalsData.discount) }}</span>
</div>
<div class="totals-row">
<span class="label">مالیات:</span>
<span class="value">{{ formatNumber(totalsData.tax) }}</span>
</div>
<div class="totals-row total">
<span class="label">مبلغ نهایی:</span>
<span class="value">{{ formatNumber(totalsData.final) }}</span>
</div>
</div>
<!-- Signature Section Element -->
<div v-else-if="elementType === 'signature-section'" class="signature-section">
<div class="signature-row">
<div class="signature-box">
<div class="signature-placeholder">مهر و امضا خریدار</div>
</div>
<div class="signature-box">
<div class="signature-placeholder">مهر و امضا فروشنده</div>
</div>
</div>
</div>
<!-- Default Element -->
<div v-else class="default-element">
{{ content }}
</div>
</div>
</div>
</template>
<script>
export default {
name: 'InvoiceElement',
props: {
elementType: {
type: String,
required: true
},
content: {
type: String,
default: ''
},
elementData: {
type: Object,
default: () => ({})
}
},
data() {
return {
// Sample data for preview
businessData: {
name: 'شرکت نمونه',
tel: '021-12345678',
address: 'تهران، خیابان نمونه'
},
customerData: {
name: 'مشتری نمونه',
mobile: '09123456789',
address: 'آدرس مشتری'
},
invoiceData: {
date: '1402/12/15',
code: 'INV-001'
},
sampleItems: [
{
name: 'کالای نمونه 1',
description: 'توضیحات کالا',
quantity: 2,
unitPrice: 100000,
discount: 10,
tax: 9000,
total: 189000
},
{
name: 'کالای نمونه 2',
description: 'توضیحات کالا',
quantity: 1,
unitPrice: 50000,
discount: 0,
tax: 4500,
total: 54500
}
],
totalsData: {
subtotal: 250000,
discount: 20000,
tax: 13500,
final: 243500
}
}
},
methods: {
getElementIcon() {
const icons = {
'business-info': 'mdi-domain',
'customer-info': 'mdi-account',
'invoice-header': 'mdi-file-document',
'items-table': 'mdi-format-list-bulleted',
'totals-section': 'mdi-calculator',
'signature-section': 'mdi-pen'
}
return icons[this.elementType] || 'mdi-view-grid'
},
getElementTitle() {
const titles = {
'business-info': 'اطلاعات کسب‌وکار',
'customer-info': 'اطلاعات مشتری',
'invoice-header': 'سربرگ فاکتور',
'items-table': 'جدول اقلام',
'totals-section': 'جمع‌ها',
'signature-section': 'امضا'
}
return titles[this.elementType] || 'عنصر'
},
formatNumber(value) {
return new Intl.NumberFormat('fa-IR').format(value)
}
}
}
</script>
<style scoped>
.invoice-element {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 16px;
background: white;
margin-bottom: 16px;
}
.element-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #f0f0f0;
font-weight: 600;
color: #333;
}
.element-content {
min-height: 60px;
}
/* Business Info Styles */
.business-info .info-row,
.customer-info .info-row {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
padding: 4px 0;
}
.info-row .label {
font-weight: 600;
color: #666;
min-width: 80px;
}
.info-row .value {
color: #333;
}
/* Invoice Header Styles */
.invoice-header .header-row {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
gap: 16px;
align-items: center;
}
.logo-section .logo-placeholder {
width: 80px;
height: 80px;
background: #f0f0f0;
border: 2px dashed #ccc;
display: flex;
align-items: center;
justify-content: center;
color: #666;
border-radius: 4px;
}
.title-section h2 {
text-align: center;
margin: 0;
font-size: 18px;
color: #333;
}
.info-section .info-item {
display: flex;
justify-content: space-between;
margin-bottom: 4px;
}
.info-item .label {
font-weight: 600;
color: #666;
}
.info-item .value {
color: #333;
}
/* Items Table Styles */
.items-table {
overflow-x: auto;
}
.invoice-table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
}
.invoice-table th,
.invoice-table td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}
.invoice-table th {
background: #f5f5f5;
font-weight: 600;
color: #333;
}
.invoice-table td {
background: white;
}
/* Totals Section Styles */
.totals-section .totals-row {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
padding: 4px 0;
}
.totals-row .label {
font-weight: 600;
color: #666;
}
.totals-row .value {
color: #333;
}
.totals-row.total {
border-top: 2px solid #333;
padding-top: 8px;
margin-top: 8px;
font-weight: bold;
font-size: 16px;
}
/* Signature Section Styles */
.signature-section .signature-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 32px;
margin-top: 16px;
}
.signature-box {
height: 80px;
border: 2px dashed #ccc;
display: flex;
align-items: center;
justify-content: center;
background: #f9f9f9;
border-radius: 4px;
}
.signature-placeholder {
color: #666;
font-size: 14px;
}
/* Default Element Styles */
.default-element {
padding: 16px;
background: #f9f9f9;
border-radius: 4px;
text-align: center;
color: #666;
}
/* Responsive */
@media (max-width: 768px) {
.invoice-header .header-row {
grid-template-columns: 1fr;
gap: 12px;
}
.signature-section .signature-row {
grid-template-columns: 1fr;
gap: 16px;
}
.invoice-table {
font-size: 10px;
}
.invoice-table th,
.invoice-table td {
padding: 4px;
}
}
</style>