anycoder-0ca1f7cf / index.html
Tahersaeedi's picture
Upload folder using huggingface_hub
9c2d201 verified
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>سیستم مدیریت ضمانت‌نامه‌های بانکی</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.rtl.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/persian-datepicker@1.2.0/dist/css/persian-datepicker.min.css">
<style>
:root {
--primary-color: #2c3e50;
--secondary-color: #3498db;
--success-color: #27ae60;
--warning-color: #f39c12;
--danger-color: #e74c3c;
--light-color: #ecf0f1;
--dark-color: #2c3e50;
}
body {
font-family: 'Vazirmatn', 'Tahoma', sans-serif;
background-color: #f5f7fa;
color: var(--dark-color);
}
.sidebar {
background-color: var(--primary-color);
color: white;
min-height: 100vh;
position: sticky;
top: 0;
}
.sidebar .nav-link {
color: rgba(255, 255, 255, 0.8);
padding: 10px 15px;
margin: 5px 0;
border-radius: 5px;
transition: all 0.3s;
}
.sidebar .nav-link:hover,
.sidebar .nav-link.active {
background-color: rgba(255, 255, 255, 0.1);
color: white;
}
.main-content {
background-color: white;
border-radius: 10px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
padding: 20px;
margin: 20px;
}
.header {
background-color: white;
padding: 10px 20px;
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
}
.card {
border: none;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
}
.card-header {
background-color: var(--light-color);
border-radius: 10px 10px 0 0 !important;
font-weight: bold;
}
.btn-primary {
background-color: var(--secondary-color);
border-color: var(--secondary-color);
}
.btn-success {
background-color: var(--success-color);
border-color: var(--success-color);
}
.btn-warning {
background-color: var(--warning-color);
border-color: var(--warning-color);
}
.btn-danger {
background-color: var(--danger-color);
border-color: var(--danger-color);
}
.status-badge {
padding: 5px 10px;
border-radius: 20px;
font-size: 0.8rem;
font-weight: bold;
}
.status-active {
background-color: rgba(46, 204, 113, 0.2);
color: var(--success-color);
}
.status-renewed {
background-color: rgba(52, 152, 219, 0.2);
color: var(--secondary-color);
}
.status-released {
background-color: rgba(155, 89, 182, 0.2);
color: #9b59b6;
}
.status-captured {
background-color: rgba(241, 196, 15, 0.2);
color: var(--warning-color);
}
.status-cancelled {
background-color: rgba(231, 76, 60, 0.2);
color: var(--danger-color);
}
.table-responsive {
overflow-x: auto;
}
.table {
margin-bottom: 0;
}
.table th,
.table td {
vertical-align: middle;
}
.modal-dialog {
max-width: 800px;
}
.form-control,
.form-select {
border-radius: 5px;
border: 1px solid #ddd;
}
.form-control:focus,
.form-select:focus {
border-color: var(--secondary-color);
box-shadow: 0 0 0 0.25rem rgba(52, 152, 219, 0.25);
}
.alert {
border-radius: 5px;
padding: 10px 15px;
margin-bottom: 20px;
}
.pagination {
justify-content: center;
}
.search-box {
position: relative;
}
.search-box input {
padding-left: 35px;
}
.search-box i {
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
color: #999;
}
.file-upload {
border: 2px dashed #ddd;
border-radius: 5px;
padding: 20px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
}
.file-upload:hover {
border-color: var(--secondary-color);
background-color: rgba(52, 152, 219, 0.05);
}
.file-list {
max-height: 200px;
overflow-y: auto;
border: 1px solid #eee;
border-radius: 5px;
padding: 10px;
}
.file-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px 0;
border-bottom: 1px solid #eee;
}
.file-item:last-child {
border-bottom: none;
}
.expiration-warning {
background-color: rgba(243, 156, 18, 0.1);
border-left: 4px solid var(--warning-color);
}
.expiration-danger {
background-color: rgba(231, 76, 60, 0.1);
border-left: 4px solid var(--danger-color);
}
.chart-container {
position: relative;
height: 300px;
}
@media (max-width: 768px) {
.sidebar {
position: relative;
min-height: auto;
}
.main-content {
margin: 10px;
}
}
.persian-datepicker {
direction: rtl;
}
.built-with {
font-size: 0.8rem;
color: #7f8c8d;
text-align: center;
padding: 10px;
background-color: #ecf0f1;
border-top: 1px solid #ddd;
}
.built-with a {
color: var(--secondary-color);
text-decoration: none;
}
</style>
</head>
<body>
<div class="container-fluid">
<div class="row">
<!-- Sidebar -->
<div class="col-md-3 col-lg-2 sidebar">
<div class="p-3">
<h4 class="text-center mb-4">مدیریت ضمانت‌نامه‌ها</h4>
<ul class="nav flex-column" id="sidebarMenu">
<li class="nav-item">
<a class="nav-link active" href="#" data-page="dashboard">
<i class="bi bi-speedometer2 me-2"></i>
داشبورد
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" data-page="guarantees">
<i class="bi bi-file-earmark-text me-2"></i>
ضمانت‌نامه‌ها
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" data-page="contractors">
<i class="bi bi-people me-2"></i>
پیمانکاران
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" data-page="banks">
<i class="bi bi-bank me-2"></i>
بانک‌ها و شعب
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" data-page="reports">
<i class="bi bi-graph-up me-2"></i>
گزارش‌ها
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" data-page="backup">
<i class="bi bi-hdd me-2"></i>
پشتیبان‌گیری
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" data-page="settings">
<i class="bi bi-gear me-2"></i>
تنظیمات
</a>
</li>
</ul>
</div>
</div>
<!-- Main Content -->
<div class="col-md-9 col-lg-10">
<div class="header">
<div>
<button class="btn btn-sm btn-outline-secondary" id="toggleSidebar">
<i class="bi bi-list"></i>
</button>
<span class="me-3">کاربر: مدیر سیستم</span>
</div>
<div>
<span id="currentDate"></span>
<button class="btn btn-sm btn-outline-danger ms-2" id="logoutBtn">
<i class="bi bi-box-arrow-left"></i> خروج
</button>
</div>
</div>
<div class="main-content" id="pageContent">
<!-- Pages will be loaded here dynamically -->
</div>
</div>
</div>
</div>
<!-- Login Modal -->
<div class="modal fade" id="loginModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">ورود به سیستم</h5>
</div>
<div class="modal-body">
<form id="loginForm">
<div class="mb-3">
<label for="username" class="form-label">نام کاربری</label>
<input type="text" class="form-control" id="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">رمز عبور</label>
<input type="password" class="form-control" id="password" required>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary">ورود</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Built with anycoder -->
<div class="built-with">
Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a>
</div>
<!-- Load Persian Datepicker -->
<script src="https://cdn.jsdelivr.net/npm/persian-date@1.1.0/dist/persian-date.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/persian-datepicker@1.2.0/dist/js/persian-datepicker.min.js"></script>
<!-- Load Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- Load XLSX for Excel export -->
<script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
<!-- Load jsPDF for PDF export -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.29/jspdf.plugin.autotable.min.js"></script>
<!-- Load JSZip for backup -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
<!-- Load MD5 for password hashing -->
<script src="https://cdn.jsdelivr.net/npm/js-md5@0.7.3/src/md5.min.js"></script>
<script>
// Database simulation (in a real app, this would be SQLite)
let db = {
users: [
{ id: 1, username: 'admin', password: '5f4dcc3b5aa765d61d8327deb882cf99' } // password: "password"
],
contractors: [],
banks: [],
guarantees: [],
files: []
};
// Current user
let currentUser = null;
// Initialize the app
document.addEventListener('DOMContentLoaded', function() {
// Check if user is logged in
const savedUser = localStorage.getItem('currentUser');
if (savedUser) {
currentUser = JSON.parse(savedUser);
loadPage('dashboard');
updateCurrentDate();
checkExpiringGuarantees();
} else {
showLogin();
}
// Set up event listeners
setupEventListeners();
// Initialize Persian datepickers
initializeDatepickers();
// Load sample data for demo
loadSampleData();
});
function setupEventListeners() {
// Sidebar navigation - FIXED: Now properly working
document.getElementById('sidebarMenu').addEventListener('click', function(e) {
if (e.target.classList.contains('nav-link')) {
e.preventDefault();
const page = e.target.getAttribute('data-page');
loadPage(page);
}
});
// Login form
document.getElementById('loginForm')?.addEventListener('submit', function(e) {
e.preventDefault();
login();
});
// Logout button
document.getElementById('logoutBtn')?.addEventListener('click', logout);
// Toggle sidebar for mobile
document.getElementById('toggleSidebar')?.addEventListener('click', function() {
document.querySelector('.sidebar').classList.toggle('d-none');
document.querySelector('.col-md-9').classList.toggle('col-md-12');
});
}
function initializeDatepickers() {
// Initialize Persian datepickers
if (typeof persianDatepicker !== 'undefined') {
document.querySelectorAll('.persian-datepicker').forEach(input => {
$(input).persianDatepicker({
format: 'YYYY/MM/DD',
autoClose: true,
persianNumbers: true,
initialValue: false
});
});
}
}
function loadSampleData() {
// Add sample banks
if (db.banks.length === 0) {
db.banks = [
{ id: 1, name: 'بانک ملی ایران', branch: 'شعبه مرکزی', code: '1001', phone: '02112345678', address: 'تهران، خیابان جمهوری' },
{ id: 2, name: 'بانک ملت', branch: 'شعبه ولیعصر', code: '2001', phone: '02187654321', address: 'تهران، خیابان ولیعصر' },
{ id: 3, name: 'بانک سپه', branch: 'شعبه انقلاب', code: '3001', phone: '02123456789', address: 'تهران، خیابان انقلاب' }
];
}
// Add sample contractors
if (db.contractors.length === 0) {
db.contractors = [
{ id: 1, name: 'شرکت ساختمانی پیشرو', nationalId: '1234567890', economicCode: '123456789', contactPerson: 'علی احمدی', phone: '02112345678', mobile: '09121234567', email: 'info@pishro.com', address: 'تهران، خیابان آزادی' },
{ id: 2, name: 'شرکت عمرانی توسعه', nationalId: '1098765432', economicCode: '987654321', contactPerson: 'محمدرضا کریمی', phone: '02187654321', mobile: '09127654321', email: 'info@tosee.com', address: 'تهران، خیابان ولیعصر' }
];
}
// Add sample guarantees
if (db.guarantees.length === 0) {
const today = new persianDate().format('YYYY/MM/DD');
const futureDate = new persianDate().add('day', 30).format('YYYY/MM/DD');
const pastDate = new persianDate().subtract('day', 30).format('YYYY/MM/DD');
db.guarantees = [
{ id: 1, number: 'BG-2023-001', type: 'تندر', bankId: 1, amount: 500000000, issueDate: today, expiryDate: futureDate, status: 'active', contractorId: 1, contractNumber: 'C-2023-001', contractTitle: 'پروژه ساخت ساختمان اداری', description: 'ضمانت‌نامه برای شرکت در مناقصه پروژه ساخت ساختمان اداری', files: [] },
{ id: 2, number: 'BG-2023-002', type: 'حسن انجام کار', bankId: 2, amount: 800000000, issueDate: pastDate, expiryDate: today, status: 'active', contractorId: 2, contractNumber: 'C-2023-002', contractTitle: 'پروژه احداث پل', description: 'ضمانت‌نامه حسن انجام کار برای پروژه احداث پل', files: [] },
{ id: 3, number: 'BG-2023-003', type: 'پیش‌پرداخت', bankId: 3, amount: 300000000, issueDate: pastDate, expiryDate: pastDate, status: 'released', contractorId: 1, contractNumber: 'C-2023-003', contractTitle: 'پروژه نوسازی مدرسه', description: 'ضمانت‌نامه پیش‌پرداخت برای پروژه نوسازی مدرسه', files: [] }
];
}
}
function showLogin() {
const loginModal = new bootstrap.Modal(document.getElementById('loginModal'));
loginModal.show();
}
function login() {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
// Simple hash function for demo (in real app, use proper hashing)
const hash = md5(password);
const user = db.users.find(u => u.username === username && u.password === hash);
if (user) {
currentUser = user;
localStorage.setItem('currentUser', JSON.stringify(user));
bootstrap.Modal.getInstance(document.getElementById('loginModal')).hide();
loadPage('dashboard');
updateCurrentDate();
checkExpiringGuarantees();
} else {
alert('نام کاربری یا رمز عبور اشتباه است');
}
}
function logout() {
currentUser = null;
localStorage.removeItem('currentUser');
showLogin();
}
function updateCurrentDate() {
const now = new persianDate();
document.getElementById('currentDate').textContent = now.format('dddd D MMMM YYYY');
}
function checkExpiringGuarantees() {
const now = new persianDate();
const alerts = [];
db.guarantees.forEach(guarantee => {
const expiryDate = new persianDate(guarantee.expiryDate);
const daysLeft = expiryDate.diff(now, 'days');
if (daysLeft <= 30 && daysLeft >= 0 && guarantee.status === 'active') {
alerts.push({
number: guarantee.number,
contractor: db.contractors.find(c => c.id === guarantee.contractorId)?.name || 'نامشخص',
expiryDate: guarantee.expiryDate,
daysLeft: daysLeft
});
}
});
if (alerts.length > 0) {
showAlerts(alerts);
}
}
function showAlerts(alerts) {
let html = '<div class="alert alert-warning">';
html += '<h6>ضمانت‌نامه‌های نزدیک به سررسید:</h6>';
html += '<ul class="mb-0">';
alerts.forEach(alert => {
html += `<li>${alert.number} - ${alert.contractor} (${alert.daysLeft} روز باقیمانده تا ${alert.expiryDate})</li>`;
});
html += '</ul></div>';
document.getElementById('alertModalBody').innerHTML = html;
const alertModal = new bootstrap.Modal(document.getElementById('alertModal'));
alertModal.show();
}
function loadPage(page) {
// Update active nav link
document.querySelectorAll('.nav-link').forEach(link => {
link.classList.remove('active');
if (link.getAttribute('data-page') === page) {
link.classList.add('active');
}
});
// Load page content
switch(page) {
case 'dashboard':
loadDashboard();
break;
case 'guarantees':
loadGuarantees();
break;
case 'contractors':
loadContractors();
break;
case 'banks':
loadBanks();
break;
case 'reports':
loadReports();
break;
case 'backup':
loadBackup();
break;
case 'settings':
loadSettings();
break;
default:
loadDashboard();
}
}
function loadDashboard() {
const now = new persianDate();
const activeGuarantees = db.guarantees.filter(g => g.status === 'active');
const expiringSoon = activeGuarantees.filter(g => {
const expiryDate = new persianDate(g.expiryDate);
return expiryDate.diff(now, 'days') <= 30 && expiryDate.diff(now, 'days') >= 0;
});
const expired = activeGuarantees.filter(g => {
const expiryDate = new persianDate(g.expiryDate);
return expiryDate.diff(now, 'days') < 0;
});
const statusCounts = {
active: db.guarantees.filter(g => g.status === 'active').length,
renewed: db.guarantees.filter(g => g.status === 'renewed').length,
released: db.guarantees.filter(g => g.status === 'released').length,
captured: db.guarantees.filter(g => g.status === 'captured').length,
cancelled: db.guarantees.filter(g => g.status === 'cancelled').length
};
const totalAmount = db.guarantees.reduce((sum, g) => sum + g.amount, 0);
let html = `
<div class="row mb-4">
<div class="col-md-12">
<h4>داشبورد مدیریت ضمانت‌نامه‌ها</h4>
</div>
</div>
<div class="row mb-4">
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<h5 class="card-title">کل ضمانت‌نامه‌ها</h5>
<p class="card-text fs-3">${db.guarantees.length}</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<h5 class="card-title">ضمانت‌نامه‌های فعال</h5>
<p class="card-text fs-3">${statusCounts.active}</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<h5 class="card-title">نزدیک به سررسید</h5>
<p class="card-text fs-3">${expiringSoon.length}</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<h5 class="card-title">منقضی شده</h5>
<p class="card-text fs-3">${expired.length}</p>
</div>
</div>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6">
<div class="card">
<div class="card-header">
وضعیت ضمانت‌نامه‌ها
</div>
<div class="card-body">
<canvas id="statusChart" width="400" height="300"></canvas>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">
جمع مبالغ (ریال)
</div>
<div class="card-body">
<canvas id="amountChart" width="400" height="300"></canvas>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
ضمانت‌نامه‌های نزدیک به سررسید
<button class="btn btn-sm btn-primary" onclick="loadPage('guarantees')">مشاهده همه</button>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>شماره</th>
<th>پیمانکار</th>
<th>بانک</th>
<th>مبلغ</th>
<th>تاریخ سررسید</th>
<th>روزهای باقیمانده</th>
<th>وضعیت</th>
</tr>
</thead>
<tbody>
`;
if (expiringSoon.length > 0) {
expiringSoon.forEach(g => {
const bank = db.banks.find(b => b.id === g.bankId);
const contractor = db.contractors.find(c => c.id === g.contractorId);
const expiryDate = new persianDate(g.expiryDate);
const now = new persianDate();
const daysLeft = expiryDate.diff(now, 'days');
html += `
<tr class="${daysLeft <= 7 ? 'expiration-danger' : 'expiration-warning'}">
<td>${g.number}</td>
<td>${contractor ? contractor.name : 'نامشخص'}</td>
<td>${bank ? `${bank.name} - ${bank.branch}` : 'نامشخص'}</td>
<td>${g.amount.toLocaleString()}</td>
<td>${g.expiryDate}</td>
<td>${daysLeft}</td>
<td><span class="status-badge status-active">فعال</span></td>
</tr>
`;
});
} else {
html += `
<tr>
<td colspan="7" class="text-center">ضمانت‌نامه نزدیک به سررسید وجود ندارد</td>
</tr>
`;
}
html += `
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
`;
document.getElementById('pageContent').innerHTML = html;
// Initialize charts
initStatusChart(statusCounts);
initAmountChart();
}
function initStatusChart(statusCounts) {
const ctx = document.getElementById('statusChart').getContext('2d');
new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['فعال', 'تمدید شده', 'آزاد شده', 'ضبط شده', 'ابطال شده'],
datasets: [{
data: [
statusCounts.active,
statusCounts.renewed,
statusCounts.released,
statusCounts.captured,
statusCounts.cancelled
],
backgroundColor: [
'rgba(46, 204, 113, 0.7)',
'rgba(52, 152, 219, 0.7)',
'rgba(155, 89, 182, 0.7)',
'rgba(241, 196, 15, 0.7)',
'rgba(231, 76, 60, 0.7)'
],
borderColor: [
'rgba(46, 204, 113, 1)',
'rgba(52, 152, 219, 1)',
'rgba(155, 89, 182, 1)',
'rgba(241, 196, 15, 1)',
'rgba(231, 76, 60, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
plugins: {
legend: {
position: 'bottom',
}
}
}
});
}
function initAmountChart() {
const typeAmounts = {};
db.guarantees.forEach(g => {
if (!typeAmounts[g.type]) {
typeAmounts[g.type] = 0;
}
typeAmounts[g.type] += g.amount;
});
const ctx = document.getElementById('amountChart').getContext('2d');
new Chart(ctx, {
type: 'bar',
data: {
labels: Object.keys(typeAmounts),
datasets: [{
label: 'مبلغ (ریال)',
data: Object.values(typeAmounts),
backgroundColor: 'rgba(52, 152, 219, 0.7)',
borderColor: 'rgba(52, 152, 219, 1)',
borderWidth: 1
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true
}
},
plugins: {
legend: {
display: false
}
}
}
});
}
function loadGuarantees() {
let html = `
<div class="row mb-4">
<div class="col-md-6">
<h4>مدیریت ضمانت‌نامه‌ها</h4>
</div>
<div class="col-md-6 text-start">
<button class="btn btn-primary" onclick="showGuaranteeModal()">
<i class="bi bi-plus-circle me-2"></i> اضافه کردن ضمانت‌نامه جدید
</button>
</div>
</div>
<div class="card">
<div class="card-header">
لیست ضمانت‌نامه‌ها
</div>
<div class="card-body">
<div class="row mb-3">
<div class="col-md-4">
<div class="search-box">
<i class="bi bi-search"></i>
<input type="text" class="form-control" id="searchGuarantees" placeholder="جستجوی ضمانت‌نامه...">
</div>
</div>
<div class="col-md-4">
<select class="form-select" id="filterStatus">
<option value="">همه وضعیت‌ها</option>
<option value="active">فعال</option>
<option value="renewed">تمدید شده</option>
<option value="released">آزاد شده</option>
<option value="captured">ضبط شده</option>
<option value="cancelled">ابطال شده</option>
</select>
</div>
<div class="col-md-4">
<select class="form-select" id="filterBank">
<option value="">همه بانک‌ها</option>
${db.banks.map(bank => `<option value="${bank.id}">${bank.name} - ${bank.branch}</option>`).join('')}
</select>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>شماره</th>
<th>نوع</th>
<th>پیمانکار</th>
<th>بانک</th>
<th>مبلغ</th>
<th>تاریخ صدور</th>
<th>تاریخ سررسید</th>
<th>وضعیت</th>
<th>عملیات</th>
</tr>
</thead>
<tbody id="guaranteesTableBody">
${db.guarantees.map(g => {
const bank = db.banks.find(b => b.id === g.bankId);
const contractor = db.contractors.find(c => c.id === g.contractorId);
return `
<tr>
<td>${g.number}</td>
<td>${g.type}</td>
<td>${contractor ? contractor.name : 'نامشخص'}</td>
<td>${bank ? `${bank.name} - ${bank.branch}` : 'نامشخص'}</td>
<td>${g.amount.toLocaleString()}</td>
<td>${g.issueDate}</td>
<td>${g.expiryDate}</td>
<td><span class="status-badge status-${g.status}">${getStatusText(g.status)}</span></td>
<td>
<button class="btn btn-sm btn-outline-primary" onclick="editGuarantee(${g.id})">
<i class="bi bi-pencil"></i>
</button>
<button class="btn btn-sm btn-outline-danger" onclick="deleteGuarantee(${g.id})">
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
`;
}).join('')}
</tbody>
</table>
</div>
<div class="d-flex justify-content-between align-items-center">
<div>
<span>نمایش 1 تا ${db.guarantees.length} از ${db.guarantees.length} مورد</span>
</div>
<nav>
<ul class="pagination">
<li class="page-item disabled">
<a class="page-link" href="#" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
<li class="page-item active"><a class="page-link" href="#">1</a></li>
<li class="page-item disabled">
<a class="page-link" href="#" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
`;
document.getElementById('pageContent').innerHTML = html;
// Set up search and filter functionality
document.getElementById('searchGuarantees').addEventListener('input', filterGuarantees);
document.getElementById('filterStatus').addEventListener('change', filterGuarantees);
document.getElementById('filterBank').addEventListener('change', filterGuarantees);
}
function loadContractors() {
let html = `
<div class="row mb-4">
<div class="col-md-6">
<h4>مدیریت پیمانکاران</h4>
</div>
<div class="col-md-6 text-start">
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#contractorModal" onclick="resetContractorForm()">
<i class="bi bi-plus-circle me-2"></i> اضافه کردن پیمانکار جدید
</button>
</div>
</div>
<div class="card">
<div class="card-header">
لیست پیمانکاران
</div>
<div class="card-body">
<div class="row mb-3">
<div class="col-md-6">
<div class="search-box">
<i class="bi bi-search"></i>
<input type="text" class="form-control" id="searchContractors" placeholder="جستجوی پیمانکار...">
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>نام شرکت</th>
<th>شناسه ملی</th>
<th>کد اقتصادی</th>
<th>مسئول</th>
<th>تلفن</th>
<th>موبایل</th>
<th>عملیات</th>
</tr>
</thead>
<tbody id="contractorsTableBody">
${db.contractors.map(c => `
<tr>
<td>${c.name}</td>
<td>${c.nationalId || '-'}</td>
<td>${c.economicCode || '-'}</td>
<td>${c.contactPerson || '-'}</td>
<td>${c.phone || '-'}</td>
<td>${c.mobile || '-'}</td>
<td>
<button class="btn btn-sm btn-outline-primary" onclick="editContractor(${c.id})">
<i class="bi bi-pencil"></i>
</button>
<button class="btn btn-sm btn-outline-danger" onclick="deleteContractor(${c.id})">
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
`).join('')}
</tbody>
</table>
</div>
</div>
</div>
`;
document.getElementById('pageContent').innerHTML = html;
// Set up search functionality
document.getElementById('searchContractors').addEventListener('input', function() {
const searchTerm = this.value.toLowerCase();
const rows = document.querySelectorAll('#contractorsTableBody tr');
rows.forEach(row => {
const text = row.textContent.toLowerCase();
row.style.display = text.includes(searchTerm) ? '' : 'none';
});
});
}
function loadBanks() {
let html = `
<div class="row mb-4">
<div class="col-md-6">
<h4>مدیریت بانک‌ها و شعب</h4>
</div>
<div class="col-md-6 text-start">
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#bankModal" onclick="resetBankForm()">
<i class="bi bi-plus-circle me-2"></i> اضافه کردن بانک/شعبه جدید
</button>
</div>
</div>
<div class="card">
<div class="card-header">
لیست بانک‌ها و شعب
</div>
<div class="card-body">
<div class="row mb-3">
<div class="col-md-6">
<div class="search-box">
<i class="bi bi-search"></i>
<input type="text" class="form-control" id="searchBanks" placeholder="جستجوی بانک...">
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>نام بانک</th>
<th>نام شعبه</th>
<th>کد شعبه</th>
<th>تلفن</th>
<th>عملیات</th>
</tr>
</thead>
<tbody id="banksTableBody">
${db.banks.map(b => `
<tr>
<td>${b.name}</td>
<td>${b.branch}</td>
<td>${b.code || '-'}</td>
<td>${b.phone || '-'}</td>
<td>
<button class="btn btn-sm btn-outline-primary" onclick="editBank(${b.id})">
<i class="bi bi-pencil"></i>
</button>
<button class="btn btn-sm btn-outline-danger" onclick="deleteBank(${b.id})">
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
`).join('')}
</tbody>
</table>
</div>
</div>
</div>
`;
document.getElementById('pageContent').innerHTML = html;
// Set up search functionality
document.getElementById('searchBanks').addEventListener('input', function() {
const searchTerm = this.value.toLowerCase();
const rows = document.querySelectorAll('#banksTableBody tr');
rows.forEach(row => {
const text = row.textContent.toLowerCase();
row.style.display = text.includes(searchTerm) ? '' : 'none';
});
});
}
function loadReports() {
let html = `
<div class="row mb-4">
<div class="col-md-12">
<h4>گزارش‌ها</h4>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6">
<div class="card">
<div class="card-header">
گزارش بر اساس وضعیت
</div>
<div class="card-body">
<canvas id="reportStatusChart" width="400" height="300"></canvas>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">
گزارش بر اساس نوع
</div>
<div class="card-body">
<canvas id="reportTypeChart" width="400" height="300"></canvas>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
گزارش کامل ضمانت‌نامه‌ها
<div>
<button class="btn btn-sm btn-outline-success" onclick="exportToExcel()">
<i class="bi bi-file-earmark-excel me-2"></i> اکسل
</button>
<button class="btn btn-sm btn-outline-danger" onclick="exportToPDF()">
<i class="bi bi-file-earmark-pdf me-2"></i> PDF
</button>
</div>
</div>
<div class="card-body">