418 lines
9.9 KiB
Vue
418 lines
9.9 KiB
Vue
|
<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>
|