Optimized the root .gitignore to exclude virtual environments, node modules, and temp folders to ensure clean and lightweight version tracking. Co-authored-by: Cursor <cursoragent@cursor.com>
3714 lines
172 KiB
JavaScript
3714 lines
172 KiB
JavaScript
// 【重要】必须使用 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: '加氢次数 1~2 次的站点' },
|
||
{ 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 { --h2-form-row-gap: 20px; --h2-form-col-gap: 24px; --h2-form-label-gap: 8px; 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(4, minmax(0, 1fr)); gap: 16px 24px; align-items: center; }',
|
||
'@media (max-width: 1280px) { .h2-station-page .lc-filter-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }',
|
||
'@media (max-width: 640px) { .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; min-height: 32px; }',
|
||
'.h2-station-page .lc-filter-field-label { flex: 0 0 88px; text-align: right; font-size: 13px; font-weight: 500; color: #475569; line-height: 32px; 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-input-affix-wrapper, .h2-station-page .lc-filter-field-control .ant-select .ant-select-selector, .h2-station-page .lc-filter-field-control .ant-cascader .ant-select-selector { width: 100%; min-height: 32px !important; border-radius: 8px !important; }',
|
||
'.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-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--create .h2-create-form--grid-4 .h2-region-address--stack-col4 { gap: 8px; }',
|
||
'.h2-station-page--create .h2-create-form--grid-4 .h2-region-address--stack-col4 .h2-region-address-cascader, .h2-station-page--create .h2-create-form--grid-4 .h2-region-address--stack-col4 .h2-region-address-detail { flex: none; max-width: 100%; width: 100%; min-width: 0; }',
|
||
'.h2-station-page--create .h2-create-form--grid-4 .h2-contract-panel { padding: 10px 12px; }',
|
||
'.h2-station-page--create .h2-create-form--grid-4 .h2-contract-upload-actions { flex-direction: column; align-items: stretch; gap: 6px; }',
|
||
'.h2-station-page--create .h2-create-form--grid-4 .h2-contract-upload-actions .ant-btn { width: 100%; }',
|
||
'.h2-station-page--create .h2-create-form--grid-4 .h2-contract-dates { flex-direction: column; align-items: stretch; gap: 6px; }',
|
||
'.h2-station-page--create .h2-create-form--grid-4 .h2-contract-dates-sep { text-align: center; line-height: 1; }',
|
||
'.h2-station-page--create .h2-create-form--grid-4 .h2-create-radio-group { gap: 8px 12px; }',
|
||
'.h2-station-page--create .h2-supplier-mode-card--compact { flex-direction: column; align-items: stretch; justify-content: flex-start; min-height: 88px; padding: 12px; gap: 8px; }',
|
||
'.h2-station-page--create .h2-supplier-mode-card--compact .h2-supplier-mode-card-icon { width: 32px; height: 32px; }',
|
||
'.h2-station-page--create .h2-supplier-mode-card--compact .h2-supplier-mode-card-title { font-size: 13px; }',
|
||
'.h2-station-page--create .h2-supplier-mode-card--compact .h2-supplier-mode-card-desc { font-size: 11px; line-height: 1.35; }',
|
||
'.h2-station-page--create .h2-create-form--grid-4 .h2-supplier-link-select { padding: 0; margin: 0; border: none; background: transparent; }',
|
||
'.h2-station-page--create .h2-create-form--grid-4 .h2-create-upload.ant-upload-wrapper .ant-upload-drag { padding: 10px 8px !important; }',
|
||
'.h2-station-page--create .h2-create-form--grid-4 .h2-create-upload.ant-upload-wrapper .ant-upload-drag .ant-upload-drag-icon { margin-bottom: 4px !important; }',
|
||
'.h2-station-page--create .h2-create-form--grid-4 .h2-create-upload.ant-upload-wrapper .ant-upload-drag p { font-size: 12px !important; }',
|
||
'.h2-station-page .h2-address-paste { display: flex; flex-direction: column; gap: 8px; width: 100%; }',
|
||
'.h2-station-page .ant-drawer-body .ant-form .ant-form-item { margin-bottom: 20px; }',
|
||
'.h2-station-page .ant-drawer-body .ant-form .ant-form-item:last-child { margin-bottom: 0; }',
|
||
'.h2-station-page .ant-drawer-body .ant-form .ant-form-item-label { padding-bottom: var(--h2-form-label-gap, 8px); }',
|
||
'.h2-station-page .ant-drawer-body .ant-form .ant-form-item-label > label { min-height: 22px; line-height: 22px; }',
|
||
'.h2-station-page .ant-drawer-body .ant-divider { margin: 4px 0 20px !important; }',
|
||
'.h2-station-page .h2-address-paste .ant-input-textarea { font-size: 13px !important; line-height: 1.45 !important; resize: vertical; min-height: 56px; }',
|
||
'.h2-station-page .h2-address-paste-actions { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }',
|
||
'.h2-station-page .h2-address-paste-hint { font-size: 11px; color: #94a3b8; line-height: 1.35; flex: 1; min-width: 0; }',
|
||
'.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: 24px 24px 0; box-sizing: border-box; }',
|
||
'.h2-station-page--create .h2-create-pagehead { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; margin-bottom: 16px; }',
|
||
'.h2-station-page--create .h2-create-pagehead-left { display: flex; align-items: center; gap: 12px; min-width: 0; }',
|
||
'.h2-station-page--create .h2-create-pagehead-title { margin: 0; font-size: 18px; font-weight: 700; color: #0f172a; line-height: 1.35; }',
|
||
'.h2-station-page--create .h2-create-pagehead-desc { margin: 2px 0 0; font-size: 13px; color: #64748b; line-height: 1.45; }',
|
||
'.h2-station-page--create .h2-create-card.ant-card { margin-bottom: 16px !important; }',
|
||
'.h2-station-page--create .h2-create-form--grid .h2-create-form-grid { width: 100%; }',
|
||
'.h2-station-page--create .h2-create-form--grid .ant-row { width: 100% !important; margin-left: 0 !important; margin-right: 0 !important; }',
|
||
'.h2-station-page--create .h2-create-form--grid .ant-col { min-width: 0; }',
|
||
'.h2-station-page--create .h2-create-form--grid .ant-form-item { margin-bottom: 0; width: 100%; }',
|
||
'.h2-station-page--create .h2-create-form--grid .ant-col > .ant-form-item { display: flex; flex-direction: column; }',
|
||
'.h2-station-page--create .h2-create-form--grid .ant-form-item-control { flex: 1; width: 100%; }',
|
||
'.h2-station-page--create .h2-create-form--grid .ant-form-item-control-input, .h2-station-page--create .h2-create-form--grid .ant-form-item-control-input-content { width: 100%; max-width: 100%; }',
|
||
'.h2-station-page--create .h2-create-form--grid .h2-create-input, .h2-station-page--create .h2-create-form--grid .ant-select, .h2-station-page--create .h2-create-form--grid .ant-cascader, .h2-station-page--create .h2-create-form--grid .ant-picker { width: 100% !important; max-width: 100% !important; }',
|
||
'.h2-station-page--create .h2-create-form--grid .h2-address-paste, .h2-station-page--create .h2-create-form--grid .h2-contract-panel, .h2-station-page--create .h2-create-form--grid .h2-create-upload { width: 100%; }',
|
||
'.h2-station-page--create .h2-create-subsection-title { margin: 4px 0 0; padding: 12px 0 10px; font-size: 13px; font-weight: 600; color: #475569; border-bottom: 1px solid #f1f5f9; width: 100%; box-sizing: border-box; }',
|
||
'.h2-station-page--create .h2-supplier-mode-picker-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; width: 100%; }',
|
||
'.h2-station-page--create .h2-supplier-mode-picker-row .h2-supplier-mode-card { height: 100%; min-height: 88px; }',
|
||
'@media (max-width: 768px) { .h2-station-page--create .h2-supplier-mode-picker-row { grid-template-columns: 1fr; gap: 12px; } }',
|
||
'.h2-station-page--create .h2-create-panel { padding: 16px 18px; border-radius: 12px; background: #f8fafc; border: 1px solid #e8ecf0; }',
|
||
'.h2-station-page--create .h2-create-panel + .h2-create-panel, .h2-station-page--create .h2-create-panel + .ant-row, .h2-station-page--create .ant-row + .h2-create-panel { margin-top: 16px; }',
|
||
'.h2-station-page--create .h2-create-panel-head { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; font-size: 13px; font-weight: 700; color: #334155; }',
|
||
'.h2-station-page--create .h2-create-panel-head::before { content: ""; width: 4px; height: 14px; border-radius: 2px; background: linear-gradient(180deg, #10b981, #6ee7b7); flex-shrink: 0; }',
|
||
'.h2-station-page--create .h2-create-panel--address .h2-region-address--inline { gap: 12px; }',
|
||
'.h2-station-page--create .h2-create-panel--address .h2-region-address--inline .h2-region-address-cascader { flex: 0 0 42%; max-width: 280px; }',
|
||
'.h2-station-page--create .h2-create-panel--address .h2-address-paste { margin-top: 12px; padding-top: 12px; border-top: 1px dashed #e2e8f0; }',
|
||
'.h2-station-page--create .h2-create-panel--contract .h2-create-radio-group { padding: 10px 14px; background: #fff; border-radius: 10px; border: 1px solid #e2e8f0; }',
|
||
'.h2-station-page--create .h2-create-contract-fields { display: grid; grid-template-columns: 1fr; gap: 16px; margin-top: 14px; }',
|
||
'@media (min-width: 640px) { .h2-station-page--create .h2-create-contract-fields { grid-template-columns: 1fr 1fr; } }',
|
||
'.h2-station-page--create .h2-supplier-link-panel { padding: 16px 18px; border-radius: 12px; background: linear-gradient(135deg, #eff6ff 0%, #f8fafc 100%); border: 1px solid #bfdbfe; }',
|
||
'.h2-station-page--create .h2-supplier-new-stack { display: flex; flex-direction: column; gap: 16px; }',
|
||
'.h2-station-page--create .h2-create-form--visual .ant-form-item-label > label { font-weight: 500; color: #334155; }',
|
||
'.h2-station-page--create .h2-create-form--visual .h2-create-input.ant-input:not(.ant-input-disabled), .h2-station-page--create .h2-create-form--visual .ant-select:not(.ant-select-disabled) .ant-select-selector, .h2-station-page--create .h2-create-form--visual .ant-cascader:not(.ant-select-disabled) .ant-select-selector, .h2-station-page--create .h2-create-form--visual .h2-create-input.ant-picker:not(.ant-picker-disabled) { border-radius: 10px !important; height: 40px !important; min-height: 40px !important; border-color: #e2e8f0 !important; }',
|
||
'.h2-station-page--create .h2-create-form--visual .ant-input { padding: 8px 14px !important; }',
|
||
'.h2-station-page--create .h2-create-form--visual .ant-select-selection-item { line-height: 38px !important; }',
|
||
'.h2-station-page--create .h2-create-form--visual .ant-input-lg { height: 44px !important; font-size: 15px !important; border-radius: 10px !important; }',
|
||
'.h2-station-page--create .h2-create-panel .ant-form-item + .ant-form-item, .h2-station-page--create .h2-create-panel .ant-form-item + .ant-row, .h2-station-page--create .h2-create-panel .ant-row + .ant-form-item, .h2-station-page--create .h2-create-panel .ant-form-item + .h2-address-paste, .h2-station-page--create .h2-create-panel .ant-row + .h2-address-paste { margin-top: 12px; }',
|
||
'.h2-station-page--create .h2-create-form--visual .h2-create-radio-group { min-height: 40px; }',
|
||
'.h2-station-page--create .h2-create-form--visual .ant-form-item-control-input { max-width: 100%; }',
|
||
'.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 24px -6px rgba(15, 23, 42, 0.06) !important; margin-bottom: 0 !important; transition: box-shadow 0.2s ease, border-color 0.2s ease, transform 0.2s ease; }',
|
||
'.h2-station-page--create .h2-create-card.ant-card:hover { box-shadow: 0 4px 24px -6px rgba(15, 23, 42, 0.06) !important; transform: none; }',
|
||
'.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: 20px 24px 24px !important; display: flex; flex-direction: column; gap: 16px; }',
|
||
'@media (max-width: 640px) { .h2-station-page--create .h2-create-card > .ant-card-body { padding: 16px 16px 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: 0; }',
|
||
'.h2-station-page .h2-form-section + .h2-form-section { margin-top: var(--h2-form-row-gap); }',
|
||
'.h2-station-page .h2-form-section-body { display: flex; flex-direction: column; gap: var(--h2-form-row-gap); }',
|
||
'.h2-station-page .h2-form-section-body > .ant-row { margin: 0 !important; align-items: flex-start; }',
|
||
'.h2-station-page .h2-form-section-body .ant-form-item { margin-bottom: 0 !important; width: 100%; }',
|
||
'.h2-station-page .h2-form-section-body .ant-col { display: flex; flex-direction: column; min-width: 0; }',
|
||
'.h2-station-page .h2-form-section-body .ant-col > .ant-form-item { flex: 1; min-width: 0; }',
|
||
'.h2-station-page--create .h2-create-form .h2-form-section-body .h2-supplier-mode-card { height: 100%; box-sizing: border-box; }',
|
||
'.h2-station-page .h2-contract-panel { padding: 14px 16px; border-radius: 10px; background: linear-gradient(180deg, #fafbfc 0%, #fff 100%); border: 1px solid #e8ecf0; }',
|
||
'.h2-station-page--create .h2-create-topbar-main { display: flex; align-items: center; gap: 14px; min-width: 0; }',
|
||
'.h2-station-page--create .h2-create-page-title { min-width: 0; }',
|
||
'.h2-station-page--create .h2-create-page-title h1 { margin: 0; font-size: 16px; font-weight: 700; color: #0f172a; line-height: 1.35; }',
|
||
'.h2-station-page--create .h2-create-page-title p { margin: 2px 0 0; font-size: 12px; color: #94a3b8; line-height: 1.4; }',
|
||
'.h2-station-page--create .h2-create-form .ant-picker-range { width: 100% !important; max-width: 100%; }',
|
||
'.h2-station-page--create .h2-create-form .ant-picker-range .ant-picker-input > input { font-size: 13px !important; }',
|
||
'.h2-station-page .h2-supplier-mode-card-body { flex: 1; min-width: 0; }',
|
||
'.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: 0; }',
|
||
'.h2-station-page--create .h2-create-form .ant-form-item-label { padding: 0 0 var(--h2-form-label-gap); min-height: 22px; }',
|
||
'.h2-station-page--create .h2-create-form .ant-form-item-label > label { display: inline-flex; align-items: center; min-height: 22px; line-height: 22px; font-size: 14px; font-weight: 400; color: #1d2129; height: auto; }',
|
||
'.h2-station-page--create .h2-create-form .ant-form-item-extra { margin-top: 6px; font-size: 12px; line-height: 1.45; }',
|
||
'.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, .h2-station-page--create .h2-create-form .h2-create-input.ant-picker:not(.ant-picker-disabled) { 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 .h2-create-input.ant-picker:not(.ant-picker-disabled):hover { border-color: #c9cdd4 !important; background: #fff !important; }',
|
||
'.h2-station-page--create .h2-create-form .h2-create-input.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 .h2-supplier-mode-card { font-family: inherit; width: 100%; box-sizing: border-box; }',
|
||
'.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), .h2-station-page--create .h2-create-form .h2-address-paste .ant-input-textarea:not(.ant-input-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 + .h2-create-card { animation-delay: 0.06s; } }',
|
||
'@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; } }',
|
||
'.h2-station-page--create .h2-create-form--list .ant-input:not(.ant-input-disabled):not(:disabled), .h2-station-page--create .h2-create-form--list .ant-input-affix-wrapper:not(.ant-input-affix-wrapper-disabled), .h2-station-page--create .h2-create-form--list .ant-select:not(.ant-select-disabled) .ant-select-selector, .h2-station-page--create .h2-create-form--list .ant-cascader:not(.ant-select-disabled) .ant-select-selector, .h2-station-page--create .h2-create-form--list .ant-picker:not(.ant-picker-disabled) { border-radius: 8px !important; border: 1px solid #e2e8f0 !important; min-height: 32px !important; height: 32px !important; font-size: 13px !important; background: #fff !important; color: #0f172a !important; box-shadow: none !important; }',
|
||
'.h2-station-page--create .h2-create-form--list .ant-input-textarea:not(.ant-input-disabled) { border-radius: 8px !important; border: 1px solid #e2e8f0 !important; height: auto !important; min-height: auto !important; font-size: 13px !important; }',
|
||
'.h2-station-page--create .h2-create-form--list .ant-input:not(:disabled):hover, .h2-station-page--create .h2-create-form--list .ant-input-affix-wrapper:not(.ant-input-affix-wrapper-disabled):hover, .h2-station-page--create .h2-create-form--list .ant-select:not(.ant-select-disabled):hover .ant-select-selector, .h2-station-page--create .h2-create-form--list .ant-cascader:not(.ant-select-disabled):hover .ant-select-selector, .h2-station-page--create .h2-create-form--list .ant-picker:not(.ant-picker-disabled):hover { border-color: #cbd5e1 !important; }',
|
||
'.h2-station-page--create .h2-create-form--list .ant-input:focus, .h2-station-page--create .h2-create-form--list .ant-input-focused, .h2-station-page--create .h2-create-form--list .ant-input-affix-wrapper-focused, .h2-station-page--create .h2-create-form--list .ant-select-focused .ant-select-selector, .h2-station-page--create .h2-create-form--list .ant-cascader-focused .ant-select-selector, .h2-station-page--create .h2-create-form--list .ant-picker-focused { border-color: #10b981 !important; box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.2) !important; }',
|
||
'.h2-station-page--create .h2-create-form--list .ant-form-item-label > label { font-size: 13px; font-weight: 500; color: #475569; }',
|
||
'.h2-station-page--create .h2-create-form--list .ant-radio-wrapper .ant-radio-checked .ant-radio-inner { border-color: #10b981; background-color: #10b981; }',
|
||
'.h2-station-page--create .h2-create-pagehead { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; margin-bottom: 16px; padding: 12px 20px; background: #fff; border-radius: 16px; border: 1px solid #e2e8f0; box-shadow: 0 4px 20px -4px rgba(15, 23, 42, 0.03); }',
|
||
'.h2-station-page--create .h2-create-card.ant-card { border-radius: 16px !important; }'
|
||
].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 h2ParseAddressText(rawText) {
|
||
var text = String(rawText || '').trim();
|
||
if (!text) return { region: [], detail: '', matched: false };
|
||
|
||
var compact = text.replace(/\s+/g, '');
|
||
var provinces = H2_REGION_CASCADER_OPTIONS.slice().sort(function (a, b) {
|
||
return String(b.value || b.label || '').length - String(a.value || a.label || '').length;
|
||
});
|
||
|
||
var matchedProvince = null;
|
||
var provinceStart = -1;
|
||
for (var i = 0; i < provinces.length; i++) {
|
||
var pName = provinces[i].value || provinces[i].label;
|
||
var idx = compact.indexOf(pName);
|
||
if (idx !== -1 && (provinceStart === -1 || idx < provinceStart)) {
|
||
provinceStart = idx;
|
||
matchedProvince = provinces[i];
|
||
}
|
||
}
|
||
|
||
if (!matchedProvince) {
|
||
return { region: [], detail: text, matched: false };
|
||
}
|
||
|
||
var provinceName = matchedProvince.value || matchedProvince.label;
|
||
var rest = compact.slice(provinceStart + provinceName.length).replace(/^[\s\-—,,、·]+/, '');
|
||
var cities = matchedProvince.children || [];
|
||
var cityMatch = h2FindCityInAddressRest(rest, cities);
|
||
|
||
if (!cityMatch && cities.length === 1) {
|
||
return {
|
||
region: [provinceName, cities[0].value || cities[0].label],
|
||
detail: rest.replace(/^[\s\-—,,、·]+/, ''),
|
||
matched: true
|
||
};
|
||
}
|
||
|
||
if (!cityMatch) {
|
||
return { region: [provinceName], detail: rest || text, matched: true, partial: true };
|
||
}
|
||
|
||
var cityName = cityMatch.city.value || cityMatch.city.label;
|
||
var detail = (cityMatch.prefix || '') + rest.slice(cityMatch.end);
|
||
detail = detail.replace(/^[\s\-—,,、·]+/, '');
|
||
|
||
return { region: [provinceName, cityName], detail: detail, matched: true };
|
||
}
|
||
|
||
function h2FindCityInAddressRest(rest, cities) {
|
||
if (!rest || !cities || !cities.length) return null;
|
||
var sorted = cities.slice().sort(function (a, b) {
|
||
return String(b.value || b.label || '').length - String(a.value || a.label || '').length;
|
||
});
|
||
var i;
|
||
for (i = 0; i < sorted.length; i++) {
|
||
var cn = sorted[i].value || sorted[i].label;
|
||
if (rest.indexOf(cn) === 0) return { city: sorted[i], prefix: '', end: cn.length };
|
||
}
|
||
for (i = 0; i < sorted.length; i++) {
|
||
var cn2 = sorted[i].value || sorted[i].label;
|
||
var idx = rest.indexOf(cn2);
|
||
if (idx > 0 && idx <= 8) return { city: sorted[i], prefix: rest.slice(0, idx), end: idx + cn2.length };
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/** 快速粘贴地址:识别后回填省/市与详细地址 */
|
||
function AddressPasteInput(props) {
|
||
var antd = window.antd;
|
||
var Input = antd.Input;
|
||
var Button = antd.Button;
|
||
var message = antd.message;
|
||
var _paste = React.useState('');
|
||
var pasteText = _paste[0];
|
||
var setPasteText = _paste[1];
|
||
var disabled = props.disabled;
|
||
var inputClassName = props.inputClassName || '';
|
||
|
||
var handleParse = function () {
|
||
var raw = (pasteText || '').trim();
|
||
if (!raw) {
|
||
message.warning('请先粘贴完整地址');
|
||
return;
|
||
}
|
||
var result = h2ParseAddressText(raw);
|
||
if (!result.matched) {
|
||
message.warning('未能识别省/市,请将内容填入详细地址');
|
||
if (props.onParsed) props.onParsed({ region: [], detail: raw });
|
||
return;
|
||
}
|
||
if (result.partial || !result.region || result.region.length < 2) {
|
||
message.warning('已识别省份,请手动补选城市');
|
||
} else {
|
||
message.success('地址识别成功');
|
||
}
|
||
if (props.onParsed) props.onParsed({ region: result.region || [], detail: result.detail || '' });
|
||
setPasteText('');
|
||
};
|
||
|
||
return React.createElement('div', { className: 'h2-address-paste' },
|
||
React.createElement(Input.TextArea, {
|
||
className: inputClassName,
|
||
value: pasteText,
|
||
disabled: disabled,
|
||
placeholder: props.placeholder || '粘贴完整地址,如:浙江省嘉兴市南湖区科技大道88号',
|
||
autoSize: { minRows: 2, maxRows: 4 },
|
||
onChange: function (e) { setPasteText(e.target.value); }
|
||
}),
|
||
React.createElement('div', { className: 'h2-address-paste-actions' },
|
||
React.createElement('span', { className: 'h2-address-paste-hint' }, '自动拆分省/市与详细地址'),
|
||
React.createElement(Button, {
|
||
type: 'link',
|
||
size: 'small',
|
||
disabled: disabled || !pasteText.trim(),
|
||
onClick: handleParse
|
||
}, '识别地址')
|
||
)
|
||
);
|
||
}
|
||
|
||
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' : '') + (props.className ? ' ' + props.className : '');
|
||
|
||
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;
|
||
var layout = props.layout || 'inline';
|
||
var rootCls = 'h2-region-address' + (layout === 'inline' ? ' h2-region-address--inline' : '') + (props.className ? ' ' + props.className : '');
|
||
|
||
return React.createElement('div', { className: rootCls },
|
||
React.createElement(Cascader, {
|
||
className: inputClassName + (layout === 'inline' ? ' 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 + (layout === 'inline' ? ' 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' } }, '点击上传,可多选')
|
||
),
|
||
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); }
|
||
}, '下载'),
|
||
!disabled
|
||
? React.createElement(Button, {
|
||
type: 'link',
|
||
size: 'small',
|
||
danger: true,
|
||
onClick: function () {
|
||
if (!props.onChange) return;
|
||
props.onChange({
|
||
fileList: fileList.filter(function (f) { return f.uid !== file.uid; })
|
||
});
|
||
}
|
||
}, '删除')
|
||
: null
|
||
)
|
||
);
|
||
})
|
||
)
|
||
: 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 高频,1~2 低频,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 Cascader = antd.Cascader;
|
||
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 Divider = antd.Divider;
|
||
var Breadcrumb = antd.Breadcrumb;
|
||
var dayjs = window.dayjs;
|
||
|
||
var inputCls = 'h2-create-input';
|
||
var progressPct = h2CreateFormProgress(ctx.station, ctx.supplier, ctx.supplierMode, ctx.linkedSupplierId);
|
||
var stationAddr = ctx.station.address || { region: [], detail: '' };
|
||
|
||
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 H2_CREATE_GUTTER = [24, 20];
|
||
|
||
var formRow = function () {
|
||
return React.createElement.apply(null, [Row, { gutter: H2_CREATE_GUTTER, align: 'stretch' }].concat(Array.prototype.slice.call(arguments)));
|
||
};
|
||
|
||
var col24 = function (node) {
|
||
return React.createElement(Col, { xs: 24, span: 24 }, node);
|
||
};
|
||
|
||
var col16 = function (node) {
|
||
return React.createElement(Col, { xs: 24, lg: 16 }, node);
|
||
};
|
||
|
||
var col12 = function (node) {
|
||
return React.createElement(Col, { xs: 24, md: 12 }, node);
|
||
};
|
||
|
||
var col8 = function (node) {
|
||
return React.createElement(Col, { xs: 24, lg: 8 }, node);
|
||
};
|
||
|
||
var gridBlock = function () {
|
||
var rows = Array.prototype.slice.call(arguments, 0);
|
||
return React.createElement('div', { className: 'h2-create-form-grid' }, rows);
|
||
};
|
||
|
||
var gridSubsection = function (text) {
|
||
return formRow(col24(React.createElement('div', { className: 'h2-create-subsection-title' }, text)));
|
||
};
|
||
|
||
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 supplierModeCard = function (mode, icon, title, desc) {
|
||
var active = ctx.supplierMode === mode;
|
||
return React.createElement('button', {
|
||
type: 'button',
|
||
className: 'h2-supplier-mode-card' + (active ? ' h2-supplier-mode-card--active' : ''),
|
||
'aria-pressed': active,
|
||
'aria-label': title + ':' + desc,
|
||
onClick: function () { ctx.handleSupplierModeChange({ target: { value: mode } }); }
|
||
},
|
||
React.createElement('span', { className: 'h2-supplier-mode-card-icon', 'aria-hidden': true }, icon),
|
||
React.createElement('span', { className: 'h2-supplier-mode-card-body' },
|
||
React.createElement('div', { className: 'h2-supplier-mode-card-title' }, title),
|
||
React.createElement('div', { className: 'h2-supplier-mode-card-desc' }, desc)
|
||
)
|
||
);
|
||
};
|
||
|
||
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', { style: { marginBottom: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 12 } },
|
||
React.createElement(Breadcrumb, { items: [{ title: '加氢站管理' }, { title: '站点信息' }, { title: '新建加氢站点' }] }),
|
||
React.createElement(Button, {
|
||
type: 'default',
|
||
icon: ctx.reqIcon,
|
||
style: ctx.reqBtnStyle,
|
||
onClick: ctx.onOpenRequirement,
|
||
'aria-label': '查看需求说明'
|
||
}, '查看需求说明')
|
||
),
|
||
React.createElement('div', { className: 'h2-create-pagehead' },
|
||
React.createElement('div', { className: 'h2-create-pagehead-left' },
|
||
React.createElement(Button, {
|
||
className: 'h2-create-back-btn',
|
||
type: 'default',
|
||
icon: H2_ICONS.back,
|
||
onClick: ctx.onCancel,
|
||
disabled: ctx.submitting,
|
||
style: { borderRadius: 8 }
|
||
}, '返回'),
|
||
React.createElement('div', null,
|
||
React.createElement('h1', { className: 'h2-create-pagehead-title' }, '新建加氢站点'),
|
||
React.createElement('p', { className: 'h2-create-pagehead-desc' }, '填写站点基础信息并关联供应商')
|
||
)
|
||
)
|
||
),
|
||
|
||
React.createElement(Form, { layout: 'vertical', requiredMark: false, className: 'h2-create-form h2-create-form--list h2-create-form--grid' },
|
||
React.createElement(Card, {
|
||
className: 'h2-create-card',
|
||
id: 'h2-create-station-card',
|
||
title: cardTitle('加氢站基本信息', H2_ICONS.building),
|
||
bordered: false
|
||
},
|
||
gridBlock(
|
||
formRow(
|
||
col24(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
|
||
})))
|
||
),
|
||
formRow(
|
||
col8(formItem('省 / 市', true, React.createElement(Cascader, {
|
||
className: inputCls,
|
||
options: H2_REGION_CASCADER_OPTIONS,
|
||
value: stationAddr.region && stationAddr.region.length ? stationAddr.region : undefined,
|
||
onChange: function (v) {
|
||
ctx.updateStation({
|
||
address: { region: v || [], detail: stationAddr.detail || '' }
|
||
});
|
||
},
|
||
placeholder: '请选择省 / 市',
|
||
allowClear: true
|
||
}))),
|
||
col16(formItem('详细地址', true, React.createElement(Input, {
|
||
className: inputCls,
|
||
value: stationAddr.detail || '',
|
||
placeholder: '街道、门牌号等',
|
||
maxLength: 200,
|
||
onChange: function (e) {
|
||
ctx.updateStation({
|
||
address: { region: stationAddr.region || [], detail: e.target.value }
|
||
});
|
||
},
|
||
onBlur: ctx.syncSupplierFromStation
|
||
})))
|
||
),
|
||
formRow(
|
||
col24(formItem('快速粘贴地址', false, React.createElement(AddressPasteInput, {
|
||
inputClassName: inputCls,
|
||
onParsed: function (parsed) {
|
||
ctx.updateStation({ address: { region: parsed.region, detail: parsed.detail } });
|
||
if (ctx.supplierMode === 'new' && parsed.region && parsed.region.length >= 2) {
|
||
ctx.updateSupplier({
|
||
city: parsed.region.slice(),
|
||
address: parsed.detail || '',
|
||
region: h2GetRegionByProvince(parsed.region[0])
|
||
});
|
||
}
|
||
}
|
||
})))
|
||
),
|
||
formRow(
|
||
col12(formItem('联系人', true, React.createElement(Input, {
|
||
className: inputCls,
|
||
value: ctx.station.contact,
|
||
placeholder: '请输入联系人',
|
||
onChange: function (e) { ctx.updateStation({ contact: e.target.value }); },
|
||
onBlur: ctx.syncSupplierFromStation
|
||
}))),
|
||
col12(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
|
||
})))
|
||
),
|
||
formRow(
|
||
col24(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
|
||
? formRow(
|
||
col12(formItem('签约时间', true, renderContractDates())),
|
||
col12(formItem('合同附件', false, React.createElement('div', { className: 'h2-contract-panel' },
|
||
React.createElement(ContractFilesUpload, {
|
||
fileList: ctx.station.contractFiles,
|
||
onChange: function (info) { ctx.updateStation({ contractFiles: info.fileList }); }
|
||
})
|
||
)))
|
||
)
|
||
: null
|
||
)
|
||
),
|
||
|
||
React.createElement(Card, {
|
||
className: 'h2-create-card',
|
||
id: 'h2-create-supplier-card',
|
||
title: cardTitle('供应商相关信息', H2_ICONS.truck),
|
||
bordered: false
|
||
},
|
||
gridBlock(
|
||
formRow(
|
||
col24(formItem('关联方式', false, React.createElement('div', { className: 'h2-supplier-mode-picker-row' },
|
||
supplierModeCard('link', H2_ICONS.link, '关联已有供应商', '从档案中搜索并绑定'),
|
||
supplierModeCard('new', H2_ICONS.plus, '新增供应商', '填写证照与开票信息')
|
||
)))
|
||
),
|
||
ctx.supplierMode === 'link'
|
||
? formRow(
|
||
col16(formItem('选择供应商', true, React.createElement(Select, {
|
||
className: inputCls,
|
||
showSearch: true,
|
||
placeholder: '请搜索并选择供应商',
|
||
value: ctx.linkedSupplierId,
|
||
options: supplierOptions,
|
||
optionFilterProp: 'label',
|
||
onChange: ctx.handleLinkSupplierChange,
|
||
dropdownStyle: { borderRadius: 8 }
|
||
})))
|
||
)
|
||
: null,
|
||
ctx.supplierMode === 'new'
|
||
? React.createElement(React.Fragment, null,
|
||
gridSubsection('主体信息'),
|
||
formRow(
|
||
col24(formItem('供应商名称', true, React.createElement(Input, {
|
||
className: inputCls,
|
||
value: ctx.supplier.name,
|
||
placeholder: '请输入供应商名称',
|
||
onChange: function (e) { ctx.updateSupplier({ name: e.target.value }); }
|
||
})))
|
||
),
|
||
formRow(
|
||
col12(formItem('省 / 市', false, React.createElement(Cascader, {
|
||
className: inputCls,
|
||
options: H2_REGION_CASCADER_OPTIONS,
|
||
value: ctx.supplier.city && ctx.supplier.city.length ? ctx.supplier.city : undefined,
|
||
onChange: ctx.handleSupplierCityChange,
|
||
placeholder: '请选择省 / 市',
|
||
allowClear: true
|
||
}))),
|
||
col12(formItem('所属区域', false, React.createElement(Input, {
|
||
className: inputCls,
|
||
value: ctx.supplier.region,
|
||
disabled: true,
|
||
placeholder: '根据省市自动关联'
|
||
})))
|
||
),
|
||
formRow(
|
||
col24(formItem('详细地址', false, React.createElement(Input, {
|
||
className: inputCls,
|
||
value: ctx.supplier.address,
|
||
placeholder: '街道、门牌号等',
|
||
maxLength: 200,
|
||
onChange: function (e) { ctx.updateSupplier({ address: e.target.value }); }
|
||
})))
|
||
),
|
||
formRow(
|
||
col24(formItem('快速粘贴地址', false, React.createElement(AddressPasteInput, {
|
||
inputClassName: inputCls,
|
||
onParsed: function (parsed) {
|
||
ctx.updateSupplier({
|
||
city: parsed.region,
|
||
address: parsed.detail,
|
||
region: parsed.region && parsed.region[0] ? h2GetRegionByProvince(parsed.region[0]) : ''
|
||
});
|
||
}
|
||
})))
|
||
),
|
||
gridSubsection('开票信息'),
|
||
formRow(
|
||
col8(formItem('纳税人识别号', false, React.createElement(Input, {
|
||
className: inputCls,
|
||
value: ctx.supplier.taxId,
|
||
placeholder: '请输入纳税人识别号',
|
||
onChange: function (e) { ctx.updateSupplier({ taxId: e.target.value }); }
|
||
}))),
|
||
col8(formItem('注册电话', false, React.createElement(Input, {
|
||
className: inputCls,
|
||
value: ctx.supplier.invoicePhone,
|
||
placeholder: '手机号或固定电话',
|
||
type: 'tel',
|
||
onChange: function (e) { ctx.updateSupplier({ invoicePhone: e.target.value }); }
|
||
}))),
|
||
col8(formItem('注册地址', false, React.createElement(Input, {
|
||
className: inputCls,
|
||
value: ctx.supplier.invoiceAddress,
|
||
placeholder: '请输入注册地址',
|
||
onChange: function (e) { ctx.updateSupplier({ invoiceAddress: e.target.value }); }
|
||
})))
|
||
),
|
||
gridSubsection('银行账户'),
|
||
formRow(
|
||
col8(formItem('开户行', false, React.createElement(Input, {
|
||
className: inputCls,
|
||
value: ctx.supplier.bankName,
|
||
placeholder: '请输入开户行',
|
||
onChange: function (e) { ctx.updateSupplier({ bankName: e.target.value }); }
|
||
}))),
|
||
col8(formItem('银行账号', false, React.createElement(Input, {
|
||
className: inputCls,
|
||
value: ctx.supplier.bankAccount,
|
||
placeholder: '请输入银行账号',
|
||
onChange: function (e) { ctx.updateSupplier({ bankAccount: e.target.value }); }
|
||
}))),
|
||
col8(formItem('营业地址', false, React.createElement(Input, {
|
||
className: inputCls,
|
||
value: ctx.supplier.businessAddress,
|
||
placeholder: '请输入营业地址',
|
||
onChange: function (e) { ctx.updateSupplier({ businessAddress: e.target.value }); }
|
||
})))
|
||
),
|
||
gridSubsection('资质证照'),
|
||
formRow(
|
||
col12(formItem('营业执照', true, uploadDragger(
|
||
ctx.supplier.businessLicenseFiles,
|
||
function (info) { ctx.updateSupplier({ businessLicenseFiles: info.fileList }); },
|
||
'点击或拖拽上传',
|
||
'支持 PDF、图片',
|
||
false
|
||
))),
|
||
col12(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,
|
||
style: { borderRadius: 8 },
|
||
'aria-label': '取消并返回列表'
|
||
}, '取消'),
|
||
React.createElement(Button, {
|
||
onClick: ctx.onReset,
|
||
disabled: ctx.submitting,
|
||
style: { borderRadius: 8 },
|
||
'aria-label': '重置表单'
|
||
}, '重置'),
|
||
React.createElement(Button, {
|
||
type: 'primary',
|
||
style: H2_PRIMARY_BTN_STYLE,
|
||
onClick: ctx.onSubmit,
|
||
loading: ctx.submitting,
|
||
'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
|
||
}, node);
|
||
};
|
||
|
||
var drawerSection = function (children) {
|
||
return React.createElement('div', { className: 'h2-drawer-section' }, 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(Cascader, {
|
||
options: H2_REGION_CASCADER_OPTIONS,
|
||
value: form.address && form.address.region && form.address.region.length ? form.address.region : undefined,
|
||
disabled: readOnly,
|
||
placeholder: '请选择省 / 市',
|
||
style: { width: '100%', borderRadius: 8 },
|
||
allowClear: !readOnly,
|
||
onChange: function (v) {
|
||
setForm(function (f) {
|
||
return Object.assign({}, f, {
|
||
address: { region: v || [], detail: (f.address && f.address.detail) || '' }
|
||
});
|
||
});
|
||
}
|
||
})),
|
||
formItem('详细地址', true, React.createElement(Input, {
|
||
value: (form.address && form.address.detail) || '',
|
||
disabled: readOnly,
|
||
placeholder: '街道、门牌号等',
|
||
maxLength: 200,
|
||
style: { borderRadius: 8 },
|
||
onChange: function (e) {
|
||
setForm(function (f) {
|
||
return Object.assign({}, f, {
|
||
address: { region: (f.address && f.address.region) || [], detail: e.target.value }
|
||
});
|
||
});
|
||
}
|
||
})),
|
||
readOnly ? null : formItem('快速粘贴', false, React.createElement(AddressPasteInput, {
|
||
onParsed: function (parsed) {
|
||
setForm(function (f) {
|
||
return Object.assign({}, f, { address: { region: parsed.region, detail: parsed.detail } });
|
||
});
|
||
}
|
||
})),
|
||
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, null),
|
||
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, null),
|
||
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;
|