吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]
查看: 2753|回复: 30
上一主题 下一主题
收起左侧

[其他转载] Deepseek写的工程项目拨付款情况一览表

  [复制链接]
跳转到指定楼层
楼主
hrbbuild 发表于 2025-7-12 07:34 回帖奖励
本帖最后由 hrbbuild 于 2025-7-12 21:01 编辑

Deepseek写的工程项目拨付款情况一览表,适合建设单位或者全过程管理单位掌握对工程项目拨付款情况的统计信息
(2025年7月12日晚修正更新)
使用说明
数据备份:点击"备份数据"按钮将当前数据保存为JSON文件
数据恢复:点击"恢复数据"按钮选择之前备份的JSON文件恢复数据
添加项目:点击"添加项目"按钮创建新项目
数据导出:使用"导出CSV"或"导出XLSX"按钮导出数据
数据验证:系统会自动验证金额输入,并在发现问题时提示
系统会在每次数据变更时自动保存到浏览器的本地存储,同时建议用户定期使用"备份数据"功能将数据保存到本地文件,以防止浏览器数据清理导致数据丢失。

修正更新内容:
1、修正导出CSV时乱码问题
2、增加高级设置功能,可以定制主题、增加自动保存开关。
3、修正选中数据后鼠标任意单击数据会被修改的BUG
4、让Deepseek更新简化完善代码。



工程项目拨付款情况一览表修正版.rar (13.17 KB, 下载次数: 140)

