hesabixCore/webUI/src/components/TemplateLibrary.vue

890 lines
22 KiB
Vue
Raw Normal View History

<template>
<div class="template-library">
<v-dialog v-model="showLibrary" max-width="800px">
<v-card>
<v-card-title class="d-flex align-center">
<v-icon class="mr-3">mdi-library</v-icon>
کتابخانه قالبهای آماده
</v-card-title>
<v-card-text>
<v-tabs v-model="activeCategory" color="primary">
<v-tab value="sales">فروش</v-tab>
<v-tab value="purchase">خرید</v-tab>
<v-tab value="return">برگشت</v-tab>
<v-tab value="custom">سفارشی</v-tab>
</v-tabs>
<v-window v-model="activeCategory" class="mt-4">
<v-window-item value="sales">
<div class="templates-grid">
<div
v-for="template in salesTemplates"
:key="template.id"
class="template-card"
@click="selectTemplate(template)"
>
<div class="template-preview">
<img :src="template.preview" :alt="template.name" />
</div>
<div class="template-info">
<h4>{{ template.name }}</h4>
<p>{{ template.description }}</p>
</div>
</div>
</div>
</v-window-item>
<v-window-item value="purchase">
<div class="templates-grid">
<div
v-for="template in purchaseTemplates"
:key="template.id"
class="template-card"
@click="selectTemplate(template)"
>
<div class="template-preview">
<img :src="template.preview" :alt="template.name" />
</div>
<div class="template-info">
<h4>{{ template.name }}</h4>
<p>{{ template.description }}</p>
</div>
</div>
</div>
</v-window-item>
<v-window-item value="return">
<div class="templates-grid">
<div
v-for="template in returnTemplates"
:key="template.id"
class="template-card"
@click="selectTemplate(template)"
>
<div class="template-preview">
<img :src="template.preview" :alt="template.name" />
</div>
<div class="template-info">
<h4>{{ template.name }}</h4>
<p>{{ template.description }}</p>
</div>
</div>
</div>
</v-window-item>
<v-window-item value="custom">
<div class="templates-grid">
<div
v-for="template in customTemplates"
:key="template.id"
class="template-card"
@click="selectTemplate(template)"
>
<div class="template-preview">
<img :src="template.preview" :alt="template.name" />
</div>
<div class="template-info">
<h4>{{ template.name }}</h4>
<p>{{ template.description }}</p>
</div>
</div>
</div>
</v-window-item>
</v-window>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn @click="showLibrary = false" variant="text">انصراف</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script>
export default {
name: 'TemplateLibrary',
props: {
modelValue: {
type: Boolean,
default: false
}
},
emits: ['update:modelValue', 'select-template'],
data() {
return {
activeCategory: 'sales',
salesTemplates: [
{
id: 'sales-standard',
name: 'قالب استاندارد فروش',
description: 'قالب ساده و کاربردی برای فاکتورهای فروش',
preview: '/templates/sales-standard.png',
code: this.getStandardSalesTemplate()
},
{
id: 'sales-luxury',
name: 'قالب لوکس فروش',
description: 'قالب زیبا و حرفه‌ای برای فاکتورهای فروش',
preview: '/templates/sales-luxury.png',
code: this.getLuxurySalesTemplate()
}
],
purchaseTemplates: [
{
id: 'purchase-standard',
name: 'قالب استاندارد خرید',
description: 'قالب مناسب برای فاکتورهای خرید',
preview: '/templates/purchase-standard.png',
code: this.getStandardPurchaseTemplate()
}
],
returnTemplates: [
{
id: 'return-standard',
name: 'قالب استاندارد برگشت',
description: 'قالب مناسب برای برگشت از فروش/خرید',
preview: '/templates/return-standard.png',
code: this.getStandardReturnTemplate()
}
],
customTemplates: [
{
id: 'custom-minimal',
name: 'قالب مینیمال',
description: 'قالب ساده و تمیز',
preview: '/templates/custom-minimal.png',
code: this.getMinimalTemplate()
}
]
}
},
computed: {
showLibrary: {
get() {
return this.modelValue
},
set(value) {
this.$emit('update:modelValue', value)
}
}
},
methods: {
selectTemplate(template) {
this.$emit('select-template', template)
this.showLibrary = false
},
getStandardSalesTemplate() {
return `<!DOCTYPE html>
<html lang="fa" direction="rtl">
<head>
<style>
.invoice-container {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
border-bottom: 2px solid #333;
padding-bottom: 20px;
margin-bottom: 20px;
}
.info-section {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 20px;
}
.info-box {
border: 1px solid #ddd;
padding: 15px;
border-radius: 5px;
}
.info-box h3 {
margin: 0 0 10px 0;
background: #f5f5f5;
padding: 5px;
border-radius: 3px;
}
.items-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
.items-table th,
.items-table td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}
.items-table th {
background: #f5f5f5;
font-weight: bold;
}
.totals {
text-align: right;
margin-bottom: 20px;
}
.totals div {
margin: 5px 0;
}
.signatures {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-top: 40px;
}
.signature-box {
border: 1px solid #ddd;
padding: 20px;
text-align: center;
min-height: 100px;
}
</style>
</head>
<body>
<div class="invoice-container">
<div class="header">
<h1>{{ business.name }}</h1>
<h2>صورتحساب فروش کالا و خدمات</h2>
<p>شماره: {{ doc.code }} | تاریخ: {{ doc.date }}</p>
</div>
<div class="info-section">
<div class="info-box">
<h3>فروشنده</h3>
<p><strong>نام:</strong> {{ business.name }}</p>
<p><strong>تلفن:</strong> {{ business.tel }}</p>
<p><strong>آدرس:</strong> {{ business.address }}</p>
</div>
<div class="info-box">
<h3>خریدار</h3>
{% if person %}
<p><strong>نام:</strong> {{ person.name }}</p>
<p><strong>موبایل:</strong> {{ person.mobile }}</p>
<p><strong>آدرس:</strong> {{ person.address }}</p>
{% else %}
<p>مشتری ناشناس</p>
{% endif %}
</div>
</div>
<table class="items-table">
<thead>
<tr>
<th>ردیف</th>
<th>کالا/خدمات</th>
<th>شرح</th>
<th>تعداد</th>
<th>فی واحد</th>
<th>تخفیف</th>
<th>مالیات</th>
<th>مبلغ کل</th>
</tr>
</thead>
<tbody>
{% for item in rows %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ item.commodity.name ?? '-' }}</td>
<td>{{ item.des }}</td>
<td>{{ item.commodityCount }}</td>
<td>{{ (item.bs / item.commodityCount) | number_format(0, '.', ',') }}</td>
<td>
{% if item.showPercentDiscount %}
{{ item.discountPercent }}%
{% else %}
{{ item.discount | number_format(0, '.', ',') }}
{% endif %}
</td>
<td>{{ item.tax | number_format(0, '.', ',') }}</td>
<td>{{ item.bs | number_format(0, '.', ',') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="totals">
{% if discount %}
<div><strong>جمع تخفیف:</strong> {{ discount | number_format(0, '.', ',') }}</div>
{% endif %}
{% if transfer %}
<div><strong>هزینه ارسال:</strong> {{ transfer | number_format(0, '.', ',') }}</div>
{% endif %}
<div><strong>جمع کل:</strong> {{ doc.amount | number_format(0, '.', ',') }}</div>
</div>
{% if note %}
<div style="margin-top: 20px; padding: 10px; background: #f9f9f9; border-radius: 5px;">
<strong>یادداشت:</strong> {{ note }}
</div>
{% endif %}
<div class="signatures">
<div class="signature-box">
<h4>مهر و امضا خریدار</h4>
</div>
<div class="signature-box">
<h4>مهر و امضا فروشنده</h4>
</div>
</div>
</div>
</body>
</html>`
},
getLuxurySalesTemplate() {
return `<!DOCTYPE html>
<html lang="fa" direction="rtl">
<head>
<style>
body {
font-family: 'Tahoma', Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
margin: 0;
padding: 20px;
}
.invoice-container {
max-width: 900px;
margin: 0 auto;
background: white;
border-radius: 15px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 {
margin: 0;
font-size: 28px;
font-weight: 300;
}
.header h2 {
margin: 10px 0;
font-size: 20px;
font-weight: 300;
}
.invoice-info {
background: #f8f9fa;
padding: 20px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
}
.info-box {
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 5px 15px rgba(0,0,0,0.08);
}
.info-box h3 {
margin: 0 0 15px 0;
color: #667eea;
font-size: 16px;
border-bottom: 2px solid #667eea;
padding-bottom: 5px;
}
.items-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
.items-table th {
background: #667eea;
color: white;
padding: 15px 10px;
font-weight: 500;
}
.items-table td {
padding: 12px 10px;
border-bottom: 1px solid #eee;
}
.items-table tr:nth-child(even) {
background: #f8f9fa;
}
.totals {
background: #f8f9fa;
padding: 20px;
text-align: right;
}
.total-row {
display: flex;
justify-content: space-between;
margin: 5px 0;
padding: 5px 0;
}
.final-total {
border-top: 2px solid #667eea;
font-size: 18px;
font-weight: bold;
color: #667eea;
}
.signatures {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
padding: 30px;
}
.signature-box {
border: 2px dashed #667eea;
padding: 30px;
text-align: center;
border-radius: 10px;
background: #f8f9fa;
}
</style>
</head>
<body>
<div class="invoice-container">
<div class="header">
<h1>{{ business.name }}</h1>
<h2>صورتحساب فروش کالا و خدمات</h2>
<p>شماره: {{ doc.code }} | تاریخ: {{ doc.date }}</p>
</div>
<div class="invoice-info">
<div class="info-box">
<h3>اطلاعات فروشنده</h3>
<p><strong>نام:</strong> {{ business.name }}</p>
<p><strong>تلفن:</strong> {{ business.tel }}</p>
<p><strong>آدرس:</strong> {{ business.address }}</p>
</div>
<div class="info-box">
<h3>اطلاعات خریدار</h3>
{% if person %}
<p><strong>نام:</strong> {{ person.name }}</p>
<p><strong>موبایل:</strong> {{ person.mobile }}</p>
<p><strong>آدرس:</strong> {{ person.address }}</p>
{% else %}
<p>مشتری ناشناس</p>
{% endif %}
</div>
</div>
<div style="padding: 0 20px;">
<table class="items-table">
<thead>
<tr>
<th>ردیف</th>
<th>کالا/خدمات</th>
<th>شرح</th>
<th>تعداد</th>
<th>فی واحد</th>
<th>تخفیف</th>
<th>مالیات</th>
<th>مبلغ کل</th>
</tr>
</thead>
<tbody>
{% for item in rows %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ item.commodity.name ?? '-' }}</td>
<td>{{ item.des }}</td>
<td>{{ item.commodityCount }}</td>
<td>{{ (item.bs / item.commodityCount) | number_format(0, '.', ',') }}</td>
<td>
{% if item.showPercentDiscount %}
{{ item.discountPercent }}%
{% else %}
{{ item.discount | number_format(0, '.', ',') }}
{% endif %}
</td>
<td>{{ item.tax | number_format(0, '.', ',') }}</td>
<td>{{ item.bs | number_format(0, '.', ',') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="totals">
{% if discount %}
<div class="total-row">
<span>جمع تخفیف:</span>
<span>{{ discount | number_format(0, '.', ',') }}</span>
</div>
{% endif %}
{% if transfer %}
<div class="total-row">
<span>هزینه ارسال:</span>
<span>{{ transfer | number_format(0, '.', ',') }}</span>
</div>
{% endif %}
<div class="total-row final-total">
<span>جمع کل:</span>
<span>{{ doc.amount | number_format(0, '.', ',') }}</span>
</div>
</div>
{% if note %}
<div style="margin: 20px; padding: 15px; background: #e3f2fd; border-radius: 10px; border-right: 4px solid #2196f3;">
<strong>یادداشت:</strong> {{ note }}
</div>
{% endif %}
<div class="signatures">
<div class="signature-box">
<h4>مهر و امضا خریدار</h4>
</div>
<div class="signature-box">
<h4>مهر و امضا فروشنده</h4>
</div>
</div>
</div>
</body>
</html>`
},
getStandardPurchaseTemplate() {
return `<!DOCTYPE html>
<html lang="fa" direction="rtl">
<head>
<style>
.invoice-container {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
border-bottom: 2px solid #333;
padding-bottom: 20px;
margin-bottom: 20px;
}
.items-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
.items-table th,
.items-table td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}
.items-table th {
background: #f5f5f5;
font-weight: bold;
}
</style>
</head>
<body>
<div class="invoice-container">
<div class="header">
<h1>{{ business.name }}</h1>
<h2>فاکتور خرید</h2>
<p>شماره: {{ doc.code }} | تاریخ: {{ doc.date }}</p>
</div>
<table class="items-table">
<thead>
<tr>
<th>ردیف</th>
<th>کالا/خدمات</th>
<th>شرح</th>
<th>تعداد</th>
<th>بدهکار</th>
<th>بستانکار</th>
</tr>
</thead>
<tbody>
{% for item in rows %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ item.commodity.name ?? '-' }}</td>
<td>{{ item.des }}</td>
<td>{{ item.commodityCount }}</td>
<td>{{ item.bd | number_format(0, '.', ',') }}</td>
<td>{{ item.bs | number_format(0, '.', ',') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</body>
</html>`
},
getStandardReturnTemplate() {
return `<!DOCTYPE html>
<html lang="fa" direction="rtl">
<head>
<style>
.invoice-container {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
border-bottom: 2px solid #333;
padding-bottom: 20px;
margin-bottom: 20px;
}
.items-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
.items-table th,
.items-table td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}
.items-table th {
background: #f5f5f5;
font-weight: bold;
}
</style>
</head>
<body>
<div class="invoice-container">
<div class="header">
<h1>{{ business.name }}</h1>
<h2>برگشت از فروش</h2>
<p>شماره: {{ doc.code }} | تاریخ: {{ doc.date }}</p>
</div>
<table class="items-table">
<thead>
<tr>
<th>ردیف</th>
<th>کالا/خدمات</th>
<th>شرح</th>
<th>تعداد</th>
<th>تخفیف</th>
<th>مالیات</th>
<th>مبلغ کل</th>
</tr>
</thead>
<tbody>
{% for item in rows %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ item.commodity.name ?? '-' }}</td>
<td>{{ item.des }}</td>
<td>{{ item.commodityCount }}</td>
<td>
{% if item.showPercentDiscount %}
{{ item.discountPercent }}%
{% else %}
{{ item.discount | number_format(0, '.', ',') }}
{% endif %}
</td>
<td>{{ item.tax | number_format(0, '.', ',') }}</td>
<td>{{ item.bs | number_format(0, '.', ',') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</body>
</html>`
},
getMinimalTemplate() {
return `<!DOCTYPE html>
<html lang="fa" direction="rtl">
<head>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 40px;
background: #fafafa;
}
.invoice-container {
max-width: 600px;
margin: 0 auto;
background: white;
padding: 40px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.header {
text-align: center;
margin-bottom: 40px;
}
.header h1 {
margin: 0;
color: #333;
font-weight: 300;
}
.info {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
margin-bottom: 30px;
}
.info-section h3 {
margin: 0 0 15px 0;
color: #666;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 1px;
}
.items-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 30px;
}
.items-table th {
background: #f8f9fa;
padding: 12px 8px;
text-align: left;
font-weight: 500;
color: #666;
border-bottom: 2px solid #eee;
}
.items-table td {
padding: 12px 8px;
border-bottom: 1px solid #eee;
}
.total {
text-align: right;
font-size: 18px;
font-weight: 500;
color: #333;
border-top: 2px solid #333;
padding-top: 15px;
}
</style>
</head>
<body>
<div class="invoice-container">
<div class="header">
<h1>{{ business.name }}</h1>
<p>شماره: {{ doc.code }} | تاریخ: {{ doc.date }}</p>
</div>
<div class="info">
<div class="info-section">
<h3>فروشنده</h3>
<p>{{ business.name }}</p>
<p>{{ business.tel }}</p>
<p>{{ business.address }}</p>
</div>
<div class="info-section">
<h3>خریدار</h3>
{% if person %}
<p>{{ person.name }}</p>
<p>{{ person.mobile }}</p>
<p>{{ person.address }}</p>
{% else %}
<p>مشتری ناشناس</p>
{% endif %}
</div>
</div>
<table class="items-table">
<thead>
<tr>
<th>کالا/خدمات</th>
<th>تعداد</th>
<th>فی واحد</th>
<th>مبلغ کل</th>
</tr>
</thead>
<tbody>
{% for item in rows %}
<tr>
<td>{{ item.commodity.name ?? '-' }}</td>
<td>{{ item.commodityCount }}</td>
<td>{{ (item.bs / item.commodityCount) | number_format(0, '.', ',') }}</td>
<td>{{ item.bs | number_format(0, '.', ',') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="total">
جمع کل: {{ doc.amount | number_format(0, '.', ',') }}
</div>
</div>
</body>
</html>`
}
}
}
</script>
<style scoped>
.template-library {
/* Component styles */
}
.templates-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
padding: 20px 0;
}
.template-card {
border: 1px solid #e0e0e0;
border-radius: 8px;
overflow: hidden;
cursor: pointer;
transition: all 0.3s ease;
background: white;
}
.template-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0,0,0,0.15);
border-color: #2196f3;
}
.template-preview {
height: 150px;
background: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
border-bottom: 1px solid #e0e0e0;
}
.template-preview img {
max-width: 100%;
max-height: 100%;
object-fit: cover;
}
.template-info {
padding: 16px;
}
.template-info h4 {
margin: 0 0 8px 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.template-info p {
margin: 0;
font-size: 14px;
color: #666;
line-height: 1.4;
}
/* Responsive */
@media (max-width: 768px) {
.templates-grid {
grid-template-columns: 1fr;
}
}
</style>