Files
ONE-OS/web端/加氢站管理/站点信息.jsx
王冕 d432d51eed feat(web): 同步 web 端目录更新至 Gitea
包含加氢站站点信息、运维交车/故障、台账与数据分析等页面新增与改动。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 19:57:30 +08:00

3354 lines
147 KiB
JavaScript
Raw 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.
// 【重要】必须使用 const Component 作为组件变量名
// 加氢站管理 - 站点信息(列表 + KPI 分类 + 独立新建页 / 编辑查看抽屉)
var H2_REGION_CASCADER_OPTIONS = [
{ value: '浙江省', label: '浙江省', children: [{ value: '嘉兴市', label: '嘉兴市' }, { value: '杭州市', label: '杭州市' }, { value: '宁波市', label: '宁波市' }] },
{ value: '上海市', label: '上海市', children: [{ value: '上海市', label: '上海市' }] },
{ value: '江苏省', label: '江苏省', children: [{ value: '南京市', label: '南京市' }, { value: '苏州市', label: '苏州市' }] },
{ value: '广东省', label: '广东省', children: [{ value: '广州市', label: '广州市' }, { value: '深圳市', label: '深圳市' }] }
];
var H2_STATION_KPI_CARDS = [
{ key: 'all', type: 'total', title: '全部加氢站', desc: '纳入台账管理的全部站点' },
{ key: 'high', type: 'normal', title: '高频加氢站点', desc: '加氢次数 ≥ 3 次的站点' },
{ key: 'low', type: 'warning', title: '低频加氢站点', desc: '加氢次数 12 次的站点' },
{ key: 'none', type: 'unuploaded', title: '无加氢站点', desc: '暂无加氢记录的站点' }
];
var H2_SIGNED_FILTER_CARDS = [
{ key: 'yes', type: 'normal', title: '已签约站点', desc: '已签约的加氢站点,点击快捷筛选' },
{ key: 'no', type: 'unuploaded', title: '未签约站点', desc: '尚未签约的加氢站点,点击快捷筛选' }
];
var H2_BUSINESS_STATUS_OPTIONS = [
{ value: '营业中', label: '营业中' },
{ value: '暂停营业', label: '暂停营业' },
{ value: '停止营业', label: '停止营业' }
];
var H2_PAGE_STYLE = [
'.h2-station-page { padding: 24px 24px 80px; height: 100vh; display: flex; flex-direction: column; background: linear-gradient(165deg, #f1f5f9 0%, #f8fafc 50%, #f1f5f9 100%); overflow: hidden; box-sizing: border-box; }',
'.h2-station-page .lc-filter-card.ant-card { border-radius: 16px !important; border: 1px solid #e2e8f0 !important; box-shadow: 0 4px 20px -4px rgba(15, 23, 42, 0.03) !important; margin-bottom: 16px; }',
'.h2-station-page .lc-filter-card > .ant-card-head { border-bottom: 1px solid #f1f5f9 !important; min-height: auto; padding: 12px 20px !important; }',
'.h2-station-page .lc-filter-card > .ant-card-head .ant-card-head-title { font-size: 15px !important; font-weight: 700 !important; color: #0f172a !important; padding: 0 !important; }',
'.h2-station-page .lc-filter-card > .ant-card-body { padding: 16px 20px 20px !important; }',
'.h2-station-page .lc-filter-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px 24px; }',
'@media (max-width: 1100px) { .h2-station-page .lc-filter-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }',
'@media (max-width: 720px) { .h2-station-page .lc-filter-grid { grid-template-columns: 1fr; } }',
'.h2-station-page .lc-filter-field { display: flex; align-items: center; gap: 12px; min-width: 0; }',
'.h2-station-page .lc-filter-field-label { flex: 0 0 100px; text-align: right; font-size: 13px; font-weight: 500; color: #475569; line-height: 1.4; white-space: nowrap; }',
'.h2-station-page .lc-filter-field-control { flex: 1; min-width: 0; }',
'.h2-station-page .lc-filter-field-control .ant-input, .h2-station-page .lc-filter-field-control .ant-select { width: 100%; }',
'.h2-station-page .lc-filter-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; padding-top: 16px; border-top: 1px solid #f1f5f9; }',
'.h2-station-page .lc-alert-stats-row { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px; }',
'@media (max-width: 1400px) { .h2-station-page .lc-alert-stats-row { grid-template-columns: repeat(3, minmax(0, 1fr)); } }',
'@media (max-width: 900px) { .h2-station-page .lc-alert-stats-row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }',
'@media (max-width: 640px) { .h2-station-page .lc-alert-stats-row { grid-template-columns: 1fr; } }',
'.h2-station-page .lc-alert-card { display: flex; align-items: flex-start; gap: 12px; padding: 14px 30px 14px 16px; border-radius: 12px; border: 1px solid #e2e8f0; background: #fff; position: relative; overflow: hidden; min-width: 0; min-height: 44px; }',
'.h2-station-page .lc-alert-card-main { flex: 1; min-width: 0; }',
'.h2-station-page .lc-alert-card-icon { flex-shrink: 0; width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; }',
'.h2-station-page .lc-alert-card-val { font-size: 26px; font-weight: 800; line-height: 1.1; color: #0f172a; font-variant-numeric: tabular-nums; }',
'.h2-station-page .lc-alert-card-title { font-size: 13px; font-weight: 600; color: #334155; margin-top: 2px; }',
'.h2-station-page .lc-alert-card-tip-anchor { position: absolute; top: 8px; right: 8px; z-index: 2; line-height: 0; }',
'.h2-station-page .lc-alert-card-tip { width: 18px; height: 18px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; color: #94a3b8; background: rgba(255,255,255,0.92); border: 1px solid #e2e8f0; cursor: help; line-height: 0; }',
'.h2-station-page .lc-alert-card-tip:hover { color: #64748b; border-color: #cbd5e1; background: #fff; }',
'.h2-station-page .lc-alert-card--total { background: linear-gradient(135deg, #f8fafc 0%, #fff 100%); }',
'.h2-station-page .lc-alert-card--total .lc-alert-card-icon { background: #e2e8f0; color: #475569; }',
'.h2-station-page .lc-alert-card--normal { background: linear-gradient(135deg, #ecfdf5 0%, #fff 55%); border-color: #bbf7d0; }',
'.h2-station-page .lc-alert-card--normal .lc-alert-card-icon { background: #d1fae5; color: #059669; }',
'.h2-station-page .lc-alert-card--normal .lc-alert-card-val { color: #047857; }',
'.h2-station-page .lc-alert-card--warning { background: linear-gradient(135deg, #fff7ed 0%, #fff 55%); border-color: #fed7aa; }',
'.h2-station-page .lc-alert-card--warning .lc-alert-card-icon { background: #ffedd5; color: #ea580c; }',
'.h2-station-page .lc-alert-card--warning .lc-alert-card-val { color: #c2410c; }',
'.h2-station-page .lc-alert-card--unuploaded { background: linear-gradient(135deg, #f8fafc 0%, #fff 55%); }',
'.h2-station-page .lc-alert-card--unuploaded .lc-alert-card-icon { background: #f1f5f9; color: #64748b; }',
'.h2-station-page .lc-alert-card--unuploaded .lc-alert-card-val { color: #64748b; }',
'.h2-station-page .lc-alert-card-clickable { cursor: pointer; transition: box-shadow 0.2s ease, border-color 0.2s ease, transform 0.2s ease; }',
'.h2-station-page .lc-alert-card-clickable:hover { box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08); }',
'.h2-station-page .lc-alert-card-clickable:focus-visible { outline: 2px solid #10b981; outline-offset: 2px; }',
'.h2-station-page .lc-alert-card-active { box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.25) !important; border-color: #10b981 !important; }',
'.h2-station-page .lc-table-section { margin-bottom: 0; flex: 1; display: flex; flex-direction: column; min-height: 0; }',
'.h2-station-page .lc-table-toolbar { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px 16px; margin-bottom: 8px; min-height: 32px; }',
'.h2-station-page .lc-table-legend-outer { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; padding: 6px 4px; font-size: 12px; color: #64748b; }',
'.h2-station-page .lc-table-legend-label { font-weight: 600; color: #64748b; }',
'.h2-station-page .lc-table-legend-item { display: inline-flex; align-items: center; gap: 6px; }',
'.h2-station-page .lc-table-legend-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }',
'.h2-station-page .lc-table-toolbar-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-left: auto; }',
'.h2-station-page .lc-table-card { background: #fff; border-radius: 16px; border: 1px solid #e2e8f0; box-shadow: 0 4px 20px -4px rgba(15, 23, 42, 0.03); overflow: hidden; flex: 1; overflow-y: auto; display: flex; flex-direction: column; }',
'.h2-station-page .lc-list-table .ant-table-wrapper, .h2-station-page .lc-list-table .ant-table { width: 100% !important; }',
'.h2-station-page .lc-table-card .ant-table-thead > tr > th { background: #f8fafc !important; color: #475569 !important; font-weight: 700 !important; font-size: 13px !important; border-bottom: 1px solid #e2e8f0 !important; padding: 12px 16px !important; }',
'.h2-station-page .lc-table-card .ant-table-tbody > tr.ant-table-measure-row, .h2-station-page .lc-table-card .ant-table-tbody > tr.ant-table-measure-row > td { height: 0 !important; max-height: 0 !important; padding: 0 !important; margin: 0 !important; border: none !important; line-height: 0 !important; font-size: 0 !important; overflow: hidden !important; visibility: hidden !important; }',
'.h2-station-page .lc-table-card .ant-table-tbody > tr:not(.ant-table-measure-row) > td { padding: 12px 16px !important; font-size: 13px; }',
'.h2-station-page .lc-table-card .ant-table-tbody > tr:not(.ant-table-measure-row):hover > td { background: #f8fafc !important; }',
'.h2-station-page .lc-table-card .ant-pagination { margin: 0 !important; padding: 12px 16px !important; border-top: 1px solid #f1f5f9; }',
'.h2-station-page .lc-action-btn { font-weight: 600 !important; color: #10b981 !important; padding: 0 !important; min-height: 44px; }',
'.h2-station-page .lc-action-btn-danger { color: #ef4444 !important; }',
'.h2-station-page .h2-action-more-btn { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 8px; color: #64748b; cursor: pointer; transition: background 0.15s ease, color 0.15s ease; }',
'.h2-station-page .h2-action-more-btn:hover { background: #f1f5f9; color: #334155; }',
'.h2-station-page .h2-action-more-btn:focus-visible { outline: 2px solid #10b981; outline-offset: 2px; }',
'.h2-station-page .h2-row-actions { display: inline-flex; align-items: center; gap: 4px; }',
'.h2-station-page .lc-station-name { font-weight: 700; color: #0f172a; font-size: 13px; }',
'.h2-station-page .lc-station-name-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }',
'.h2-station-page .lc-station-name-row .lc-station-name { min-width: 0; }',
'.h2-station-page .lc-station-signed-tag { margin: 0 !important; border-radius: 6px !important; font-weight: 600 !important; flex-shrink: 0; line-height: 20px !important; }',
'.h2-station-page .lc-refuel-kg-row { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; min-width: 0; }',
'.h2-station-page .lc-refuel-freq-tag { margin: 0 !important; border-radius: 6px !important; font-weight: 600 !important; flex-shrink: 0; line-height: 20px !important; }',
'.h2-station-page .lc-station-region { color: #64748b; font-size: 12px; margin-bottom: 2px; }',
'.h2-station-page .lc-station-contact-name { font-weight: 600; color: #0f172a; font-size: 13px; line-height: 1.35; }',
'.h2-station-page .lc-station-contact-phone { color: #64748b; font-size: 12px; margin-top: 2px; line-height: 1.35; font-variant-numeric: tabular-nums; }',
'.h2-station-page .h2-drawer-section-title { font-size: 14px; font-weight: 700; color: #0f172a; margin: 4px 0 12px; display: flex; align-items: center; gap: 8px; }',
'.h2-station-page .h2-drawer-section-title::before { content: ""; width: 3px; height: 14px; border-radius: 2px; background: linear-gradient(180deg, #10b981, #34d399); flex-shrink: 0; }',
'.h2-station-page .h2-region-address { display: flex; flex-direction: column; gap: 12px; width: 100%; }',
'.h2-station-page .h2-region-address .ant-select, .h2-station-page .h2-region-address .ant-input { width: 100%; }',
'.h2-station-page .h2-region-address--inline { flex-direction: row; align-items: center; gap: 8px; }',
'.h2-station-page .h2-region-address--inline .h2-region-address-cascader { flex: 0 0 38%; max-width: 220px; min-width: 140px; }',
'.h2-station-page .h2-region-address--inline .h2-region-address-detail { flex: 1; min-width: 0; }',
'.h2-station-page .h2-create-radio-group { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; min-height: 32px; }',
'.h2-station-page .h2-create-radio-group .ant-radio-wrapper { margin-inline-end: 0; font-size: 14px; color: #1d2129; }',
'.h2-station-page .h2-contract-dates { display: flex; align-items: center; gap: 8px; width: 100%; flex-wrap: wrap; }',
'.h2-station-page .h2-contract-dates-sep { color: #94a3b8; font-size: 13px; flex-shrink: 0; }',
'.h2-station-page .h2-contract-upload { display: flex; flex-direction: column; gap: 10px; width: 100%; }',
'.h2-station-page .h2-contract-upload-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }',
'.h2-station-page .h2-contract-file-list { display: flex; flex-direction: column; gap: 6px; }',
'.h2-station-page .h2-contract-file-item { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 10px; border-radius: 6px; background: #f8fafc; border: 1px solid #e2e8f0; font-size: 13px; }',
'.h2-station-page .h2-contract-file-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #334155; }',
'.h2-station-page .h2-contract-file-btns { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }',
'.h2-station-page--create .h2-create-form .h2-create-upload-btn.ant-upload-wrapper { width: auto; }',
'.h2-station-page--create .h2-create-form .h2-region-address { gap: 12px; margin-top: 0; }',
'.h2-station-page .h2-business-hours { display: flex; flex-direction: column; gap: 12px; width: 100%; }',
'.h2-station-page .h2-business-hours-range { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; width: 100%; }',
'.h2-station-page .h2-business-hours-range-item { display: flex; flex-direction: column; gap: 6px; min-width: 0; }',
'.h2-station-page .h2-business-hours-range-label { font-size: 12px; color: #64748b; line-height: 1.2; }',
'.h2-station-page--create .h2-create-form .h2-business-hours .ant-picker { width: 100% !important; height: 32px !important; border-radius: 2px !important; border: 1px solid #e5e6eb !important; background: #fff !important; }',
'.h2-station-page--create .h2-create-form .h2-business-hours .ant-picker .ant-picker-input > input { font-size: 14px !important; color: #1d2129 !important; }',
'.h2-station-page--create .h2-create-form .h2-business-hours .ant-picker:not(.ant-picker-disabled):hover { border-color: #c9cdd4 !important; background: #fff !important; }',
'.h2-station-page--create .h2-create-form .h2-business-hours .ant-picker-focused { border-color: #10b981 !important; box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.2) !important; background: #fff !important; }',
'.h2-station-page--create .h2-create-form .h2-business-hours--col4 { gap: 8px; max-width: 100%; }',
'.h2-station-page--create .h2-create-form .h2-business-hours--col4 .ant-select { width: 100% !important; max-width: 100%; }',
'.h2-station-page--create .h2-create-form .h2-business-hours--col4 .h2-business-hours-range { grid-template-columns: 1fr; gap: 8px; }',
'.h2-station-page--create .h2-create-form .ant-col-6 .ant-form-item-control-input { max-width: 100%; }',
'.h2-station-page .h2-prd-modal .ant-modal-body { max-height: 70vh; overflow: auto; }',
'.h2-station-page .h2-prd-content { padding: 8px 0; white-space: pre-wrap; font-size: 13px; line-height: 1.65; color: #475569; }',
'.h2-station-page .h2-import-template-bar { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 14px 16px; margin-bottom: 14px; border-radius: 12px; background: linear-gradient(135deg, #ecfdf5 0%, #f8fafc 100%); border: 1px solid #bbf7d0; }',
'.h2-station-page .h2-import-template-bar-text { font-size: 13px; color: #475569; line-height: 1.55; flex: 1; min-width: 0; }',
'.h2-station-page .h2-import-preview { margin-top: 14px; padding: 12px 14px; border-radius: 10px; background: #f8fafc; border: 1px solid #e2e8f0; font-size: 13px; color: #334155; }',
'.h2-station-page .h2-import-error-list { margin: 8px 0 0; padding-left: 18px; max-height: 120px; overflow: auto; font-size: 12px; color: #b91c1c; }',
'.h2-station-page .h2-status-log-section { margin-top: 20px; padding-top: 16px; border-top: 1px solid #f1f5f9; }',
'.h2-station-page .h2-status-log-title { font-size: 14px; font-weight: 700; color: #0f172a; margin-bottom: 10px; }',
'.h2-station-page .h2-status-log-table .ant-table-thead > tr > th { background: #f8fafc !important; font-size: 12px !important; padding: 8px 12px !important; }',
'.h2-station-page .h2-status-log-table .ant-table-tbody > tr > td { font-size: 12px !important; padding: 8px 12px !important; }',
'.h2-station-page .h2-refuel-drill-link { border: none; background: none; padding: 0; font-weight: 700; color: #059669; cursor: pointer; font-variant-numeric: tabular-nums; font-size: 13px; }',
'.h2-station-page .h2-refuel-drill-link:hover { color: #047857; text-decoration: underline; }',
'.h2-station-page .h2-refuel-drill-link:focus-visible { outline: 2px solid #10b981; outline-offset: 2px; border-radius: 4px; }',
'.h2-station-page .h2-ledger-totals-bar { display: flex; align-items: stretch; gap: 0; margin-bottom: 12px; border: 1px solid #bae6fd; border-radius: 10px; overflow: hidden; background: #f8fafc; box-shadow: 0 1px 0 rgba(15, 23, 42, 0.04); }',
'.h2-station-page .h2-ledger-totals-bar__title { display: flex; align-items: center; justify-content: center; min-width: 72px; padding: 10px 14px; font-size: 14px; font-weight: 700; color: #0f172a; background: #e8f4fc; border-right: 1px solid #bae6fd; flex-shrink: 0; }',
'.h2-station-page .h2-ledger-totals-bar__items { display: flex; flex: 1; flex-wrap: wrap; }',
'.h2-station-page .h2-ledger-totals-bar__item { flex: 1; min-width: 140px; padding: 8px 20px; border-right: 1px solid #e2e8f0; display: flex; flex-direction: column; justify-content: center; gap: 4px; }',
'.h2-station-page .h2-ledger-totals-bar__item:last-child { border-right: none; }',
'.h2-station-page .h2-ledger-totals-bar__label { font-size: 12px; color: rgba(15, 23, 42, 0.55); font-weight: 500; line-height: 1.2; }',
'.h2-station-page .h2-ledger-totals-bar__value { font-size: 16px; font-weight: 700; color: #0f172a; font-variant-numeric: tabular-nums; line-height: 1.3; }',
'.h2-station-page .h2-refuel-record-table .ant-table-thead > tr > th { background: #f8fafc !important; font-size: 12px !important; padding: 8px 12px !important; }',
'.h2-station-page .h2-refuel-record-table .ant-table-tbody > tr > td { font-size: 12px !important; padding: 8px 12px !important; }',
'.h2-station-page .h2-prepaid-balance-cell { display: flex; align-items: center; justify-content: flex-end; gap: 6px; flex-wrap: nowrap; box-sizing: border-box; }',
'.h2-station-page .h2-prepaid-balance-cell .h2-prepaid-balance-amount { flex: 0 0 auto; white-space: nowrap; border: none; background: none; padding: 0; font: inherit; font-weight: 700; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; font-variant-numeric: tabular-nums; }',
'.h2-station-page .h2-prepaid-balance-cell .h2-prepaid-balance-amount:focus-visible { outline: 2px solid #10b981; outline-offset: 2px; border-radius: 4px; }',
'.h2-station-page .h2-prepaid-balance-cell .lc-station-signed-tag { flex-shrink: 0; }',
'.h2-station-page .lc-table-card .ant-table-tbody > tr:not(.ant-table-measure-row) > td.h2-cell-prepaid-balance { overflow: visible !important; }',
'.h2-station-page .h2-balance-record-table .ant-table-thead > tr > th { background: #f8fafc !important; font-size: 12px !important; padding: 8px 12px !important; }',
'.h2-station-page .h2-balance-record-table .ant-table-tbody > tr > td { font-size: 12px !important; padding: 8px 12px !important; }',
'.h2-station-page.h2-station-page--create { padding: 0 0 96px; height: auto; min-height: 100dvh; overflow: auto; }',
'.h2-station-page--create .h2-create-shell { width: 100%; max-width: none; margin: 0; padding: 16px 20px 0; box-sizing: border-box; }',
'.h2-station-page--create .h2-create-topbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 16px; padding: 12px 16px; background: #fff; border-radius: 4px; border: 1px solid #e2e8f0; }',
'.h2-station-page--create .h2-create-back-btn { display: inline-flex !important; align-items: center; gap: 6px; height: 32px; padding: 0 12px !important; border-radius: 4px !important; font-weight: 500; color: #475569 !important; border: 1px solid #e2e8f0 !important; background: #fff !important; }',
'.h2-station-page--create .h2-create-back-btn:hover { color: #059669 !important; border-color: #10b981 !important; background: #f0fdf4 !important; }',
'.h2-station-page--create .h2-create-back-btn:focus-visible { outline: 2px solid #10b981; outline-offset: 2px; }',
'.h2-station-page--create .h2-create-topbar-actions { display: flex; align-items: center; gap: 10px; }',
'.h2-station-page .h2-create-card.ant-card { border-radius: 16px !important; border: 1px solid #e2e8f0 !important; box-shadow: 0 4px 20px -4px rgba(15, 23, 42, 0.05) !important; margin-bottom: 16px; transition: box-shadow 0.2s ease, border-color 0.2s ease; }',
'.h2-station-page .h2-create-card:hover { box-shadow: 0 8px 28px -6px rgba(15, 23, 42, 0.08) !important; }',
'.h2-station-page .h2-create-card > .ant-card-head { border-bottom: 1px solid #f1f5f9 !important; min-height: auto; padding: 16px 22px !important; background: linear-gradient(180deg, #fafbfc 0%, #fff 100%); }',
'.h2-station-page .h2-create-card > .ant-card-head .ant-card-head-title { font-size: 15px !important; font-weight: 700 !important; color: #0f172a !important; padding: 0 !important; }',
'.h2-station-page .h2-create-card > .ant-card-body { padding: 8px 22px 20px !important; }',
'.h2-station-page .h2-card-title-bar { display: inline-flex; align-items: center; gap: 10px; }',
'.h2-station-page .h2-card-title-bar::before { content: ""; width: 3px; height: 16px; border-radius: 2px; background: linear-gradient(180deg, #10b981, #34d399); flex-shrink: 0; }',
'.h2-station-page .h2-card-title-icon { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 10px; background: #ecfdf5; color: #059669; flex-shrink: 0; }',
'.h2-station-page .h2-form-section { margin-bottom: 4px; }',
'.h2-station-page .h2-form-section + .h2-form-section { margin-top: 8px; padding-top: 8px; border-top: 1px solid #f1f5f9; }',
'.h2-station-page--create .h2-create-form .ant-row { width: 100%; }',
'.h2-station-page--create .h2-create-form .ant-col-6 { min-width: 0; }',
'.h2-station-page--create .h2-create-form .ant-form-item { margin-bottom: 24px; }',
'.h2-station-page--create .h2-create-form .ant-form-item-label { padding: 0 0 8px; }',
'.h2-station-page--create .h2-create-form .ant-form-item-label > label { font-size: 14px; font-weight: 400; color: #1d2129; height: auto; }',
'.h2-station-page--create .h2-create-form .ant-form-item-label > label::after { display: none !important; }',
'.h2-station-page--create .h2-create-input.ant-input:not(.ant-input-disabled):not(:disabled), .h2-station-page--create .h2-create-form .ant-select:not(.ant-select-disabled) .ant-select-selector, .h2-station-page--create .h2-create-form .ant-cascader:not(.ant-select-disabled) .ant-select-selector { height: 32px !important; min-height: 32px !important; border-radius: 2px !important; font-size: 14px !important; border: 1px solid #e5e6eb !important; background: #fff !important; color: #1d2129 !important; }',
'.h2-station-page--create .h2-create-form .ant-input { padding: 4px 12px !important; }',
'.h2-station-page--create .h2-create-form .ant-input-textarea:not(.ant-input-disabled):not(:disabled) { height: auto !important; min-height: auto !important; border-radius: 2px !important; background: #fff !important; color: #1d2129 !important; border: 1px solid #e5e6eb !important; }',
'.h2-station-page--create .h2-create-form .ant-input:not(:disabled):not(.ant-input-disabled):hover, .h2-station-page--create .h2-create-form .ant-select:not(.ant-select-disabled):hover .ant-select-selector, .h2-station-page--create .h2-create-form .ant-cascader:not(.ant-select-disabled):hover .ant-select-selector { background: #fff !important; border-color: #c9cdd4 !important; }',
'.h2-station-page--create .h2-create-form .ant-input:focus, .h2-station-page--create .h2-create-form .ant-input-focused, .h2-station-page--create .h2-create-form .ant-select-focused .ant-select-selector, .h2-station-page--create .h2-create-form .ant-cascader-focused .ant-select-selector { background: #fff !important; border-color: #10b981 !important; box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.2) !important; }',
'.h2-station-page--create .h2-create-form .ant-input-disabled, .h2-station-page--create .h2-create-form .ant-input:disabled, .h2-station-page--create .h2-create-form .ant-select-disabled .ant-select-selector, .h2-station-page--create .h2-create-form .ant-cascader.ant-select-disabled .ant-select-selector { background: #f2f3f5 !important; color: rgba(0, 0, 0, 0.25) !important; cursor: not-allowed !important; }',
'.h2-station-page--create .h2-create-form .ant-select-selection-item { line-height: 30px !important; }',
'.h2-station-page--create .h2-signed-toggle { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; padding: 14px 16px; border-radius: 12px; background: #f8fafc; border: 1px solid #e2e8f0; margin-bottom: 4px; }',
'.h2-station-page--create .h2-signed-toggle-label { font-size: 13px; font-weight: 600; color: #334155; }',
'.h2-station-page--create .h2-signed-panel { display: grid; grid-template-rows: 0fr; opacity: 0; transition: grid-template-rows 0.28s ease-out, opacity 0.22s ease-out; }',
'.h2-station-page--create .h2-signed-panel--open { grid-template-rows: 1fr; opacity: 1; }',
'.h2-station-page--create .h2-signed-panel-inner { overflow: hidden; min-height: 0; }',
'.h2-station-page--create .h2-signed-panel-content { padding-top: 12px; }',
'.h2-station-page--create .h2-create-upload.ant-upload-wrapper .ant-upload-drag { border-radius: 12px !important; border: 1px dashed #cbd5e1 !important; background: #fafbfc !important; padding: 16px 12px !important; transition: border-color 0.2s ease, background 0.2s ease; }',
'.h2-station-page--create .h2-create-upload.ant-upload-wrapper .ant-upload-drag:hover { border-color: #10b981 !important; background: #f0fdf4 !important; }',
'.h2-station-page--create .h2-create-upload-hint { font-size: 12px; color: #64748b; margin-top: 4px; }',
'.h2-station-page .h2-supplier-mode-bar { margin-bottom: 0; }',
'.h2-station-page .h2-supplier-mode-card { position: relative; display: flex; align-items: flex-start; gap: 12px; width: 100%; padding: 14px 16px; min-height: 72px; border-radius: 12px; border: 2px solid #e2e8f0; background: #fff; cursor: pointer; text-align: left; transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease, transform 0.15s ease; }',
'.h2-station-page .h2-supplier-mode-card:hover { border-color: #86efac; background: #fafffe; }',
'.h2-station-page .h2-supplier-mode-card:active { transform: scale(0.99); }',
'.h2-station-page .h2-supplier-mode-card:focus-visible { outline: 2px solid #10b981; outline-offset: 2px; }',
'.h2-station-page .h2-supplier-mode-card--active { border-color: #10b981; background: linear-gradient(135deg, #ecfdf5 0%, #fff 70%); box-shadow: 0 4px 16px -4px rgba(16, 185, 129, 0.25); }',
'.h2-station-page .h2-supplier-mode-card-icon { flex-shrink: 0; width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; background: #f1f5f9; color: #64748b; transition: background 0.2s ease, color 0.2s ease; }',
'.h2-station-page .h2-supplier-mode-card--active .h2-supplier-mode-card-icon { background: #d1fae5; color: #047857; }',
'.h2-station-page .h2-supplier-mode-card-title { font-size: 14px; font-weight: 700; color: #0f172a; line-height: 1.3; }',
'.h2-station-page .h2-supplier-mode-card-desc { font-size: 12px; color: #64748b; margin-top: 4px; line-height: 1.45; }',
'.h2-station-page .h2-supplier-mode-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 14px; margin-bottom: 16px; padding: 10px 14px; border-radius: 10px; background: #f8fafc; border: 1px solid #e2e8f0; }',
'.h2-station-page .h2-supplier-type-tag { margin: 0 !important; border-radius: 6px !important; font-weight: 600 !important; }',
'.h2-station-page .h2-supplier-link-select { margin-bottom: 16px; padding: 14px 16px; border-radius: 12px; background: linear-gradient(135deg, #eff6ff 0%, #f8fafc 100%); border: 1px solid #bfdbfe; }',
'.h2-station-page .h2-create-footer { position: fixed; bottom: 0; left: 0; right: 0; z-index: 100; background: rgba(255, 255, 255, 0.92); backdrop-filter: blur(10px); border-top: 1px solid #e2e8f0; box-shadow: 0 -8px 24px rgba(15, 23, 42, 0.06); }',
'.h2-station-page .h2-create-footer-inner { width: 100%; max-width: none; margin: 0; padding: 14px 24px; display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; box-sizing: border-box; }',
'.h2-station-page .h2-create-footer-hint { font-size: 13px; color: #64748b; display: flex; align-items: center; gap: 10px; min-width: 0; }',
'.h2-station-page .h2-create-footer-progress { flex: 1; min-width: 120px; max-width: 200px; }',
'.h2-station-page .h2-create-footer-progress .ant-progress-text { font-size: 12px !important; font-weight: 700; color: #059669 !important; }',
'.h2-station-page .h2-create-footer-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-left: auto; }',
'.h2-station-page .h2-create-footer-actions .ant-btn { min-height: 44px; padding: 0 20px; border-radius: 10px; font-weight: 600; }',
'.h2-station-page .h2-create-footer-actions .ant-btn-primary { min-width: 120px; box-shadow: 0 4px 14px -2px rgba(16, 185, 129, 0.45); }',
'.h2-station-page .h2-create-footer-actions .ant-btn-primary:not(:disabled):hover { box-shadow: 0 6px 18px -2px rgba(16, 185, 129, 0.5); transform: translateY(-1px); }',
'.h2-station-page .h2-field-readonly .ant-input, .h2-station-page .h2-field-readonly .ant-select-selector, .h2-station-page .h2-field-readonly .ant-input-textarea { background: #f1f5f9 !important; color: #64748b !important; cursor: default !important; border-style: dashed !important; }',
'@media (prefers-reduced-motion: no-preference) { .h2-station-page--create .h2-create-card { animation: h2CreateCardIn 0.35s ease-out backwards; } .h2-station-page--create .h2-create-card:nth-of-type(2) { animation-delay: 0.08s; } }',
'@keyframes h2CreateCardIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }',
'@media (prefers-reduced-motion: reduce) { .h2-station-page--create .h2-create-card { animation: none; } .h2-station-page--create .h2-signed-panel { transition: none; } }'
].join('\n');
var H2_CURRENT_OPERATOR = '系统管理员';
function h2OperateTimestamp() {
return new Date().toISOString().slice(0, 16).replace('T', ' ');
}
function h2CreateBusinessStatusLog(beforeStatus, afterStatus, operator) {
return {
id: 'bsl-' + Date.now() + '-' + Math.floor(Math.random() * 1000),
operateTime: h2OperateTimestamp(),
operator: operator || H2_CURRENT_OPERATOR,
beforeStatus: beforeStatus || '—',
afterStatus: afterStatus || '—'
};
}
var H2_IMPORT_TEMPLATE_HEADERS = [
'加氢站名称', '省', '市', '详细地址', '是否签约', '签约开始时间', '签约结束时间', '营业状态', '营业时间', '联系人', '联系电话'
];
var H2_IMPORT_TEMPLATE_SAMPLE = [
['苏州新区加氢站(导入示例)', '江苏省', '苏州市', '工业园区星湖街100号', '是', '2025-01-01', '2027-12-31', '营业中', '08:00-20:00', '周八', '13900001111']
];
var H2_IMPORT_HEADER_MAP = {
'加氢站名称': 'name',
'站点名称': 'name',
'名称': 'name',
'省': 'province',
'省份': 'province',
'市': 'city',
'城市': 'city',
'详细地址': 'detail',
'地址详情': 'detail',
'是否签约': 'isSigned',
'签约状态': 'isSigned',
'签约开始时间': 'contractStart',
'签约开始': 'contractStart',
'签约结束时间': 'contractEnd',
'签约结束': 'contractEnd',
'营业状态': 'businessStatus',
'营业时间': 'businessHours',
'联系人': 'contact',
'联系电话': 'phone',
'电话': 'phone'
};
function h2CsvEscape(v) {
var s = String(v == null ? '' : v);
if (/[",\n\r]/.test(s)) return '"' + s.replace(/"/g, '""') + '"';
return s;
}
function h2DownloadCsv(filename, headers, rows) {
var lines = [headers.map(h2CsvEscape).join(',')].concat(
(rows || []).map(function (r) { return r.map(h2CsvEscape).join(','); })
);
var blob = new Blob(['\uFEFF' + lines.join('\n')], { type: 'text/csv;charset=utf-8;' });
var a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = filename;
a.click();
URL.revokeObjectURL(a.href);
}
function h2ParseCsvLine(line) {
var out = [];
var cur = '';
var inQuote = false;
var i;
for (i = 0; i < line.length; i++) {
var ch = line.charAt(i);
if (inQuote) {
if (ch === '"') {
if (line.charAt(i + 1) === '"') { cur += '"'; i++; }
else inQuote = false;
} else cur += ch;
} else if (ch === '"') inQuote = true;
else if (ch === ',') { out.push(cur.trim()); cur = ''; }
else cur += ch;
}
out.push(cur.trim());
return out;
}
function h2ParseSignedLabel(val) {
var s = String(val || '').trim();
if (!s) return false;
var lower = s.toLowerCase();
if (s === '是' || s === '已签约' || lower === 'yes' || lower === 'y' || lower === 'true' || lower === '1') return true;
if (s === '否' || s === '未签约' || lower === 'no' || lower === 'n' || lower === 'false' || lower === '0') return false;
return false;
}
function h2NormalizeBusinessStatus(val) {
var s = String(val || '').trim();
var i;
for (i = 0; i < H2_BUSINESS_STATUS_OPTIONS.length; i++) {
if (H2_BUSINESS_STATUS_OPTIONS[i].value === s) return s;
}
if (s.indexOf('暂停') >= 0) return '暂停营业';
if (s.indexOf('停止') >= 0 || s.indexOf('停业') >= 0) return '停止营业';
if (s.indexOf('营业') >= 0) return '营业中';
return '';
}
function h2ParseImportCsv(text) {
var raw = String(text || '').replace(/^\uFEFF/, '');
var lines = raw.split(/\r?\n/).filter(function (ln) { return ln.trim().length > 0; });
if (lines.length < 2) return { rows: [], headerError: '文件至少需要表头行与一行数据' };
var headers = h2ParseCsvLine(lines[0]).map(function (h) { return String(h || '').trim().replace(/^\uFEFF/, ''); });
var fieldIdx = {};
var hi;
for (hi = 0; hi < headers.length; hi++) {
var key = H2_IMPORT_HEADER_MAP[headers[hi]];
if (key && fieldIdx[key] == null) fieldIdx[key] = hi;
}
if (fieldIdx.name == null) return { rows: [], headerError: '缺少必填列「加氢站名称」' };
var rows = [];
var li;
for (li = 1; li < lines.length; li++) {
var cells = h2ParseCsvLine(lines[li]);
if (!cells.some(function (c) { return String(c || '').trim(); })) continue;
var get = function (field) {
var idx = fieldIdx[field];
return idx == null || idx < 0 ? '' : String(cells[idx] == null ? '' : cells[idx]).trim();
};
rows.push({
lineNo: li + 1,
name: get('name'),
province: get('province'),
city: get('city'),
detail: get('detail'),
isSigned: h2ParseSignedLabel(get('isSigned')),
contractStart: get('contractStart'),
contractEnd: get('contractEnd'),
businessStatus: h2NormalizeBusinessStatus(get('businessStatus')),
businessHours: get('businessHours'),
contact: get('contact'),
phone: get('phone')
});
}
return { rows: rows, headerError: null };
}
function h2ValidateImportRow(row, existingNames) {
var errors = [];
if (!(row.name || '').trim()) errors.push('加氢站名称不能为空');
else if (existingNames[(row.name || '').trim()]) errors.push('站点名称「' + row.name + '」已存在');
if (!(row.province || '').trim()) errors.push('省不能为空');
if (!(row.city || '').trim()) errors.push('市不能为空');
if (!(row.detail || '').trim()) errors.push('详细地址不能为空');
if (!(row.contact || '').trim()) errors.push('联系人不能为空');
if (!(row.phone || '').trim()) errors.push('联系电话不能为空');
if (!(row.businessStatus || '').trim()) errors.push('营业状态无效,请填写:营业中 / 暂停营业 / 停止营业');
if (row.isSigned) {
if (!row.contractStart) errors.push('已签约站点需填写签约开始时间');
if (!row.contractEnd) errors.push('已签约站点需填写签约结束时间');
}
return errors;
}
function h2ImportRowToRecord(row, id) {
var region = [row.province, row.city];
var form = {
name: row.name,
address: { region: region, detail: row.detail },
isSigned: row.isSigned,
contractStart: row.isSigned ? (row.contractStart || '') : '',
contractEnd: row.isSigned ? (row.contractEnd || '') : '',
contractFiles: [],
businessStatus: row.businessStatus || '营业中',
businessHours: row.businessHours || '',
contact: row.contact,
phone: row.phone
};
var record = h2FormToRecord(form, id);
record.businessStatusLogs = [];
return record;
}
function h2SvgIcon(paths, size) {
var s = size || 18;
return React.createElement('svg', {
width: s,
height: s,
viewBox: '0 0 24 24',
fill: 'none',
stroke: 'currentColor',
strokeWidth: 2,
strokeLinecap: 'round',
strokeLinejoin: 'round',
'aria-hidden': true
}, paths.map(function (p, i) {
if (p.tag === 'circle') return React.createElement('circle', { key: i, cx: p.cx, cy: p.cy, r: p.r });
if (p.tag === 'line') return React.createElement('line', { key: i, x1: p.x1, y1: p.y1, x2: p.x2, y2: p.y2 });
if (p.tag === 'rect') return React.createElement('rect', { key: i, x: p.x, y: p.y, width: p.width, height: p.height, rx: p.rx });
return React.createElement('path', { key: i, d: p.d });
}));
}
var H2_ICONS = {
station: h2SvgIcon([{ d: 'M3 21h18M5 21V7l8-4v18M19 21V11l-6-4' }]),
high: h2SvgIcon([{ d: 'M13 2L3 14h9l-1 8 10-12h-9l1-8z' }], 16),
low: h2SvgIcon([{ d: 'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z' }], 16),
none: h2SvgIcon([{ d: 'M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z' }, { tag: 'line', x1: 12, y1: 9, x2: 12, y2: 13 }, { tag: 'line', x1: 12, y1: 17, x2: 12.01, y2: 17 }], 16),
doc: h2SvgIcon([{ d: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z' }, { d: 'M14 2v6h6' }, { tag: 'line', x1: 16, y1: 13, x2: 8, y2: 13 }, { tag: 'line', x1: 16, y1: 17, x2: 8, y2: 17 }], 14),
upload: h2SvgIcon([{ d: 'M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4' }, { d: 'M17 8l-5-5-5 5' }, { tag: 'line', x1: 12, y1: 3, x2: 12, y2: 15 }], 14),
empty: h2SvgIcon([{ tag: 'circle', cx: 12, cy: 12, r: 10 }, { tag: 'line', x1: 8, y1: 12, x2: 16, y2: 12 }], 40),
back: h2SvgIcon([{ tag: 'line', x1: 19, y1: 12, x2: 5, y2: 12 }, { d: 'M12 19l-7-7 7-7' }], 16),
mapPin: h2SvgIcon([{ tag: 'path', d: 'M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z' }, { tag: 'circle', cx: 12, cy: 10, r: 3 }], 16),
user: h2SvgIcon([{ tag: 'path', d: 'M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2' }, { tag: 'circle', cx: 12, cy: 7, r: 4 }], 16),
building: h2SvgIcon([{ d: 'M3 21h18M5 21V7l8-4v18M19 21V11l-6-4' }], 18),
truck: h2SvgIcon([{ d: 'M1 3h15v13H1zM16 8h4l3 3v5h-7V8z' }, { tag: 'circle', cx: 5.5, cy: 18.5, r: 2.5 }, { tag: 'circle', cx: 18.5, cy: 18.5, r: 2.5 }], 16),
link: h2SvgIcon([{ tag: 'path', d: 'M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71' }, { tag: 'path', d: 'M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71' }], 16),
plus: h2SvgIcon([{ tag: 'line', x1: 12, y1: 5, x2: 12, y2: 19 }, { tag: 'line', x1: 5, y1: 12, x2: 19, y2: 12 }], 16),
file: h2SvgIcon([{ d: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z' }, { d: 'M14 2v6h6' }], 16)
};
function h2MoreIcon() {
return React.createElement('svg', {
viewBox: '0 0 16 16',
width: 16,
height: 16,
fill: 'currentColor',
'aria-hidden': true
},
React.createElement('circle', { cx: 8, cy: 3, r: 1.5 }),
React.createElement('circle', { cx: 8, cy: 8, r: 1.5 }),
React.createElement('circle', { cx: 8, cy: 13, r: 1.5 })
);
}
function h2DeriveFrequencyByRefuelCount(refuelCount) {
var n = typeof refuelCount === 'number' ? refuelCount : parseInt(refuelCount, 10);
if (!n || n <= 0) return 'none';
if (n >= 3) return 'high';
return 'low';
}
function h2FormatRegion(region) {
if (!region || !region.length) return '—';
return region.join('-');
}
function h2MatchRegionFilter(recordRegion, filterRegion) {
if (!filterRegion || !filterRegion.length) return true;
var rr = recordRegion || [];
if (filterRegion[0] && rr[0] !== filterRegion[0]) return false;
if (filterRegion[1] && rr[1] !== filterRegion[1]) return false;
return true;
}
function h2EmptyListFilters() {
return { name: '', signed: undefined, region: undefined, businessStatus: undefined };
}
/** 距签约结束日天数:正=剩余,负=已过期 */
function h2DaysUntilContractEnd(dateStr) {
if (!dateStr) return null;
var parts = String(dateStr).trim().split('-');
if (parts.length < 3) return null;
var y = parseInt(parts[0], 10);
var m = parseInt(parts[1], 10) - 1;
var d = parseInt(parts[2], 10);
if (isNaN(y) || isNaN(m) || isNaN(d)) return null;
var end = new Date(y, m, d, 23, 59, 59, 999);
var today = new Date();
today.setHours(0, 0, 0, 0);
return Math.ceil((end.getTime() - today.getTime()) / (1000 * 60 * 60 * 24));
}
function h2RenderContractRemainTag(contractEnd) {
var days = h2DaysUntilContractEnd(contractEnd);
if (days == null) return null;
var Tag = window.antd && window.antd.Tag;
if (!Tag) return null;
var tagProps = { style: { marginTop: 4, borderRadius: 6, fontWeight: 600, fontSize: 11 } };
if (days < 0) {
return React.createElement(Tag, Object.assign({}, tagProps, {
color: 'error',
'aria-label': '已过期 ' + Math.abs(days) + ' 天'
}), '已过期 ' + Math.abs(days) + ' 天');
}
if (days <= 30) {
return React.createElement(Tag, Object.assign({}, tagProps, {
color: 'warning',
'aria-label': '剩余 ' + days + ' 天'
}), '剩余 ' + days + ' 天');
}
return React.createElement(Tag, Object.assign({}, tagProps, {
color: 'success',
'aria-label': '剩余 ' + days + ' 天'
}), '剩余 ' + days + ' 天');
}
function h2BuildFullAddress(region, detail) {
var base = h2FormatRegion(region);
if (!detail) return base === '—' ? '' : base;
return base === '—' ? detail : base + detail;
}
function h2EmptyAddressValue() {
return { region: [], detail: '' };
}
function h2KpiIcon(key) {
if (key === 'high') return H2_ICONS.high;
if (key === 'low') return H2_ICONS.low;
if (key === 'none') return H2_ICONS.none;
return H2_ICONS.station;
}
function h2SignedFilterIcon(key) {
if (key === 'yes') {
return h2SvgIcon([{ d: 'M22 11.08V12a10 10 0 1 1-5.93-9.14' }, { d: 'M22 4 12 14.01l-3-3' }], 16);
}
return h2SvgIcon([{ tag: 'circle', cx: 12, cy: 12, r: 10 }, { tag: 'line', x1: 15, y1: 9, x2: 9, y2: 15 }, { tag: 'line', x1: 9, y1: 9, x2: 15, y2: 15 }], 16);
}
/** 地址组件:省/市级联 + 详细地址(无子标题,挂在「地址」表单项下) */
function RegionAddressInput(props) {
var antd = window.antd;
var Cascader = antd.Cascader;
var Input = antd.Input;
var value = props.value || h2EmptyAddressValue();
var onChange = props.onChange;
var disabled = props.disabled;
var inputClassName = props.inputClassName || '';
var layout = props.layout || 'stack';
var detailPlaceholder = props.detailPlaceholder || '请输入街道、门牌号等详细地址';
var regionPlaceholder = props.regionPlaceholder || '请选择省 / 市';
var fieldStyle = props.fieldStyle || { width: '100%', borderRadius: 8 };
var rootCls = 'h2-region-address' + (layout === 'inline' ? ' h2-region-address--inline' : '');
return React.createElement('div', { className: rootCls },
React.createElement(Cascader, {
className: inputClassName + (layout === 'inline' ? ' h2-region-address-cascader' : ''),
options: H2_REGION_CASCADER_OPTIONS,
value: value.region && value.region.length ? value.region : undefined,
onChange: function (v) { onChange && onChange({ region: v || [], detail: value.detail || '' }); },
placeholder: regionPlaceholder,
style: layout === 'inline' ? { width: '100%', borderRadius: fieldStyle.borderRadius || 8 } : fieldStyle,
disabled: disabled,
allowClear: !disabled
}),
React.createElement(Input, {
className: inputClassName + (layout === 'inline' ? ' h2-region-address-detail' : ''),
value: value.detail || '',
onChange: function (e) { onChange && onChange({ region: value.region || [], detail: e.target.value }); },
placeholder: detailPlaceholder,
disabled: disabled,
maxLength: 200,
style: layout === 'inline' ? { width: '100%', borderRadius: fieldStyle.borderRadius || 8 } : fieldStyle
})
);
}
/** 供应商通讯地址:省/市 + 详细地址(横向嵌入) */
function SupplierCityAddressInput(props) {
var antd = window.antd;
var Cascader = antd.Cascader;
var Input = antd.Input;
var city = props.city;
var address = props.address || '';
var onChange = props.onChange;
var disabled = props.disabled;
var inputClassName = props.inputClassName || '';
var onCityChange = props.onCityChange;
return React.createElement('div', { className: 'h2-region-address h2-region-address--inline' },
React.createElement(Cascader, {
className: inputClassName + ' h2-region-address-cascader',
options: H2_REGION_CASCADER_OPTIONS,
value: city && city.length ? city : undefined,
onChange: onCityChange,
placeholder: '请选择省 / 市',
style: { width: '100%' },
disabled: disabled,
allowClear: !disabled
}),
React.createElement(Input, {
className: inputClassName + ' h2-region-address-detail',
value: address,
disabled: disabled,
placeholder: '请输入详细地址',
maxLength: 200,
style: { width: '100%' },
onChange: function (e) { onChange && onChange(e.target.value); }
})
);
}
function h2GetUploadFileUrl(file) {
if (!file) return '';
if (file.url) return file.url;
if (file.thumbUrl) return file.thumbUrl;
if (file.originFileObj && typeof URL !== 'undefined' && URL.createObjectURL) {
try { return URL.createObjectURL(file.originFileObj); } catch (e) { return ''; }
}
return '';
}
function h2DownloadUploadFile(file) {
var url = h2GetUploadFileUrl(file);
if (!url) return;
var a = document.createElement('a');
a.href = url;
a.download = file.name || '附件';
a.target = '_blank';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
/** 合同附件:按钮上传 + 预览/下载 */
function ContractFilesUpload(props) {
var antd = window.antd;
var Upload = antd.Upload;
var Button = antd.Button;
var fileList = props.fileList || [];
var disabled = props.disabled;
return React.createElement('div', { className: 'h2-contract-upload' },
React.createElement('div', { className: 'h2-contract-upload-actions' },
React.createElement(Upload, {
className: 'h2-create-upload-btn',
multiple: true,
disabled: disabled,
fileList: fileList,
beforeUpload: function () { return false; },
onChange: props.onChange,
showUploadList: false
},
React.createElement(Button, {
type: 'default',
icon: H2_ICONS.upload,
disabled: disabled
}, '上传附件')
),
React.createElement('span', { style: { fontSize: 12, color: '#94a3b8' } }, '支持 PDF、图片可多选非必填')
),
fileList.length
? React.createElement('div', { className: 'h2-contract-file-list' },
fileList.map(function (file) {
return React.createElement('div', { key: file.uid, className: 'h2-contract-file-item' },
React.createElement('span', { className: 'h2-contract-file-name', title: file.name }, file.name || '未命名附件'),
React.createElement('div', { className: 'h2-contract-file-btns' },
React.createElement(Button, {
type: 'link',
size: 'small',
disabled: disabled,
onClick: function () {
var url = h2GetUploadFileUrl(file);
if (url) window.open(url, '_blank');
}
}, '预览'),
React.createElement(Button, {
type: 'link',
size: 'small',
disabled: disabled,
onClick: function () { h2DownloadUploadFile(file); }
}, '下载')
)
);
})
)
: null
);
}
function h2StationContactPhone(station) {
return (station.mobilePhone || '').trim() || (station.landlinePhone || '').trim();
}
function h2ApplyStationContactPhone(station, text) {
var v = String(text || '').trim();
if (/^1\d{10}$/.test(v.replace(/\s/g, ''))) {
return Object.assign({}, station, { mobilePhone: v.replace(/\s/g, ''), landlinePhone: '' });
}
return Object.assign({}, station, { mobilePhone: '', landlinePhone: v });
}
var H2_BUSINESS_HOURS_MODE_OPTIONS = [
{ label: '全天营业', value: 'allDay' },
{ label: '非全天营业', value: 'custom' }
];
function h2IsAllDayBusinessHours(str) {
var s = String(str || '').trim();
if (!s || s === '—') return false;
if (s === '全天营业' || s === '24小时' || s === '24 小时') return true;
return /^00:00\s*[-]\s*24:00$/.test(s);
}
function h2ParseBusinessHours(str) {
var s = String(str || '').trim();
if (!s || s === '—') {
return { mode: 'allDay', start: '08:00', end: '22:00' };
}
if (h2IsAllDayBusinessHours(s)) {
return { mode: 'allDay', start: '08:00', end: '22:00' };
}
var parts = s.split('-');
if (parts.length >= 2) {
return {
mode: 'custom',
start: (parts[0] || '').trim(),
end: (parts.slice(1).join('-') || '').trim()
};
}
return { mode: 'custom', start: '', end: '' };
}
function h2FormatBusinessHours(val) {
if (!val || val.mode === 'allDay') return '00:00-24:00';
var start = (val.start || '').trim();
var end = (val.end || '').trim();
if (!start || !end) return '';
return start + '-' + end;
}
function h2DisplayBusinessHours(str) {
var s = String(str || '').trim();
if (!s || s === '—') return '—';
if (h2IsAllDayBusinessHours(s) || s === '全天营业') return '全天营业';
var parsed = h2ParseBusinessHours(s);
if (parsed.mode === 'custom' && parsed.start && parsed.end) return parsed.start + '-' + parsed.end;
return s;
}
function h2NormalizeTimeText(text) {
var s = String(text || '').trim();
if (!s) return '';
var m = /^(\d{1,2}):(\d{2})$/.exec(s);
if (!m) return s;
var h = parseInt(m[1], 10);
var min = parseInt(m[2], 10);
if (isNaN(h) || isNaN(min) || h < 0 || h > 23 || min < 0 || min > 59) return s;
return (h < 10 ? '0' : '') + h + ':' + (min < 10 ? '0' : '') + min;
}
function h2TimeTextToDayjs(text) {
var dayjs = window.dayjs;
if (!dayjs) return null;
var norm = h2NormalizeTimeText(text);
if (!norm) return null;
var parts = norm.split(':');
return dayjs().hour(parseInt(parts[0], 10)).minute(parseInt(parts[1], 10)).second(0).millisecond(0);
}
function h2DayjsToTimeText(d) {
var dayjs = window.dayjs;
if (!d || !dayjs) return '';
return dayjs(d).format('HH:mm');
}
/** 营业时间:全天 / 非全天 + 起止时间(时:分,可输入) */
function BusinessHoursInput(props) {
var antd = window.antd;
var Select = antd.Select;
var TimePicker = antd.TimePicker;
var Input = antd.Input;
var parsed = h2ParseBusinessHours(props.value);
var onChange = props.onChange;
var disabled = props.disabled;
var inputClassName = props.inputClassName || '';
var fieldStyle = props.fieldStyle || { width: '100%' };
var layout = props.layout || 'full';
var dayjs = window.dayjs;
var rootClass = 'h2-business-hours' + (layout === 'col4' ? ' h2-business-hours--col4' : '');
var emit = function (next) {
onChange && onChange(h2FormatBusinessHours(next));
};
var renderTimeField = function (label, timeKey, placeholder) {
var timeVal = parsed[timeKey] || '';
var onTimeChange = function (nextText) {
var patch = { mode: 'custom', start: parsed.start || '', end: parsed.end || '' };
patch[timeKey] = h2NormalizeTimeText(nextText);
emit(patch);
};
return React.createElement('div', { className: 'h2-business-hours-range-item', key: timeKey },
React.createElement('span', { className: 'h2-business-hours-range-label' }, label),
dayjs
? React.createElement(TimePicker, {
className: inputClassName,
format: 'HH:mm',
minuteStep: 1,
hourStep: 1,
showNow: false,
allowClear: !disabled,
inputReadOnly: false,
disabled: disabled,
style: fieldStyle,
placeholder: placeholder,
value: h2TimeTextToDayjs(timeVal),
onChange: function (d) { onTimeChange(d ? h2DayjsToTimeText(d) : ''); }
})
: React.createElement(Input, {
className: inputClassName,
disabled: disabled,
style: fieldStyle,
placeholder: placeholder || 'HH:mm',
value: timeVal,
maxLength: 5,
onChange: function (e) { onTimeChange(e.target.value); },
onBlur: function (e) { onTimeChange(e.target.value); }
})
);
};
return React.createElement('div', { className: rootClass },
React.createElement(Select, {
className: inputClassName,
value: parsed.mode,
options: H2_BUSINESS_HOURS_MODE_OPTIONS,
style: fieldStyle,
disabled: disabled,
placeholder: '请选择营业时间',
onChange: function (mode) {
if (mode === 'allDay') emit({ mode: 'allDay', start: parsed.start, end: parsed.end });
else emit({
mode: 'custom',
start: parsed.start || '08:00',
end: parsed.end || '22:00'
});
},
dropdownStyle: { borderRadius: 8 }
}),
parsed.mode === 'custom'
? React.createElement('div', { className: 'h2-business-hours-range' },
renderTimeField('开始时间', 'start', '请选择开始时间'),
renderTimeField('结束时间', 'end', '请选择结束时间')
)
: null
);
}
function h2CreateEmptyForm() {
return {
name: '',
address: h2EmptyAddressValue(),
isSigned: true,
contractStart: '',
contractEnd: '',
contractFiles: [],
businessStatus: '营业中',
businessHours: '',
contact: '',
phone: ''
};
}
function h2RecordToForm(record) {
if (!record) return h2CreateEmptyForm();
return {
name: record.name || '',
address: {
region: (record.region || []).slice(),
detail: record.addressDetail || ''
},
isSigned: record.isSigned !== false,
contractStart: record.contractStart || '',
contractEnd: record.contractEnd || '',
contractFiles: (record.contractFiles || []).map(function (f, i) {
return Object.assign({}, f, { uid: f.uid || ('f-' + i), status: 'done' });
}),
businessStatus: record.businessStatus || '营业中',
businessHours: record.businessHours || '',
contact: record.contact || '',
phone: record.phone || ''
};
}
function h2FormToRecord(form, id) {
var files = (form.contractFiles || []).map(function (f) {
return { uid: f.uid, name: f.name || '合同附件.pdf', url: f.url || '' };
});
return {
id: id,
name: (form.name || '').trim(),
region: form.address.region || [],
addressDetail: (form.address.detail || '').trim(),
fullAddress: h2BuildFullAddress(form.address.region, form.address.detail),
isSigned: !!form.isSigned,
contractStart: form.contractStart || '',
contractEnd: form.contractEnd || '',
contractFiles: files,
businessStatus: form.businessStatus || '营业中',
businessHours: (form.businessHours || '').trim(),
contact: (form.contact || '').trim(),
phone: (form.phone || '').trim(),
updateTime: new Date().toISOString().slice(0, 16).replace('T', ' ')
};
}
var H2_MOCK_STATIONS = [
{
id: 1,
name: '嘉兴加氢站(一期)',
region: ['浙江省', '嘉兴市'],
addressDetail: '南湖区科技大道88号',
fullAddress: '浙江省-嘉兴市南湖区科技大道88号',
isSigned: true,
contractStart: '2024-01-01',
contractEnd: '2026-12-31',
contractFiles: [{ uid: 'c1', name: '嘉兴加氢站签约合同.pdf' }],
businessStatus: '营业中',
businessHours: '08:00-22:00',
costUnitPrice: 42.5,
customerUnitPrice: 45,
prepaidBalance: 85620.0,
contact: '张三',
phone: '13800138001',
businessStatusLogs: [],
updateTime: '2026-05-20 14:30'
},
{
id: 2,
name: '杭州临平加氢站',
region: ['浙江省', '杭州市'],
addressDetail: '临平区东湖街道能源路16号',
fullAddress: '浙江省-杭州市临平区东湖街道能源路16号',
isSigned: true,
contractStart: '2025-03-01',
contractEnd: '2027-02-28',
contractFiles: [{ uid: 'c2', name: '临平加氢站合作协议.pdf' }, { uid: 'c3', name: '临平加氢站补充协议.pdf' }],
businessStatus: '营业中',
businessHours: '00:00-24:00',
prepaidBalance: 125000.5,
contact: '李四',
phone: '13900139002',
updateTime: '2026-06-01 09:15'
},
{
id: 3,
name: '上海宝山加氢站',
region: ['上海市', '上海市'],
addressDetail: '宝山区富联路128号',
fullAddress: '上海市-上海市宝山区富联路128号',
isSigned: true,
contractStart: '2023-06-01',
contractEnd: '2025-05-31',
contractFiles: [{ uid: 'c4', name: '宝山加氢站合同(即将到期).pdf' }],
businessStatus: '暂停营业',
businessHours: '09:00-18:00',
prepaidBalance: -3250.0,
businessStatusLogs: [
{ id: 'bsl-3-2', operateTime: '2026-04-01 10:00', operator: '王五', beforeStatus: '营业中', afterStatus: '暂停营业' },
{ id: 'bsl-3-1', operateTime: '2026-03-15 09:30', operator: '系统管理员', beforeStatus: '暂停营业', afterStatus: '营业中' }
],
contact: '王五',
phone: '13700137003',
updateTime: '2026-04-12 16:40'
},
{
id: 4,
name: '平湖合作停车场(待建加氢)',
region: ['浙江省', '嘉兴市'],
addressDetail: '平湖市乍嘉公路与平善大道交叉口',
fullAddress: '浙江省-嘉兴市平湖市乍嘉公路与平善大道交叉口',
isSigned: false,
contractStart: '',
contractEnd: '',
contractFiles: [],
businessStatus: '停止营业',
businessHours: '—',
prepaidBalance: 0,
contact: '赵六',
phone: '13600136004',
updateTime: '2026-03-08 11:20'
},
{
id: 5,
name: '苏州工业园区备用站',
region: ['江苏省', '苏州市'],
addressDetail: '工业园区星湖街328号',
fullAddress: '江苏省-苏州市工业园区星湖街328号',
isSigned: false,
contractStart: '',
contractEnd: '',
contractFiles: [],
businessStatus: '停止营业',
businessHours: '10:00-17:00',
prepaidBalance: 15800.0,
contact: '钱七',
phone: '13500135005',
updateTime: '2026-02-18 08:50'
}
];
/** 站点加氢记录 Mock字段对齐车辆氢费明细 */
var H2_MOCK_REFUEL_RECORDS = [
{ id: 'rf-1', stationName: '嘉兴加氢站(一期)', hydrogenTime: '2026-05-28 10:21:08', plateNo: '浙A12345F', customerName: '嘉兴市鑫峤供应链科技有限公司', hydrogenKg: 12.5, costUnitPrice: 42.5, costAmount: 531.25, customerUnitPrice: 45, customerAmount: 562.5 },
{ id: 'rf-2', stationName: '嘉兴加氢站(一期)', hydrogenTime: '2026-05-26 14:08:33', plateNo: '浙A67890F', customerName: '浙江绿运物流有限公司', hydrogenKg: 10.0, costUnitPrice: 42.5, costAmount: 425.0, customerUnitPrice: 45, customerAmount: 450.0 },
{ id: 'rf-3', stationName: '嘉兴加氢站(一期)', hydrogenTime: '2026-05-22 09:15:00', plateNo: '浙A88888F', customerName: '嘉兴市鑫峤供应链科技有限公司', hydrogenKg: 18.3, costUnitPrice: 42.5, costAmount: 777.75, customerUnitPrice: 45, customerAmount: 823.5 },
{ id: 'rf-4', stationName: '嘉兴加氢站(一期)', hydrogenTime: '2026-05-18 16:42:11', plateNo: '浙A03561F', customerName: '嘉兴港务氢能运输队', hydrogenKg: 15.6, costUnitPrice: 42.5, costAmount: 663.0, customerUnitPrice: 45, customerAmount: 702.0 },
{ id: 'rf-5', stationName: '杭州临平加氢站', hydrogenTime: '2026-05-30 09:30:22', plateNo: '浙B23456F', customerName: '杭州临平城配中心', hydrogenKg: 15.3, costUnitPrice: 43.0, costAmount: 657.9, customerUnitPrice: 46, customerAmount: 703.8 },
{ id: 'rf-6', stationName: '杭州临平加氢站', hydrogenTime: '2026-05-27 18:10:05', plateNo: '浙B99999F', customerName: '浙江氢运科技', hydrogenKg: 18.2, costUnitPrice: 43.0, costAmount: 782.6, customerUnitPrice: 46, customerAmount: 837.2 },
{ id: 'rf-7', stationName: '杭州临平加氢站', hydrogenTime: '2026-05-24 11:05:40', plateNo: '浙B58888F', customerName: '杭州临平城配中心', hydrogenKg: 11.8, costUnitPrice: 43.0, costAmount: 507.4, customerUnitPrice: 46, customerAmount: 542.8 },
{ id: 'rf-8', stationName: '上海宝山加氢站', hydrogenTime: '2026-04-20 16:45:18', plateNo: '沪A88888F', customerName: '上海羚牛氢运', hydrogenKg: 8.0, costUnitPrice: 44.0, costAmount: 352.0, customerUnitPrice: 47, customerAmount: 376.0 },
{ id: 'rf-9', stationName: '上海宝山加氢站', hydrogenTime: '2026-04-08 09:12:55', plateNo: '沪BDB9161F', customerName: '宝山园区试运车队', hydrogenKg: 9.5, costUnitPrice: 44.0, costAmount: 418.0, customerUnitPrice: 47, customerAmount: 446.5 },
{ id: 'rf-10', stationName: '苏州工业园区备用站', hydrogenTime: '2026-03-15 10:00:00', plateNo: '苏E33333F', customerName: '苏州试运客户', hydrogenKg: 6.2, costUnitPrice: 41.0, costAmount: 254.2, customerUnitPrice: 44, customerAmount: 272.8 }
];
function h2FormatKgNum(v) {
var n = typeof v === 'number' ? v : parseFloat(v);
return isNaN(n) ? '0.00' : n.toFixed(2);
}
function h2FormatYuanNum(v) {
var n = typeof v === 'number' ? v : parseFloat(v);
return isNaN(n) ? '0.00' : n.toFixed(2);
}
function h2NumOrZero(v) {
var n = typeof v === 'number' ? v : parseFloat(v);
return isNaN(n) ? 0 : n;
}
function h2FormatLedgerMoney(v) {
if (v === null || v === undefined || v === '' || Number(v) === 0) return '—';
return h2FormatYuanNum(v);
}
/** 原型:加氢站预付余额变更明细(联调后对接加氢站打款/余额流水接口) */
function h2BuildMockPrepaidBalanceRows(record) {
var seed = 0;
var code = String(record && record.id != null ? record.id : '');
var nameKey = String((record && record.name) || '');
var i;
for (i = 0; i < code.length; i++) seed += code.charCodeAt(i);
for (i = 0; i < nameKey.length; i++) seed += nameKey.charCodeAt(i);
var stationName = (record && record.name) || '—';
var finalBalance = h2NumOrZero(record && record.prepaidBalance);
var lineCount = Math.max(5, 6 + (seed % 5));
var rows = [];
var openingBalance = Math.round((finalBalance + 38000 + seed * 620) * 100) / 100;
if (openingBalance < 0) openingBalance = Math.abs(openingBalance) + 50000;
rows.push({
key: code + '-bal-0',
stationName: stationName,
incomeAmount: openingBalance,
expenseAmount: null,
balance: openingBalance,
orderNo: 'QC' + code + '260101'
});
var balance = openingBalance;
for (i = 1; i < lineCount - 1; i++) {
var isIncome = (seed + i) % 3 === 0;
var incomeAmount = null;
var expenseAmount = null;
if (isIncome) {
incomeAmount = Math.round((6000 + (seed + i) * 380) * 100) / 100;
balance = Math.round((balance + incomeAmount) * 100) / 100;
} else {
expenseAmount = Math.round((2800 + (seed + i) * 210) * 100) / 100;
balance = Math.round((balance - expenseAmount) * 100) / 100;
}
rows.push({
key: code + '-bal-' + i,
stationName: stationName,
incomeAmount: incomeAmount,
expenseAmount: expenseAmount,
balance: balance,
orderNo: (isIncome ? 'DK' : 'JQ') + code + String(200 + i).padStart(5, '0')
});
}
var diff = Math.round((finalBalance - balance) * 100) / 100;
if (Math.abs(diff) < 0.01) {
rows.push({
key: code + '-bal-last',
stationName: stationName,
incomeAmount: null,
expenseAmount: null,
balance: finalBalance,
orderNo: 'BZ' + code + String(900).padStart(5, '0')
});
} else if (diff > 0) {
rows.push({
key: code + '-bal-last',
stationName: stationName,
incomeAmount: diff,
expenseAmount: null,
balance: finalBalance,
orderNo: 'DK' + code + String(999).padStart(5, '0')
});
} else {
rows.push({
key: code + '-bal-last',
stationName: stationName,
incomeAmount: null,
expenseAmount: Math.round(Math.abs(diff) * 100) / 100,
balance: finalBalance,
orderNo: 'JQ' + code + String(999).padStart(5, '0')
});
}
return rows;
}
function h2GetRefuelRecordsByStation(stationName) {
var name = String(stationName || '').trim();
return H2_MOCK_REFUEL_RECORDS.filter(function (r) { return r.stationName === name; }).slice().sort(function (a, b) {
return String(b.hydrogenTime || '').localeCompare(String(a.hydrogenTime || ''));
});
}
function h2CalcRefuelStats(stationName) {
var records = h2GetRefuelRecordsByStation(stationName);
var totalKg = 0;
var i;
for (i = 0; i < records.length; i++) totalKg += records[i].hydrogenKg || 0;
return { count: records.length, totalKg: totalKg };
}
var H2_MOCK_EXISTING_SUPPLIERS = [
{
id: 'sup-h2-1',
name: '嘉兴氢能供应有限公司',
type: '加氢站',
city: ['浙江省', '嘉兴市'],
address: '南湖区科技大道66号',
region: '华东',
dept: '能源部',
manager: '张经理',
remark: '嘉兴区域主力加氢站运营商',
contactName: '李供',
contactMobile: '13800138088',
contactTitle: '站长',
taxId: '91330400MA2ABCDEF1',
invoiceAddress: '浙江省嘉兴市南湖区科技大道66号',
invoicePhone: '0573-88886666',
bankName: '中国工商银行嘉兴南湖支行',
bankAccount: '6222021203001234567',
mailingAddress: '浙江省嘉兴市南湖区科技大道66号',
businessAddress: '浙江省嘉兴市南湖区科技大道66号',
businessLicenseFiles: [{ uid: 'bl-1', name: '营业执照_嘉兴氢能.pdf', status: 'done' }],
fillingLicenseFiles: [{ uid: 'fl-1', name: '充装许可证_嘉兴氢能.pdf', status: 'done' }]
},
{
id: 'sup-h2-2',
name: '上海羚牛氢能科技',
type: '加氢站',
city: ['上海市', '上海市'],
address: '宝山区富联路200号',
region: '华东',
dept: '能源部',
manager: '王专员',
remark: '',
contactName: '陈氢',
contactMobile: '13900139001',
contactTitle: '运营主管',
taxId: '91310100MA1XYZ7890',
invoiceAddress: '上海市宝山区富联路200号',
invoicePhone: '021-66886688',
bankName: '招商银行上海宝山支行',
bankAccount: '6214830210123456789',
mailingAddress: '上海市宝山区富联路200号',
businessAddress: '上海市宝山区富联路200号',
businessLicenseFiles: [{ uid: 'bl-2', name: '营业执照_羚牛氢能.pdf', status: 'done' }],
fillingLicenseFiles: [{ uid: 'fl-2', name: '充装许可证_羚牛氢能.pdf', status: 'done' }]
},
{
id: 'sup-h2-3',
name: '苏州工业园区氢源科技',
type: '加氢站',
city: ['江苏省', '苏州市'],
address: '工业园区星湖街328号',
region: '华东',
dept: '华东大区',
manager: '赵经理',
remark: '备用站点供应商',
contactName: '钱七',
contactMobile: '13500135005',
contactTitle: '联系人',
taxId: '91320500MA2SUPPLIER',
invoiceAddress: '江苏省苏州市工业园区星湖街328号',
invoicePhone: '0512-66668888',
bankName: '中国银行苏州工业园区支行',
bankAccount: '6216600100009876543',
mailingAddress: '江苏省苏州市工业园区星湖街328号',
businessAddress: '江苏省苏州市工业园区星湖街328号',
businessLicenseFiles: [],
fillingLicenseFiles: []
},
{
id: 'sup-other-1',
name: '杭州绿能备件有限公司',
type: '备件供应商',
city: ['浙江省', '杭州市'],
address: '余杭区文一西路998号',
region: '华东',
dept: '采购部',
manager: '孙采购',
remark: '',
contactName: '周备件',
contactMobile: '13600136001',
contactTitle: '销售',
taxId: '91330100MA3OTHER01',
invoiceAddress: '浙江省杭州市余杭区文一西路998号',
invoicePhone: '0571-88880001',
bankName: '中国建设银行杭州余杭支行',
bankAccount: '6227000012345678901',
mailingAddress: '浙江省杭州市余杭区文一西路998号',
businessAddress: '浙江省杭州市余杭区文一西路998号',
businessLicenseFiles: [],
fillingLicenseFiles: []
}
];
function h2CreateEmptyStationForm() {
return {
name: '',
address: h2EmptyAddressValue(),
isSigned: true,
contractStart: '',
contractEnd: '',
contractFiles: [],
businessStatus: '营业中',
businessHours: '00:00-24:00',
contact: '',
mobilePhone: '',
landlinePhone: '',
costUnitPrice: '',
customerUnitPrice: '',
prepaidBalance: 0
};
}
function h2CreateEmptySupplierForm() {
return {
name: '',
city: undefined,
address: '',
region: '',
dept: '',
manager: '',
remark: '',
contactName: '',
contactMobile: '',
contactTitle: '',
taxId: '',
invoiceAddress: '',
invoicePhone: '',
bankName: '',
bankAccount: '',
mailingAddress: '',
businessAddress: '',
businessLicenseFiles: [],
fillingLicenseFiles: []
};
}
function h2GetRegionByProvince(province) {
var a = String(province || '').trim();
if (!a) return '';
if (a === '北京市' || a === '天津市' || a === '河北省' || a === '山西省' || a === '内蒙古') return '华北';
if (a === '上海市' || a === '江苏省' || a === '浙江省' || a === '安徽省' || a === '福建省' || a === '江西省' || a === '山东省') return '华东';
if (a === '广东省' || a === '广西省' || a === '海南省') return '华南';
if (a === '河南省' || a === '湖北省' || a === '湖南省') return '华中';
if (a === '辽宁省' || a === '吉林省' || a === '黑龙江省') return '东北';
if (a === '四川省' || a === '云南省' || a === '贵州省' || a === '重庆市') return '西南';
if (a === '陕西省' || a === '甘肃省' || a === '青海省' || a === '宁夏' || a === '新疆') return '西北';
return '';
}
function h2SupplierToForm(s) {
if (!s) return h2CreateEmptySupplierForm();
return {
name: s.name || '',
city: s.city ? s.city.slice() : undefined,
address: s.address || '',
region: s.region || '',
dept: s.dept || '',
manager: s.manager || '',
remark: s.remark || '',
contactName: s.contactName || '',
contactMobile: s.contactMobile || '',
contactTitle: s.contactTitle || '',
taxId: s.taxId || '',
invoiceAddress: s.invoiceAddress || '',
invoicePhone: s.invoicePhone || '',
bankName: s.bankName || '',
bankAccount: s.bankAccount || '',
mailingAddress: s.mailingAddress || '',
businessAddress: s.businessAddress || s.mailingAddress || '',
businessLicenseFiles: (s.businessLicenseFiles || []).map(function (f, i) {
return Object.assign({}, f, { uid: f.uid || ('bl-' + i), status: 'done' });
}),
fillingLicenseFiles: (s.fillingLicenseFiles || []).map(function (f, i) {
return Object.assign({}, f, { uid: f.uid || ('fl-' + i), status: 'done' });
})
};
}
function getH2StationRequirementDoc() {
return [
'加氢站管理 - 站点信息',
'',
'一、页面定位',
' 管理全部加氢站点基础信息,支持 KPI 分类筛选、条件检索、新建、编辑、查看与删除。',
'',
'二、站点分类 KPI',
' · 全部加氢站:展示全部记录',
' · 高频 / 低频 / 无加氢站点按加氢次数自动划分≥3 高频12 低频0 无加氢)',
'',
'三、列表字段',
' 加氢站名称(含签约标签)、地址、签约起止时间、营业状态、营业时间、加氢次数、加氢量(含高频/低频标签)、预付余额、联系方式、操作',
' · 加氢次数/加氢量可点击,弹窗展示该站点加氢记录(对齐车辆氢费明细字段)',
' · 预付余额:可点击查看余额变更明细;负值红色展示(已欠费);更多菜单支持生成对账单',
'',
'四、表单字段',
' · 新建:同页内嵌视图,含加氢站基本信息、供应商相关信息两张卡片;供应商类型固定「加氢站」',
' · 编辑/查看:抽屉;基本信息含名称、地址、营业时间、签约信息、联系方式;营业状态仅在列表「更多-营业状态」维护',
'',
'五、交互',
' · 筛选:加氢站名称、是否签约、地区(省-市)、营业状态',
' · KPI 统计:全部加氢站右侧为已签约/未签约站点快捷筛选,其后为高频/低频/无加氢分类',
' · 未签约时签约时间与附件可选填;已签约建议填写完整',
' · 查看模式只读;编辑/新建可保存',
' · 列表支持分页,默认每页 10 条,可切换 5/10/20/50筛选或 KPI 切换后回到第 1 页',
' · 操作列:查看 + 更多(编辑、删除、营业状态、价格配置、生成对账单)',
' · 营业状态弹窗:修改营业状态/时间,并展示状态变更记录(操作时间、操作人、修改前/后状态)',
'',
'六、批量导入',
' · 下载 CSV 模板,填写后上传;支持 .csv推荐、.xlsx、.xls',
' · 模板字段:加氢站名称、省、市、详细地址、是否签约、签约起止时间、营业状态、营业时间、联系人、联系电话',
' · 站点名称不可与现有台账重复;解析后确认导入'
].join('\n');
}
var H2_PRIMARY_BTN_STYLE = {
borderRadius: 8,
fontWeight: 600,
background: 'linear-gradient(135deg, #10b981 0%, #059669 100%)',
border: 'none'
};
var H2_REQ_BTN_STYLE = {
borderRadius: 8,
border: '1px solid #cbd5e1',
fontWeight: 600,
display: 'inline-flex',
alignItems: 'center',
boxShadow: '0 1px 2px rgba(0,0,0,0.05)',
color: '#475569'
};
function h2CreateFormDirty(station, supplier, supplierMode, linkedSupplierId) {
if ((station.name || '').trim()) return true;
if ((station.contact || '').trim()) return true;
if ((station.mobilePhone || '').trim() || (station.landlinePhone || '').trim()) return true;
if (station.address && ((station.address.region && station.address.region.length) || (station.address.detail || '').trim())) return true;
if ((supplier.name || '').trim()) return true;
if (supplierMode === 'link' && linkedSupplierId) return true;
if ((supplier.businessLicenseFiles || []).length || (supplier.fillingLicenseFiles || []).length) return true;
if ((station.contractFiles || []).length) return true;
return false;
}
function h2CreateFormProgress(station, supplier, supplierMode, linkedSupplierId) {
var checks = [
!!(station.name || '').trim(),
station.address && station.address.region && station.address.region.length >= 2 && !!(station.address.detail || '').trim(),
!!(station.contact || '').trim(),
!!((station.mobilePhone || '').trim() || (station.landlinePhone || '').trim()),
supplierMode === 'link' ? !!linkedSupplierId : !!(supplier.name || '').trim(),
supplierMode === 'new'
? (supplier.businessLicenseFiles || []).length > 0 && (supplier.fillingLicenseFiles || []).length > 0
: !!linkedSupplierId
];
var done = checks.filter(Boolean).length;
return Math.round((done / checks.length) * 100);
}
function h2BuildStationCreateView(ctx) {
var antd = window.antd;
var Card = antd.Card;
var Button = antd.Button;
var Input = antd.Input;
var Select = antd.Select;
var Radio = antd.Radio;
var DatePicker = antd.DatePicker;
var Upload = antd.Upload;
var Form = antd.Form;
var Progress = antd.Progress;
var Row = antd.Row;
var Col = antd.Col;
var dayjs = window.dayjs;
var inputCls = 'h2-create-input';
var progressPct = h2CreateFormProgress(ctx.station, ctx.supplier, ctx.supplierMode, ctx.linkedSupplierId);
var H2_COL_4 = 6;
var H2_COL_HALF = 12;
var H2_COL_FULL = 24;
var formItem = function (label, required, node, extra) {
return React.createElement(Form.Item, {
label: required ? React.createElement('span', null, React.createElement('span', { style: { color: '#ef4444', marginRight: 4 } }, '*'), label) : label,
extra: extra
}, node);
};
var formRow = function () {
return React.createElement.apply(null, [Row, { gutter: 24 }].concat(Array.prototype.slice.call(arguments)));
};
var col4 = function (node) {
return React.createElement(Col, { span: H2_COL_4 }, node);
};
var col12 = function (node) {
return React.createElement(Col, { span: H2_COL_HALF }, node);
};
var colFull = function (node) {
return React.createElement(Col, { span: H2_COL_FULL }, node);
};
var cardTitle = function (text, icon) {
return React.createElement('span', { className: 'h2-card-title-bar' },
icon ? React.createElement('span', { className: 'h2-card-title-icon', 'aria-hidden': true }, icon) : null,
text
);
};
var uploadDragger = function (fileList, onChange, btnText, hint, disabled) {
return React.createElement(Upload.Dragger, {
className: 'h2-create-upload',
multiple: true,
disabled: disabled,
fileList: fileList,
beforeUpload: function () { return false; },
onChange: onChange,
showUploadList: true
},
React.createElement('p', { className: 'ant-upload-drag-icon', style: { marginBottom: 8 } }, H2_ICONS.upload),
React.createElement('p', { style: { margin: 0, fontWeight: 600, color: '#334155' } }, btnText),
React.createElement('p', { className: 'h2-create-upload-hint' }, hint)
);
};
var supplierOptions = H2_MOCK_EXISTING_SUPPLIERS.map(function (s) {
return {
value: s.id,
label: s.name + (s.type ? '' + s.type + '' : '') + (s.city && s.city.length ? ' · ' + s.city.join('-') : '')
};
});
var contractDateRangeValue = null;
if (dayjs && ctx.station.contractStart && ctx.station.contractEnd) {
var ds = dayjs(ctx.station.contractStart);
var de = dayjs(ctx.station.contractEnd);
if (ds.isValid() && de.isValid()) contractDateRangeValue = [ds, de];
}
var renderContractDates = function () {
if (dayjs && DatePicker && DatePicker.RangePicker) {
return React.createElement(DatePicker.RangePicker, {
className: inputCls,
style: { width: '100%' },
format: 'YYYY-MM-DD',
placeholder: ['开始日期', '结束日期'],
value: contractDateRangeValue,
onChange: function (dates) {
if (!dates || dates.length < 2) {
ctx.updateStation({ contractStart: '', contractEnd: '' });
return;
}
ctx.updateStation({
contractStart: dayjs(dates[0]).format('YYYY-MM-DD'),
contractEnd: dayjs(dates[1]).format('YYYY-MM-DD')
});
}
});
}
return React.createElement('div', { className: 'h2-contract-dates' },
React.createElement(Input, {
className: inputCls,
type: 'date',
value: ctx.station.contractStart || '',
style: { flex: 1, minWidth: 0 },
onChange: function (e) { ctx.updateStation({ contractStart: e.target.value }); }
}),
React.createElement('span', { className: 'h2-contract-dates-sep' }, '至'),
React.createElement(Input, {
className: inputCls,
type: 'date',
value: ctx.station.contractEnd || '',
style: { flex: 1, minWidth: 0 },
onChange: function (e) { ctx.updateStation({ contractEnd: e.target.value }); }
})
);
};
return React.createElement(React.Fragment, null,
React.createElement('div', { className: 'h2-create-shell' },
React.createElement('div', { className: 'h2-create-topbar' },
React.createElement(Button, {
className: 'h2-create-back-btn',
type: 'default',
icon: H2_ICONS.back,
onClick: ctx.onCancel,
disabled: ctx.submitting
}, '返回'),
React.createElement('div', { className: 'h2-create-topbar-actions' },
React.createElement(Button, {
type: 'default',
icon: ctx.reqIcon,
style: ctx.reqBtnStyle,
onClick: ctx.onOpenRequirement,
'aria-label': '查看需求说明'
}, '需求说明')
)
),
React.createElement(Form, { layout: 'vertical', requiredMark: false, className: 'h2-create-form' },
React.createElement(Card, {
className: 'h2-create-card',
id: 'h2-create-station-card',
title: cardTitle('加氢站基本信息', H2_ICONS.building),
bordered: false
},
formRow(
col4(formItem('加氢站名称', true, React.createElement(Input, {
className: inputCls,
value: ctx.station.name,
placeholder: '请输入加氢站名称',
maxLength: 80,
onChange: function (e) { ctx.updateStation({ name: e.target.value }); },
onBlur: ctx.syncSupplierFromStation
}))),
col4(formItem('是否签约站点', false, React.createElement(Radio.Group, {
className: 'h2-create-radio-group',
value: ctx.station.isSigned ? 'signed' : 'unsigned',
onChange: function (e) {
var signed = e.target.value === 'signed';
ctx.updateStation({
isSigned: signed,
contractStart: signed ? ctx.station.contractStart : '',
contractEnd: signed ? ctx.station.contractEnd : ''
});
}
},
React.createElement(Radio, { value: 'signed' }, '签约'),
React.createElement(Radio, { value: 'unsigned' }, '非签约')
))),
ctx.station.isSigned
? col12(formItem('签约时间', true, renderContractDates()))
: null
),
formRow(
col12(formItem('地址', true, React.createElement(RegionAddressInput, {
value: ctx.station.address,
layout: 'inline',
inputClassName: inputCls,
regionPlaceholder: '省 / 市',
detailPlaceholder: '请输入详细地址',
onChange: function (v) { ctx.updateStation({ address: v }); }
}))),
col12(formItem('合同附件', false, React.createElement(ContractFilesUpload, {
fileList: ctx.station.contractFiles,
onChange: function (info) { ctx.updateStation({ contractFiles: info.fileList }); }
})))
),
formRow(
col4(formItem('联系人', true, React.createElement(Input, {
className: inputCls,
value: ctx.station.contact,
placeholder: '请输入联系人',
onChange: function (e) { ctx.updateStation({ contact: e.target.value }); },
onBlur: ctx.syncSupplierFromStation
}))),
col4(formItem('联系电话', true, React.createElement(Input, {
className: inputCls,
value: h2StationContactPhone(ctx.station),
placeholder: '手机号或固定电话',
type: 'tel',
autoComplete: 'tel',
onChange: function (e) { ctx.updateStation(h2ApplyStationContactPhone(ctx.station, e.target.value)); },
onBlur: ctx.syncSupplierFromStation
})))
)
),
React.createElement(Card, {
className: 'h2-create-card',
id: 'h2-create-supplier-card',
title: cardTitle('供应商相关信息', H2_ICONS.truck),
bordered: false
},
formRow(
col12(formItem('关联方式', true, React.createElement(Radio.Group, {
className: 'h2-create-radio-group',
value: ctx.supplierMode,
onChange: function (e) { ctx.handleSupplierModeChange({ target: { value: e.target.value } }); }
},
React.createElement(Radio, { value: 'link' }, '关联已有供应商'),
React.createElement(Radio, { value: 'new' }, '新增供应商')
))),
ctx.supplierMode === 'link'
? col12(formItem('供应商', true, React.createElement(Select, {
className: inputCls,
showSearch: true,
placeholder: '请搜索并选择供应商',
value: ctx.linkedSupplierId,
options: supplierOptions,
optionFilterProp: 'label',
style: { width: '100%' },
onChange: ctx.handleLinkSupplierChange,
dropdownStyle: { borderRadius: 8 }
})))
: null
),
ctx.supplierMode === 'new'
? React.createElement(React.Fragment, null,
formRow(
col4(formItem('供应商名称', true, React.createElement(Input, {
className: inputCls,
value: ctx.supplier.name,
placeholder: '请输入供应商名称',
onChange: function (e) { ctx.updateSupplier({ name: e.target.value }); }
}))),
col12(formItem('通讯地址', false, React.createElement(SupplierCityAddressInput, {
city: ctx.supplier.city,
address: ctx.supplier.address,
inputClassName: inputCls,
onCityChange: ctx.handleSupplierCityChange,
onChange: function (v) { ctx.updateSupplier({ address: v }); }
}))),
col4(formItem('区域', false, React.createElement(Input, {
className: inputCls,
value: ctx.supplier.region,
disabled: true,
placeholder: '根据省市自动关联'
})))
),
formRow(
col4(formItem('纳税人识别号', false, React.createElement(Input, {
className: inputCls,
value: ctx.supplier.taxId,
placeholder: '请输入纳税人识别号',
onChange: function (e) { ctx.updateSupplier({ taxId: e.target.value }); }
}))),
col4(formItem('注册地址', false, React.createElement(Input, {
className: inputCls,
value: ctx.supplier.invoiceAddress,
placeholder: '请输入注册地址',
onChange: function (e) { ctx.updateSupplier({ invoiceAddress: e.target.value }); }
}))),
col4(formItem('注册电话', false, React.createElement(Input, {
className: inputCls,
value: ctx.supplier.invoicePhone,
placeholder: '手机号或固定电话',
type: 'tel',
onChange: function (e) { ctx.updateSupplier({ invoicePhone: e.target.value }); }
})))
),
formRow(
col4(formItem('开户行', false, React.createElement(Input, {
className: inputCls,
value: ctx.supplier.bankName,
placeholder: '请输入开户行',
onChange: function (e) { ctx.updateSupplier({ bankName: e.target.value }); }
}))),
col4(formItem('银行账号', false, React.createElement(Input, {
className: inputCls,
value: ctx.supplier.bankAccount,
placeholder: '请输入银行账号',
onChange: function (e) { ctx.updateSupplier({ bankAccount: e.target.value }); }
}))),
col4(formItem('营业地址', false, React.createElement(Input, {
className: inputCls,
value: ctx.supplier.businessAddress,
placeholder: '请输入营业地址',
onChange: function (e) { ctx.updateSupplier({ businessAddress: e.target.value }); }
})))
),
formRow(
col4(formItem('营业执照', true, uploadDragger(
ctx.supplier.businessLicenseFiles,
function (info) { ctx.updateSupplier({ businessLicenseFiles: info.fileList }); },
'点击或拖拽上传',
'支持 PDF、图片',
false
))),
col4(formItem('充装许可证', true, uploadDragger(
ctx.supplier.fillingLicenseFiles,
function (info) { ctx.updateSupplier({ fillingLicenseFiles: info.fileList }); },
'点击或拖拽上传',
'支持 PDF、图片',
false
)))
)
)
: null
)
)
),
React.createElement('footer', { className: 'h2-create-footer' },
React.createElement('div', { className: 'h2-create-footer-inner' },
React.createElement('div', { className: 'h2-create-footer-hint' },
React.createElement(Progress, {
className: 'h2-create-footer-progress',
type: 'line',
percent: progressPct,
strokeColor: { from: '#34d399', to: '#059669' },
trailColor: '#e2e8f0',
size: 'small',
'aria-label': '表单完成度 ' + progressPct + '%'
}),
React.createElement('span', null, progressPct >= 100 ? '必填项已就绪,可提交' : '请完善必填项后提交(' + progressPct + '%')
),
React.createElement('div', { className: 'h2-create-footer-actions' },
React.createElement(Button, {
onClick: ctx.onCancel,
disabled: ctx.submitting,
'aria-label': '取消并返回列表'
}, '取消'),
React.createElement(Button, {
onClick: ctx.onReset,
disabled: ctx.submitting,
'aria-label': '重置表单'
}, '重置'),
React.createElement(Button, {
type: 'primary',
onClick: ctx.onSubmit,
loading: ctx.submitting,
style: H2_PRIMARY_BTN_STYLE,
'aria-label': '提交新建加氢站点'
}, '提交创建')
)
)
)
);
}
const Component = function () {
var useState = React.useState;
var useMemo = React.useMemo;
var useCallback = React.useCallback;
var antd = window.antd;
var Breadcrumb = antd.Breadcrumb;
var Card = antd.Card;
var Table = antd.Table;
var Button = antd.Button;
var Select = antd.Select;
var Input = antd.Input;
var Space = antd.Space;
var Modal = antd.Modal;
var Drawer = antd.Drawer;
var Form = antd.Form;
var Switch = antd.Switch;
var Upload = antd.Upload;
var Tag = antd.Tag;
var Tooltip = antd.Tooltip;
var Divider = antd.Divider;
var Alert = antd.Alert;
var Dropdown = antd.Dropdown;
var Cascader = antd.Cascader;
var Radio = antd.Radio;
var message = antd.message;
var listState = useState(H2_MOCK_STATIONS.slice());
var listData = listState[0];
var setListData = listState[1];
var categoryTabState = useState('all');
var categoryTab = categoryTabState[0];
var setCategoryTab = categoryTabState[1];
var listFiltersState = useState(h2EmptyListFilters());
var listFilters = listFiltersState[0];
var setListFilters = listFiltersState[1];
var appliedFiltersState = useState(h2EmptyListFilters());
var appliedFilters = appliedFiltersState[0];
var setAppliedFilters = appliedFiltersState[1];
var drawerState = useState({ open: false, mode: 'create', record: null });
var drawer = drawerState[0];
var setDrawer = drawerState[1];
var formState = useState(h2CreateEmptyForm());
var form = formState[0];
var setForm = formState[1];
var deleteModalState = useState({ open: false, record: null });
var deleteModal = deleteModalState[0];
var setDeleteModal = deleteModalState[1];
var requirementModalState = useState(false);
var requirementModalOpen = requirementModalState[0];
var setRequirementModalOpen = requirementModalState[1];
var importModalState = useState(false);
var importModalOpen = importModalState[0];
var setImportModalOpen = importModalState[1];
var importFileListState = useState([]);
var importFileList = importFileListState[0];
var setImportFileList = importFileListState[1];
var importPreviewState = useState(null);
var importPreview = importPreviewState[0];
var setImportPreview = importPreviewState[1];
var pageState = useState(1);
var page = pageState[0];
var setPage = pageState[1];
var pageSizeState = useState(10);
var pageSize = pageSizeState[0];
var setPageSize = pageSizeState[1];
var businessModalState = useState({ open: false, record: null, businessStatus: '营业中', businessHours: '', originBusinessStatus: '营业中', statusLogs: [] });
var businessModal = businessModalState[0];
var setBusinessModal = businessModalState[1];
var priceModalState = useState({ open: false, record: null, costUnitPrice: '', customerUnitPrice: '' });
var priceModal = priceModalState[0];
var setPriceModal = priceModalState[1];
var refuelModalState = useState({ open: false, station: null, records: [] });
var refuelModal = refuelModalState[0];
var setRefuelModal = refuelModalState[1];
var statementModalState = useState({ open: false, record: null, period: '2026-05' });
var statementModal = statementModalState[0];
var setStatementModal = statementModalState[1];
var prepaidBalanceDrillState = useState({ open: false, stationName: '', endingBalance: 0, rows: [] });
var prepaidBalanceDrill = prepaidBalanceDrillState[0];
var setPrepaidBalanceDrill = prepaidBalanceDrillState[1];
var subViewState = useState('list');
var subView = subViewState[0];
var setSubView = subViewState[1];
var createStationState = useState(h2CreateEmptyStationForm());
var createStation = createStationState[0];
var setCreateStation = createStationState[1];
var createSupplierModeState = useState('new');
var createSupplierMode = createSupplierModeState[0];
var setCreateSupplierMode = createSupplierModeState[1];
var createLinkedSupplierIdState = useState(undefined);
var createLinkedSupplierId = createLinkedSupplierIdState[0];
var setCreateLinkedSupplierId = createLinkedSupplierIdState[1];
var createSupplierState = useState(h2CreateEmptySupplierForm());
var createSupplier = createSupplierState[0];
var setCreateSupplier = createSupplierState[1];
var createSubmittingState = useState(false);
var createSubmitting = createSubmittingState[0];
var setCreateSubmitting = createSubmittingState[1];
var createSupplierReadonly = createSupplierMode === 'link' && !!createLinkedSupplierId;
var readOnly = drawer.mode === 'view';
var existingNameMap = useMemo(function () {
var map = {};
listData.forEach(function (r) {
if (r.name) map[String(r.name).trim()] = true;
});
return map;
}, [listData]);
var categoryCounts = useMemo(function () {
var counts = { all: listData.length, high: 0, low: 0, none: 0 };
listData.forEach(function (r) {
var stats = h2CalcRefuelStats(r.name);
var k = h2DeriveFrequencyByRefuelCount(stats.count);
if (counts[k] != null) counts[k] += 1;
});
return counts;
}, [listData]);
var signedStats = useMemo(function () {
var signed = 0;
listData.forEach(function (r) { if (r.isSigned) signed += 1; });
return { signed: signed, unsigned: listData.length - signed };
}, [listData]);
var filteredList = useMemo(function () {
var list = listData.slice();
if (categoryTab !== 'all') {
list = list.filter(function (r) {
var stats = h2CalcRefuelStats(r.name);
return h2DeriveFrequencyByRefuelCount(stats.count) === categoryTab;
});
}
var kw = (appliedFilters.name || '').trim().toLowerCase();
if (kw) list = list.filter(function (r) { return (r.name || '').toLowerCase().indexOf(kw) !== -1; });
if (appliedFilters.signed === 'yes') list = list.filter(function (r) { return r.isSigned; });
if (appliedFilters.signed === 'no') list = list.filter(function (r) { return !r.isSigned; });
if (appliedFilters.region && appliedFilters.region.length) {
list = list.filter(function (r) { return h2MatchRegionFilter(r.region, appliedFilters.region); });
}
if (appliedFilters.businessStatus) {
list = list.filter(function (r) { return r.businessStatus === appliedFilters.businessStatus; });
}
return list.map(function (r) {
var stats = h2CalcRefuelStats(r.name);
return Object.assign({}, r, {
refuelCount: stats.count,
refuelTotalKg: stats.totalKg,
refuelFreqKey: h2DeriveFrequencyByRefuelCount(stats.count)
});
});
}, [listData, categoryTab, appliedFilters]);
var totalCount = filteredList.length;
var displayList = useMemo(function () {
var start = (page - 1) * pageSize;
return filteredList.slice(start, start + pageSize);
}, [filteredList, page, pageSize]);
var tablePagination = useMemo(function () {
return {
current: page,
pageSize: pageSize,
total: totalCount,
showSizeChanger: true,
pageSizeOptions: ['5', '10', '20', '50'],
showTotal: function (t) { return '共 ' + t + ' 条'; },
onChange: function (p, size) {
setPage(p);
if (size && size !== pageSize) setPageSize(size);
}
};
}, [page, pageSize, totalCount]);
var handleKpiCardClick = useCallback(function (key) {
setCategoryTab(key);
setPage(1);
}, []);
var handleSignedFilterCardClick = useCallback(function (key) {
var nextSigned = appliedFilters.signed === key ? undefined : key;
setListFilters(function (p) { return Object.assign({}, p, { signed: nextSigned }); });
setAppliedFilters(function (p) { return Object.assign({}, p, { signed: nextSigned }); });
setPage(1);
}, [appliedFilters.signed]);
var handleListFilterQuery = useCallback(function () {
setAppliedFilters({
name: listFilters.name,
signed: listFilters.signed,
region: listFilters.region,
businessStatus: listFilters.businessStatus
});
setPage(1);
}, [listFilters]);
var handleListFilterReset = useCallback(function () {
var empty = h2EmptyListFilters();
setListFilters(empty);
setAppliedFilters(empty);
setPage(1);
}, []);
var renderFilterField = useCallback(function (label, control) {
return React.createElement('div', { className: 'lc-filter-field' },
React.createElement('span', { className: 'lc-filter-field-label' }, label),
React.createElement('div', { className: 'lc-filter-field-control' }, control)
);
}, []);
var renderAlertStatCard = useCallback(function (card, options) {
var active = options.active;
var count = options.count;
var onClick = options.onClick;
var icon = options.icon;
return React.createElement('div', {
key: card.key,
role: 'button',
tabIndex: 0,
className: 'lc-alert-card lc-alert-card--' + card.type + ' lc-alert-card-clickable' + (active ? ' lc-alert-card-active' : ''),
onClick: onClick,
onKeyDown: function (e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
onClick();
}
},
'aria-pressed': active,
'aria-label': card.title + ',共 ' + count + ' 个'
},
React.createElement('div', { className: 'lc-alert-card-tip-anchor' },
React.createElement(Tooltip, { title: card.desc, placement: 'topRight', overlayStyle: { maxWidth: 320 } },
React.createElement('span', {
className: 'lc-alert-card-tip',
role: 'img',
'aria-label': card.title + '说明',
onClick: function (e) { e.stopPropagation(); },
onMouseDown: function (e) { e.stopPropagation(); }
},
h2SvgIcon([{ tag: 'circle', cx: 12, cy: 12, r: 10 }, { tag: 'line', x1: 12, y1: 16, x2: 12, y2: 12 }, { tag: 'line', x1: 12, y1: 8, x2: 12.01, y2: 8 }], 12)
)
)
),
React.createElement('div', { className: 'lc-alert-card-icon' }, icon),
React.createElement('div', { className: 'lc-alert-card-main' },
React.createElement('div', { className: 'lc-alert-card-val' }, count),
React.createElement('div', { className: 'lc-alert-card-title' }, card.title)
)
);
}, []);
var resetCreateForm = useCallback(function () {
setCreateStation(h2CreateEmptyStationForm());
setCreateSupplierMode('new');
setCreateLinkedSupplierId(undefined);
setCreateSupplier(h2CreateEmptySupplierForm());
}, []);
var openCreate = useCallback(function () {
resetCreateForm();
setSubView('create');
}, [resetCreateForm]);
var handleCreatePageBack = useCallback(function () {
setCreateSubmitting(false);
setSubView('list');
}, []);
var handleCreateCancel = useCallback(function () {
if (createSubmitting) return;
if (h2CreateFormDirty(createStation, createSupplier, createSupplierMode, createLinkedSupplierId)) {
Modal.confirm({
title: '放弃未保存的更改?',
content: '当前填写内容尚未提交,返回列表后将丢失。',
okText: '放弃并返回',
cancelText: '继续填写',
okButtonProps: { danger: true },
centered: true,
onOk: handleCreatePageBack
});
return;
}
handleCreatePageBack();
}, [createSubmitting, createStation, createSupplier, createSupplierMode, createLinkedSupplierId, handleCreatePageBack]);
var updateCreateStation = useCallback(function (patch) {
setCreateStation(function (prev) { return Object.assign({}, prev, patch); });
}, []);
var updateCreateSupplier = useCallback(function (patch) {
setCreateSupplier(function (prev) { return Object.assign({}, prev, patch); });
}, []);
var handleCreateSupplierModeChange = useCallback(function (e) {
setCreateSupplierMode(e.target.value);
setCreateLinkedSupplierId(undefined);
setCreateSupplier(h2CreateEmptySupplierForm());
}, []);
var handleCreateLinkSupplierChange = useCallback(function (id) {
setCreateLinkedSupplierId(id);
var found = H2_MOCK_EXISTING_SUPPLIERS.filter(function (s) { return s.id === id; })[0];
setCreateSupplier(h2SupplierToForm(found));
}, []);
var handleCreateSupplierCityChange = useCallback(function (v) {
updateCreateSupplier({
city: v,
region: v && v[0] ? h2GetRegionByProvince(v[0]) : ''
});
}, [updateCreateSupplier]);
var syncCreateSupplierFromStation = useCallback(function () {
if (createSupplierMode !== 'new') return;
setCreateSupplier(function (supplier) {
var patch = {};
if (createStation.name && !supplier.name) patch.name = createStation.name;
if (createStation.address && createStation.address.region && createStation.address.region.length >= 2) {
patch.city = createStation.address.region.slice();
patch.region = h2GetRegionByProvince(createStation.address.region[0]);
}
if (createStation.address && createStation.address.detail && !supplier.address) patch.address = createStation.address.detail;
if (createStation.contact && !supplier.contactName) patch.contactName = createStation.contact;
if (createStation.mobilePhone && !supplier.contactMobile) patch.contactMobile = createStation.mobilePhone;
return Object.keys(patch).length ? Object.assign({}, supplier, patch) : supplier;
});
}, [createSupplierMode, createStation]);
var validateCreateForm = useCallback(function () {
if (!(createStation.name || '').trim()) {
message.warning('请填写加氢站名称');
return false;
}
if (!createStation.address.region || createStation.address.region.length < 2) {
message.warning('请选择加氢站地址的省 / 市');
return false;
}
if (!(createStation.address.detail || '').trim()) {
message.warning('请填写加氢站详细地址');
return false;
}
if (!(createStation.contact || '').trim()) {
message.warning('请填写联系人');
return false;
}
if (!h2StationContactPhone(createStation)) {
message.warning('请填写联系电话');
return false;
}
if (createStation.isSigned) {
if (!createStation.contractStart || !createStation.contractEnd) {
message.warning('签约站点请填写签约开始与结束时间');
return false;
}
}
var hoursParsed = h2ParseBusinessHours(createStation.businessHours);
if (hoursParsed.mode === 'custom') {
if (!(hoursParsed.start || '').trim() || !(hoursParsed.end || '').trim()) {
message.warning('非全天营业请选择开始与结束时间');
return false;
}
if (!/^(\d{1,2}):(\d{2})$/.test(h2NormalizeTimeText(hoursParsed.start)) || !/^(\d{1,2}):(\d{2})$/.test(h2NormalizeTimeText(hoursParsed.end))) {
message.warning('营业时间格式须为 HH:mm');
return false;
}
}
if (createSupplierMode === 'link' && !createLinkedSupplierId) {
message.warning('请选择要关联的已有供应商');
return false;
}
if (createSupplierMode === 'new') {
if (!(createSupplier.name || '').trim()) {
message.warning('请填写供应商名称');
return false;
}
if (!createSupplier.businessLicenseFiles || !createSupplier.businessLicenseFiles.length) {
message.warning('请上传营业执照');
return false;
}
if (!createSupplier.fillingLicenseFiles || !createSupplier.fillingLicenseFiles.length) {
message.warning('请上传充装许可证');
return false;
}
}
return true;
}, [createStation, createSupplierMode, createLinkedSupplierId, createSupplier]);
var handleCreatePageSubmit = useCallback(function (payload) {
var station = payload && payload.station;
if (!station) return;
var nextId = listData.reduce(function (m, r) { return Math.max(m, r.id || 0); }, 0) + 1;
var created = Object.assign({}, station, { id: nextId });
setListData(function (prev) { return [created].concat(prev); });
setPage(1);
setSubView('list');
var supplierHint = payload.supplierMode === 'link' ? '已关联已有供应商' : '已同步创建加氢站类型供应商';
message.success('站点已创建;' + supplierHint + '(原型)');
}, [listData]);
var handleCreateSubmit = useCallback(function () {
if (createSubmitting) return;
if (!validateCreateForm()) return;
setCreateSubmitting(true);
syncCreateSupplierFromStation();
var now = h2OperateTimestamp();
var phoneDisplay = createStation.mobilePhone || createStation.landlinePhone || '';
if (createStation.mobilePhone && createStation.landlinePhone) phoneDisplay = createStation.mobilePhone;
var stationRecord = {
name: (createStation.name || '').trim(),
region: createStation.address.region || [],
addressDetail: (createStation.address.detail || '').trim(),
fullAddress: h2BuildFullAddress(createStation.address.region, createStation.address.detail),
isSigned: !!createStation.isSigned,
contractStart: createStation.isSigned ? createStation.contractStart : '',
contractEnd: createStation.isSigned ? createStation.contractEnd : '',
contractFiles: (createStation.contractFiles || []).map(function (f) {
return { uid: f.uid, name: f.name || '合同附件.pdf', url: f.url || '' };
}),
businessStatus: createStation.businessStatus || '营业中',
businessHours: (createStation.businessHours || '').trim(),
contact: (createStation.contact || '').trim(),
phone: phoneDisplay,
mobilePhone: (createStation.mobilePhone || '').trim(),
landlinePhone: (createStation.landlinePhone || '').trim(),
costUnitPrice: createStation.costUnitPrice ? parseFloat(createStation.costUnitPrice) : undefined,
customerUnitPrice: createStation.customerUnitPrice ? parseFloat(createStation.customerUnitPrice) : undefined,
prepaidBalance: 0,
businessStatusLogs: [],
updateTime: now,
supplierMode: createSupplierMode,
linkedSupplierId: createSupplierMode === 'link' ? createLinkedSupplierId : undefined,
supplier: Object.assign({ type: '加氢站' }, createSupplier)
};
window.setTimeout(function () {
handleCreatePageSubmit({ station: stationRecord, supplier: createSupplier, supplierMode: createSupplierMode });
setCreateSubmitting(false);
}, 380);
}, [createSubmitting, validateCreateForm, syncCreateSupplierFromStation, createStation, createSupplier, createSupplierMode, createLinkedSupplierId, handleCreatePageSubmit]);
var handleCreateReset = useCallback(function () {
resetCreateForm();
message.info('表单已重置');
}, [resetCreateForm]);
var openRefuelModal = useCallback(function (record) {
setRefuelModal({
open: true,
station: record,
records: h2GetRefuelRecordsByStation(record.name)
});
}, []);
var closeRefuelModal = useCallback(function () {
setRefuelModal({ open: false, station: null, records: [] });
}, []);
var openPrepaidBalanceDrill = useCallback(function (record) {
setPrepaidBalanceDrill({
open: true,
stationName: record.name || '',
endingBalance: h2NumOrZero(record.prepaidBalance),
rows: h2BuildMockPrepaidBalanceRows(record)
});
}, []);
var closePrepaidBalanceDrill = useCallback(function () {
setPrepaidBalanceDrill({ open: false, stationName: '', endingBalance: 0, rows: [] });
}, []);
var openStatementModal = useCallback(function (record) {
setStatementModal({ open: true, record: record, period: '2026-05' });
}, []);
var closeStatementModal = useCallback(function () {
setStatementModal({ open: false, record: null, period: '2026-05' });
}, []);
var handleGenerateStatement = useCallback(function () {
if (!statementModal.record) return;
if (!statementModal.period) {
message.warning('请选择对账周期');
return;
}
var periodLabel = statementModal.period.replace('-', '年') + '月';
message.success('已生成「' + statementModal.record.name + '」' + periodLabel + '氢费对账单(原型)');
closeStatementModal();
}, [statementModal, closeStatementModal]);
var openEdit = useCallback(function (record) {
setForm(h2RecordToForm(record));
setDrawer({ open: true, mode: 'edit', record: record });
}, []);
var openView = useCallback(function (record) {
setForm(h2RecordToForm(record));
setDrawer({ open: true, mode: 'view', record: record });
}, []);
var openBusinessSetting = useCallback(function (record) {
setBusinessModal({
open: true,
record: record,
businessStatus: record.businessStatus || '营业中',
businessHours: record.businessHours === '—' ? '' : (record.businessHours || ''),
originBusinessStatus: record.businessStatus || '营业中',
statusLogs: (record.businessStatusLogs || []).slice()
});
}, []);
var closeBusinessModal = useCallback(function () {
setBusinessModal({ open: false, record: null, businessStatus: '营业中', businessHours: '', originBusinessStatus: '营业中', statusLogs: [] });
}, []);
var handleSaveBusinessSetting = useCallback(function () {
if (!businessModal.record) return;
var nextStatus = businessModal.businessStatus || '营业中';
var statusChanged = nextStatus !== businessModal.originBusinessStatus;
var newLog = statusChanged
? h2CreateBusinessStatusLog(businessModal.originBusinessStatus, nextStatus, H2_CURRENT_OPERATOR)
: null;
setListData(function (prev) {
return prev.map(function (r) {
if (r.id !== businessModal.record.id) return r;
var logs = (r.businessStatusLogs || []).slice();
if (newLog) logs.unshift(newLog);
return Object.assign({}, r, {
businessStatus: nextStatus,
businessHours: (businessModal.businessHours || '').trim() || '—',
businessStatusLogs: logs,
updateTime: h2OperateTimestamp()
});
});
});
message.success(statusChanged ? '营业状态已更新(原型)' : '营业时间已保存(原型)');
closeBusinessModal();
}, [businessModal, closeBusinessModal]);
var openPriceConfig = useCallback(function (record) {
setPriceModal({
open: true,
record: record,
costUnitPrice: record.costUnitPrice != null ? String(record.costUnitPrice) : '',
customerUnitPrice: record.customerUnitPrice != null ? String(record.customerUnitPrice) : ''
});
}, []);
var closePriceModal = useCallback(function () {
setPriceModal({ open: false, record: null, costUnitPrice: '', customerUnitPrice: '' });
}, []);
var handleSavePriceConfig = useCallback(function () {
if (!priceModal.record) return;
var cost = parseFloat(priceModal.costUnitPrice);
var customer = parseFloat(priceModal.customerUnitPrice);
if (priceModal.costUnitPrice !== '' && isNaN(cost)) {
message.warning('请输入有效的成本单价');
return;
}
if (priceModal.customerUnitPrice !== '' && isNaN(customer)) {
message.warning('请输入有效的对客单价');
return;
}
setListData(function (prev) {
return prev.map(function (r) {
if (r.id !== priceModal.record.id) return r;
return Object.assign({}, r, {
costUnitPrice: priceModal.costUnitPrice === '' ? null : cost,
customerUnitPrice: priceModal.customerUnitPrice === '' ? null : customer,
updateTime: new Date().toISOString().slice(0, 16).replace('T', ' ')
});
});
});
message.success('价格配置已保存(原型)');
closePriceModal();
}, [priceModal, closePriceModal]);
var getRowMoreMenuItems = useCallback(function (record) {
return [
{ key: 'edit', label: '编辑', onClick: function () { openEdit(record); } },
{ key: 'business', label: '营业状态', onClick: function () { openBusinessSetting(record); } },
{ key: 'price', label: '价格配置', onClick: function () { openPriceConfig(record); } },
{ key: 'statement', label: '生成对账单', onClick: function () { openStatementModal(record); } },
{ type: 'divider' },
{ key: 'delete', label: '删除', danger: true, onClick: function () { setDeleteModal({ open: true, record: record }); } }
];
}, [openEdit, openBusinessSetting, openPriceConfig, openStatementModal]);
var closeDrawer = useCallback(function () {
setDrawer({ open: false, mode: 'create', record: null });
}, []);
var validateForm = useCallback(function () {
if (!(form.name || '').trim()) {
message.warning('请填写加氢站名称');
return false;
}
if (!form.address.region || form.address.region.length < 2) {
message.warning('请选择省 / 市');
return false;
}
if (!(form.address.detail || '').trim()) {
message.warning('请填写详细地址');
return false;
}
if (!(form.contact || '').trim()) {
message.warning('请填写联系人');
return false;
}
if (!(form.phone || '').trim()) {
message.warning('请填写联系电话');
return false;
}
if (form.isSigned) {
if (!form.contractStart || !form.contractEnd) {
message.warning('已签约站点请填写签约开始与结束时间');
return false;
}
}
return true;
}, [form]);
var handleSave = useCallback(function () {
if (!validateForm()) return;
if (!drawer.record) return;
var updated = h2FormToRecord(form, drawer.record.id);
updated.businessStatus = drawer.record.businessStatus || '营业中';
updated.costUnitPrice = drawer.record.costUnitPrice;
updated.customerUnitPrice = drawer.record.customerUnitPrice;
updated.businessStatusLogs = drawer.record.businessStatusLogs || [];
updated.prepaidBalance = drawer.record.prepaidBalance;
updated.mobilePhone = drawer.record.mobilePhone;
updated.landlinePhone = drawer.record.landlinePhone;
updated.supplier = drawer.record.supplier;
updated.linkedSupplierId = drawer.record.linkedSupplierId;
setListData(function (prev) {
return prev.map(function (r) { return r.id === updated.id ? updated : r; });
});
message.success('站点已保存(原型)');
closeDrawer();
}, [validateForm, drawer, form, closeDrawer]);
var closeImportModal = useCallback(function () {
setImportModalOpen(false);
setImportFileList([]);
setImportPreview(null);
}, []);
var downloadImportTemplate = useCallback(function () {
h2DownloadCsv('加氢站点批量导入模板.csv', H2_IMPORT_TEMPLATE_HEADERS, H2_IMPORT_TEMPLATE_SAMPLE);
message.success('已下载导入模板');
}, []);
var parseImportFile = useCallback(function (file) {
if (!file) return;
var name = String(file.name || '').toLowerCase();
if (name.endsWith('.xls') || name.endsWith('.xlsx')) {
message.warning('原型环境请使用 CSV 模板导入;联调后将支持 Excel 直接上传');
setImportFileList([file]);
setImportPreview(null);
return;
}
if (!name.endsWith('.csv')) {
message.error('仅支持 .csv、.xls、.xlsx 格式');
return;
}
setImportFileList([file]);
var reader = new FileReader();
reader.onload = function (ev) {
var text = (ev && ev.target && ev.target.result) || '';
var parsed = h2ParseImportCsv(text);
if (parsed.headerError) {
message.error(parsed.headerError);
setImportPreview(null);
return;
}
if (!parsed.rows.length) {
message.warning('未解析到有效数据,请检查文件内容');
setImportPreview(null);
return;
}
var nameMap = Object.assign({}, existingNameMap);
var valid = [];
var errors = [];
var ri;
for (ri = 0; ri < parsed.rows.length; ri++) {
var row = parsed.rows[ri];
var rowErrors = h2ValidateImportRow(row, nameMap);
if (rowErrors.length) {
errors.push({ lineNo: row.lineNo, name: row.name || '—', reasons: rowErrors });
} else {
valid.push(row);
if (row.name) nameMap[String(row.name).trim()] = true;
}
}
setImportPreview({ valid: valid, errors: errors, fileName: file.name });
};
reader.onerror = function () {
message.error('文件读取失败');
};
reader.readAsText(file, 'UTF-8');
}, [existingNameMap]);
var handleConfirmImport = useCallback(function () {
if (!importPreview || !importPreview.valid.length) {
message.warning('没有可导入的有效数据');
return;
}
setListData(function (prev) {
var maxId = prev.reduce(function (m, r) { return Math.max(m, r.id || 0); }, 0);
var imported = importPreview.valid.map(function (row, idx) {
return h2ImportRowToRecord(row, maxId + idx + 1);
});
return imported.concat(prev);
});
var errN = (importPreview.errors || []).length;
if (errN) {
message.success('成功导入 ' + importPreview.valid.length + ' 条,' + errN + ' 条校验失败已跳过');
} else {
message.success('成功导入 ' + importPreview.valid.length + ' 条站点');
}
setPage(1);
closeImportModal();
}, [importPreview, closeImportModal]);
React.useEffect(function () {
var maxPage = Math.max(1, Math.ceil(totalCount / pageSize) || 1);
if (page > maxPage) setPage(maxPage);
}, [totalCount, pageSize, page]);
var renderRefuelFreqShortTag = function (freqKey) {
if (freqKey === 'high') {
return React.createElement(Tag, {
color: 'success',
className: 'lc-refuel-freq-tag'
}, '高频');
}
if (freqKey === 'low') {
return React.createElement(Tag, {
color: 'warning',
className: 'lc-refuel-freq-tag'
}, '低频');
}
return null;
};
var renderBusinessStatusTag = function (v) {
if (v === '营业中') return React.createElement(Tag, { color: 'success', style: { borderRadius: 6, fontWeight: 600 } }, v);
if (v === '暂停营业') return React.createElement(Tag, { color: 'warning', style: { borderRadius: 6, fontWeight: 600 } }, v);
if (v === '停止营业') return React.createElement(Tag, { color: 'error', style: { borderRadius: 6, fontWeight: 600 } }, v);
return React.createElement(Tag, { style: { borderRadius: 6, fontWeight: 600, color: '#64748b', background: '#f1f5f9', border: '1px solid #e2e8f0' } }, v || '—');
};
var renderBusinessStatusText = function (v, tone) {
var color = v === '营业中' ? '#059669' : v === '暂停营业' ? '#ea580c' : v === '停止营业' ? '#dc2626' : '#64748b';
if (tone === 'muted') color = '#94a3b8';
return React.createElement('span', { style: { fontWeight: 600, color: color } }, v || '—');
};
var renderRefuelDrillLink = function (text, record, ariaLabel) {
return React.createElement('button', {
type: 'button',
className: 'h2-refuel-drill-link',
onClick: function (e) {
e.stopPropagation();
openRefuelModal(record);
},
'aria-label': ariaLabel
}, text);
};
var renderPrepaidBalance = useCallback(function (v, record) {
if (v == null || v === '') return React.createElement('span', { style: { color: '#94a3b8' } }, '—');
var n = typeof v === 'number' ? v : parseFloat(v);
if (isNaN(n)) return '—';
if (!record) {
var plainColor = n < 0 ? '#dc2626' : '#0f172a';
return React.createElement('span', {
style: { fontWeight: 700, color: plainColor, fontVariantNumeric: 'tabular-nums' },
title: n < 0 ? '预付余额不足,已欠费' : undefined
}, h2FormatYuanNum(n));
}
var isArrears = n < 0;
var amountStyle = isArrears
? { color: '#dc2626', fontVariantNumeric: 'tabular-nums' }
: { color: '#059669', fontVariantNumeric: 'tabular-nums' };
return React.createElement('div', { className: 'h2-prepaid-balance-cell' },
isArrears ? React.createElement(Tag, { color: 'error', className: 'lc-station-signed-tag' }, '已欠费') : null,
React.createElement('button', {
type: 'button',
className: 'h2-prepaid-balance-amount',
style: amountStyle,
title: '点击查看余额变更明细',
'aria-label': '查看「' + (record.name || '') + '」余额变更明细',
onClick: function (e) {
e.stopPropagation();
openPrepaidBalanceDrill(record);
}
}, h2FormatYuanNum(n))
);
}, [openPrepaidBalanceDrill]);
var prepaidBalanceDrillColumns = [
{ title: '加氢站名称', dataIndex: 'stationName', key: 'stationName', width: 220, ellipsis: true },
{ title: '收入金额(元)', dataIndex: 'incomeAmount', key: 'incomeAmount', width: 120, align: 'right', render: function (v) { return h2FormatLedgerMoney(v); } },
{ title: '支出金额(元)', dataIndex: 'expenseAmount', key: 'expenseAmount', width: 120, align: 'right', render: function (v) { return h2FormatLedgerMoney(v); } },
{
title: '余额(元)',
dataIndex: 'balance',
key: 'balance',
width: 120,
align: 'right',
render: function (v) {
var bn = h2NumOrZero(v);
var style = bn < 0 ? { color: '#dc2626', fontWeight: 600, fontVariantNumeric: 'tabular-nums' } : { fontVariantNumeric: 'tabular-nums' };
return React.createElement('span', { style: style }, h2FormatYuanNum(v));
}
},
{
title: '订单编号',
dataIndex: 'orderNo',
key: 'orderNo',
width: 168,
align: 'center',
render: function (v) {
return React.createElement('span', { style: { fontFamily: 'monospace', fontSize: 12 } }, v || '—');
}
}
];
var prepaidBalanceDrillSummary = useMemo(function () {
if (!prepaidBalanceDrill.rows || !prepaidBalanceDrill.rows.length) {
return { incomeTotal: 0, expenseTotal: 0, endingBalance: 0 };
}
var last = prepaidBalanceDrill.rows[prepaidBalanceDrill.rows.length - 1];
return prepaidBalanceDrill.rows.reduce(function (acc, r) {
acc.incomeTotal += h2NumOrZero(r.incomeAmount);
acc.expenseTotal += h2NumOrZero(r.expenseAmount);
return acc;
}, { incomeTotal: 0, expenseTotal: 0, endingBalance: h2NumOrZero(last.balance) });
}, [prepaidBalanceDrill.rows]);
var renderPrepaidBalanceDrillSummary = useCallback(function () {
return React.createElement(Table.Summary, null,
React.createElement(Table.Summary.Row, null,
React.createElement(Table.Summary.Cell, { index: 0, align: 'center' }, '合计'),
React.createElement(Table.Summary.Cell, { index: 1, align: 'right' }, h2FormatYuanNum(prepaidBalanceDrillSummary.incomeTotal)),
React.createElement(Table.Summary.Cell, { index: 2, align: 'right' }, h2FormatYuanNum(prepaidBalanceDrillSummary.expenseTotal)),
React.createElement(Table.Summary.Cell, { index: 3, align: 'right' }, h2FormatYuanNum(prepaidBalanceDrillSummary.endingBalance)),
React.createElement(Table.Summary.Cell, { index: 4 })
)
);
}, [prepaidBalanceDrillSummary]);
var refuelRecordColumns = [
{ title: '序号', key: 'seq', width: 52, align: 'center', render: function (_, __, index) { return index + 1; } },
{ title: '加氢时间', dataIndex: 'hydrogenTime', key: 'hydrogenTime', width: 168 },
{ title: '车牌号', dataIndex: 'plateNo', key: 'plateNo', width: 110 },
{ title: '客户名称', dataIndex: 'customerName', key: 'customerName', width: 180, ellipsis: true },
{ title: '加氢量(kg)', dataIndex: 'hydrogenKg', key: 'hydrogenKg', width: 100, align: 'right', render: function (v) { return h2FormatKgNum(v); } },
{ title: '成本单价', dataIndex: 'costUnitPrice', key: 'costUnitPrice', width: 92, align: 'right', render: function (v) { return h2FormatYuanNum(v); } },
{ title: '成本总价', dataIndex: 'costAmount', key: 'costAmount', width: 92, align: 'right', render: function (v) { return h2FormatYuanNum(v); } },
{ title: '加氢单价', dataIndex: 'customerUnitPrice', key: 'customerUnitPrice', width: 92, align: 'right', render: function (v) { return h2FormatYuanNum(v); } },
{ title: '加氢总价', dataIndex: 'customerAmount', key: 'customerAmount', width: 92, align: 'right', render: function (v) { return h2FormatYuanNum(v); } }
];
var refuelModalSummary = useMemo(function () {
var records = refuelModal.records || [];
var totalKg = 0;
var totalCost = 0;
var totalCustomer = 0;
var i;
for (i = 0; i < records.length; i++) {
totalKg += records[i].hydrogenKg || 0;
totalCost += records[i].costAmount || 0;
totalCustomer += records[i].customerAmount || 0;
}
return { count: records.length, totalKg: totalKg, totalCost: totalCost, totalCustomer: totalCustomer };
}, [refuelModal.records]);
var renderRefuelTotalsBar = useCallback(function (summary) {
var items = [
{ key: 'count', label: '加氢次数(次)', value: String(summary.count || 0) },
{ key: 'hydrogenKg', label: '加氢量(kg)', value: h2FormatKgNum(summary.totalKg) },
{ key: 'costTotal', label: '成本总价(元)', value: h2FormatYuanNum(summary.totalCost) },
{ key: 'customerAmount', label: '加氢总价(元)', value: h2FormatYuanNum(summary.totalCustomer) }
];
return React.createElement('div', { className: 'h2-ledger-totals-bar' },
React.createElement('div', { className: 'h2-ledger-totals-bar__title' }, '合计'),
React.createElement('div', { className: 'h2-ledger-totals-bar__items' },
items.map(function (item) {
return React.createElement('div', { key: item.key, className: 'h2-ledger-totals-bar__item' },
React.createElement('div', { className: 'h2-ledger-totals-bar__label' }, item.label),
React.createElement('div', { className: 'h2-ledger-totals-bar__value' }, item.value)
);
})
)
);
}, []);
var businessStatusLogColumns = [
{ title: '操作时间', dataIndex: 'operateTime', key: 'operateTime', width: 150 },
{ title: '操作人', dataIndex: 'operator', key: 'operator', width: 100, ellipsis: true },
{
title: '修改前状态',
dataIndex: 'beforeStatus',
key: 'beforeStatus',
width: 110,
render: function (v) { return renderBusinessStatusText(v, 'muted'); }
},
{
title: '修改后状态',
dataIndex: 'afterStatus',
key: 'afterStatus',
width: 110,
render: function (v) { return renderBusinessStatusText(v); }
}
];
var columns = [
{
title: '加氢站名称',
dataIndex: 'name',
key: 'name',
width: 248,
fixed: 'left',
render: function (v, r) {
return React.createElement('div', { className: 'lc-station-name-row' },
React.createElement('div', { className: 'lc-station-name' }, v || '—'),
React.createElement(Tag, {
color: r.isSigned ? 'success' : 'default',
className: 'lc-station-signed-tag',
style: r.isSigned ? undefined : { color: '#64748b', background: '#f1f5f9', border: '1px solid #e2e8f0' }
}, r.isSigned ? '已签约' : '未签约')
);
}
},
{
title: '地址',
key: 'address',
width: 280,
ellipsis: true,
render: function (_, r) {
return React.createElement('div', null,
React.createElement('div', { className: 'lc-station-region' }, h2FormatRegion(r.region)),
React.createElement('div', { style: { color: '#334155' } }, r.addressDetail || '—')
);
}
},
{
title: '签约时间',
key: 'contractRange',
width: 220,
render: function (_, r) {
if (!r.isSigned) return React.createElement('span', { style: { color: '#94a3b8' } }, '—');
return React.createElement('div', null,
React.createElement('div', { style: { fontSize: 12, fontWeight: 600, color: '#334155' } },
(r.contractStart || '—') + ' 至 ' + (r.contractEnd || '—')
),
r.contractEnd ? h2RenderContractRemainTag(r.contractEnd) : null
);
}
},
{
title: '营业状态',
dataIndex: 'businessStatus',
key: 'businessStatus',
width: 110,
render: renderBusinessStatusTag
},
{ title: '营业时间', dataIndex: 'businessHours', key: 'businessHours', width: 140, render: function (v) { return h2DisplayBusinessHours(v); } },
{
title: '加氢次数',
dataIndex: 'refuelCount',
key: 'refuelCount',
width: 96,
align: 'right',
render: function (v, record) {
return renderRefuelDrillLink(String(v || 0), record, '查看加氢记录,共 ' + (v || 0) + ' 次');
}
},
{
title: '加氢量(kg)',
dataIndex: 'refuelTotalKg',
key: 'refuelTotalKg',
width: 148,
align: 'right',
render: function (v, record) {
return React.createElement('div', { className: 'lc-refuel-kg-row' },
renderRefuelFreqShortTag(record.refuelFreqKey),
renderRefuelDrillLink(h2FormatKgNum(v), record, '查看加氢记录,合计 ' + h2FormatKgNum(v) + ' kg')
);
}
},
{
title: '预付余额(元)',
dataIndex: 'prepaidBalance',
key: 'prepaidBalance',
width: 188,
align: 'right',
className: 'h2-col-prepaid-balance',
onCell: function () {
return { className: 'h2-cell-prepaid-balance' };
},
render: function (v, record) { return renderPrepaidBalance(v, record); }
},
{
title: '联系方式',
key: 'contactInfo',
width: 120,
render: function (_, r) {
var mobile = r.mobilePhone || r.phone || '';
var landline = r.landlinePhone || '';
return React.createElement('div', null,
React.createElement('div', { className: 'lc-station-contact-name' }, r.contact || '—'),
mobile ? React.createElement('div', { className: 'lc-station-contact-phone' }, mobile) : null,
landline ? React.createElement('div', { className: 'lc-station-contact-phone' }, landline) : null,
!mobile && !landline ? React.createElement('div', { className: 'lc-station-contact-phone' }, '—') : null
);
}
},
{
title: '操作',
key: 'action',
width: 108,
fixed: 'right',
render: function (_, record) {
return React.createElement('div', { className: 'h2-row-actions' },
React.createElement(Button, {
type: 'link',
size: 'small',
className: 'lc-action-btn',
onClick: function () { openView(record); }
}, '查看'),
React.createElement(Dropdown, {
trigger: ['click'],
placement: 'bottomRight',
menu: { items: getRowMoreMenuItems(record) }
},
React.createElement(Tooltip, { title: '更多' },
React.createElement('span', {
className: 'h2-action-more-btn',
role: 'button',
tabIndex: 0,
'aria-label': '更多操作',
onClick: function (e) { e.stopPropagation(); }
}, h2MoreIcon())
)
)
);
}
}
];
var formItem = function (label, required, node, extra) {
return React.createElement(Form.Item, {
label: required ? React.createElement('span', null, React.createElement('span', { style: { color: '#ef4444', marginRight: 4 } }, '*'), label) : label,
extra: extra,
style: { marginBottom: 16 }
}, node);
};
var drawerSection = function (title, children) {
return React.createElement('div', { style: { marginBottom: 8 } },
React.createElement('div', { className: 'h2-drawer-section-title' }, title),
children
);
};
var drawerTitle = drawer.mode === 'edit' ? '编辑加氢站点' : '查看加氢站点';
var createViewNode = subView === 'create' ? h2BuildStationCreateView({
station: createStation,
supplier: createSupplier,
supplierMode: createSupplierMode,
linkedSupplierId: createLinkedSupplierId,
supplierReadonly: createSupplierReadonly,
updateStation: updateCreateStation,
updateSupplier: updateCreateSupplier,
syncSupplierFromStation: syncCreateSupplierFromStation,
handleSupplierModeChange: handleCreateSupplierModeChange,
handleLinkSupplierChange: handleCreateLinkSupplierChange,
handleSupplierCityChange: handleCreateSupplierCityChange,
onCancel: handleCreateCancel,
onReset: handleCreateReset,
onSubmit: handleCreateSubmit,
submitting: createSubmitting,
onOpenRequirement: function () { setRequirementModalOpen(true); },
reqIcon: H2_ICONS.doc,
reqBtnStyle: H2_REQ_BTN_STYLE
}) : null;
var emptyNode = React.createElement('div', { style: { padding: '40px 0', textAlign: 'center' } },
H2_ICONS.empty,
React.createElement('div', { style: { color: '#94a3b8', marginTop: 12 } }, '暂无符合检索条件的站点')
);
return React.createElement('div', {
className: 'h2-station-page lc-edit-page' + (subView === 'create' ? ' h2-station-page--create' : '')
},
React.createElement('style', null, H2_PAGE_STYLE),
createViewNode,
subView === 'list' ? React.createElement('div', { style: { display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' } },
React.createElement('div', { style: { marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 12 } },
React.createElement(Breadcrumb, { items: [{ title: '加氢站管理' }, { title: '站点信息' }] }),
React.createElement(Button, {
type: 'default',
icon: H2_ICONS.doc,
style: H2_REQ_BTN_STYLE,
onClick: function () { setRequirementModalOpen(true); },
'aria-label': '查看需求说明'
}, '查看需求说明')
),
React.createElement(Card, { className: 'lc-filter-card', title: '筛选条件', bordered: false },
React.createElement('div', { className: 'lc-filter-grid' },
renderFilterField('加氢站名称', React.createElement(Input, {
placeholder: '请输入加氢站名称',
value: listFilters.name,
onChange: function (e) { setListFilters(function (p) { return Object.assign({}, p, { name: e.target.value }); }); },
onPressEnter: handleListFilterQuery,
allowClear: true,
style: { borderRadius: 8 }
})),
renderFilterField('是否签约', React.createElement(Select, {
placeholder: '全部',
allowClear: true,
value: listFilters.signed,
onChange: function (v) { setListFilters(function (p) { return Object.assign({}, p, { signed: v }); }); },
options: [{ value: 'yes', label: '已签约' }, { value: 'no', label: '未签约' }],
style: { width: '100%' },
dropdownStyle: { borderRadius: 8 }
})),
renderFilterField('地区(省-市)', React.createElement(Cascader, {
options: H2_REGION_CASCADER_OPTIONS,
value: listFilters.region && listFilters.region.length ? listFilters.region : undefined,
onChange: function (v) { setListFilters(function (p) { return Object.assign({}, p, { region: v || undefined }); }); },
placeholder: '请选择省 / 市',
allowClear: true,
style: { width: '100%', borderRadius: 8 },
changeOnSelect: true
})),
renderFilterField('营业状态', React.createElement(Select, {
placeholder: '全部',
allowClear: true,
value: listFilters.businessStatus,
onChange: function (v) { setListFilters(function (p) { return Object.assign({}, p, { businessStatus: v }); }); },
options: H2_BUSINESS_STATUS_OPTIONS,
style: { width: '100%' },
dropdownStyle: { borderRadius: 8 }
}))
),
React.createElement('div', { className: 'lc-filter-actions' },
React.createElement(Button, { onClick: handleListFilterReset, style: { borderRadius: 8 } }, '重置'),
React.createElement(Button, { type: 'primary', onClick: handleListFilterQuery, style: H2_PRIMARY_BTN_STYLE }, '查询')
)
),
React.createElement('div', { className: 'lc-alert-stats-row' },
renderAlertStatCard(H2_STATION_KPI_CARDS[0], {
active: categoryTab === 'all',
count: categoryCounts.all || 0,
onClick: function () { handleKpiCardClick('all'); },
icon: h2KpiIcon('all')
}),
H2_SIGNED_FILTER_CARDS.map(function (card) {
return renderAlertStatCard(card, {
active: appliedFilters.signed === card.key,
count: card.key === 'yes' ? signedStats.signed : signedStats.unsigned,
onClick: function () { handleSignedFilterCardClick(card.key); },
icon: h2SignedFilterIcon(card.key)
});
}),
H2_STATION_KPI_CARDS.slice(1).map(function (card) {
return renderAlertStatCard(card, {
active: categoryTab === card.key,
count: categoryCounts[card.key] || 0,
onClick: function () { handleKpiCardClick(card.key); },
icon: h2KpiIcon(card.key)
});
})
),
React.createElement('div', { className: 'lc-table-section' },
React.createElement('div', { className: 'lc-table-toolbar' },
React.createElement('div', { className: 'lc-table-toolbar-actions' },
React.createElement(Button, {
type: 'default',
icon: H2_ICONS.upload,
style: { borderRadius: 8, fontWeight: 600, borderColor: '#10b981', color: '#059669' },
onClick: function () { setImportModalOpen(true); },
'aria-label': '批量导入加氢站点'
}, '批量导入'),
React.createElement(Button, {
type: 'primary',
style: H2_PRIMARY_BTN_STYLE,
onClick: openCreate,
'aria-label': '新建加氢站点'
}, '新建站点')
)
),
React.createElement('div', { className: 'lc-table-card' },
React.createElement(Table, {
className: 'lc-list-table',
rowKey: 'id',
columns: columns,
dataSource: displayList,
pagination: tablePagination,
size: 'middle',
scroll: { x: 1570 },
locale: { emptyText: emptyNode }
})
)
)
) : null,
React.createElement(Drawer, {
title: drawerTitle,
width: 580,
open: drawer.open,
onClose: closeDrawer,
destroyOnClose: true,
styles: { body: { paddingTop: 8 } },
footer: readOnly ? React.createElement(Button, { onClick: closeDrawer, style: { borderRadius: 8 } }, '关闭') : React.createElement(Space, null,
React.createElement(Button, { onClick: closeDrawer, style: { borderRadius: 8 } }, '取消'),
React.createElement(Button, { type: 'primary', onClick: handleSave, style: H2_PRIMARY_BTN_STYLE }, '保存')
)
},
React.createElement(Form, { layout: 'vertical', requiredMark: false },
drawerSection('基本信息',
React.createElement(React.Fragment, null,
formItem('加氢站名称', true, React.createElement(Input, {
value: form.name,
disabled: readOnly,
placeholder: '请输入加氢站名称',
maxLength: 80,
style: { borderRadius: 8 },
onChange: function (e) { setForm(function (f) { return Object.assign({}, f, { name: e.target.value }); }); }
})),
formItem('地址', true, React.createElement(RegionAddressInput, {
value: form.address,
disabled: readOnly,
onChange: function (v) { setForm(function (f) { return Object.assign({}, f, { address: v }); }); }
})),
formItem('营业时间', false, React.createElement(BusinessHoursInput, {
value: form.businessHours,
disabled: readOnly,
fieldStyle: { width: '100%', borderRadius: 8 },
onChange: function (v) { setForm(function (f) { return Object.assign({}, f, { businessHours: v }); }); }
}))
)
),
React.createElement(Divider, { style: { margin: '8px 0 20px' } }),
drawerSection('签约信息',
React.createElement(React.Fragment, null,
formItem('是否签约', false, React.createElement(Switch, {
checked: form.isSigned,
disabled: readOnly,
checkedChildren: '已签约',
unCheckedChildren: '未签约',
onChange: function (v) { setForm(function (f) { return Object.assign({}, f, { isSigned: v }); }); }
})),
formItem('签约开始时间', form.isSigned, React.createElement(Input, {
type: 'date',
style: { width: '100%', borderRadius: 8 },
disabled: readOnly || !form.isSigned,
value: form.contractStart || '',
onChange: function (e) { setForm(function (f) { return Object.assign({}, f, { contractStart: e.target.value }); }); }
})),
formItem('签约结束时间', form.isSigned, React.createElement(Input, {
type: 'date',
style: { width: '100%', borderRadius: 8 },
disabled: readOnly || !form.isSigned,
value: form.contractEnd || '',
onChange: function (e) { setForm(function (f) { return Object.assign({}, f, { contractEnd: e.target.value }); }); }
}))
)
),
React.createElement(Divider, { style: { margin: '8px 0 20px' } }),
drawerSection('联系信息',
React.createElement(React.Fragment, null,
formItem('联系人', true, React.createElement(Input, {
value: form.contact,
disabled: readOnly,
placeholder: '请输入联系人',
style: { borderRadius: 8 },
onChange: function (e) { setForm(function (f) { return Object.assign({}, f, { contact: e.target.value }); }); }
})),
formItem('联系电话', true, React.createElement(Input, {
value: form.phone,
disabled: readOnly,
placeholder: '请输入联系电话',
style: { borderRadius: 8 },
onChange: function (e) { setForm(function (f) { return Object.assign({}, f, { phone: e.target.value }); }); }
}))
)
)
)
),
React.createElement(Modal, {
title: '确认删除',
open: deleteModal.open,
centered: true,
onCancel: function () { setDeleteModal({ open: false, record: null }); },
onOk: function () {
if (deleteModal.record) {
setListData(function (prev) { return prev.filter(function (r) { return r.id !== deleteModal.record.id; }); });
message.success('已删除');
}
setDeleteModal({ open: false, record: null });
},
okButtonProps: { danger: true },
okText: '删除',
cancelText: '取消'
}, '确定删除站点「' + ((deleteModal.record && deleteModal.record.name) || '') + '」吗?此操作不可撤销。'),
React.createElement(Modal, {
className: 'h2-prd-modal',
title: React.createElement('span', { style: { fontWeight: 700 } }, '需求说明 · 站点信息'),
open: requirementModalOpen,
onCancel: function () { setRequirementModalOpen(false); },
width: 640,
centered: true,
footer: React.createElement(Button, { onClick: function () { setRequirementModalOpen(false); }, style: { borderRadius: 8 } }, '关闭')
}, React.createElement('div', { className: 'h2-prd-content' }, getH2StationRequirementDoc())),
React.createElement(Modal, {
title: '批量导入加氢站点',
open: importModalOpen,
onCancel: closeImportModal,
width: 560,
centered: true,
destroyOnClose: true,
okText: '确认导入',
cancelText: '取消',
okButtonProps: {
disabled: !importPreview || !importPreview.valid.length,
style: H2_PRIMARY_BTN_STYLE
},
onOk: handleConfirmImport
},
React.createElement('div', { className: 'h2-import-template-bar' },
React.createElement('div', { className: 'h2-import-template-bar-text' },
React.createElement('div', { style: { fontWeight: 700, marginBottom: 4, color: '#0f172a' } }, '第一步:下载 CSV 导入模板'),
'模板含加氢站名称、省、市、详细地址、是否签约、签约起止时间、营业状态、营业时间、联系人、联系电话;与新建表单字段一致。'
),
React.createElement(Button, {
type: 'primary',
ghost: true,
style: { borderColor: '#10b981', color: '#059669', fontWeight: 600, flexShrink: 0, borderRadius: 8 },
onClick: downloadImportTemplate
}, '下载模板')
),
React.createElement(Alert, {
type: 'info',
showIcon: true,
style: { marginBottom: 14, borderRadius: 10 },
message: '第二步:填写模板后上传文件',
description: '支持 .csv推荐、.xlsx、.xls原型阶段 Excel 请另存为 CSV UTF-8 后上传。上传后系统将校验并预览可导入条数。'
}),
React.createElement(Upload.Dragger, {
accept: '.csv,.xlsx,.xls',
multiple: false,
maxCount: 1,
fileList: importFileList,
beforeUpload: function (file) {
parseImportFile(file);
return false;
},
onRemove: function () {
setImportFileList([]);
setImportPreview(null);
return true;
}
},
React.createElement('p', { style: { margin: '8px 0 4px', fontWeight: 600, color: '#334155' } }, '点击或拖拽文件到此处上传'),
React.createElement('p', { style: { margin: 0, fontSize: 12, color: '#94a3b8' } }, '单次上传一个文件')
),
importPreview ? React.createElement('div', { className: 'h2-import-preview' },
React.createElement('div', { style: { fontWeight: 700, marginBottom: 6 } }, '解析结果 · ' + (importPreview.fileName || '')),
React.createElement('div', null,
React.createElement('span', { style: { color: '#059669', fontWeight: 600 } }, '可导入 ' + importPreview.valid.length + ' 条'),
importPreview.errors.length ? React.createElement('span', { style: { marginLeft: 12, color: '#dc2626', fontWeight: 600 } }, '失败 ' + importPreview.errors.length + ' 条') : null
),
importPreview.errors.length ? React.createElement('ul', { className: 'h2-import-error-list' },
importPreview.errors.slice(0, 8).map(function (err, ei) {
return React.createElement('li', { key: ei },
'第 ' + err.lineNo + ' 行「' + err.name + '」:' + err.reasons.join('')
);
}).concat(
importPreview.errors.length > 8
? [React.createElement('li', { key: 'more' }, '… 另有 ' + (importPreview.errors.length - 8) + ' 条错误未展示')]
: []
)
) : null
) : null
),
React.createElement(Modal, {
title: '营业状态',
open: businessModal.open,
onCancel: closeBusinessModal,
onOk: handleSaveBusinessSetting,
okText: '保存',
cancelText: '取消',
centered: true,
width: 680,
destroyOnClose: true,
okButtonProps: { style: H2_PRIMARY_BTN_STYLE }
},
React.createElement('div', { style: { marginBottom: 12, fontSize: 13, color: '#64748b' } },
'站点:', React.createElement('strong', { style: { color: '#0f172a' } }, (businessModal.record && businessModal.record.name) || '—')
),
formItem('营业状态', true, React.createElement(Select, {
style: { width: '100%' },
value: businessModal.businessStatus,
options: H2_BUSINESS_STATUS_OPTIONS,
onChange: function (v) { setBusinessModal(function (m) { return Object.assign({}, m, { businessStatus: v }); }); },
dropdownStyle: { borderRadius: 8 }
})),
formItem('营业时间', false, React.createElement(BusinessHoursInput, {
value: businessModal.businessHours,
fieldStyle: { width: '100%', borderRadius: 8 },
onChange: function (v) { setBusinessModal(function (m) { return Object.assign({}, m, { businessHours: v }); }); }
}), '暂停或停止营业时可将类型改为非全天并清空时间'),
React.createElement('div', { className: 'h2-status-log-section' },
React.createElement('div', { className: 'h2-status-log-title' }, '营业状态变更记录'),
React.createElement(Table, {
className: 'h2-status-log-table',
size: 'small',
rowKey: 'id',
columns: businessStatusLogColumns,
dataSource: businessModal.statusLogs || [],
pagination: (businessModal.statusLogs || []).length > 5 ? { pageSize: 5, size: 'small' } : false,
locale: { emptyText: '暂无状态变更记录' },
scroll: { x: 520 }
})
)
),
React.createElement(Modal, {
title: '加氢记录' + (refuelModal.station && refuelModal.station.name ? ' · ' + refuelModal.station.name : ''),
open: refuelModal.open,
onCancel: closeRefuelModal,
footer: React.createElement(Button, { onClick: closeRefuelModal, style: { borderRadius: 8 } }, '关闭'),
width: 960,
centered: true,
destroyOnClose: true,
styles: { body: { maxHeight: '72vh', overflow: 'auto', paddingTop: 8 } }
},
renderRefuelTotalsBar(refuelModalSummary),
React.createElement(Table, {
className: 'h2-refuel-record-table',
size: 'small',
bordered: true,
rowKey: 'id',
columns: refuelRecordColumns,
dataSource: refuelModal.records || [],
pagination: (refuelModal.records || []).length > 8 ? { pageSize: 8, showSizeChanger: false, size: 'small' } : false,
locale: { emptyText: '暂无加氢记录' },
scroll: { x: 'max-content', y: 360 }
})
),
React.createElement(Modal, {
title: '余额变更明细' + (prepaidBalanceDrill.stationName ? ' · ' + prepaidBalanceDrill.stationName : ''),
open: prepaidBalanceDrill.open,
onCancel: closePrepaidBalanceDrill,
footer: React.createElement(Button, { onClick: closePrepaidBalanceDrill, style: { borderRadius: 8 } }, '关闭'),
width: 880,
centered: true,
destroyOnClose: true,
styles: { body: { maxHeight: '72vh', overflow: 'auto', paddingTop: 8 } }
},
React.createElement(Table, {
className: 'h2-balance-record-table',
size: 'small',
bordered: true,
rowKey: 'key',
columns: prepaidBalanceDrillColumns,
dataSource: prepaidBalanceDrill.rows || [],
pagination: (prepaidBalanceDrill.rows || []).length > 10 ? { pageSize: 10, showSizeChanger: false, size: 'small' } : false,
summary: renderPrepaidBalanceDrillSummary,
locale: { emptyText: '暂无余额变更记录' },
scroll: { x: 'max-content' }
})
),
React.createElement(Modal, {
title: '生成对账单',
open: statementModal.open,
onCancel: closeStatementModal,
onOk: handleGenerateStatement,
okText: '生成对账单',
cancelText: '取消',
centered: true,
width: 520,
destroyOnClose: true,
okButtonProps: { style: H2_PRIMARY_BTN_STYLE }
},
React.createElement('div', { style: { marginBottom: 12, fontSize: 13, color: '#64748b' } },
'站点:', React.createElement('strong', { style: { color: '#0f172a' } }, (statementModal.record && statementModal.record.name) || '—')
),
React.createElement(Alert, {
type: 'info',
showIcon: true,
style: { marginBottom: 14, borderRadius: 10 },
message: '按周期汇总站点加氢明细,生成氢费对账单(对站)',
description: '对账单将汇总该周期内加氢量、成本总价等,提交后可进入审批流程(原型演示)。'
}),
formItem('对账周期', true, React.createElement(Input, {
type: 'month',
style: { width: '100%', borderRadius: 8 },
value: statementModal.period || '',
onChange: function (e) { setStatementModal(function (m) { return Object.assign({}, m, { period: e.target.value }); }); }
})),
statementModal.record ? React.createElement('div', { style: { fontSize: 12, color: '#64748b', lineHeight: 1.6 } },
'当前预付余额:',
renderPrepaidBalance(statementModal.record.prepaidBalance),
';本站点累计加氢 ',
React.createElement('strong', { style: { color: '#0f172a' } }, String(statementModal.record.refuelCount != null ? statementModal.record.refuelCount : h2CalcRefuelStats(statementModal.record.name).count)),
' 次'
) : null
),
React.createElement(Modal, {
title: '价格配置',
open: priceModal.open,
onCancel: closePriceModal,
onOk: handleSavePriceConfig,
okText: '保存',
cancelText: '取消',
centered: true,
width: 480,
destroyOnClose: true,
okButtonProps: { style: H2_PRIMARY_BTN_STYLE }
},
React.createElement('div', { style: { marginBottom: 12, fontSize: 13, color: '#64748b' } },
'站点:', React.createElement('strong', { style: { color: '#0f172a' } }, (priceModal.record && priceModal.record.name) || '—')
),
formItem('成本单价(元/kg', false, React.createElement(Input, {
value: priceModal.costUnitPrice,
placeholder: '请输入成本单价',
style: { borderRadius: 8 },
onChange: function (e) { setPriceModal(function (m) { return Object.assign({}, m, { costUnitPrice: e.target.value }); }); }
})),
formItem('对客单价(元/kg', false, React.createElement(Input, {
value: priceModal.customerUnitPrice,
placeholder: '请输入对客单价',
style: { borderRadius: 8 },
onChange: function (e) { setPriceModal(function (m) { return Object.assign({}, m, { customerUnitPrice: e.target.value }); }); }
}), '用于加氢订单结算参考,联调后对接价格体系')
)
);
};
if (typeof window !== 'undefined') window.Component = Component;