Files
ylt_diy/templates/index.html

496 lines
27 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>订单日报系统</title>
<link rel="stylesheet" href="/public/static/css/style.css?v=2026071507">
</head>
<body>
<!-- 登录遮罩层 -->
<div id="login-overlay" class="login-overlay">
<div class="login-box">
<h2>订单日报系统</h2>
<p class="login-subtitle">请登录以继续</p>
<form id="login-form" onsubmit="handleLogin(event)">
<div class="form-group">
<label>用户名</label>
<input type="text" id="login-username" placeholder="请输入用户名" value="admin">
</div>
<div class="form-group">
<label>密码</label>
<input type="password" id="login-password" placeholder="请输入密码">
</div>
<button type="submit" class="btn btn-primary btn-block" id="login-btn">登 录</button>
</form>
<p class="login-tip">默认账号admin / 123586</p>
</div>
</div>
<div class="container" id="main-container" style="display: none;">
<div class="header-bar">
<h1>订单日报系统</h1>
<div class="user-info">
<span id="user-display">admin</span>
<button class="btn btn-link" onclick="showChangePasswordModal()">修改密码</button>
<button class="btn btn-link" onclick="handleLogout()">退出登录</button>
</div>
</div>
<div class="tabs">
<button class="tab active" onclick="switchTab('config')">配置管理</button>
<button class="tab" onclick="switchTab('generate')">日报生成</button>
<button class="tab" onclick="switchTab('history')">历史记录</button>
<button class="tab" onclick="switchTab('sum-data')">求和数据</button>
</div>
<!-- 配置管理 -->
<div id="config-tab" class="tab-content active">
<div class="card">
<button class="btn btn-primary" onclick="showCreateModal()">创建配置</button>
<button class="btn btn-info" onclick="exportConfigs()">导出配置</button>
<button class="btn btn-warning" onclick="downloadTemplate()">下载模板</button>
<button class="btn btn-success" onclick="document.getElementById('import-config-file').click()">导入配置</button>
<input type="file" id="import-config-file" accept=".xlsx,.xls" style="display: none;" onchange="importConfigs(event)">
</div>
<div class="card">
<table>
<thead>
<tr>
<th style="min-width: 60px; width: 60px;">序号</th>
<th>配置名称</th>
<th>拆分方式</th>
<th>拆分值</th>
<th>字段数</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="config-list">
<tr><td colspan="7" class="loading">加载中...</td></tr>
</tbody>
</table>
</div>
</div>
<!-- 日报生成 -->
<div id="generate-tab" class="tab-content">
<div class="card">
<div class="alert alert-info" style="margin-bottom: 20px;">
<strong> 使用说明:</strong><br>
1. 选择已创建的配置(可多选)<br>
2. 选择时间范围(可点击预设按钮快速选择)<br>
3. 点击"生成日报"按钮<br>
4. 生成成功后,点击"立即下载 Excel 文件"按钮下载,或切换到"历史记录"标签页查看和下载
</div>
<h3 style="margin-bottom: 20px;">生成日报</h3>
<div class="form-group">
<label>选择配置(可多选):</label>
<div style="margin-bottom: 10px;">
<button type="button" class="btn btn-sm" onclick="toggleSelectAllConfigs()">全选/取消全选</button>
</div>
<div id="generate-config-list" style="max-height: 300px; overflow-y: auto; border: 1px solid var(--border); border-radius: 6px; padding: 10px;">
<div class="loading">加载中...</div>
</div>
</div>
<div class="form-group">
<label>时间范围:</label>
<div style="display: flex; gap: 10px; align-items: center; flex-wrap: wrap;">
<input type="datetime-local" id="start-time" class="form-control">
<span></span>
<input type="datetime-local" id="end-time" class="form-control">
<button type="button" class="btn btn-sm" onclick="setPresetTime('yesterday')">昨天</button>
<button type="button" class="btn btn-sm" onclick="setPresetTime('last3days')">最近 3 天</button>
<button type="button" class="btn btn-sm" onclick="setPresetTime('last7days')">最近 7 天</button>
</div>
</div>
<button id="generate-btn" class="btn btn-success" onclick="generateReport()">生成日报</button>
<div id="generate-result" style="margin-top: 20px;"></div>
</div>
</div>
<!-- 历史记录 -->
<div id="history-tab" class="tab-content">
<div class="card">
<div style="display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; align-items: center;">
<select id="history-status-filter" class="form-control" style="width: auto;" onchange="onHistoryStatusChange()">
<option value="">全部状态</option>
<option value="1">成功</option>
<option value="0">失败</option>
</select>
<input type="date" id="history-start-date" class="form-control" style="width: auto;">
<span style="line-height: 38px;"></span>
<input type="date" id="history-end-date" class="form-control" style="width: auto;">
<input type="text" id="history-config-name" class="form-control" style="width: 180px;" placeholder="配置名称搜索" autocomplete="off" onkeyup="if(event.key==='Enter') queryHistoryByDate()">
<button class="btn btn-primary" onclick="queryHistoryByDate()">查询</button>
<button class="btn" onclick="clearHistoryFilter()">清除</button>
<div style="margin-left: auto; display: flex; gap: 10px; align-items: center;">
<span style="font-size: 14px; color: #666;">每页显示:</span>
<select id="history-page-size" class="form-control" style="width: auto;" onchange="onHistoryPageSizeChange()">
<option value="10">10条</option>
<option value="20">20条</option>
<option value="50">50条</option>
<option value="100">100条</option>
</select>
</div>
<button class="btn btn-danger" onclick="batchDeleteHistory()">批量删除</button>
<button class="btn btn-success" onclick="batchDownloadHistory()">批量下载</button>
</div>
<table>
<thead>
<tr>
<th><input type="checkbox" id="select-all-history" onchange="toggleSelectAllHistory()"></th>
<th>报表日期</th>
<th>时间范围</th>
<th>配置名称</th>
<th>拆分值</th>
<th>订单数</th>
<th>总电量(kWh)</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="history-list">
<tr><td colspan="9" class="loading">加载中...</td></tr>
</tbody>
</table>
<div id="history-pagination" style="margin-top: 20px; display: flex; justify-content: center; gap: 5px;"></div>
</div>
</div>
<!-- 求和数据 -->
<div id="sum-data-tab" class="tab-content">
<div class="card">
<div style="display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; align-items: center;">
<input type="date" id="sum-data-start-date" class="form-control" style="width: auto;">
<span style="color: #999;"></span>
<input type="date" id="sum-data-end-date" class="form-control" style="width: auto;">
<input type="text" id="sum-data-config-name" class="form-control" style="width: 180px;" placeholder="配置名称搜索" autocomplete="off">
<select id="sum-data-source" class="form-control" style="width: auto;" onchange="loadSumData()">
<option value="">全部来源</option>
<option value="auto">自动采集</option>
<option value="manual">手动编辑</option>
</select>
<button class="btn btn-primary" onclick="loadSumData()">查询</button>
<button class="btn" onclick="clearSumDataQuery()">清除</button>
<button class="btn btn-success" onclick="showAddSumDataModal()">手动添加</button>
<button class="btn btn-warning" onclick="collectSumDataFromHistory()">从历史采集</button>
<button class="btn btn-info" onclick="exportSumData()">导出</button>
<button class="btn btn-secondary" onclick="showSumDataConfigModal()">全局配置</button>
<button class="btn btn-danger" onclick="batchDeleteSumData()" style="margin-left: auto;">批量删除</button>
</div>
<div style="overflow-x: auto;">
<table id="sum-data-table">
<thead>
<tr>
<th style="min-width: 40px;"><input type="checkbox" id="select-all-sum-data" onchange="toggleSelectAllSumData()"></th>
<th style="min-width: 110px;">报表日期</th>
<th style="min-width: 100px;">配置名称</th>
<th style="min-width: 120px;">拆分值</th>
<th id="th-charge-degree" style="min-width: 120px; background: #eff6ff; color: #1d4ed8;">充电电量(kWh) <span style="font-weight: normal; font-size: 11px;">(必选)</span></th>
<th id="th-total-orders" style="min-width: 80px;">订单数</th>
<th style="min-width: 90px;">数据来源</th>
<th style="min-width: 150px;">修改原因/备注</th>
<th style="min-width: 140px;">操作</th>
</tr>
</thead>
<tbody id="sum-data-list">
<tr><td colspan="12" class="loading">加载中...</td></tr>
</tbody>
</table>
</div>
<div id="sum-data-pagination" style="margin-top: 20px; display: flex; justify-content: center; gap: 5px;"></div>
</div>
</div>
</div>
<!-- 创建/编辑配置模态框 -->
<div id="config-modal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2 id="modal-title">创建配置</h2>
<div style="display: flex; align-items: center; gap: 10px;">
<button class="btn btn-sm" onclick="closeModal()">取消</button>
<button class="btn btn-sm btn-primary" onclick="saveConfig()">保存</button>
<button class="close-btn" onclick="closeModal()">&times;</button>
</div>
</div>
<div class="modal-body">
<input type="hidden" id="config-id">
<div class="form-group">
<label>配置名称:</label>
<input type="text" id="config-name" class="form-control" placeholder="例如108 路日报" autocomplete="off">
</div>
<div class="form-group">
<label>拆分方式:</label>
<select id="split-type" class="form-control" onchange="onSplitTypeChange()">
<option value="company_id">按企业</option>
<option value="user_id">按用户</option>
<option value="station_id">按场站</option>
</select>
</div>
<div class="form-group">
<label id="split-value-label">选择企业(可多选):</label>
<div style="margin-bottom: 10px;">
<input type="text" id="entity-search" class="form-control" placeholder="搜索..." onkeyup="handleSearchEnter(event)" style="width: 200px; display: inline-block;" autocomplete="off">
<button type="button" class="btn btn-sm" onclick="searchEntities()" style="display: inline-block;">搜索</button>
<button type="button" class="btn btn-sm" onclick="toggleSelectAllEntities()" style="display: inline-block;">全选/取消全选</button>
<span id="selected-count" style="margin-left: 10px; color: var(--muted-foreground);">已选0 个</span>
</div>
<div id="entity-list" style="max-height: 300px; overflow-y: auto; border: 1px solid var(--border); border-radius: 6px; padding: 10px;">
<div class="loading">加载中...</div>
</div>
<div id="entity-pagination" style="margin-top: 10px; text-align: center;"></div>
</div>
<div class="form-group">
<label>选择字段:</label>
<div id="field-list" style="max-height: 400px; overflow-y: auto; border: 1px solid var(--border); border-radius: 6px; padding: 10px;">
<div class="loading">加载中...</div>
</div>
</div>
<div class="form-group" id="field-order-section" style="display: none;">
<label>字段顺序(上移/下移调整):</label>
<div id="selected-fields-order" style="border: 1px solid var(--border); border-radius: 6px; padding: 10px; min-height: 50px;">
<div class="empty">请先选择字段</div>
</div>
</div>
<div class="form-group">
<label>求和字段(仅数值类型字段):</label>
<div id="sum-fields-list" style="border: 1px solid var(--border); border-radius: 6px; padding: 10px; min-height: 50px;">
<div class="empty">请先选择字段,数值类型字段将显示在此处</div>
</div>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="merge-telecom" onchange="toggleTelecomVehicleNo()">
合并特来电平台数据
</label>
</div>
<div class="form-group" id="telecom-vehicle-section" style="display: none;">
<label>特来电车量自编号(多个用逗号分隔):</label>
<input type="text" id="telecom-vehicle-no" class="form-control" placeholder="例如:车 001,车 002" autocomplete="off">
</div>
<div class="form-group">
<label>自定义服务费单价(元/kWh</label>
<input type="number" id="custom-service-fee-price" class="form-control" step="0.0001" placeholder="留空则不启用,设置后按充电电量×单价计算自定义服务费" style="width: 200px;">
</div>
<div class="form-group">
<label>自定义服务费表头名称:</label>
<input type="text" id="custom-service-fee-name" class="form-control" placeholder="留空则使用默认名称(如:自定义服务费(0.8元/kWh)" style="width: 300px;" autocomplete="off">
</div>
<div class="form-group">
<label>
<input type="checkbox" id="show-custom-service-fee" class="inline-checkbox" onchange="onVirtualFieldToggle(this)">
在报表中显示自定义服务费字段
</label>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="show-total-amount" class="inline-checkbox" onchange="onVirtualFieldToggle(this)">
在报表中显示实收总金额字段(实收电费+自定义服务费)
</label>
</div>
<div class="form-group">
<label>实收总金额表头名称:</label>
<input type="text" id="total-amount-name" class="form-control" placeholder="留空则使用默认名称(实收总金额)" style="width: 300px;" autocomplete="off">
</div>
<div class="form-group">
<label>分时段电量统计:</label>
<div id="time-period-editor">
<div style="margin-bottom: 10px;">
<button type="button" class="btn btn-sm" onclick="clearTimePeriods()">清空</button>
<button type="button" class="btn btn-sm" onclick="setDefaultTimePeriods()">默认配置</button>
</div>
<div id="tp-hours-row" style="display: grid; grid-template-columns: 60px repeat(24, 1fr); gap: 2px; margin-bottom: 10px;"></div>
<div id="tp-period-rows"></div>
<div class="time-period-summary" id="time-period-summary"></div>
</div>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="show-monthly-total">
报表底部显示当月充电量累计总计(数据来源于求和采集表,对账后数据)
</label>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="balance-electricity" checked>
找平电量(当尖+峰+平+谷之和不等于充电电量时,以充电电量为准,将差额按 谷→平→峰→尖 的顺序加到对应时段上)
</label>
</div>
</div>
<div class="modal-footer">
<button class="btn" onclick="closeModal()">取消</button>
<button class="btn btn-primary" onclick="saveConfig()">保存</button>
</div>
</div>
</div>
<!-- 求和数据全局配置模态框 -->
<div id="sum-data-config-modal" class="modal">
<div class="modal-content" style="max-width: 500px;">
<div class="modal-header">
<h2>求和数据全局配置</h2>
<button class="close-btn" onclick="closeSumDataConfigModal()">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>采集字段(勾选后将在求和数据页面显示和采集,充电电量始终采集):</label>
<div id="sum-data-config-fields-list" style="border: 1px solid var(--border); border-radius: 6px; padding: 10px; min-height: 100px; max-height: 300px; overflow-y: auto;">
<div class="loading">加载中...</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn" onclick="closeSumDataConfigModal()">取消</button>
<button class="btn btn-primary" onclick="saveSumDataConfig()">保存</button>
</div>
</div>
</div>
<!-- 添加/编辑求和数据模态框 -->
<div id="sum-data-modal" class="modal">
<div class="modal-content" style="max-width: 600px;">
<div class="modal-header">
<h2 id="sum-data-modal-title">添加求和数据</h2>
<button class="close-btn" onclick="closeSumDataModal()">&times;</button>
</div>
<div class="modal-body">
<input type="hidden" id="sum-data-id">
<div class="form-group">
<label>报表日期:</label>
<input type="date" id="sum-data-report-date-input" class="form-control">
</div>
<div class="form-group">
<label>配置名称:</label>
<input type="text" id="sum-data-config-name-input" class="form-control" placeholder="请输入配置名称" autocomplete="off">
</div>
<div class="form-group">
<label>拆分方式:</label>
<select id="sum-data-split-type-input" class="form-control">
<option value="company_id">按企业</option>
<option value="user_id">按用户</option>
<option value="station_id">按场站</option>
</select>
</div>
<div class="form-group">
<label>拆分值:</label>
<input type="text" id="sum-data-split-value-input" class="form-control" placeholder="请输入拆分值" autocomplete="off">
</div>
<div class="form-group">
<label>拆分显示名称:</label>
<input type="text" id="sum-data-split-name-input" class="form-control" placeholder="请输入拆分显示名称" autocomplete="off">
</div>
<div class="form-group">
<label>求和字段值:</label>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
<div class="form-group" style="margin-bottom: 0;">
<label>充电电量(kWh) <span style="color: #dc3545;">*</span></label>
<input type="number" step="0.001" id="sum-data-charge-degree-input" class="form-control" placeholder="充电电量">
</div>
<div class="form-group" style="margin-bottom: 0;">
<label>尖时电量(kWh)</label>
<input type="number" step="0.001" id="sum-data-peak-degree-input" class="form-control" placeholder="尖时电量">
</div>
<div class="form-group" style="margin-bottom: 0;">
<label>峰时电量(kWh)</label>
<input type="number" step="0.001" id="sum-data-peak-time-input" class="form-control" placeholder="峰时电量">
</div>
<div class="form-group" style="margin-bottom: 0;">
<label>平时电量(kWh)</label>
<input type="number" step="0.001" id="sum-data-normal-time-input" class="form-control" placeholder="平时电量">
</div>
<div class="form-group" style="margin-bottom: 0;">
<label>谷时电量(kWh)</label>
<input type="number" step="0.001" id="sum-data-valley-time-input" class="form-control" placeholder="谷时电量">
</div>
</div>
</div>
<div class="form-group">
<label>订单数:</label>
<input type="number" id="sum-data-total-orders-input" class="form-control" placeholder="请输入订单数" value="0">
</div>
<div class="form-group">
<label>修改原因 <span style="color: red;">*</span></label>
<textarea id="sum-data-remark-input" class="form-control" rows="3" placeholder="请输入修改原因(必填)"></textarea>
</div>
</div>
<div class="modal-footer">
<button class="btn" onclick="closeSumDataModal()">取消</button>
<button class="btn btn-primary" onclick="saveSumData()">保存</button>
</div>
</div>
</div>
<!-- 修改密码弹窗 -->
<div id="change-password-modal" class="modal">
<div class="modal-content" style="max-width: 450px;">
<div class="modal-header">
<h2>修改密码</h2>
<span class="close" onclick="closeChangePasswordModal()">&times;</span>
</div>
<div class="modal-body">
<div class="form-group">
<label>旧密码 <span style="color: red;">*</span></label>
<input type="password" id="old-password" class="form-control" placeholder="请输入旧密码">
</div>
<div class="form-group">
<label>新密码 <span style="color: red;">*</span></label>
<input type="password" id="new-password" class="form-control" placeholder="请输入新密码至少6位">
</div>
<div class="form-group">
<label>确认新密码 <span style="color: red;">*</span></label>
<input type="password" id="confirm-password" class="form-control" placeholder="请再次输入新密码">
</div>
</div>
<div class="modal-footer">
<button class="btn" onclick="closeChangePasswordModal()">取消</button>
<button class="btn btn-primary" onclick="saveChangePassword()">保存</button>
</div>
</div>
</div>
<!-- JavaScript 文件 -->
<script src="/public/static/js/common.js?v=2026072102"></script>
<script src="/public/static/js/config.js?v=2026071507"></script>
<script src="/public/static/js/entity.js?v=2026071507"></script>
<script src="/public/static/js/report.js?v=2026072103"></script>
<script src="/public/static/js/history.js?v=2026072104"></script>
<script src="/public/static/js/sum_data.js?v=2026072103"></script>
</body>
</html>