[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>工程项目款批复管理系统</title>
    <script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        /* 新增主题颜色变量 */
        :root {
            --primary: #1a6dcc;
            --primary-dark: #0d4a9e;
            --secondary: #0d9e4a;
            --light-bg: #f8fafd;
            --border: #d1dbe5;
            --text: #333;
            --text-light: #7a8ca5;
            --success: #4caf50;
            --danger: #e53935;
            --warning: #ff9800;
            --header-gradient: linear-gradient(90deg, var(--primary), var(--primary-dark));
            --btn-gradient: linear-gradient(90deg, var(--primary), var(--primary-dark));
            --progress-gradient: linear-gradient(90deg, #4caf50, #2e7d32);
            --alert-header: linear-gradient(90deg, var(--warning), #e65100);
        }
        
        /* 紫色主题 */
        .theme-purple {
            --primary: #7e57c2;
            --primary-dark: #5e35b1;
            --secondary: #ab47bc;
            --btn-gradient: linear-gradient(90deg, #7e57c2, #5e35b1);
            --header-gradient: linear-gradient(90deg, #7e57c2, #5e35b1);
            --progress-gradient: linear-gradient(90deg, #ab47bc, #8e24aa);
            --alert-header: linear-gradient(90deg, #ff7043, #f4511e);
        }
        
        /* 橙色主题 */
        .theme-orange {
            --primary: #ff7043;
            --primary-dark: #f4511e;
            --secondary: #ffa726;
            --btn-gradient: linear-gradient(90deg, #ff7043, #f4511e);
            --header-gradient: linear-gradient(90deg, #ff7043, #f4511e);
            --progress-gradient: linear-gradient(90deg, #ffa726, #fb8c00);
            --alert-header: linear-gradient(90deg, #7e57c2, #5e35b1);
        }
        
        /* 绿色主题 */
        .theme-green {
            --primary: #43a047;
            --primary-dark: #2e7d32;
            --secondary: #7cb342;
            --btn-gradient: linear-gradient(90deg, #43a047, #2e7d32);
            --header-gradient: linear-gradient(90deg, #43a047, #2e7d32);
            --progress-gradient: linear-gradient(90deg, #7cb342, #689f38);
            --alert-header: linear-gradient(90deg, #ff7043, #f4511e);
        }
        
        /* 红色主题 */
        .theme-red {
            --primary: #e53935;
            --primary-dark: #c62828;
            --secondary: #f44336;
            --btn-gradient: linear-gradient(90deg, #e53935, #c62828);
            --header-gradient: linear-gradient(90deg, #e53935, #c62828);
            --progress-gradient: linear-gradient(90deg, #f44336, #d32f2f);
            --alert-header: linear-gradient(90deg, #7e57c2, #5e35b1);
        }
        
        /* 粉色主题 */
        .theme-pink {
            --primary: #ec407a;
            --primary-dark: #d81b60;
            --secondary: #f48fb1;
            --btn-gradient: linear-gradient(90deg, #ec407a, #d81b60);
            --header-gradient: linear-gradient(90deg, #ec407a, #d81b60);
            --progress-gradient: linear-gradient(90deg, #f48fb1, #f06292);
            --alert-header: linear-gradient(90deg, #ff7043, #f4511e);
        }
        
        /* 可调整列宽样式 */
        .resizable-table th {
            position: relative;
        }
        
        .resizer {
            position: absolute;
            top: 0;
            right: 0;
            width: 5px;
            height: 100%;
            background-color: rgba(255, 255, 255, 0.3);
            cursor: col-resize;
            user-select: none;
            z-index: 20;
        }
        
        .resizer:hover, .resizer.active {
            background-color: #fff;
        }
        
        .table-container {
            user-select: none;
        }
        
        .table-container input {
            user-select: auto;
        }

        /* 基础样式 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);
            min-height: 100vh;
            padding: 20px;
            color: var(--text);
            transition: background 0.3s ease;
        }
        
        .container {
            max-width: 1600px;
            margin: 0 auto;
            background-color: white;
            border-radius: 12px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
            overflow: hidden;
            display: flex;
            flex-direction: column;
            height: calc(100vh - 40px);
        }
        
        header {
            background: var(--header-gradient);
            color: white;
            padding: 25px 30px;
            text-align: center;
            position: relative;
        }
        
        h1 {
            font-size: 2.4rem;
            font-weight: 600;
            margin-bottom: 5px;
            letter-spacing: 1px;
            text-shadow: 0 2px 4px rgba(0,0,0,0.2);
        }
        
        .subtitle {
            display: flex;
            align-items: center;
            justify-content: center;
            margin-top: 15px;
            font-size: 1.1rem;
        }
        
        .subtitle input {
            background: rgba(255, 255, 255, 0.15);
            border: 1px solid rgba(255, 255, 255, 0.3);
            border-radius: 4px;
            color: white;
            padding: 8px 15px;
            margin-left: 10px;
            width: 350px;
            font-size: 1.05rem;
            outline: none;
            transition: all 0.3s;
        }
        
        .subtitle input:focus {
            background: rgba(255, 255, 255, 0.25);
            box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.2);
        }
        
        .subtitle input::placeholder {
            color: rgba(255, 255, 255, 0.7);
        }
        
        .controls {
            display: flex;
            justify-content: space-between;
            padding: 15px 30px;
            background-color: var(--light-bg);
            border-bottom: 1px solid var(--border);
            flex-wrap: wrap;
            gap: 15px;
        }
        
        .controls-left, .controls-right {
            display: flex;
            gap: 15px;
            flex-wrap: wrap;
        }
        
        .btn {
            background: var(--btn-gradient);
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 6px;
            font-size: 1rem;
            font-weight: 500;
            cursor: pointer;
            transition: all 0.3s ease;
            display: flex;
            align-items: center;
            gap: 8px;
            box-shadow: 0 4px 10px rgba(26, 109, 204, 0.2);
            min-width: 140px;
            justify-content: center;
        }
        
        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 15px rgba(26, 109, 204, 0.3);
        }
        
        .btn:active {
            transform: translateY(1px);
        }
        
        .btn i {
            font-style: normal;
            font-size: 1.2rem;
        }
        
        .btn.add {
            background: linear-gradient(90deg, var(--secondary), #0a7c3a);
        }
        
        .btn.add:hover {
            box-shadow: 0 6px 15px rgba(13, 158, 74, 0.3);
        }
        
        .btn.export {
            background: linear-gradient(90deg, #ff9800, #f57c00);
        }
        
        .btn.export:hover {
            box-shadow: 0 6px 15px rgba(255, 152, 0, 0.3);
        }
        
        .btn.backup {
            background: linear-gradient(90deg, #9c27b0, #7b1fa2);
        }
        
        .btn.restore {
            background: linear-gradient(90deg, #00bcd4, #0097a7);
        }
        
        .btn.settings {
            background: linear-gradient(90deg, #607d8b, #455a64);
        }
        
        .table-container {
            flex: 1;
            overflow: auto;
            position: relative;
        }
        
        table {
            width: auto;
            min-width: 100%;
            border-collapse: collapse;
            table-layout: auto;
        }
        
        thead {
            background: var(--header-gradient);
            color: white;
            position: sticky;
            top: 0;
            z-index: 10;
        }
        
        th {
            padding: 14px 8px;
            text-align: center;
            font-weight: 500;
            font-size: 0.95rem;
            white-space: nowrap;
        }
        
        tbody tr {
            border-bottom: 1px solid var(--border);
            transition: background-color 0.2s;
        }
        
        tbody tr:nth-child(even) {
            background-color: var(--light-bg);
        }
        
        tbody tr:nth-child(odd) {
            background-color: #ffffff;
        }
        
        tbody tr:hover {
            background-color: #edf5ff;
        }
        
        td {
            padding: 12px 8px;
            text-align: center;
            font-size: 0.9rem;
            position: relative;
            white-space: nowrap;
        }
        
        input {
            width: 100%;
            padding: 8px 10px;
            border: 1px solid var(--border);
            border-radius: 4px;
            font-size: 0.9rem;
            text-align: center;
            transition: border 0.3s;
            background: rgba(255, 255, 255, 0.7);
        }
        
        input:focus {
            outline: none;
            border-color: var(--primary);
            box-shadow: 0 0 0 2px rgba(26, 109, 204, 0.2);
        }
        
        input[type="number"]::-webkit-outer-spin-button,
        input[type="number"]::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        input[type="number"] {
            -moz-appearance: textfield;
        }
        
        .calc-cell {
            font-weight: 600;
            color: var(--primary);
            background: rgba(26, 109, 204, 0.05);
        }
        
        .progress-container {
            display: flex;
            align-items: center;
            gap: 10px;
            padding: 0 5px;
        }
        
        .progress-bar {
            flex: 1;
            height: 20px;
            background-color: #e0e6ed;
            border-radius: 10px;
            overflow: hidden;
            position: relative;
            box-shadow: inset 0 1px 2px rgba(0,0,0,0.1);
        }
        
        .progress-fill {
            height: 100%;
            background: var(--progress-gradient);
            border-radius: 10px;
            transition: width 0.5s ease;
            min-width: 5%;
        }
        
        .progress-text {
            min-width: 60px;
            font-size: 0.85rem;
            font-weight: 500;
            color: #2e7d32;
        }
        
        .actions {
            display: flex;
            gap: 8px;
            justify-content: center;
        }
        
        .action-btn {
            width: 30px;
            height: 30px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            transition: all 0.2s;
            background: #f0f4f9;
            border: 1px solid var(--border);
            font-weight: bold;
            font-size: 1rem;
        }
        
        .action-btn:hover {
            background: #e4edf5;
            transform: scale(1.1);
        }
        
        .delete-btn {
            color: var(--danger);
        }
        
        .status-bar {
            padding: 12px 30px;
            background-color: var(--light-bg);
            border-top: 1px solid var(--border);
            display: flex;
            justify-content: space-between;
            align-items: center;
            font-size: 0.95rem;
            color: var(--text-light);
        }
        
        .stats {
            display: flex;
            gap: 20px;
        }
        
        .stat-item {
            display: flex;
            align-items: center;
            gap: 6px;
        }
        
        .stat-value {
            font-weight: 600;
            color: var(--primary);
        }
        
        .tooltip {
            position: absolute;
            top: -40px;
            left: 50%;
            transform: translateX(-50%);
            background-color: #f0f0f0;
            color: #333;
            padding: 8px 12px;
            border-radius: 4px;
            font-size: 0.9rem;
            white-space: nowrap;
            z-index: 1000;
            display: none;
            box-shadow: 0 3px 10px rgba(0,0,0,0.2);
            max-width: 400px;
            overflow: hidden;
            text-overflow: ellipsis;
            border: 1px solid #ccc;
        }
        
        .tooltip::after {
            content: '';
            position: absolute;
            bottom: -8px;
            left: 50%;
            transform: translateX(-50%);
            border-width: 8px 8px 0;
            border-style: solid;
            border-color: #f0f0f0 transparent transparent;
        }
        
        .amount-cell:hover .tooltip {
            display: block;
        }
        
        .name-cell:hover .tooltip {
            display: block;
        }
        
        .amount-input {
            text-align: right;
        }
        
        .chinese-input {
            text-align: center;
        }
        
        @media (max-width: 1200px) {
            .container {
                height: auto;
                min-height: calc(100vh - 40px);
            }
            
            .controls {
                flex-direction: column;
                align-items: center;
            }
            
            .controls-left, .controls-right {
                width: 100%;
                justify-content: center;
                flex-wrap: wrap;
            }
        }
        
        /* 自定义滚动条 */
        .table-container::-webkit-scrollbar {
            height: 8px;
            width: 8px;
        }
        
        .table-container::-webkit-scrollbar-track {
            background: #f1f1f1;
            border-radius: 4px;
        }
        
        .table-container::-webkit-scrollbar-thumb {
            background: #c1c1c1;
            border-radius: 4px;
        }
        
        .table-container::-webkit-scrollbar-thumb:hover {
            background: #a8a8a8;
        }
        
        /* 空数据提示 */
        .empty-message {
            text-align: center;
            padding: 40px;
            color: var(--text-light);
            font-size: 1.1rem;
        }
        
        /* 动画效果 */
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }
        
        tbody tr {
            animation: fadeIn 0.4s ease-out;
        }
        
        /* 提示弹窗 */
        .alert-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 2000;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.3s;
        }
        
        .alert-overlay.active {
            opacity: 1;
            pointer-events: all;
        }
        
        .alert-box {
            background: white;
            border-radius: 10px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            width: 450px;
            max-width: 90%;
            overflow: hidden;
            transform: translateY(20px);
            transition: transform 0.3s;
        }
        
        .alert-overlay.active .alert-box {
            transform: translateY(0);
        }
        
        .alert-header {
            background: var(--alert-header);
            color: white;
            padding: 20px;
            text-align: center;
            font-size: 1.3rem;
            font-weight: 500;
        }
        
        .alert-body {
            padding: 25px;
            font-size: 1.05rem;
            line-height: 1.6;
            color: var(--text);
        }
        
        .alert-footer {
            padding: 15px 25px 25px;
            display: flex;
            justify-content: center;
            gap: 15px;
        }
        
        .alert-btn {
            background: var(--primary);
            color: white;
            border: none;
            padding: 10px 30px;
            border-radius: 6px;
            font-size: 1rem;
            font-weight: 500;
            cursor: pointer;
            transition: background 0.3s;
        }
        
        .alert-btn:hover {
            background: var(--primary-dark);
        }
        
        .alert-btn.cancel {
            background: #b0bec5;
        }
        
        .alert-btn.cancel:hover {
            background: #78909c;
        }
        
        .highlight {
            color: var(--primary);
            font-weight: 600;
        }
        
        .warning {
            color: #e65100;
            font-weight: 600;
        }
        
        .backup-info {
            background: #e3f2fd;
            border-left: 4px solid var(--primary);
            padding: 10px 15px;
            margin: 10px 30px 5px;
            border-radius: 4px;
            font-size: 0.9rem;
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            gap: 10px;
        }
        
        .info-icon {
            color: var(--primary);
            font-size: 1.1rem;
        }
        
        .data-status {
            display: flex;
            align-items: center;
            gap: 5px;
            white-space: nowrap;
        }
        
        .last-saved {
            font-weight: 600;
            color: var(--primary);
        }
        
        /* 高级设置弹窗 - 更紧凑 */
        .settings-panel {
            background: white;
            border-radius: 10px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            width: 500px;
            max-width: 95%;
            overflow: hidden;
            transform: translateY(20px);
            transition: transform 0.3s;
        }
        
        .settings-overlay.active .settings-panel {
            transform: translateY(0);
        }
        
        .settings-header {
            background: var(--header-gradient);
            color: white;
            padding: 15px 20px;
            text-align: center;
            font-size: 1.2rem;
            font-weight: 500;
        }
        
        .settings-body {
            padding: 15px 20px;
            font-size: 1rem;
            color: var(--text);
            max-height: 60vh;
            overflow-y: auto;
        }
        
        .settings-group {
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 1px solid var(--border);
        }
        
        .settings-group h3 {
            margin-bottom: 10px;
            color: var(--primary);
            font-size: 1.05rem;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .settings-group h3 i {
            font-size: 1.1rem;
        }
        
        .theme-selector {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            justify-content: space-between;
        }
        
        .theme-option {
            width: 110px;
            height: 70px;
            border-radius: 6px;
            cursor: pointer;
            overflow: hidden;
            position: relative;
            border: 2px solid transparent;
            transition: all 0.2s;
        }
        
        .theme-option:hover {
            transform: translateY(-3px);
        }
        
        .theme-option.active {
            border-color: var(--text);
            box-shadow: 0 3px 8px rgba(0,0,0,0.15);
        }
        
        .theme-option .theme-preview {
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
        }
        
        .theme-option .header-preview {
            height: 25%;
            background: var(--header-gradient);
        }
        
        .theme-option .content-preview {
            flex: 1;
            display: flex;
        }
        
        .theme-option .sidebar-preview {
            width: 20%;
            background: var(--light-bg);
        }
        
        .theme-option .main-preview {
            flex: 1;
            background: white;
        }
        
        .theme-option .theme-name {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            background: rgba(0,0,0,0.7);
            color: white;
            text-align: center;
            padding: 4px;
            font-size: 0.75rem;
        }
        
        .form-group {
            margin-bottom: 10px;
        }
        
        .form-group label {
            display: block;
            margin-bottom: 6px;
            font-weight: 500;
            font-size: 0.95rem;
        }
        
        .form-group input[type="text"],
        .form-group input[type="number"],
        .form-group select {
            width: 100%;
            padding: 8px 10px;
            border: 1px solid var(--border);
            border-radius: 4px;
            font-size: 0.95rem;
        }
        
        .form-group input:focus {
            outline: none;
            border-color: var(--primary);
            box-shadow: 0 0 0 2px rgba(26, 109, 204, 0.2);
        }
        
        .toggle-switch {
            position: relative;
            display: inline-block;
            width: 45px;
            height: 22px;
        }
        
        .toggle-switch input {
            opacity: 0;
            width: 0;
            height: 0;
        }
        
        .toggle-slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: #ccc;
            transition: .4s;
            border-radius: 24px;
        }
        
        .toggle-slider:before {
            position: absolute;
            content: "";
            height: 16px;
            width: 16px;
            left: 3px;
            bottom: 3px;
            background-color: white;
            transition: .4s;
            border-radius: 50%;
        }
        
        input:checked + .toggle-slider {
            background-color: var(--primary);
        }
        
        input:checked + .toggle-slider:before {
            transform: translateX(23px);
        }
        
        .toggle-label {
            display: flex;
            align-items: center;
            gap: 8px;
            font-size: 0.95rem;
        }
        
        .settings-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 2000;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.3s;
        }
        
        .settings-overlay.active {
            opacity: 1;
            pointer-events: all;
        }
        
        /* 系统设置在同一行 */
        .system-settings-row {
            display: flex;
            gap: 20px;
        }
        
        .system-setting-item {
            flex: 1;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1><i class="fas fa-hard-hat"></i> 工程项目拨付款情况一览表</h1>
            <div class="subtitle">
                <span>单位名称:</span>
                <input type="text" id="company-name" placeholder="请输入单位名称">
            </div>
        </header>
        
        <div class="controls">
            <div class="controls-left">
                <button class="btn add" id="add-project">
                    <i class="fas fa-plus"></i> 添加项目
                </button>
                <button class="btn backup" id="backup-data">
                    <i class="fas fa-save"></i> 备份数据
                </button>
                <button class="btn settings" id="settings-btn">
                    <i class="fas fa-cog"></i> 高级设置
                </button>
            </div>
            <div class="controls-right">
                <button class="btn restore" id="restore-data">
                    <i class="fas fa-file-import"></i> 恢复数据
                </button>
                <button class="btn export" id="export-csv">
                    <i class="fas fa-file-csv"></i> 导出CSV
                </button>
                <button class="btn export" id="export-xlsx">
                    <i class="fas fa-file-excel"></i> 导出XLSX
                </button>
            </div>
        </div>
        
        <div class="backup-info">
            <i class="fas fa-info-circle info-icon"></i>
            <p>数据备份提示:请定期使用"备份数据"功能将数据保存到本地文件,防止浏览器数据清理导致数据丢失。</p>
            <div class="data-status">
                <i class="fas fa-clock"></i>
                <span>最后保存:</span>
                <span id="last-saved" class="last-saved">--</span>
            </div>
        </div>
        
        <div class="table-container">
            <table id="projects-table" class="resizable-table">
                <thead>
                    <tr>
                        <th width="40">序号</th>
                        <th>项目名称</th>
                        <th>施工单位</th>
                        <th>合同金额(元)</th>
                        <th>审定金额(元)</th>
                        <th>第一次拨付</th>
                        <th>第二次拨付</th>
                        <th>第三次拨付</th>
                        <th>第四次拨付</th>
                        <th>第五次拨付</th>
                        <th>累计拨付(元)</th>
                        <th>拨付比例</th>
                        <th>质保金(元)</th>
                        <th width="70">操作</th>
                    </tr>
                </thead>
                <tbody id="projects-body">
                    <!-- 数据行将由JavaScript动态生成 -->
                </tbody>
            </table>
            <div id="empty-state" class="empty-message" style="display: none;">
                <h3><i class="fas fa-inbox"></i> 暂无项目数据</h3>
                <p>点击"添加项目"按钮开始录入项目信息</p>
            </div>
        </div>
        
        <div class="status-bar">
            <div class="stats">
                <div class="stat-item"><i class="fas fa-list"></i> 项目总数: <span class="stat-value" id="total-projects">0</span></div>
                <div class="stat-item"><i class="fas fa-file-contract"></i> 总合同金额: <span class="stat-value" id="total-contract">0</span> 元</div>
                <div class="stat-item"><i class="fas fa-money-check"></i> 已拨付款: <span class="stat-value" id="total-paid">0</span> 元</div>
            </div>
            <div><i class="fas fa-cloud"></i> 本地数据状态: <span id="data-status">已保存</span></div>
        </div>
    </div>
    
    <!-- 提示弹窗 -->
    <div class="alert-overlay" id="alert-overlay">
        <div class="alert-box">
            <div class="alert-header" id="alert-header">提示</div>
            <div class="alert-body" id="alert-body"></div>
            <div class="alert-footer">
                <button class="alert-btn" id="alert-close">确定</button>
            </div>
        </div>
    </div>
    
    <!-- 高级设置弹窗 - 更紧凑 -->
    <div class="settings-overlay" id="settings-overlay">
        <div class="settings-panel">
            <div class="settings-header">
                <i class="fas fa-cog"></i> 高级设置
            </div>
            <div class="settings-body">
                <div class="settings-group">
                    <h3><i class="fas fa-palette"></i> 主题设置</h3>
                    <div class="theme-selector">
                        <div class="theme-option active" data-theme="default">
                            <div class="theme-preview">
                                <div class="header-preview" style="background: linear-gradient(90deg, #1a6dcc, #0d4a9e);"></div>
                                <div class="content-preview">
                                    <div class="sidebar-preview" style="background: #f8fafd;"></div>
                                    <div class="main-preview" style="background: white;"></div>
                                </div>
                            </div>
                            <div class="theme-name">默认主题</div>
                        </div>
                        <div class="theme-option" data-theme="purple">
                            <div class="theme-preview">
                                <div class="header-preview" style="background: linear-gradient(90deg, #7e57c2, #5e35b1);"></div>
                                <div class="content-preview">
                                    <div class="sidebar-preview" style="background: #f5f3f7;"></div>
                                    <div class="main-preview" style="background: white;"></div>
                                </div>
                            </div>
                            <div class="theme-name">紫色主题</div>
                        </div>
                        <div class="theme-option" data-theme="orange">
                            <div class="theme-preview">
                                <div class="header-preview" style="background: linear-gradient(90deg, #ff7043, #f4511e);"></div>
                                <div class="content-preview">
                                    <div class="sidebar-preview" style="background: #fdf6f3;"></div>
                                    <div class="main-preview" style="background: white;"></div>
                                </div>
                            </div>
                            <div class="theme-name">橙色主题</div>
                        </div>
                        <div class="theme-option" data-theme="green">
                            <div class="theme-preview">
                                <div class="header-preview" style="background: linear-gradient(90deg, #43a047, #2e7d32);"></div>
                                <div class="content-preview">
                                    <div class="sidebar-preview" style="background: #f3f8f4;"></div>
                                    <div class="main-preview" style="background: white;"></div>
                                </div>
                            </div>
                            <div class="theme-name">绿色主题</div>
                        </div>
                        <div class="theme-option" data-theme="red">
                            <div class="theme-preview">
                                <div class="header-preview" style="background: linear-gradient(90deg, #e53935, #c62828);"></div>
                                <div class="content-preview">
                                    <div class="sidebar-preview" style="background: #fdeaea;"></div>
                                    <div class="main-preview" style="background: white;"></div>
                                </div>
                            </div>
                            <div class="theme-name">红色主题</div>
                        </div>
                        <div class="theme-option" data-theme="pink">
                            <div class="theme-preview">
                                <div class="header-preview" style="background: linear-gradient(90deg, #ec407a, #d81b60);"></div>
                                <div class="content-preview">
                                    <div class="sidebar-preview" style="background: #fce4ec;"></div>
                                    <div class="main-preview" style="background: white;"></div>
                                </div>
                            </div>
                            <div class="theme-name">粉色主题</div>
                        </div>
                    </div>
                </div>
                
                <div class="settings-group">
                    <h3><i class="fas fa-building"></i> 单位设置</h3>
                    <div class="form-group">
                        <input type="text" id="company-name-settings" placeholder="请输入单位名称" style="width: 100%;">
                    </div>
                </div>
                
                <div class="settings-group">
                    <h3><i class="fas fa-tools"></i> 系统设置</h3>
                    <div class="system-settings-row">
                        <div class="system-setting-item">
                            <div class="form-group">
                                <label class="toggle-label">
                                    <span>自动保存</span>
                                    <label class="toggle-switch">
                                        <input type="checkbox" id="auto-save" checked>
                                        <span class="toggle-slider"></span>
                                    </label>
                                </label>
                            </div>
                        </div>
                        <div class="system-setting-item">
                            <div class="form-group">
                                <label class="toggle-label">
                                    <span>显示备份提示</span>
                                    <label class="toggle-switch">
                                        <input type="checkbox" id="show-backup-tips" checked>
                                        <span class="toggle-slider"></span>
                                    </label>
                                </label>
                            </div>
                        </div>
                    </div>
                </div>
                
                <div class="settings-group">
                    <h3><i class="fas fa-table"></i> 表格设置</h3>
                    <div class="form-group">
                        <label for="default-payments">默认付款次数</label>
                        <select id="default-payments" style="width: 100%;">
                            <option value="3">3次</option>
                            <option value="4">4次</option>
                            <option value="5" selected>5次</option>
                            <option value="6">6次</option>
                        </select>
                    </div>
                </div>
            </div>
            <div class="alert-footer">
                <button class="alert-btn cancel" id="settings-cancel">取消</button>
                <button class="alert-btn" id="settings-save">保存设置</button>
            </div>
        </div>
    </div>

    <script>
        // 初始示例数据
        const initialData = [
            {
                name: "市政道路改造工程",
                contractor: "城建集团第一分公司",
                contractAmount: "12500000.00",
                auditAmount: "12350000.00",
                payments: ["4500000.00", "3000000.00", "2000000.00", "1500000.00", "1000000.00"],
                qualityDeposit: "750000.00"
            },
            {
                name: "城市公园建设项目",
                contractor: "园林建设有限公司",
                contractAmount: "8500000.00",
                auditAmount: "8300000.00",
                payments: ["2500000.00", "2000000.00", "1500000.00", "1200000.00", "800000.00"],
                qualityDeposit: "500000.00"
            }
        ];

        // DOM元素
        const companyNameInput = document.getElementById('company-name');
        const projectsBody = document.getElementById('projects-body');
        const addProjectBtn = document.getElementById('add-project');
        const exportCsvBtn = document.getElementById('export-csv');
        const exportXlsxBtn = document.getElementById('export-xlsx');
        const backupDataBtn = document.getElementById('backup-data');
        const restoreDataBtn = document.getElementById('restore-data');
        const settingsBtn = document.getElementById('settings-btn');
        const emptyState = document.getElementById('empty-state');
        const totalProjectsEl = document.getElementById('total-projects');
        const totalContractEl = document.getElementById('total-contract');
        const totalPaidEl = document.getElementById('total-paid');
        const lastSavedEl = document.getElementById('last-saved');
        const alertOverlay = document.getElementById('alert-overlay');
        const alertHeader = document.getElementById('alert-header');
        const alertBody = document.getElementById('alert-body');
        const alertClose = document.getElementById('alert-close');
        const dataStatusEl = document.getElementById('data-status');
        const settingsOverlay = document.getElementById('settings-overlay');
        const settingsSaveBtn = document.getElementById('settings-save');
        const settingsCancelBtn = document.getElementById('settings-cancel');
        const companyNameSettings = document.getElementById('company-name-settings');
        const autoSaveCheckbox = document.getElementById('auto-save');
        const defaultPaymentsSelect = document.getElementById('default-payments');
        const showBackupTipsCheckbox = document.getElementById('show-backup-tips');
        
        // 全局变量
        let projects = [];
        let lastSavedTime = null;
        let isSaving = false;
        let lastAlertTime = 0;
        const alertCooldown = 3000;
        let currentTheme = 'default';
        let settings = {
            autoSave: true,
            showBackupTips: true,
            defaultPayments: 5
        };

        // 初始化
        document.addEventListener('DOMContentLoaded', () => {
            loadData();
            renderProjects();
            updateStats();
            updateLastSaved();
            loadSettings();
            
            // 添加事件监听
            addProjectBtn.addEventListener('click', addProject);
            exportCsvBtn.addEventListener('click', exportToCsv);
            exportXlsxBtn.addEventListener('click', exportToXlsx);
            backupDataBtn.addEventListener('click', backupData);
            restoreDataBtn.addEventListener('click', restoreData);
            companyNameInput.addEventListener('input', saveData);
            alertClose.addEventListener('click', () => {
                alertOverlay.classList.remove('active');
            });
            
            // 高级设置相关事件
            settingsBtn.addEventListener('click', openSettings);
            settingsSaveBtn.addEventListener('click', saveSettings);
            settingsCancelBtn.addEventListener('click', closeSettings);
            
            // 主题选择事件
            document.querySelectorAll('.theme-option').forEach(option => {
                option.addEventListener('click', function() {
                    document.querySelector('.theme-option.active').classList.remove('active');
                    this.classList.add('active');
                    currentTheme = this.dataset.theme;
                });
            });
        });

        // 打开高级设置面板
        function openSettings() {
            // 从主界面同步单位名称到设置面板
            companyNameSettings.value = companyNameInput.value;
            
            // 设置当前选中的主题
            document.querySelector('.theme-option.active').classList.remove('active');
            document.querySelector(`.theme-option[data-theme="${currentTheme}"]`).classList.add('active');
            
            // 更新设置面板中的值
            autoSaveCheckbox.checked = settings.autoSave;
            showBackupTipsCheckbox.checked = settings.showBackupTips;
            defaultPaymentsSelect.value = settings.defaultPayments;
            
            // 显示设置面板
            settingsOverlay.classList.add('active');
        }
        
        // 关闭高级设置面板
        function closeSettings() {
            settingsOverlay.classList.remove('active');
        }
        
        // 保存设置
        function saveSettings() {
            // 保存单位名称
            companyNameInput.value = companyNameSettings.value;
            
            // 更新主题
            document.body.className = '';
            document.body.classList.add(`theme-${currentTheme}`);
            
            // 更新设置
            settings.autoSave = autoSaveCheckbox.checked;
            settings.showBackupTips = showBackupTipsCheckbox.checked;
            settings.defaultPayments = parseInt(defaultPaymentsSelect.value);
            
            // 保存设置到localStorage
            localStorage.setItem('appSettings', JSON.stringify(settings));
            localStorage.setItem('appTheme', currentTheme);
            
            // 更新UI效果
            document.querySelector('.backup-info').style.display = settings.showBackupTips ? 'flex' : 'none';
            
            // 保存数据(包括单位名称)
            saveData();
            
            // 关闭设置面板
            closeSettings();
            
            showAlert("设置已保存", "您的设置已成功保存并应用。");
        }
        
        // 加载设置
        function loadSettings() {
            const savedSettings = localStorage.getItem('appSettings');
            const savedTheme = localStorage.getItem('appTheme');
            
            if (savedSettings) {
                try {
                    settings = JSON.parse(savedSettings);
                } catch (e) {
                    console.error("解析设置失败:", e);
                }
            }
            
            if (savedTheme) {
                currentTheme = savedTheme;
            }
            
            // 应用主题
            document.body.className = '';
            document.body.classList.add(`theme-${currentTheme}`);
            
            // 应用其他设置
            document.querySelector('.backup-info').style.display = settings.showBackupTips ? 'flex' : 'none';
        }

        // 加载数据
        function loadData() {
            // 尝试从localStorage加载数据
            const savedData = localStorage.getItem('projectPaymentData');
            const savedCompany = localStorage.getItem('companyName');
            
            if (savedData) {
                try {
                    projects = JSON.parse(savedData);
                    dataStatusEl.textContent = "已加载本地存储数据";
                    dataStatusEl.style.color = "var(--success)";
                } catch (e) {
                    console.error("解析本地存储数据失败:", e);
                    projects = [...initialData];
                    dataStatusEl.textContent = "加载失败,使用示例数据";
                    dataStatusEl.style.color = "var(--danger)";
                }
            } else {
                projects = [...initialData];
                dataStatusEl.textContent = "使用示例数据";
                dataStatusEl.style.color = "var(--warning)";
            }
            
            if (savedCompany) {
                companyNameInput.value = savedCompany;
            }
            
            const savedTime = localStorage.getItem('lastSavedTime');
            if (savedTime) {
                lastSavedTime = new Date(savedTime);
            }
        }

        // 保存数据到localStorage
        function saveData() {
            // 防止连续保存
            if (isSaving) return;
            
            isSaving = true;
            dataStatusEl.textContent = "保存中...";
            dataStatusEl.style.color = "var(--warning)";
            
            localStorage.setItem('projectPaymentData', JSON.stringify(projects));
            localStorage.setItem('companyName', companyNameInput.value);
            
            lastSavedTime = new Date();
            localStorage.setItem('lastSavedTime', lastSavedTime.toISOString());
            
            updateLastSaved();
            
            // 保存完成后重置标志
            setTimeout(() => {
                isSaving = false;
                dataStatusEl.textContent = "已保存";
                dataStatusEl.style.color = "var(--success)";
            }, 300);
        }

        // 备份数据到文件
        function backupData() {
            const data = {
                companyName: companyNameInput.value,
                projects: projects,
                lastSavedTime: new Date().toISOString()
            };
            
            const dataStr = JSON.stringify(data, null, 2);
            const blob = new Blob([dataStr], {type: "application/json"});
            const url = URL.createObjectURL(blob);
            
            const a = document.createElement('a');
            a.href = url;
            a.download = `工程项目数据备份_${formatDateForFile()}.json`;
            document.body.appendChild(a);
            a.click();
            
            // 清理
            setTimeout(() => {
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
                showAlert("备份成功", "数据已成功备份到本地文件,请妥善保存。");
            }, 100);
        }

        // 从文件恢复数据
        function restoreData() {
            const input = document.createElement('input');
            input.type = 'file';
            input.accept = '.json';
            
            input.onchange = e => {
                const file = e.target.files[0];
                if (!file) return;
                
                const reader = new FileReader();
                reader.onload = event => {
                    try {
                        const data = JSON.parse(event.target.result);
                        
                        // 验证数据格式
                        if (!data.companyName || !data.projects || !Array.isArray(data.projects)) {
                            throw new Error('数据格式不正确');
                        }
                        
                        // 恢复数据
                        companyNameInput.value = data.companyName;
                        projects = data.projects;
                        lastSavedTime = new Date(data.lastSavedTime);
                        
                        saveData();
                        renderProjects();
                        updateStats();
                        updateLastSaved();
                        
                        showAlert("恢复成功", "数据已成功从备份文件恢复!");
                    } catch (err) {
                        console.error(err);
                        showAlert("恢复失败", "数据格式不正确或已损坏,请选择有效的备份文件。", true);
                    }
                };
                reader.readAsText(file);
            };
            
            input.click();
        }

        // 更新最后保存时间显示
        function updateLastSaved() {
            if (lastSavedTime) {
                const options = { 
                    year: 'numeric', 
                    month: '2-digit', 
                    day: '2-digit',
                    hour: '2-digit',
                    minute: '2-digit',
                    second: '2-digit'
                };
                lastSavedEl.textContent = lastSavedTime.toLocaleString('zh-CN', options);
            } else {
                lastSavedEl.textContent = '--';
            }
        }

        // 显示提示弹窗
        function showAlert(title, message, isWarning = false) {
            const now = Date.now();
            if (now - lastAlertTime < alertCooldown) return;
            
            lastAlertTime = now;
            
            alertHeader.textContent = title;
            alertBody.innerHTML = message;
            
            if (isWarning) {
                alertHeader.style.background = "linear-gradient(90deg, #e53935, #b71c1c)";
            } else {
                alertHeader.style.background = "linear-gradient(90deg, var(--success), #2e7d32)";
            }
            
            alertOverlay.classList.add('active');
        }

        // 格式化金额输入(保留两位小数)
        function formatAmountInput(value) {
            if (!value) return "";
            
            // 转换为数字
            let num = parseFloat(value);
            if (isNaN(num)) return "";
            
            // 保留两位小数
            return num.toFixed(2);
        }

        // 格式化金额显示(千分位分隔符)
        function formatAmountDisplay(value) {
            if (!value) return "";
            
            // 转换为数字
            let num = parseFloat(value);
            if (isNaN(num)) return "";
            
            // 保留两位小数并添加千分位分隔符
            return num.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
        }

        // 渲染项目表格
        function renderProjects() {
            projectsBody.innerHTML = '';
            
            if (projects.length === 0) {
                emptyState.style.display = 'block';
                return;
            } else {
                emptyState.style.display = 'none';
            }
            
            projects.forEach((project, index) => {
                const row = document.createElement('tr');
                row.dataset.index = index;
                
                // 计算累计拨付款
                const totalPayment = project.payments.reduce((sum, payment) => {
                    return sum + (payment ? parseFloat(payment) : 0);
                }, 0);
                
                // 计算拨付比例
                const contractAmount = parseFloat(project.contractAmount) || 0;
                const qualityDeposit = parseFloat(project.qualityDeposit) || 0;
                const paymentRatio = contractAmount > 0 ? totalPayment / contractAmount : 0;
                const paymentPercent = Math.min(100, (paymentRatio * 100).toFixed(2));
                
                // 金额转大写
                const contractAmountCN = project.contractAmount ? numberToChinese(project.contractAmount) : '';
                const auditAmountCN = project.auditAmount ? numberToChinese(project.auditAmount) : '';
                const depositCN = project.qualityDeposit ? numberToChinese(project.qualityDeposit) : '';
                
                row.innerHTML = `
                    <td>${index + 1}</td>
                    <td class="name-cell">
                        <input type="text" class="chinese-input" value="${project.name || ''}" data-index="${index}" data-field="name">
                        <div class="tooltip">${project.name || ''}</div>
                    </td>
                    <td class="name-cell">
                        <input type="text" class="chinese-input" value="${project.contractor || ''}" data-index="${index}" data-field="contractor">
                        <div class="tooltip">${project.contractor || ''}</div>
                    </td>
                    <td class="amount-cell">
                        <input type="text" class="amount-input" value="${formatAmountDisplay(project.contractAmount)}" data-index="${index}" data-field="contractAmount">
                        <div class="tooltip">${contractAmountCN}</div>
                    </td>
                    <td class="amount-cell">
                        <input type="text" class="amount-input" value="${formatAmountDisplay(project.auditAmount)}" data-index="${index}" data-field="auditAmount">
                        <div class="tooltip">${auditAmountCN}</div>
                    </td>
                    <td>
                        <input type="text" class="amount-input" value="${formatAmountDisplay(project.payments[0])}" data-index="${index}" data-payment="0">
                    </td>
                    <td>
                        <input type="text" class="amount-input" value="${formatAmountDisplay(project.payments[1])}" data-index="${index}" data-payment="1">
                    </td>
                    <td>
                        <input type="text" class="amount-input" value="${formatAmountDisplay(project.payments[2])}" data-index="${index}" data-payment="2">
                    </td>
                    <td>
                        <input type="text" class="amount-input" value="${formatAmountDisplay(project.payments[3])}" data-index="${index}" data-payment="3">
                    </td>
                    <td>
                        <input type="text" class="amount-input" value="${formatAmountDisplay(project.payments[4])}" data-index="${index}" data-payment="4">
                    </td>
                    <td class="calc-cell">${formatAmountDisplay(totalPayment)}</td>
                    <td>
                        <div class="progress-container">
                            <div class="progress-bar">
                                <div class="progress-fill" style="width: ${paymentPercent}%"></div>
                            </div>
                            <div class="progress-text">${paymentPercent}%</div>
                        </div>
                    </td>
                    <td class="amount-cell">
                        <input type="text" class="amount-input" value="${formatAmountDisplay(project.qualityDeposit)}" data-index="${index}" data-field="qualityDeposit">
                        <div class="tooltip">${depositCN}</div>
                    </td>
                    <td class="actions">
                        <div class="action-btn delete-btn" data-index="${index}" title="删除项目"><i class="fas fa-trash"></i></div>
                    </td>
                `;
                
                projectsBody.appendChild(row);
            });
            
            // 添加输入事件监听
            document.querySelectorAll('input').forEach(input => {
                // 在输入时进行格式化
                input.addEventListener('input', handleInputFormatting);
                
                // 在失去焦点时更新数据
                input.addEventListener('blur', handleInputChange);
                
                // 添加 focus 事件,选中输入框内容
                input.addEventListener('focus', function() {
                    this.select();
                });
                
                // 防止点击其他地方导致数据被删改
                input.addEventListener('mousedown', (e) => {
                    e.stopPropagation();
                });
            });
            
            // 添加删除事件监听
            document.querySelectorAll('.delete-btn').forEach(btn => {
                btn.addEventListener('click', deleteProject);
                btn.addEventListener('mousedown', (e) => {
                    if (document.activeElement && document.activeElement.tagName === 'INPUT') {
                        document.activeElement.blur();
                    }
                });
            });
            
            updateStats();
        }

        // 处理输入格式化
        function handleInputFormatting(e) {
            const input = e.target;
            const value = input.value;
            
            // 金额输入框的特殊处理
            if (input.classList.contains('amount-input')) {
                // 允许数字和小数点
                let newValue = value.replace(/[^0-9.]/g, '');
                
                // 处理多个小数点
                const decimalCount = newValue.split('.').length - 1;
                if (decimalCount > 1) {
                    newValue = newValue.slice(0, newValue.lastIndexOf('.'));
                }
                
                // 限制小数点后两位
                if (newValue.includes('.')) {
                    const parts = newValue.split('.');
                    if (parts[1].length > 2) {
                        newValue = parts[0] + '.' + parts[1].slice(0, 2);
                    }
                }
                
                // 更新输入框值
                input.value = newValue;
            }
        }

        // 处理输入变化(在失去焦点时)
        function handleInputChange(e) {
            const input = e.target;
            const index = parseInt(input.dataset.index);
            const field = input.dataset.field;
            const paymentIndex = input.dataset.payment;
            
            // 获取输入值
            let value = input.value;
            
            // 金额输入框的特殊处理 - 添加千分位格式
            if (input.classList.contains('amount-input')) {
                // 先保存原始值
                const rawValue = value.replace(/,/g, '');
                
                if (field) {
                    projects[index][field] = rawValue;
                } else if (paymentIndex !== undefined) {
                    projects[index].payments[paymentIndex] = rawValue;
                }
                
                // 然后格式化显示
                input.value = formatAmountDisplay(rawValue);
            } else {
                if (field) {
                    projects[index][field] = value;
                } else if (paymentIndex !== undefined) {
                    projects[index].payments[paymentIndex] = value;
                }
            }
            
            // 更新当前行的工具提示
            updateRowTooltips(index);
            
            // 更新当前行的计算结果
            updateRowCalculation(index);
            
            // 更新统计信息
            updateStats();
            
            // 保存数据
            saveData();
        }
        
        // 更新行工具提示
        function updateRowTooltips(index) {
            const row = projectsBody.querySelector(`tr[data-index="${index}"]`);
            if (!row) return;
            
            const project = projects[index];
            
            // 更新项目名称提示
            const nameTooltip = row.querySelector('.name-cell:nth-child(2) .tooltip');
            if (nameTooltip) {
                nameTooltip.textContent = project.name || '';
            }
            
            // 更新施工单位提示
            const contractorTooltip = row.querySelector('.name-cell:nth-child(3) .tooltip');
            if (contractorTooltip) {
                contractorTooltip.textContent = project.contractor || '';
            }
            
            // 更新合同金额大写提示
            const contractAmountTooltip = row.querySelector('.amount-cell:nth-child(4) .tooltip');
            if (contractAmountTooltip) {
                contractAmountTooltip.textContent = project.contractAmount ? numberToChinese(project.contractAmount) : '';
            }
            
            // 更新审计金额大写提示
            const auditAmountTooltip = row.querySelector('.amount-cell:nth-child(5) .tooltip');
            if (auditAmountTooltip) {
                auditAmountTooltip.textContent = project.auditAmount ? numberToChinese(project.auditAmount) : '';
            }
            
            // 更新质量保证金大写提示
            const depositTooltip = row.querySelector('.amount-cell:nth-child(14) .tooltip');
            if (depositTooltip) {
                depositTooltip.textContent = project.qualityDeposit ? numberToChinese(project.qualityDeposit) : '';
            }
        }
        
        // 更新行计算结果
        function updateRowCalculation(index) {
            const row = projectsBody.querySelector(`tr[data-index="${index}"]`);
            if (!row) return;
            
            const project = projects[index];
            
            // 计算累计拨付款
            const totalPayment = project.payments.reduce((sum, payment) => {
                return sum + (payment ? parseFloat(payment) : 0);
            }, 0);
            
            // 计算拨付比例
            const contractAmount = parseFloat(project.contractAmount) || 0;
            const qualityDeposit = parseFloat(project.qualityDeposit) || 0;
            const paymentRatio = contractAmount > 0 ? totalPayment / contractAmount : 0;
            const paymentPercent = Math.min(100, (paymentRatio * 100).toFixed(2));
            
            // 更新累计拨付款单元格
            const totalPaymentCell = row.querySelector('.calc-cell');
            if (totalPaymentCell) {
                totalPaymentCell.textContent = formatAmountDisplay(totalPayment);
            }
            
            // 更新进度条
            const progressFill = row.querySelector('.progress-fill');
            if (progressFill) {
                progressFill.style.width = `${paymentPercent}%`;
            }
            
            // 更新比例文本
            const progressText = row.querySelector('.progress-text');
            if (progressText) {
                progressText.textContent = `${paymentPercent}%`;
            }
            
            // 检查是否需要弹框提示
            if (contractAmount > 0) {
                // 检查累计拨付进度款是否大于合同金额
                if (totalPayment > contractAmount) {
                    const message = `
                        <p>项目 <span class="highlight">${project.name || '未命名项目'}</span> 的累计拨付进度款为 
                        <span class="warning">${formatAmountDisplay(totalPayment)}</span> 元,</p>
                        <p>已超过合同金额 <span class="highlight">${formatAmountDisplay(contractAmount)}</span> 元!</p>
                        <p style="margin-top: 15px;">请核对拨付金额是否正确。</p>
                    `;
                    showAlert("警告:超额拨付", message, true);
                }
                
                // 检查累计拨付进度款加上质量保证金是否等于合同金额
                const totalWithDeposit = totalPayment + qualityDeposit;
                // 使用容差比较浮点数
                if (Math.abs(totalWithDeposit - contractAmount) < 0.01) {
                    const message = `
                        <p>项目 <span class="highlight">${project.name || '未命名项目'}</span> 的款项拨付已完成:</p>
                        <ul style="margin: 15px 0 15px 20px;">
                            <li>累计拨付进度款:<span class="highlight">${formatAmountDisplay(totalPayment)}</span> 元</li>
                            <li>质量保证金:<span class="highlight">${formatAmountDisplay(qualityDeposit)}</span> 元</li>
                            <li>合同金额:<span class="highlight">${formatAmountDisplay(contractAmount)}</span> 元</li>
                        </ul>
                        <p>累计拨付进度款 + 质量保证金 = 合同金额</p>
                    `;
                    showAlert("付款完成", message);
                }
            }
        }

        // 添加新项目 - 使用默认付款次数设置
        function addProject() {
            // 根据设置中的默认付款次数创建空付款数组
            const payments = Array(settings.defaultPayments).fill("");
            
            projects.push({
                name: "",
                contractor: "",
                contractAmount: "",
                auditAmount: "",
                payments: payments,
                qualityDeposit: ""
            });
            
            saveData();
            renderProjects();
            
            // 滚动到新项目
            setTimeout(() => {
                projectsBody.lastElementChild.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
            }, 100);
        }

        // 删除项目
        function deleteProject(e) {
            const index = parseInt(e.currentTarget.dataset.index);
            if (confirm('确定要删除此项目吗?')) {
                projects.splice(index, 1);
                saveData();
                renderProjects();
            }
        }

        // 更新统计数据
        function updateStats() {
            totalProjectsEl.textContent = projects.length;
            
            const totalContract = projects.reduce((sum, project) => {
                return sum + (project.contractAmount ? parseFloat(project.contractAmount) : 0);
            }, 0);
            
            const totalPaid = projects.reduce((sum, project) => {
                const projectPaid = project.payments.reduce((pSum, payment) => {
                    return pSum + (payment ? parseFloat(payment) : 0);
                }, 0);
                return sum + projectPaid;
            }, 0);
            
            totalContractEl.textContent = formatAmountDisplay(totalContract);
            totalPaidEl.textContent = formatAmountDisplay(totalPaid);
        }

        // 导出到CSV(修复乱码问题)
        function exportToCsv() {
            if (!validateExport()) return;
            
            // CSV内容添加BOM解决中文乱码问题
            const BOM = "\uFEFF";
            let csvContent = "data:text/csv;charset=utf-8," + BOM;
            
            // 标题行
            csvContent += `"${companyNameInput.value}工程项目拨付款情况一览表"\n\n`;
            
            // 表头
            const headers = [
                "序号", "项目名称", "施工单位", "合同金额(元)", "审计金额(元)", 
                "第一次拨付款(元)", "第二次拨付款(元)", "第三次拨付款(元)", 
                "第四次拨付款(元)", "第五次拨付款(元)", "累计拨付进度款(元)", 
                "已拨付金额比例", "质量保证金(元)"
            ];
            csvContent += headers.join(",") + "\n";
            
            // 数据行
            projects.forEach((project, index) => {
                const totalPayment = project.payments.reduce((sum, payment) => {
                    return sum + (payment ? parseFloat(payment) : 0);
                }, 0);
                
                const contractAmount = parseFloat(project.contractAmount) || 1;
                const paymentPercent = ((totalPayment / contractAmount) * 100).toFixed(2) + "%";
                
                const row = [
                    index + 1,
                    `"${project.name}"`,
                    `"${project.contractor}"`,
                    project.contractAmount,
                    project.auditAmount,
                    ...project.payments.map(p => p || "0.00"),
                    totalPayment.toFixed(2),
                    paymentPercent,
                    project.qualityDeposit || "0.00"
                ];
                
                csvContent += row.join(",") + "\n";
            });
            
            // 创建下载链接
            const encodedUri = encodeURI(csvContent);
            const link = document.createElement("a");
            link.setAttribute("href", encodedUri);
            link.setAttribute("download", `工程项目拨付款情况表_${formatDateForFile()}.csv`);
            document.body.appendChild(link);
            
            // 触发下载
            link.click();
            document.body.removeChild(link);
        }

        // 导出到XLSX
        function exportToXlsx() {
            if (!validateExport()) return;
            
            // 创建工作簿
            const wb = XLSX.utils.book_new();
            
            // 准备数据
            const data = [];
            
            // 添加标题行
            data.push([`${companyNameInput.value}工程项目拨付款情况一览表`]);
            data.push([]); // 空行
            
            // 添加表头
            const headers = [
                "序号", "项目名称", "施工单位", "合同金额(元)", "审计金额(元)", 
                "第一次拨付款(元)", "第二次拨付款(元)", "第三次拨付款(元)", 
                "第四次拨付款(元)", "第五次拨付款(元)", "累计拨付进度款(元)", 
                "已拨付金额比例", "质量保证金(元)"
            ];
            data.push(headers);
            
            // 添加数据行
            projects.forEach((project, index) => {
                const totalPayment = project.payments.reduce((sum, payment) => {
                    return sum + (payment ? parseFloat(payment) : 0);
                }, 0);
                
                const contractAmount = parseFloat(project.contractAmount) || 1;
                const paymentPercent = ((totalPayment / contractAmount) * 100).toFixed(2) + "%";
                
                const row = [
                    index + 1,
                    project.name,
                    project.contractor,
                    project.contractAmount,
                    project.auditAmount,
                    ...project.payments.map(p => p || "0.00"),
                    totalPayment.toFixed(2),
                    paymentPercent,
                    project.qualityDeposit || "0.00"
                ];
                
                data.push(row);
            });
            
            // 创建工作表
            const ws = XLSX.utils.aoa_to_sheet(data);
            
            // 设置列宽
            const colWidths = [
                { wch: 6 },   // 序号
                { wch: 25 },  // 项目名称
                { wch: 20 },  // 施工单位
                { wch: 15 },  // 合同金额
                { wch: 15 },  // 审计金额
                { wch: 15 },  // 第一次拨付
                { wch: 15 },  // 第二次拨付
                { wch: 15 },  // 第三次拨付
                { wch: 15 },  // 第四次拨付
                { wch: 15 },  // 第五次拨付
                { wch: 18 },  // 累计拨付
                { wch: 18 },  // 拨付比例
                { wch: 15 }   // 质量保证金
            ];
            ws['!cols'] = colWidths;
            
            // 合并标题行
            ws['!merges'] = [
                { s: { r: 0, c: 0 }, e: { r: 0, c: 12 } }
            ];
            
            // 添加工作表到工作簿
            XLSX.utils.book_append_sheet(wb, ws, "工程项目款批复");
            
            // 导出文件
            XLSX.writeFile(wb, `工程项目拨付款情况表_${formatDateForFile()}.xlsx`);
        }

        // 验证导出条件
        function validateExport() {
            if (!companyNameInput.value) {
                showAlert("导出失败", "请先填写单位名称", true);
                companyNameInput.focus();
                return false;
            }
            
            if (projects.length === 0) {
                showAlert("导出失败", "没有项目数据可导出", true);
                return false;
            }
            
            return true;
        }

        // 为文件名格式化日期
        function formatDateForFile() {
            const now = new Date();
            return `${now.getFullYear()}${(now.getMonth()+1).toString().padStart(2, '0')}${now.getDate().toString().padStart(2, '0')}_${now.getHours().toString().padStart(2, '0')}${now.getMinutes().toString().padStart(2, '0')}`;
        }
        
        // 修复后的数字转中文大写函数
        function numberToChinese(numStr) {
            if (!numStr || isNaN(parseFloat(numStr))) return "";
            
            const num = parseFloat(numStr);
            if (num === 0) return "零元整";
            
            // 定义中文数字和单位
            const cnNums = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
            const cnIntUnits = ["", "拾", "佰", "仟"];
            const cnDecUnits = ["角", "分"];
            const cnBigUnits = ["", "万", "亿"];
            const cnInteger = "整";
            const cnIntLast = "元";
            
            // 分离整数和小数部分
            let integerNum = Math.floor(num);
            let decimalNum = Math.round((num - integerNum) * 100);
            
            let chineseStr = "";
            
            // 处理整数部分
            if (integerNum > 0) {
                let integerStr = integerNum.toString();
                let zeroCount = 0;
                let IntLen = integerStr.length;
                
                for (let i = 0; i < IntLen; i++) {
                    let n = parseInt(integerStr[i]);
                    let p = IntLen - i - 1;
                    let q = Math.floor(p / 4);
                    let m = p % 4;
                    
                    if (n === 0) {
                        zeroCount++;
                    } else {
                        if (zeroCount > 0) {
                            chineseStr += cnNums[0];
                        }
                        zeroCount = 0;
                        chineseStr += cnNums[n] + cnIntUnits[m];
                    }
                    
                    if (m === 0 && zeroCount < 4) {
                        chineseStr += cnBigUnits[q];
                        zeroCount = 0;
                    }
                }
                chineseStr += cnIntLast;
            }
            
            // 处理小数部分
            if (decimalNum > 0) {
                let decStr = decimalNum.toString().padStart(2, '0');
                for (let i = 0; i < decStr.length; i++) {
                    let n = parseInt(decStr[i]);
                    if (n > 0) {
                        chineseStr += cnNums[n] + cnDecUnits[i];
                    }
                }
            } else {
                chineseStr += cnInteger;
            }
            
            // 特殊情况处理
            chineseStr = chineseStr
                .replace(/零拾/g, '零')
                .replace(/零佰/g, '零')
                .replace(/零仟/g, '零')
                .replace(/零+万/g, '万')
                .replace(/零+亿/g, '亿')
                .replace(/亿万/g, '亿')
                .replace(/零+元/g, '元')
                .replace(/零角/g, '零')
                .replace(/零分/g, '')
                .replace(/零{2,}/g, '零')
                .replace(/零整/g, '整');
            
            return chineseStr;
        }
    </script>
</body>
</html>



免费评分

参与人数 5吾爱币 +11 热心值 +5 收起 理由
人生如茶 + 1 + 1 谢谢@Thanks!
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
cioceo + 1 + 1 谢谢@Thanks!
tzxinqing + 1 + 1 用心讨论,共获提升!
daixiangjiang + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
 楼主| hrbbuild 发表于 2025-8-16 10:48 |楼主
a·hao 发表于 2025-8-15 19:17
老哥,看到您这边有亿图图示的绿色版,那个帖子的123盘链接失效了,可以再发一下吗?感谢

EdrawMax(万兴亿图图示)14.5.4.1333:
链接:https://pan.quark.cn/s/20965fa66ab7?pwd=PunE
提取码:PunE
(有效期7天)
推荐
 楼主| hrbbuild 发表于 2025-7-12 15:52 |楼主
jiujian118 发表于 2025-7-12 15:50
用AI编程怎么提问呢?

以下是我第一次提问的内容,然后不断更新迭代壹满足自己的需要并测试功能是否正常,发挥你的想象吧!

以表格形式展示一个工程项目工程款批复情况,这个表的结构如下:
第1列,序号(从1开始)
第2列,项目名称(空白,待项目完成后由用户输入)
第3列,施工单位(空白,待项目完成后由用户输入)
第4列,合同金额(元)(空白,待项目完成后由用户输入)
第5列,审计金额(元)(空白,待项目完成后由用户输入)
第6列,第一次拨付款(元)(日期,空白,待项目完成后由用户输入)
第7列,第二次拨付款(元)(空白,待项目完成后由用户输入)
第8列,第三次拨付款(元)(空白,待项目完成后由用户输入)
第9列,第四次拨付款(元)(空白,待项目完成后由用户输入)
第10列,第五次拨付款(元)(空白,待项目完成后由用户输入)
第11列,累积拨付进度款(元)(累加汇总第6列至第10列金额)
第12列,已拨付金额比例(元)(第11列金额占第4列金额的比例,前面用短竖线的进度条形式表示金额比例,后面用百分比百分比显示)
第13列,质量保证金(元)(空白,待项目完成后由用户输入)

功能要求:
1.导出表到csv文件功能,导出当前项目完成进度;
2.持久化存储;
3.界面美观;
4.相邻的项目使用浅色颜色区分标记;
5.使用本地化的css;
6.使用本地化的js;
7.不使用font-awesome图标字体等外部资源;
页面布局:
第1行:title:工程项目拨付款情况一览表
第2行:单位名称:
第3行: 表头
第4行:表格数据

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
jiujian118 + 1 + 1 谢谢@Thanks!

查看全部评分

沙发
 楼主| hrbbuild 发表于 2025-7-12 07:42 |楼主
其他说明:
1、付款比例按合同金额与拨付款总额比例,未考虑审定金额。
2、鼠标指针指向工程名称、施工单位会有全名称提示。
3、鼠标指针指向合同金额、审定金额、质量保证金时会有大写金额提示。
3、项目总数是所有行总数,并不是所有工程总数,这是这个bug
4、因工作需要通过deepseek经过十几次调试写成,发上来与大家共同学习。
3#
XXTK 发表于 2025-7-12 10:43
没准改行时用得着
4#
skzhaixing 发表于 2025-7-12 11:25
你这是专业的吧
5#
cokeseyo 发表于 2025-7-12 11:33
刚好可以,用用试试
6#
junshuiyujianni 发表于 2025-7-12 11:35
现在用不上,下载试试,说不定什么时候就用上了,感谢分享。
7#
 楼主| hrbbuild 发表于 2025-7-12 11:36 |楼主

第一次用Deepseek写,看见大家都用Deepseek写,工作需要所以写一个试试
8#
tzxinqing 发表于 2025-7-12 12:14
测试了下,导出CSV会乱码,XLSX是正常的楼主可以再改改。

9#
ljt543 发表于 2025-7-12 12:27
界面挺好看的啊。
10#
 楼主| hrbbuild 发表于 2025-7-12 13:05 |楼主
本帖最后由 hrbbuild 于 2025-7-12 13:24 编辑

tzxinqing 发表于 2025-7-12 12:14
测试了下,导出CSV会乱码,XLSX是正常的楼主可以再改改。

deepseek的答复:我们注意到原代码中已经使用了xlsx.full.min.js库来处理Excel导出,而CSV导出是直接通过生成data URI实现的。对于乱码问题,通常CSV文件在Excel中打开时可能会出现乱码,这是因为编码问题。我们可以通过添加BOM(Byte Order Mark)来解决UTF-8编码的CSV在Excel中打开乱码的问题。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-7-21 13:28

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表