初始化版本
This commit is contained in:
849
admin.js
Normal file
849
admin.js
Normal file
@@ -0,0 +1,849 @@
|
||||
// 全局变量
|
||||
let fundsData = [];
|
||||
let fundChart = null;
|
||||
|
||||
// 页面加载完成后初始化
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadFundsData();
|
||||
loadOperationLog();
|
||||
populateFundSelector();
|
||||
|
||||
// 表单提交事件
|
||||
document.getElementById('fundForm').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
saveFund();
|
||||
});
|
||||
});
|
||||
|
||||
// 加载推荐基金数据
|
||||
async function loadRecommendedFunds() {
|
||||
try {
|
||||
showLoading();
|
||||
|
||||
const response = await fetch('admin_api.php?action=get_recommended_funds');
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
renderRecommendedFundsTable(result.data);
|
||||
} else {
|
||||
throw new Error(result.message || '加载数据失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载推荐基金数据失败:', error);
|
||||
showMessage('数据加载失败: ' + error.message, 'error');
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染推荐基金表格
|
||||
function renderRecommendedFundsTable(data) {
|
||||
const tbody = document.getElementById('recommendedFundsList');
|
||||
|
||||
if (!data || data.length === 0) {
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="7" style="text-align: center; padding: 40px; color: var(--gray);">
|
||||
<i class="fas fa-inbox" style="font-size: 3rem; margin-bottom: 10px; display: block; opacity: 0.5;"></i>
|
||||
暂无推荐基金数据
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '';
|
||||
data.forEach((fund, index) => {
|
||||
// 处理状态显示,支持多种可能的状态值
|
||||
const getStatusText = (status) => {
|
||||
const normalizedStatus = (status || '').toLowerCase().trim();
|
||||
if (normalizedStatus.includes('approve') || normalizedStatus === '已批准') {
|
||||
return '已批准';
|
||||
} else if (normalizedStatus.includes('pend') || normalizedStatus === '待审核') {
|
||||
return '待审核';
|
||||
} else if (normalizedStatus.includes('reject') || normalizedStatus === '已拒绝') {
|
||||
return '已拒绝';
|
||||
}
|
||||
return '未知';
|
||||
};
|
||||
|
||||
const getStatusClass = (status) => {
|
||||
const normalizedStatus = (status || '').toLowerCase().trim();
|
||||
if (normalizedStatus.includes('approve') || normalizedStatus === '已批准') {
|
||||
return 'status-approved';
|
||||
} else if (normalizedStatus.includes('pend') || normalizedStatus === '待审核') {
|
||||
return 'status-pending';
|
||||
} else if (normalizedStatus.includes('reject') || normalizedStatus === '已拒绝') {
|
||||
return 'status-rejected';
|
||||
}
|
||||
return 'status-unknown';
|
||||
};
|
||||
|
||||
const statusText = getStatusText(fund.status);
|
||||
const statusClass = getStatusClass(fund.status);
|
||||
|
||||
// 根据状态决定操作按钮
|
||||
let actionButtons = '';
|
||||
if (fund.status === 'pending') {
|
||||
actionButtons = `
|
||||
<button class="btn btn-primary btn-sm" onclick="approveRecommendedFund('${fund.fund_code}')">
|
||||
<i class="fas fa-check"></i> 批准
|
||||
</button>
|
||||
<button class="btn btn-danger btn-sm" onclick="deleteRecommendedFund('${fund.fund_code}')">
|
||||
<i class="fas fa-trash"></i> 删除
|
||||
</button>
|
||||
`;
|
||||
} else {
|
||||
// 已批准或已拒绝状态只显示删除按钮
|
||||
actionButtons = `
|
||||
<button class="btn btn-danger btn-sm" onclick="deleteRecommendedFund('${fund.fund_code}')">
|
||||
<i class="fas fa-trash"></i> 删除
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
|
||||
html += `
|
||||
<tr class="fund-row">
|
||||
<td class="fund-code-cell"><strong>${fund.fund_code}</strong></td>
|
||||
<td class="fund-ip-cell">${fund.ip}</td>
|
||||
<td class="fund-time-cell">${fund.timestamp}</td>
|
||||
<td class="fund-channel-cell">${fund.channel}</td>
|
||||
<td class="fund-amount-cell">${parseFloat(fund.amount).toFixed(2)}</td>
|
||||
<td class="fund-status-cell">
|
||||
<span class="status-badge ${statusClass}">
|
||||
${statusText}
|
||||
</span>
|
||||
</td>
|
||||
<td class="fund-actions-cell">
|
||||
<div class="action-buttons">
|
||||
${actionButtons}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
tbody.innerHTML = html;
|
||||
}
|
||||
|
||||
// 搜索推荐基金
|
||||
function searchRecommendedFunds(keyword) {
|
||||
const rows = document.querySelectorAll('#recommendedFundsList tr');
|
||||
keyword = keyword.toLowerCase();
|
||||
|
||||
rows.forEach(row => {
|
||||
const fundCode = row.querySelector('td:first-child').textContent.toLowerCase();
|
||||
if (fundCode.includes(keyword)) {
|
||||
row.style.display = '';
|
||||
} else {
|
||||
row.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 批准推荐基金
|
||||
async function approveRecommendedFund(fundCode) {
|
||||
if (!confirm(`确定要批准基金 ${fundCode} 吗?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
showLoading();
|
||||
|
||||
const response = await fetch('admin_api.php?action=approve_recommended_fund&fund_code=' + fundCode);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showMessage('基金批准成功', 'success');
|
||||
loadRecommendedFunds();
|
||||
} else {
|
||||
throw new Error(result.message || '操作失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('批准推荐基金失败:', error);
|
||||
showMessage('操作失败: ' + error.message, 'error');
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
// 删除推荐基金
|
||||
async function deleteRecommendedFund(fundCode) {
|
||||
if (!confirm(`确定要删除推荐基金 ${fundCode} 吗?此操作不可恢复。`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
showLoading();
|
||||
|
||||
const response = await fetch('admin_api.php?action=delete_recommended_fund&fund_code=' + fundCode);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showMessage('基金删除成功', 'success');
|
||||
loadRecommendedFunds();
|
||||
} else {
|
||||
throw new Error(result.message || '操作失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除推荐基金失败:', error);
|
||||
showMessage('操作失败: ' + error.message, 'error');
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
// 切换标签页
|
||||
function switchTab(tabName) {
|
||||
// 隐藏所有标签内容
|
||||
document.querySelectorAll('.tab-content').forEach(tab => {
|
||||
tab.classList.remove('active');
|
||||
});
|
||||
|
||||
// 移除所有标签的激活状态
|
||||
document.querySelectorAll('.tab').forEach(tab => {
|
||||
tab.classList.remove('active');
|
||||
});
|
||||
|
||||
// 显示选中的标签内容
|
||||
document.getElementById(tabName).classList.add('active');
|
||||
|
||||
// 激活选中的标签
|
||||
event.target.classList.add('active');
|
||||
|
||||
// 如果是图表标签,加载默认图表
|
||||
if (tabName === 'fundCharts') {
|
||||
const fundSelector = document.getElementById('fundSelector');
|
||||
if (fundSelector.value) {
|
||||
loadFundChart(fundSelector.value);
|
||||
}
|
||||
} else if (tabName === 'recommendedFunds') {
|
||||
// 加载推荐基金数据
|
||||
loadRecommendedFunds();
|
||||
|
||||
// 添加搜索事件监听
|
||||
const searchInput = document.getElementById('searchRecommendedFund');
|
||||
searchInput.oninput = function() {
|
||||
searchRecommendedFunds(this.value);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 加载基金数据
|
||||
async function loadFundsData() {
|
||||
try {
|
||||
showLoading();
|
||||
|
||||
const response = await fetch('admin_api.php?action=get_funds');
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
fundsData = result.data;
|
||||
renderFundsTable();
|
||||
populateFundSelector();
|
||||
} else {
|
||||
throw new Error(result.message || '加载数据失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载基金数据失败:', error);
|
||||
showMessage('数据加载失败: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染基金表格
|
||||
function renderFundsTable() {
|
||||
const tbody = document.getElementById('fundsTableBody');
|
||||
|
||||
if (fundsData.length === 0) {
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="5" style="text-align: center; padding: 40px; color: var(--gray);">
|
||||
<i class="fas fa-inbox" style="font-size: 3rem; margin-bottom: 10px; display: block; opacity: 0.5;"></i>
|
||||
暂无基金数据,点击"添加基金"开始配置
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '';
|
||||
fundsData.forEach((fund, index) => {
|
||||
const channelName = getChannelName(fund.channel);
|
||||
const channelClass = getChannelClass(fund.channel);
|
||||
|
||||
html += `
|
||||
<tr>
|
||||
<td><strong>${fund.fund_code}</strong></td>
|
||||
<td>${fund.name || '加载中...'}</td>
|
||||
<td>
|
||||
<span class="channel-badge ${channelClass}">
|
||||
${getChannelIcon(fund.channel)} ${channelName}
|
||||
</span>
|
||||
</td>
|
||||
<td>${parseFloat(fund.investment).toFixed(2)}</td>
|
||||
<td>
|
||||
<div class="action-buttons">
|
||||
<button class="btn btn-outline btn-sm" onclick="editFund(${index})">
|
||||
<i class="fas fa-edit"></i> 编辑
|
||||
</button>
|
||||
<button class="btn btn-danger btn-sm" onclick="deleteFund(${index})">
|
||||
<i class="fas fa-trash"></i> 删除
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
tbody.innerHTML = html;
|
||||
|
||||
// 加载基金名称
|
||||
loadFundNames();
|
||||
}
|
||||
|
||||
// 加载基金名称
|
||||
async function loadFundNames() {
|
||||
const nameCells = document.querySelectorAll('#fundsTableBody td:nth-child(2)');
|
||||
|
||||
// 先尝试从localStorage获取缓存的基金名称
|
||||
const fundNameCache = JSON.parse(localStorage.getItem('fundNameCache') || '{}');
|
||||
|
||||
// 收集所有需要获取名称的基金代码
|
||||
const fundsWithoutNames = fundsData.filter(fund => !fund.name && !fundNameCache[fund.fund_code]);
|
||||
|
||||
// 先应用缓存的名称
|
||||
fundsData.forEach((fund, index) => {
|
||||
if (fundNameCache[fund.fund_code]) {
|
||||
nameCells[index].textContent = fundNameCache[fund.fund_code];
|
||||
fundsData[index].name = fundNameCache[fund.fund_code];
|
||||
}
|
||||
});
|
||||
|
||||
// 如果有需要获取名称的基金,通过服务器端代理获取
|
||||
if (fundsWithoutNames.length > 0) {
|
||||
try {
|
||||
const fundCodes = fundsWithoutNames.map(fund => fund.fund_code).join(',');
|
||||
const response = await fetch(`admin_api.php?action=get_fund_names&fund_codes=${fundCodes}`);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success && result.data) {
|
||||
// 更新页面显示和缓存
|
||||
fundsData.forEach((fund, index) => {
|
||||
if (result.data[fund.fund_code]) {
|
||||
const fundName = result.data[fund.fund_code];
|
||||
nameCells[index].textContent = fundName;
|
||||
fundsData[index].name = fundName;
|
||||
fundNameCache[fund.fund_code] = fundName;
|
||||
}
|
||||
});
|
||||
|
||||
// 保存缓存
|
||||
localStorage.setItem('fundNameCache', JSON.stringify(fundNameCache));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取基金名称失败:', error);
|
||||
// 即使失败也给每个基金一个默认名称
|
||||
fundsData.forEach((fund, index) => {
|
||||
if (!fund.name && !fundNameCache[fund.fund_code]) {
|
||||
nameCells[index].textContent = `基金${fund.fund_code}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 填充基金选择器
|
||||
function populateFundSelector() {
|
||||
const selector = document.getElementById('fundSelector');
|
||||
selector.innerHTML = '<option value="">请选择基金</option>';
|
||||
|
||||
fundsData.forEach(fund => {
|
||||
const option = document.createElement('option');
|
||||
option.value = fund.fund_code;
|
||||
option.textContent = `${fund.fund_code} - ${fund.name || '加载中...'}`;
|
||||
selector.appendChild(option);
|
||||
});
|
||||
}
|
||||
|
||||
// 加载操作日志
|
||||
async function loadOperationLog() {
|
||||
try {
|
||||
const response = await fetch('admin_api.php?action=get_operation_log&limit=50');
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
renderOperationLog(result.data);
|
||||
} else {
|
||||
throw new Error(result.message || '加载操作日志失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载操作日志失败:', error);
|
||||
document.getElementById('operationLogContent').innerHTML = `
|
||||
<div style="text-align: center; padding: 40px; color: var(--gray);">
|
||||
<i class="fas fa-exclamation-triangle"></i> 加载操作日志失败: ${error.message}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染操作日志
|
||||
function renderOperationLog(operations) {
|
||||
const container = document.getElementById('operationLogContent');
|
||||
|
||||
if (operations.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div style="text-align: center; padding: 40px; color: var(--gray);">
|
||||
<i class="fas fa-inbox"></i> 暂无操作记录
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '';
|
||||
operations.forEach(operation => {
|
||||
const typeClass = `type-${operation.type}`;
|
||||
const typeText = {
|
||||
'add': '添加',
|
||||
'update': '更新',
|
||||
'delete': '删除'
|
||||
}[operation.type] || operation.type;
|
||||
|
||||
const channelName = getChannelName(operation.channel);
|
||||
|
||||
html += `
|
||||
<div class="operation-item">
|
||||
<div class="operation-details">
|
||||
<span class="operation-type ${typeClass}">${typeText}</span>
|
||||
<strong>${operation.fund_code}</strong>
|
||||
${operation.channel ? ` - ${channelName}` : ''}
|
||||
${operation.investment ? ` - ${operation.investment}元` : ''}
|
||||
${operation.details ? ` - ${operation.details}` : ''}
|
||||
</div>
|
||||
<div class="operation-time">${formatTime(operation.date)}</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
// 加载基金图表
|
||||
async function loadFundChart(fundCode) {
|
||||
if (!fundCode) {
|
||||
document.getElementById('chartTitle').textContent = '请选择基金查看净值变化';
|
||||
if (fundChart) {
|
||||
fundChart.destroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`api.php?action=get_fund_chart&fund_code=${fundCode}`);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
renderFundChart(fundCode, result.data);
|
||||
} else {
|
||||
throw new Error(result.message || '加载图表数据失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载基金图表失败:', error);
|
||||
document.getElementById('chartTitle').textContent = `加载图表失败: ${error.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染基金图表
|
||||
function renderFundChart(fundCode, chartData) {
|
||||
const ctx = document.getElementById('fundChart').getContext('2d');
|
||||
const fundName = fundsData.find(f => f.fund_code === fundCode)?.name || fundCode;
|
||||
|
||||
document.getElementById('chartTitle').textContent = `${fundName} - 近5日净值变化`;
|
||||
|
||||
// 销毁现有图表
|
||||
if (fundChart) {
|
||||
fundChart.destroy();
|
||||
}
|
||||
|
||||
// 创建新图表
|
||||
fundChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: chartData.labels,
|
||||
datasets: [
|
||||
{
|
||||
label: '估算净值',
|
||||
data: chartData.netValues,
|
||||
borderColor: '#6366f1',
|
||||
backgroundColor: 'rgba(99, 102, 241, 0.2)',
|
||||
borderWidth: 3,
|
||||
fill: true,
|
||||
tension: 1, // 最大张力,使曲线更平滑
|
||||
pointRadius: 5,
|
||||
pointHoverRadius: 8,
|
||||
pointBackgroundColor: '#ffffff',
|
||||
pointBorderColor: '#6366f1',
|
||||
pointBorderWidth: 2,
|
||||
pointHoverBackgroundColor: '#6366f1',
|
||||
pointHoverBorderColor: '#ffffff',
|
||||
pointHoverBorderWidth: 2
|
||||
},
|
||||
{
|
||||
label: '涨跌幅 (%)',
|
||||
data: chartData.changes,
|
||||
borderColor: '#10b981',
|
||||
backgroundColor: 'rgba(16, 185, 129, 0.2)',
|
||||
borderWidth: 3,
|
||||
fill: false,
|
||||
tension: 1, // 最大张力,使曲线更平滑
|
||||
pointRadius: 5,
|
||||
pointHoverRadius: 8,
|
||||
pointBackgroundColor: '#ffffff',
|
||||
pointBorderColor: '#10b981',
|
||||
pointBorderWidth: 2,
|
||||
pointHoverBackgroundColor: '#10b981',
|
||||
pointHoverBorderColor: '#ffffff',
|
||||
pointHoverBorderWidth: 2,
|
||||
yAxisID: 'y1'
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
interaction: {
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
axis: 'x'
|
||||
},
|
||||
animation: {
|
||||
duration: 1500,
|
||||
easing: 'easeInOutQuart'
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
grid: {
|
||||
display: false
|
||||
},
|
||||
ticks: {
|
||||
font: {
|
||||
size: 12
|
||||
}
|
||||
}
|
||||
},
|
||||
y: {
|
||||
type: 'linear',
|
||||
display: true,
|
||||
position: 'left',
|
||||
title: {
|
||||
display: true,
|
||||
text: '估算净值',
|
||||
font: {
|
||||
size: 14,
|
||||
weight: 'bold'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
color: 'rgba(0, 0, 0, 0.05)'
|
||||
},
|
||||
ticks: {
|
||||
font: {
|
||||
size: 11
|
||||
},
|
||||
callback: function(value) {
|
||||
return value.toFixed(4);
|
||||
}
|
||||
}
|
||||
},
|
||||
y1: {
|
||||
type: 'linear',
|
||||
display: true,
|
||||
position: 'right',
|
||||
title: {
|
||||
display: true,
|
||||
text: '涨跌幅 (%)',
|
||||
font: {
|
||||
size: 14,
|
||||
weight: 'bold'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
drawOnChartArea: false,
|
||||
},
|
||||
ticks: {
|
||||
font: {
|
||||
size: 11
|
||||
},
|
||||
callback: function(value) {
|
||||
return value > 0 ? '+' + value.toFixed(2) + '%' : value.toFixed(2) + '%';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'top',
|
||||
labels: {
|
||||
usePointStyle: true,
|
||||
padding: 20,
|
||||
font: {
|
||||
size: 13
|
||||
}
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
||||
padding: 12,
|
||||
titleFont: {
|
||||
size: 14,
|
||||
weight: 'bold'
|
||||
},
|
||||
bodyFont: {
|
||||
size: 13
|
||||
},
|
||||
borderColor: '#6366f1',
|
||||
borderWidth: 1,
|
||||
displayColors: true,
|
||||
callbacks: {
|
||||
title: function(tooltipItems) {
|
||||
return tooltipItems[0].label;
|
||||
},
|
||||
label: function(context) {
|
||||
let label = context.dataset.label || '';
|
||||
if (label) {
|
||||
label += ': ';
|
||||
}
|
||||
if (context.datasetIndex === 0) {
|
||||
label += context.parsed.y.toFixed(4);
|
||||
} else {
|
||||
const value = context.parsed.y;
|
||||
label += (value > 0 ? '+' : '') + value.toFixed(2) + '%';
|
||||
}
|
||||
return label;
|
||||
},
|
||||
afterBody: function(context) {
|
||||
// 添加额外信息或空行以美化显示
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 显示添加模态框
|
||||
function showAddModal() {
|
||||
document.getElementById('modalTitle').textContent = '添加基金';
|
||||
document.getElementById('fundForm').reset();
|
||||
document.getElementById('editIndex').value = '';
|
||||
document.getElementById('fundModal').style.display = 'flex';
|
||||
}
|
||||
|
||||
// 编辑基金
|
||||
function editFund(index) {
|
||||
const fund = fundsData[index];
|
||||
|
||||
document.getElementById('modalTitle').textContent = '编辑基金';
|
||||
document.getElementById('fundCode').value = fund.fund_code;
|
||||
document.getElementById('channel').value = fund.channel;
|
||||
document.getElementById('investment').value = fund.investment;
|
||||
document.getElementById('editIndex').value = index;
|
||||
|
||||
document.getElementById('fundModal').style.display = 'flex';
|
||||
}
|
||||
|
||||
// 关闭模态框
|
||||
function closeModal() {
|
||||
document.getElementById('fundModal').style.display = 'none';
|
||||
}
|
||||
|
||||
// 保存基金
|
||||
async function saveFund() {
|
||||
const editIndex = document.getElementById('editIndex').value;
|
||||
const fundCode = document.getElementById('fundCode').value.trim();
|
||||
const channel = document.getElementById('channel').value;
|
||||
const investment = parseFloat(document.getElementById('investment').value);
|
||||
|
||||
// 验证表单数据
|
||||
if (!fundCode) {
|
||||
showMessage('请输入基金代码', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!/^\d{6}$/.test(fundCode)) {
|
||||
showMessage('基金代码必须是6位数字', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel) {
|
||||
showMessage('请选择渠道', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!investment || investment <= 0) {
|
||||
showMessage('投资金额必须大于0', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查重复(添加时检查,编辑时不检查自身)
|
||||
if (editIndex === '' || fundsData[editIndex].fund_code !== fundCode) {
|
||||
const exists = fundsData.some((fund, index) =>
|
||||
fund.fund_code === fundCode && fund.channel === channel &&
|
||||
(editIndex === '' || index !== parseInt(editIndex))
|
||||
);
|
||||
|
||||
if (exists) {
|
||||
showMessage('该渠道下已存在相同的基金代码', 'error');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const action = editIndex === '' ? 'add_fund' : 'update_fund';
|
||||
const payload = {
|
||||
fund_code: fundCode,
|
||||
channel: channel,
|
||||
investment: investment
|
||||
};
|
||||
|
||||
if (editIndex !== '') {
|
||||
payload.index = parseInt(editIndex);
|
||||
}
|
||||
|
||||
console.log('发送请求:', action, payload);
|
||||
|
||||
const response = await fetch('admin_api.php?action=' + action, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
console.log('响应结果:', result);
|
||||
|
||||
if (result.success) {
|
||||
showMessage(result.message, 'success');
|
||||
closeModal();
|
||||
loadFundsData();
|
||||
loadOperationLog(); // 刷新操作日志
|
||||
} else {
|
||||
throw new Error(result.message || '保存失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存基金失败:', error);
|
||||
showMessage('保存失败: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 删除基金
|
||||
async function deleteFund(index) {
|
||||
if (!confirm('确定要删除这只基金吗?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('admin_api.php?action=delete_fund', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ index: index })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showMessage(result.message, 'success');
|
||||
loadFundsData();
|
||||
loadOperationLog(); // 刷新操作日志
|
||||
} else {
|
||||
throw new Error(result.message || '删除失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除基金失败:', error);
|
||||
showMessage('删除失败: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 工具函数
|
||||
function getChannelName(channel) {
|
||||
const channels = {
|
||||
'0': '招商银行',
|
||||
'1': '天天基金',
|
||||
'2': '支付宝'
|
||||
};
|
||||
return channels[channel] || '未知渠道';
|
||||
}
|
||||
|
||||
function getChannelClass(channel) {
|
||||
const classMap = {
|
||||
'0': 'channel-cmb',
|
||||
'1': 'channel-tt',
|
||||
'2': 'channel-zfb'
|
||||
};
|
||||
return classMap[channel] || 'channel-cmb';
|
||||
}
|
||||
|
||||
function getChannelIcon(channel) {
|
||||
const iconMap = {
|
||||
'0': '🏦',
|
||||
'1': '📱',
|
||||
'2': '💙'
|
||||
};
|
||||
return iconMap[channel] || '🏦';
|
||||
}
|
||||
|
||||
// 显示消息
|
||||
function showMessage(message, type) {
|
||||
const messageEl = document.getElementById('message');
|
||||
messageEl.textContent = message;
|
||||
messageEl.className = `alert alert-${type === 'success' ? 'success' : 'error'}`;
|
||||
messageEl.style.display = 'block';
|
||||
|
||||
// 自动隐藏成功消息,错误消息保持显示直到用户操作
|
||||
if (type === 'success') {
|
||||
setTimeout(() => {
|
||||
messageEl.style.display = 'none';
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
// 显示加载状态
|
||||
function showLoading() {
|
||||
const tbody = document.getElementById('fundsTableBody');
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="5" style="text-align: center; padding: 40px; color: var(--gray);">
|
||||
<div style="display: inline-block; width: 20px; height: 20px; border: 2px solid #f3f3f3; border-top: 2px solid var(--primary); border-radius: 50%; animation: spin 1s linear infinite;"></div>
|
||||
加载中...
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
|
||||
// 格式化时间
|
||||
function formatTime(dateString) {
|
||||
const date = new Date(dateString);
|
||||
const now = new Date();
|
||||
const diff = now - date;
|
||||
|
||||
if (diff < 60000) {
|
||||
return '刚刚';
|
||||
} else if (diff < 3600000) {
|
||||
return Math.floor(diff / 60000) + '分钟前';
|
||||
} else if (diff < 86400000) {
|
||||
return Math.floor(diff / 3600000) + '小时前';
|
||||
} else {
|
||||
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
|
||||
}
|
||||
}
|
||||
|
||||
// 点击模态框外部关闭
|
||||
window.onclick = function(event) {
|
||||
const modal = document.getElementById('fundModal');
|
||||
if (event.target === modal) {
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user