feat: 毛菜加工任务新增弹窗 + 调料位置设置交互优化
- 毛菜加工秤:新增毛菜加工任务弹窗(上游任务选择+食材复选表格),提交后直接入已完成分页 - 毛菜加工秤:所有重量统一为 g 单位,复选食材自动反显重量 - 调料位置设置:格子状态三态(未分配/已分配未称重黄色/已称重绿色),大格子参与一键分配 - 调料位置设置:今日需求 Chip 三态同步、超16个折叠展开 - 调料位置设置:去掉弹窗重量输入行,重量由硬件反显 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
6dd8e3e03a
commit
dbdc1891e1
@@ -13,196 +13,272 @@
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
/* PAD 设备外壳 */
|
||||
.device-frame {
|
||||
width: 720px; height: 960px;
|
||||
background: #0e1326;
|
||||
border-radius: 24px;
|
||||
width: 720px; height: 960px; background: #0b1020;
|
||||
border-radius: 24px; overflow: hidden;
|
||||
box-shadow: 0 24px 64px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.04);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: flex; flex-direction: column;
|
||||
}
|
||||
/* 顶部栏 */
|
||||
.top-bar { display: flex; align-items: center; height: 44px; background: #1a2b4a; padding: 0 20px; }
|
||||
.back-btn { font-size: 14px; cursor: pointer; color: rgba(255,255,255,0.7); text-decoration: none; transition: color 0.2s; }
|
||||
.back-btn:hover { color: #fff; }
|
||||
.top-bar__title { flex: 1; text-align: center; font-size: 15px; font-weight: 600; color: rgba(255,255,255,0.85); }
|
||||
.top-bar__user { font-size: 12px; color: rgba(255,255,255,0.5); }
|
||||
|
||||
/* 主内容 */
|
||||
.main-content { flex: 1; padding: 20px 40px; display: flex; flex-direction: column; gap: 16px; overflow: hidden; }
|
||||
/* ===== 顶栏 ===== */
|
||||
.top-bar {
|
||||
display: flex; align-items: center; height: 52px;
|
||||
background: linear-gradient(180deg, #111d38 0%, #0e182c 100%);
|
||||
padding: 0 20px; gap: 14px;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.04);
|
||||
}
|
||||
.top-bar__back {
|
||||
font-size: 14px; color: rgba(255,255,255,0.55); cursor: pointer;
|
||||
text-decoration: none; transition: color 0.2s; flex-shrink: 0;
|
||||
}
|
||||
.top-bar__back:hover { color: #fff; }
|
||||
.top-bar__title {
|
||||
font-size: 15px; font-weight: 700; color: rgba(255,255,255,0.9);
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.top-bar__spacer { flex: 1; }
|
||||
.top-bar__btn {
|
||||
padding: 5px 14px; border-radius: 6px; font-size: 12px; font-weight: 600;
|
||||
cursor: pointer; border: none; font-family: inherit; transition: all 0.2s;
|
||||
}
|
||||
.top-bar__btn--reset {
|
||||
background: rgba(255,255,255,0.05); color: rgba(255,255,255,0.5);
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
}
|
||||
.top-bar__btn--reset:hover { background: rgba(255,255,255,0.1); color: #fff; }
|
||||
.top-bar__btn--save {
|
||||
background: #4a90d9; color: #fff;
|
||||
}
|
||||
.top-bar__btn--save:hover { background: #5ba0e9; }
|
||||
.top-bar__btn--auto {
|
||||
background: rgba(250,173,21,0.12); color: #faad14;
|
||||
border: 1px solid rgba(250,173,21,0.2);
|
||||
}
|
||||
.top-bar__btn--auto:hover { background: rgba(250,173,21,0.22); }
|
||||
.top-bar__btn:active { transform: scale(0.96); }
|
||||
.top-bar__user {
|
||||
font-size: 11px; color: rgba(255,255,255,0.35);
|
||||
margin-left: 4px; flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 说明栏 */
|
||||
.info-bar {
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
background: rgba(74,144,217,0.08); border: 1px solid rgba(74,144,217,0.2);
|
||||
border-radius: 10px; padding: 10px 16px; font-size: 12px; color: rgba(255,255,255,0.6);
|
||||
/* ===== 主内容 ===== */
|
||||
.main-content {
|
||||
flex: 1; padding: 12px 36px 16px;
|
||||
display: flex; flex-direction: column; gap: 8px; overflow: hidden;
|
||||
}
|
||||
.info-bar__icon { font-size: 16px; }
|
||||
.info-bar__text { flex: 1; line-height: 1.5; }
|
||||
.info-bar__save-btn {
|
||||
padding: 6px 16px; border-radius: 6px; border: none; cursor: pointer;
|
||||
background: #4a90d9; color: #fff; font-size: 13px; font-weight: 600;
|
||||
transition: all 0.2s; flex-shrink: 0;
|
||||
}
|
||||
.info-bar__save-btn:hover { background: #5ba0e9; }
|
||||
.info-bar__save-btn:active { transform: scale(0.97); }
|
||||
.info-bar__reset-btn {
|
||||
padding: 6px 14px; border-radius: 6px; cursor: pointer;
|
||||
background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.6);
|
||||
border: 1px solid rgba(255,255,255,0.12); font-size: 13px; transition: all 0.2s; flex-shrink: 0;
|
||||
}
|
||||
.info-bar__reset-btn:hover { background: rgba(255,255,255,0.1); color: #fff; }
|
||||
|
||||
/* 调料秤网格 */
|
||||
/* ===== 提示条 ===== */
|
||||
.hint-bar {
|
||||
font-size: 11px; color: rgba(255,255,255,0.28);
|
||||
padding: 0 2px; line-height: 1;
|
||||
}
|
||||
|
||||
/* ===== 需求 Chip 条 ===== */
|
||||
.demand-strip {
|
||||
display: flex; align-items: flex-start; gap: 8px;
|
||||
padding: 8px 12px; border-radius: 10px;
|
||||
background: rgba(250,173,21,0.03); border: 1px solid rgba(250,173,21,0.07);
|
||||
}
|
||||
.demand-strip__label {
|
||||
font-size: 11px; font-weight: 600; color: #faad14;
|
||||
flex-shrink: 0; padding-top: 3px; white-space: nowrap;
|
||||
}
|
||||
.demand-strip__chips {
|
||||
display: flex; flex-wrap: wrap; gap: 5px; flex: 1;
|
||||
}
|
||||
.demand-chip {
|
||||
display: inline-flex; align-items: center; gap: 4px;
|
||||
padding: 3px 9px; border-radius: 14px;
|
||||
font-size: 11px; font-weight: 600;
|
||||
background: rgba(255,255,255,0.04); color: rgba(255,255,255,0.65);
|
||||
border: 1px solid rgba(255,255,255,0.06);
|
||||
transition: all 0.25s; white-space: nowrap;
|
||||
}
|
||||
.demand-chip__name { color: rgba(255,255,255,0.8); }
|
||||
.demand-chip__qty { color: rgba(255,255,255,0.4); font-weight: 500; }
|
||||
.demand-chip__status {
|
||||
font-size: 10px; margin-left: 2px;
|
||||
}
|
||||
.demand-chip__status--pending { color: rgba(255,255,255,0.25); }
|
||||
.demand-chip__status--done { color: #52c41a; }
|
||||
.demand-chip--placed {
|
||||
opacity: 0.45; border-color: rgba(82,196,26,0.2);
|
||||
}
|
||||
.demand-chip--warning {
|
||||
border-color: rgba(250,173,21,0.3); background: rgba(250,173,21,0.04);
|
||||
}
|
||||
.demand-chip__status--warning { color: #faad14; }
|
||||
.demand-chip--toggle {
|
||||
cursor: pointer; color: #4a90d9; border-color: rgba(74,144,217,0.25);
|
||||
background: rgba(74,144,217,0.06); font-weight: 500;
|
||||
}
|
||||
.demand-chip--toggle:hover {
|
||||
background: rgba(74,144,217,0.14); border-color: rgba(74,144,217,0.45);
|
||||
}
|
||||
|
||||
/* ===== 网格容器 ===== */
|
||||
.grid-container {
|
||||
flex: 1; display: flex; align-items: center; justify-content: center;
|
||||
flex: 1; display: flex; align-items: flex-start; justify-content: center;
|
||||
}
|
||||
.seasoning-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
grid-template-rows: repeat(3, 100px);
|
||||
gap: 5px;
|
||||
gap: 8px; width: 100%;
|
||||
}
|
||||
/* 调料格基类 */
|
||||
|
||||
/* ===== 单元格基类 ===== */
|
||||
.seasoning-cell {
|
||||
background: #1a2b4a; border: 1px solid rgba(255,255,255,0.06);
|
||||
border-radius: 8px; padding: 4px 6px;
|
||||
aspect-ratio: 1;
|
||||
background: rgba(255,255,255,0.02);
|
||||
border: 1px solid rgba(255,255,255,0.05);
|
||||
border-radius: 12px; padding: 10px 12px;
|
||||
display: flex; flex-direction: column; justify-content: center;
|
||||
font-size: 10px; color: rgba(255,255,255,0.5);
|
||||
transition: all 0.2s; position: relative;
|
||||
}
|
||||
/* 信息格:位置0(油),2列×2行大格 */
|
||||
|
||||
/* 信息格:油 (0) — 2×2 */
|
||||
.seasoning-cell--info {
|
||||
grid-column: 1 / span 2; grid-row: 1 / span 2;
|
||||
background: rgba(250,173,21,0.08); border: 2px solid rgba(250,173,21,0.3);
|
||||
padding: 8px 10px; gap: 4px; cursor: pointer;
|
||||
background: linear-gradient(135deg, rgba(250,173,21,0.07) 0%, rgba(250,173,21,0.02) 100%);
|
||||
border: 2px solid rgba(250,173,21,0.25); cursor: pointer; padding: 14px 16px; gap: 8px;
|
||||
}
|
||||
.seasoning-cell--info:hover { border-color: rgba(250,173,21,0.5); background: rgba(250,173,21,0.12); }
|
||||
.seasoning-cell--info .sea-name {
|
||||
font-size: 18px; font-weight: 700; color: #faad14; line-height: 1.2;
|
||||
display: flex; align-items: center; gap: 4px; margin-bottom: 6px;
|
||||
.seasoning-cell--info:hover {
|
||||
border-color: rgba(250,173,21,0.45);
|
||||
background: linear-gradient(135deg, rgba(250,173,21,0.1) 0%, rgba(250,173,21,0.03) 100%);
|
||||
}
|
||||
.seasoning-cell--info .sea-name-icon { font-size: 22px; }
|
||||
.seasoning-cell--info .sea-fields {
|
||||
display: grid; grid-template-columns: 1fr 1fr; gap: 4px 12px;
|
||||
.seasoning-cell--info .sc-name {
|
||||
font-size: 22px; font-weight: 700; color: #faad14;
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
}
|
||||
.seasoning-cell--info .sea-field {
|
||||
display: flex; align-items: center; gap: 4px; font-size: 14px;
|
||||
.seasoning-cell--info .sc-name em { font-style: normal; font-size: 26px; }
|
||||
.seasoning-cell--info .sc-meta {
|
||||
display: flex; gap: 24px; font-size: 15px;
|
||||
}
|
||||
.seasoning-cell--info .sea-field__label { color: rgba(255,255,255,0.35); }
|
||||
.seasoning-cell--info .sea-field__value { color: rgba(255,255,255,0.75); font-weight: 500; }
|
||||
/* 调料格(位置1-11) */
|
||||
.seasoning-cell--slot { cursor: pointer; }
|
||||
.seasoning-cell--slot:hover { border-color: rgba(74,144,217,0.3); background: rgba(74,144,217,0.06); }
|
||||
.seasoning-cell--occupied { border-color: rgba(255,255,255,0.12); }
|
||||
.sea-slot__name {
|
||||
font-size: 14px; font-weight: 600; color: rgba(255,255,255,0.85);
|
||||
line-height: 1.2; display: flex; align-items: center; gap: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.sea-slot__name-icon { font-size: 16px; }
|
||||
.sea-slot__fields {
|
||||
display: grid; grid-template-columns: 1fr 1fr; gap: 2px 8px;
|
||||
}
|
||||
.sea-slot__field {
|
||||
display: flex; gap: 3px; font-size: 11px; line-height: 1.4;
|
||||
}
|
||||
.sea-slot__field-label { color: rgba(255,255,255,0.35); }
|
||||
.sea-slot__field-value { color: rgba(255,255,255,0.65); font-weight: 500; }
|
||||
.sea-slot__empty { font-size: 11px; color: rgba(255,255,255,0.2); text-align: center; }
|
||||
.seasoning-cell--info .sc-meta span { color: rgba(255,255,255,0.5); }
|
||||
.seasoning-cell--info .sc-meta strong { color: rgba(255,255,255,0.8); font-weight: 600; }
|
||||
|
||||
/* 下拉选择浮层 */
|
||||
/* 调料格 (1-11) */
|
||||
.seasoning-cell--slot { cursor: pointer; }
|
||||
.seasoning-cell--slot:hover {
|
||||
border-color: rgba(74,144,217,0.25); background: rgba(74,144,217,0.04);
|
||||
}
|
||||
.seasoning-cell--occupied {
|
||||
border-color: rgba(255,255,255,0.1); background: rgba(255,255,255,0.03);
|
||||
}
|
||||
.sc-name {
|
||||
font-size: 16px; font-weight: 600; color: rgba(255,255,255,0.85);
|
||||
display: flex; align-items: center; gap: 6px; margin-bottom: 5px;
|
||||
}
|
||||
.sc-name em { font-style: normal; font-size: 18px; }
|
||||
.sc-weight {
|
||||
font-size: 13px; color: rgba(255,255,255,0.4); font-weight: 500;
|
||||
}
|
||||
|
||||
/* 格子状态标识 */
|
||||
.seasoning-cell--warning {
|
||||
border-color: rgba(250,173,21,0.4) !important;
|
||||
background: rgba(250,173,21,0.04) !important;
|
||||
}
|
||||
.seasoning-cell--warning .sc-weight { color: #faad14; }
|
||||
.seasoning-cell--success {
|
||||
border-color: rgba(82,196,26,0.3) !important;
|
||||
background: rgba(82,196,26,0.03) !important;
|
||||
}
|
||||
.seasoning-cell--success .sc-weight { color: #52c41a; }
|
||||
/* 信息格(油)的成功/警告状态 */
|
||||
.seasoning-cell--info.seasoning-cell--warning {
|
||||
border-color: rgba(250,173,21,0.45) !important;
|
||||
}
|
||||
.seasoning-cell--info.seasoning-cell--success {
|
||||
border-color: rgba(82,196,26,0.35) !important;
|
||||
}
|
||||
.sc-empty {
|
||||
text-align: center; color: rgba(255,255,255,0.12);
|
||||
}
|
||||
.sc-empty__icon { font-size: 22px; margin-bottom: 2px; }
|
||||
.sc-empty__text { font-size: 10px; }
|
||||
|
||||
/* ===== 选择浮层 ===== */
|
||||
.select-overlay {
|
||||
position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 100;
|
||||
display: none; align-items: center; justify-content: center;
|
||||
position: fixed; inset: 0; background: rgba(0,0,0,0.55);
|
||||
z-index: 100; display: none; align-items: center; justify-content: center;
|
||||
}
|
||||
.select-overlay.show { display: flex; }
|
||||
.select-panel {
|
||||
background: #1a2b4a; border-radius: 14px; border: 1px solid rgba(255,255,255,0.08);
|
||||
padding: 20px 24px; width: 420px; display: flex; flex-direction: column; gap: 14px;
|
||||
background: #141f38; border-radius: 16px; border: 1px solid rgba(255,255,255,0.08);
|
||||
padding: 22px 26px; width: 420px; display: flex; flex-direction: column; gap: 14px;
|
||||
box-shadow: 0 20px 48px rgba(0,0,0,0.5);
|
||||
}
|
||||
.select-panel__title {
|
||||
font-size: 14px; font-weight: 600; color: rgba(255,255,255,0.85);
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
font-size: 15px; font-weight: 600; color: rgba(255,255,255,0.85);
|
||||
}
|
||||
.select-panel__pos-tag {
|
||||
font-size: 11px; padding: 2px 8px; border-radius: 4px;
|
||||
background: rgba(74,144,217,0.15); color: #4a90d9; font-weight: 600;
|
||||
}
|
||||
/* 搜索框 */
|
||||
.select-panel__search-wrap { position: relative; flex: 1; }
|
||||
.select-panel__search-row { display: flex; gap: 8px; align-items: flex-start; }
|
||||
.select-panel__btn--reset-inline {
|
||||
padding: 10px 14px; border-radius: 8px; font-size: 13px; font-weight: 600;
|
||||
cursor: pointer; transition: all 0.2s; border: none; font-family: inherit; flex-shrink: 0;
|
||||
background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.5);
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
}
|
||||
.select-panel__btn--reset-inline:hover { background: rgba(255,255,255,0.1); color: #fff; }
|
||||
.select-panel__search-wrap { position: relative; flex: 1; }
|
||||
.select-panel__search-input {
|
||||
width: 100%; padding: 10px 14px; background: #121832;
|
||||
border: 1px solid rgba(255,255,255,0.1); border-radius: 8px;
|
||||
color: #fff; font-size: 14px; outline: none; transition: border-color 0.2s;
|
||||
font-family: inherit;
|
||||
width: 100%; padding: 10px 14px; background: #0d1529;
|
||||
border: 1px solid rgba(255,255,255,0.08); border-radius: 8px;
|
||||
color: #fff; font-size: 14px; outline: none; font-family: inherit;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
.select-panel__search-input:focus { border-color: #4a90d9; }
|
||||
/* 搜索结果列表 */
|
||||
.select-panel__search-results {
|
||||
position: absolute; top: 100%; left: 0; right: 0; z-index: 10;
|
||||
background: #121832; border: 1px solid rgba(255,255,255,0.1);
|
||||
border-radius: 0 0 8px 8px; max-height: 180px; overflow-y: auto;
|
||||
display: none;
|
||||
background: #0d1529; border: 1px solid rgba(255,255,255,0.08);
|
||||
border-radius: 0 0 8px 8px; max-height: 180px; overflow-y: auto; display: none;
|
||||
}
|
||||
.select-panel__search-results.show { display: block; }
|
||||
.select-panel__search-item {
|
||||
padding: 10px 14px; cursor: pointer; font-size: 13px; color: rgba(255,255,255,0.8);
|
||||
transition: background 0.15s; display: flex; align-items: center; gap: 8px;
|
||||
padding: 10px 14px; cursor: pointer; font-size: 13px; color: rgba(255,255,255,0.75);
|
||||
display: flex; align-items: center; gap: 8px; transition: background 0.15s;
|
||||
}
|
||||
.select-panel__search-item:hover { background: rgba(74,144,217,0.12); color: #fff; }
|
||||
.select-panel__search-item--selected { background: rgba(74,144,217,0.18); color: #4a90d9; }
|
||||
.select-panel__search-item--demand { background: rgba(250,173,21,0.05); }
|
||||
.select-panel__search-item--demand:hover { background: rgba(250,173,21,0.12); }
|
||||
.search-item__badge {
|
||||
font-size: 10px; padding: 1px 6px; border-radius: 3px;
|
||||
background: rgba(250,173,21,0.15); color: #faad14;
|
||||
font-weight: 600; margin-left: auto; flex-shrink: 0;
|
||||
}
|
||||
.select-panel__search-divider {
|
||||
padding: 5px 14px; font-size: 10px; color: rgba(255,255,255,0.2);
|
||||
border-top: 1px solid rgba(255,255,255,0.05); pointer-events: none;
|
||||
}
|
||||
.select-panel__search-item:hover { background: rgba(74,144,217,0.15); color: #fff; }
|
||||
.select-panel__search-item--selected { background: rgba(74,144,217,0.2); color: #4a90d9; }
|
||||
.select-panel__search-empty {
|
||||
padding: 16px; text-align: center; font-size: 12px; color: rgba(255,255,255,0.3);
|
||||
display: none;
|
||||
padding: 16px; text-align: center; font-size: 12px; color: rgba(255,255,255,0.25); display: none;
|
||||
}
|
||||
.select-panel__search-empty.show { display: block; }
|
||||
/* 重量输入行 */
|
||||
.select-panel__weight-row { display: flex; align-items: center; gap: 10px; }
|
||||
.select-panel__weight-label { font-size: 13px; color: rgba(255,255,255,0.6); flex-shrink: 0; }
|
||||
.select-panel__weight-input {
|
||||
flex: 1; padding: 10px 14px; background: #121832;
|
||||
border: 1px solid rgba(255,255,255,0.1); border-radius: 8px;
|
||||
color: #fff; font-size: 14px; outline: none; transition: border-color 0.2s;
|
||||
font-family: inherit; -moz-appearance: textfield;
|
||||
.select-panel__btn--reset-inline {
|
||||
padding: 10px 14px; border-radius: 8px; font-size: 13px; font-weight: 600;
|
||||
cursor: pointer; border: none; font-family: inherit; flex-shrink: 0;
|
||||
background: rgba(255,255,255,0.04); color: rgba(255,255,255,0.4);
|
||||
border: 1px solid rgba(255,255,255,0.08); transition: all 0.2s;
|
||||
}
|
||||
.select-panel__weight-input:focus { border-color: #faad14; }
|
||||
.select-panel__weight-input::-webkit-outer-spin-button,
|
||||
.select-panel__weight-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
|
||||
.select-panel__weight-unit { font-size: 13px; color: rgba(255,255,255,0.4); }
|
||||
.select-panel__btn--reset-inline:hover { background: rgba(255,255,255,0.08); color: #fff; }
|
||||
|
||||
.select-panel__actions { display: flex; gap: 10px; }
|
||||
.select-panel__btn {
|
||||
flex: 1; padding: 10px 0; border-radius: 8px; font-size: 13px; font-weight: 600;
|
||||
cursor: pointer; transition: all 0.2s; border: none; font-family: inherit;
|
||||
cursor: pointer; border: none; font-family: inherit; transition: all 0.2s;
|
||||
}
|
||||
.select-panel__btn--clear {
|
||||
background: rgba(255,77,79,0.08); color: rgba(255,77,79,0.7);
|
||||
border: 1px solid rgba(255,77,79,0.2);
|
||||
background: rgba(255,77,79,0.06); color: rgba(255,77,79,0.6);
|
||||
border: 1px solid rgba(255,77,79,0.15);
|
||||
}
|
||||
.select-panel__btn--clear:hover { background: rgba(255,77,79,0.18); color: #ff4d4f; }
|
||||
.select-panel__btn--clear:hover { background: rgba(255,77,79,0.15); color: #ff4d4f; }
|
||||
.select-panel__btn--cancel {
|
||||
background: rgba(255,255,255,0.08); color: rgba(255,255,255,0.6);
|
||||
background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.5);
|
||||
}
|
||||
.select-panel__btn--cancel:hover { background: rgba(255,255,255,0.12); color: #fff; }
|
||||
.select-panel__btn--cancel:hover { background: rgba(255,255,255,0.1); color: #fff; }
|
||||
.select-panel__btn--confirm {
|
||||
background: #4a90d9; color: #fff;
|
||||
}
|
||||
.select-panel__btn--confirm:hover { background: #5ba0e9; }
|
||||
|
||||
/* Toast */
|
||||
/* ===== Toast ===== */
|
||||
.toast {
|
||||
position: fixed; top: 60px; left: 50%; transform: translateX(-50%) translateY(-20px);
|
||||
background: rgba(0,0,0,0.85); color: #fff; padding: 12px 28px; border-radius: 8px;
|
||||
background: rgba(0,0,0,0.9); color: #fff; padding: 12px 28px; border-radius: 8px;
|
||||
font-size: 13px; z-index: 1000; opacity: 0; visibility: hidden;
|
||||
transition: opacity 0.3s, transform 0.3s, visibility 0.3s;
|
||||
white-space: nowrap; pointer-events: none;
|
||||
@@ -214,31 +290,35 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="device-frame">
|
||||
<!-- 顶栏 -->
|
||||
<div class="top-bar">
|
||||
<a class="back-btn" id="backBtn" href="javascript:void(0)">◀ 返回</a>
|
||||
<a class="top-bar__back" id="backBtn" href="javascript:void(0)">◀ 返回</a>
|
||||
<span class="top-bar__title">调料位置设置</span>
|
||||
<span class="top-bar__spacer"></span>
|
||||
<button class="top-bar__btn top-bar__btn--auto" onclick="autoAssignAll()">一键分配</button>
|
||||
<button class="top-bar__btn top-bar__btn--reset" onclick="resetConfig()">重置</button>
|
||||
<button class="top-bar__btn top-bar__btn--save" onclick="saveConfig()">保存</button>
|
||||
<span class="top-bar__user" id="topUser">--</span>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<!-- 说明栏 -->
|
||||
<div class="info-bar">
|
||||
<span class="info-bar__icon">💡</span>
|
||||
<span class="info-bar__text">点击格子配置调料名称和放置重量。配置完成后点击「保存」生效。</span>
|
||||
<button class="info-bar__reset-btn" onclick="resetConfig()">重置</button>
|
||||
<button class="info-bar__save-btn" onclick="saveConfig()">保存</button>
|
||||
<!-- 提示条 -->
|
||||
<div class="hint-bar">点击格子配置调料名称,重量由硬件自动反显,完成后点击「保存」生效</div>
|
||||
|
||||
<!-- 今日需求 Chip 条 -->
|
||||
<div class="demand-strip" id="demandStrip">
|
||||
<span class="demand-strip__label">📋 今日需求</span>
|
||||
<div class="demand-strip__chips" id="demandChips"></div>
|
||||
</div>
|
||||
|
||||
<!-- 调料秤网格 -->
|
||||
<div class="grid-container">
|
||||
<div class="seasoning-grid" id="seasoningGrid">
|
||||
<!-- 动态渲染 -->
|
||||
</div>
|
||||
<div class="seasoning-grid" id="seasoningGrid"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 下拉选择浮层 -->
|
||||
<!-- 选择浮层 -->
|
||||
<div class="select-overlay" id="selectOverlay">
|
||||
<div class="select-panel">
|
||||
<div class="select-panel__title" id="selectTitle">选择调料</div>
|
||||
@@ -248,12 +328,7 @@
|
||||
<div class="select-panel__search-results" id="searchResults"></div>
|
||||
<div class="select-panel__search-empty" id="searchEmpty">无匹配调料</div>
|
||||
</div>
|
||||
<button class="select-panel__btn--reset-inline" id="resetInlineBtn" onclick="resetSlot()">重置</button>
|
||||
</div>
|
||||
<div class="select-panel__weight-row">
|
||||
<span class="select-panel__weight-label">放置重量:</span>
|
||||
<input type="number" class="select-panel__weight-input" id="seasoningWeight" min="0" step="0.1" placeholder="0">
|
||||
<span class="select-panel__weight-unit">克</span>
|
||||
<button class="select-panel__btn--reset-inline" onclick="resetSlot()">重置</button>
|
||||
</div>
|
||||
<div class="select-panel__actions">
|
||||
<button class="select-panel__btn select-panel__btn--clear" onclick="clearSlot()">清空</button>
|
||||
@@ -298,19 +373,14 @@
|
||||
{ name: '姜末', icon: '🥜' }
|
||||
];
|
||||
|
||||
/* 存储键名 */
|
||||
var STORAGE_KEY = 'seasoning_position_config_v2';
|
||||
|
||||
/* 当前编辑的位置(0=信息格油,1-11=调料格) */
|
||||
var editingPos = -1;
|
||||
|
||||
/* 加载配置(兼容旧格式 {pos:'name'} → 新格式 {pos:{name,weight}}) */
|
||||
function loadConfig() {
|
||||
var raw = localStorage.getItem(STORAGE_KEY);
|
||||
if (raw) {
|
||||
try { return JSON.parse(raw); } catch(e) {}
|
||||
}
|
||||
/* 默认配置 */
|
||||
return {
|
||||
0: { name: '油', weight: 1000 },
|
||||
1: { name: '盐', weight: 500 },
|
||||
@@ -322,115 +392,104 @@
|
||||
};
|
||||
}
|
||||
|
||||
/* 保存配置 */
|
||||
function saveConfigData(config) {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(config));
|
||||
}
|
||||
|
||||
var config = loadConfig();
|
||||
|
||||
/* 渲染网格(位置0=信息格 2×2,位置1-11=调料格) */
|
||||
/* 渲染网格 */
|
||||
function renderGrid() {
|
||||
var grid = document.getElementById('seasoningGrid');
|
||||
grid.innerHTML = '';
|
||||
|
||||
/* 位置0:信息格(油),2列×2行大格 */
|
||||
/* 位置0:油信息格 2×2 */
|
||||
var infoCell = document.createElement('div');
|
||||
infoCell.className = 'seasoning-cell seasoning-cell--info';
|
||||
var oilCfg = config[0];
|
||||
if (oilCfg && oilCfg.name) {
|
||||
var hasWeight = (oilCfg.weight || 0) > 0;
|
||||
infoCell.classList.add(hasWeight ? 'seasoning-cell--success' : 'seasoning-cell--warning');
|
||||
var opt = SEASONING_OPTIONS.find(function(o) { return o.name === oilCfg.name; });
|
||||
var icon = opt ? opt.icon : '🛢';
|
||||
var weightDisplay = hasWeight ? (oilCfg.weight + 'g') : '0g';
|
||||
infoCell.innerHTML =
|
||||
'<div class="sea-name"><span class="sea-name-icon">' + icon + '</span>' + oilCfg.name + '</div>' +
|
||||
'<div class="sea-fields">' +
|
||||
'<div class="sea-field"><span class="sea-field__value">' + (oilCfg.weight || 0) + 'g</span></div>' +
|
||||
'</div>';
|
||||
'<div class="sc-name"><em>' + icon + '</em>' + oilCfg.name + '</div>' +
|
||||
'<div class="sc-meta"><strong>' + weightDisplay + '</strong></div>';
|
||||
} else {
|
||||
infoCell.innerHTML = '<div class="sea-name" style="color:rgba(255,255,255,0.3)">点击配置</div>';
|
||||
infoCell.innerHTML = '<div class="sc-empty"><div class="sc-empty__icon">+</div><div class="sc-empty__text">点击配置</div></div>';
|
||||
}
|
||||
infoCell.onclick = (function(p) { return function() { openSelect(p); }; })(0);
|
||||
grid.appendChild(infoCell);
|
||||
|
||||
/* 位置1-11:普通调料格 */
|
||||
/* 位置1-11 */
|
||||
for (var pos = 1; pos <= 11; pos++) {
|
||||
var cell = document.createElement('div');
|
||||
cell.className = 'seasoning-cell seasoning-cell--slot';
|
||||
var cfg = config[pos];
|
||||
if (cfg && cfg.name) {
|
||||
cell.classList.add('seasoning-cell--occupied');
|
||||
var hasWeight = (cfg.weight || 0) > 0;
|
||||
cell.classList.add(hasWeight ? 'seasoning-cell--success' : 'seasoning-cell--warning');
|
||||
var opt2 = SEASONING_OPTIONS.find(function(o) { return o.name === cfg.name; });
|
||||
var icon2 = opt2 ? opt2.icon : '🧂';
|
||||
var weightDisplay = hasWeight ? (cfg.weight + 'g') : '0g';
|
||||
cell.innerHTML =
|
||||
'<div class="sea-slot__name"><span class="sea-slot__name-icon">' + icon2 + '</span>' + cfg.name + '</div>' +
|
||||
'<div class="sea-slot__fields">' +
|
||||
'<div class="sea-slot__field"><span class="sea-slot__field-value">' + (cfg.weight || 0) + 'g</span></div>' +
|
||||
'</div>';
|
||||
'<div class="sc-name"><em>' + icon2 + '</em>' + cfg.name + '</div>' +
|
||||
'<div class="sc-weight">' + weightDisplay + '</div>';
|
||||
} else {
|
||||
cell.innerHTML = '<div class="sea-slot__empty">点击配置</div>';
|
||||
cell.innerHTML = '<div class="sc-empty"><div class="sc-empty__icon">+</div><div class="sc-empty__text">点击配置</div></div>';
|
||||
}
|
||||
cell.onclick = (function(p) { return function() { openSelect(p); }; })(pos);
|
||||
grid.appendChild(cell);
|
||||
}
|
||||
}
|
||||
|
||||
/* 打开选择弹窗(所有位置统一体验) */
|
||||
/* 打开选择弹窗(重量由硬件反显,弹窗不设重量输入) */
|
||||
function openSelect(pos) {
|
||||
editingPos = pos;
|
||||
document.getElementById('selectTitle').textContent = '选择调料';
|
||||
|
||||
var searchInput = document.getElementById('seasoningSearch');
|
||||
searchInput.value = config[pos] && config[pos].name ? config[pos].name : '';
|
||||
searchInput.disabled = false;
|
||||
searchInput.style.opacity = '1';
|
||||
renderSearchResults('');
|
||||
|
||||
/* 填充重量 */
|
||||
var weightInput = document.getElementById('seasoningWeight');
|
||||
weightInput.value = (config[pos] && config[pos].weight) ? config[pos].weight : '';
|
||||
|
||||
document.getElementById('selectOverlay').classList.add('show');
|
||||
}
|
||||
|
||||
/* 确认选择 */
|
||||
/* 确认选择(重量由硬件反显,此处仅配置调料名称) */
|
||||
function confirmSelect() {
|
||||
var name = document.getElementById('seasoningSearch').value.trim();
|
||||
var weight = parseFloat(document.getElementById('seasoningWeight').value) || 0;
|
||||
|
||||
if (!name) {
|
||||
showToast('请输入或选择调料名称', 1500, 'error');
|
||||
return;
|
||||
}
|
||||
/* 检查是否在候选清单中 */
|
||||
var found = SEASONING_OPTIONS.find(function(o) { return o.name === name; });
|
||||
if (!found) {
|
||||
showToast('调料"' + name + '"不在候选清单中', 1500, 'error');
|
||||
return;
|
||||
}
|
||||
config[editingPos] = { name: name, weight: weight };
|
||||
/* 保留已有重量或初始化为 0,等待硬件反显 */
|
||||
var oldWeight = (config[editingPos] && config[editingPos].weight) ? config[editingPos].weight : 0;
|
||||
config[editingPos] = { name: name, weight: oldWeight };
|
||||
renderDemandChips();
|
||||
renderGrid();
|
||||
closeSelect();
|
||||
showToast('位置 ' + editingPos + ' 已配置为 ' + name + ' (' + weight + 'g)', 1500, 'success');
|
||||
showToast('位置 ' + editingPos + ' 已配置为 ' + name + ',等待称重', 1500, 'success');
|
||||
}
|
||||
|
||||
/* 清空位置(重量归零,保留调料名称) */
|
||||
/* 清空位置 */
|
||||
function clearSlot() {
|
||||
if (config[editingPos] && config[editingPos].name) {
|
||||
config[editingPos].weight = 0;
|
||||
} else {
|
||||
config[editingPos] = { name: '', weight: 0 };
|
||||
}
|
||||
document.getElementById('seasoningWeight').value = '0';
|
||||
config[editingPos] = { name: '', weight: 0 };
|
||||
document.getElementById('seasoningSearch').value = '';
|
||||
renderGrid();
|
||||
showToast('位置 ' + editingPos + ' 重量已清零', 1500, 'success');
|
||||
renderDemandChips();
|
||||
showToast('位置 ' + editingPos + ' 已清空', 1500, 'success');
|
||||
}
|
||||
|
||||
/* 重置调料选择(清除搜索框,清空重量输入) */
|
||||
/* 重置选择 */
|
||||
function resetSlot() {
|
||||
var searchInput = document.getElementById('seasoningSearch');
|
||||
var weightInput = document.getElementById('seasoningWeight');
|
||||
searchInput.value = '';
|
||||
weightInput.value = '';
|
||||
document.getElementById('seasoningSearch').value = '';
|
||||
document.getElementById('searchResults').classList.remove('show');
|
||||
document.getElementById('searchEmpty').classList.remove('show');
|
||||
showToast('位置 ' + editingPos + ' 调料选择已清除', 1500, 'success');
|
||||
@@ -444,46 +503,7 @@
|
||||
document.getElementById('searchEmpty').classList.remove('show');
|
||||
}
|
||||
|
||||
/* 渲染搜索结果列表 */
|
||||
function renderSearchResults(query) {
|
||||
var resultsEl = document.getElementById('searchResults');
|
||||
var emptyEl = document.getElementById('searchEmpty');
|
||||
resultsEl.innerHTML = '';
|
||||
resultsEl.classList.remove('show');
|
||||
emptyEl.classList.remove('show');
|
||||
|
||||
var filtered = SEASONING_OPTIONS;
|
||||
if (query) {
|
||||
var q = query.toLowerCase();
|
||||
filtered = SEASONING_OPTIONS.filter(function(o) {
|
||||
return o.name.toLowerCase().indexOf(q) >= 0;
|
||||
});
|
||||
}
|
||||
|
||||
if (filtered.length === 0) {
|
||||
emptyEl.classList.add('show');
|
||||
return;
|
||||
}
|
||||
|
||||
filtered.forEach(function(o) {
|
||||
var item = document.createElement('div');
|
||||
item.className = 'select-panel__search-item';
|
||||
var currentName = document.getElementById('seasoningSearch').value;
|
||||
if (o.name === currentName) {
|
||||
item.classList.add('select-panel__search-item--selected');
|
||||
}
|
||||
item.innerHTML = o.icon + ' ' + o.name;
|
||||
item.onclick = function() {
|
||||
document.getElementById('seasoningSearch').value = o.name;
|
||||
resultsEl.classList.remove('show');
|
||||
emptyEl.classList.remove('show');
|
||||
};
|
||||
resultsEl.appendChild(item);
|
||||
});
|
||||
resultsEl.classList.add('show');
|
||||
}
|
||||
|
||||
/* 保存配置 */
|
||||
/* 保存 */
|
||||
function saveConfig() {
|
||||
saveConfigData(config);
|
||||
showToast('调料位置配置已保存', 2000, 'success');
|
||||
@@ -495,6 +515,7 @@
|
||||
config = {};
|
||||
saveConfigData(config);
|
||||
renderGrid();
|
||||
renderDemandChips();
|
||||
showToast('配置已重置', 1500, 'success');
|
||||
}
|
||||
|
||||
@@ -524,15 +545,13 @@
|
||||
}
|
||||
})();
|
||||
|
||||
/* 搜索框输入事件 */
|
||||
/* 搜索框事件 */
|
||||
document.getElementById('seasoningSearch').addEventListener('input', function() {
|
||||
renderSearchResults(this.value);
|
||||
});
|
||||
/* 点击搜索框时显示全部候选 */
|
||||
document.getElementById('seasoningSearch').addEventListener('focus', function() {
|
||||
renderSearchResults(this.value);
|
||||
});
|
||||
/* 点击空白处关闭搜索结果 */
|
||||
document.addEventListener('click', function(e) {
|
||||
var wrap = document.querySelector('.select-panel__search-wrap');
|
||||
if (wrap && !wrap.contains(e.target)) {
|
||||
@@ -541,8 +560,194 @@
|
||||
}
|
||||
});
|
||||
|
||||
/* ==================== 今日调料需求 ==================== */
|
||||
var MOCK_DEMAND = [
|
||||
{ name: '酱油', qty: 2500 },
|
||||
{ name: '盐', qty: 2000 },
|
||||
{ name: '料酒', qty: 1800 },
|
||||
{ name: '白糖', qty: 1500 },
|
||||
{ name: '醋', qty: 1400 },
|
||||
{ name: '蚝油', qty: 1200 },
|
||||
{ name: '豆瓣酱', qty: 1000 },
|
||||
{ name: '鸡精', qty: 900 },
|
||||
{ name: '味精', qty: 800 },
|
||||
{ name: '蒜蓉', qty: 750 },
|
||||
{ name: '花椒', qty: 700 },
|
||||
{ name: '胡椒粉', qty: 600 },
|
||||
{ name: '甜面酱', qty: 550 },
|
||||
{ name: '干辣椒', qty: 500 },
|
||||
{ name: '桂皮', qty: 400 },
|
||||
{ name: '八角', qty: 350 }
|
||||
];
|
||||
|
||||
/* 查找需求调料在配置中的称重状态: -1=未分配, 0=已分配未称重, >0=已分配且已称重 */
|
||||
function getDemandSlotWeight(name) {
|
||||
for (var pos = 0; pos <= 11; pos++) {
|
||||
if (config[pos] && config[pos].name === name) {
|
||||
return config[pos].weight || 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function isDemandItem(name) {
|
||||
return MOCK_DEMAND.some(function(d) {
|
||||
if (d.name !== name) return false;
|
||||
return getDemandSlotWeight(name) <= 0; /* 未分配 或 已分配但未称重,仍算需求项 */
|
||||
});
|
||||
}
|
||||
|
||||
function getDemandWeight(name) {
|
||||
var found = MOCK_DEMAND.find(function(d) { return d.name === name; });
|
||||
return found ? found.qty : 0;
|
||||
}
|
||||
|
||||
/* 渲染搜索结果 */
|
||||
function renderSearchResults(query) {
|
||||
var resultsEl = document.getElementById('searchResults');
|
||||
var emptyEl = document.getElementById('searchEmpty');
|
||||
resultsEl.innerHTML = '';
|
||||
resultsEl.classList.remove('show');
|
||||
emptyEl.classList.remove('show');
|
||||
|
||||
var filtered = SEASONING_OPTIONS;
|
||||
if (query) {
|
||||
var q = query.toLowerCase();
|
||||
filtered = SEASONING_OPTIONS.filter(function(o) {
|
||||
return o.name.toLowerCase().indexOf(q) >= 0;
|
||||
});
|
||||
}
|
||||
|
||||
if (filtered.length === 0) {
|
||||
emptyEl.classList.add('show');
|
||||
return;
|
||||
}
|
||||
|
||||
var demandItems = filtered.filter(function(o) { return isDemandItem(o.name); });
|
||||
var otherItems = filtered.filter(function(o) { return !isDemandItem(o.name); });
|
||||
var currentName = document.getElementById('seasoningSearch').value.trim();
|
||||
|
||||
demandItems.forEach(function(o) {
|
||||
resultsEl.appendChild(buildSearchItem(o, currentName, true));
|
||||
});
|
||||
|
||||
if (demandItems.length > 0 && otherItems.length > 0) {
|
||||
var divider = document.createElement('div');
|
||||
divider.className = 'select-panel__search-divider';
|
||||
divider.textContent = '其它调料';
|
||||
resultsEl.appendChild(divider);
|
||||
}
|
||||
|
||||
otherItems.forEach(function(o) {
|
||||
resultsEl.appendChild(buildSearchItem(o, currentName, false));
|
||||
});
|
||||
|
||||
resultsEl.classList.add('show');
|
||||
}
|
||||
|
||||
function buildSearchItem(o, currentName, isDemand) {
|
||||
var item = document.createElement('div');
|
||||
item.className = 'select-panel__search-item';
|
||||
if (o.name === currentName) item.classList.add('select-panel__search-item--selected');
|
||||
if (isDemand) item.classList.add('select-panel__search-item--demand');
|
||||
var label = o.icon + ' ' + o.name;
|
||||
if (isDemand) {
|
||||
label += '<span class="search-item__badge">📋 今日需求</span>';
|
||||
}
|
||||
item.innerHTML = label;
|
||||
item.onclick = function() {
|
||||
document.getElementById('seasoningSearch').value = o.name;
|
||||
document.getElementById('searchResults').classList.remove('show');
|
||||
document.getElementById('searchEmpty').classList.remove('show');
|
||||
};
|
||||
return item;
|
||||
}
|
||||
|
||||
/* 折叠展开控制 */
|
||||
var demandExpanded = false;
|
||||
var DEMAND_COLLAPSE_LIMIT = 16;
|
||||
|
||||
function toggleDemandExpand() {
|
||||
demandExpanded = !demandExpanded;
|
||||
renderDemandChips();
|
||||
}
|
||||
|
||||
/* 渲染需求 Chips(三态:未分配 / 已分配未称重 / 已称重,超过16个折叠) */
|
||||
function renderDemandChips() {
|
||||
var container = document.getElementById('demandChips');
|
||||
container.innerHTML = '';
|
||||
|
||||
var total = MOCK_DEMAND.length;
|
||||
var needsCollapse = total > DEMAND_COLLAPSE_LIMIT;
|
||||
var list = (!needsCollapse || demandExpanded) ? MOCK_DEMAND : MOCK_DEMAND.slice(0, DEMAND_COLLAPSE_LIMIT);
|
||||
|
||||
list.forEach(function(d) {
|
||||
var chip = document.createElement('span');
|
||||
chip.className = 'demand-chip';
|
||||
var slotW = getDemandSlotWeight(d.name);
|
||||
|
||||
var statusClass, statusIcon, weightText;
|
||||
if (slotW < 0) {
|
||||
/* 未分配 → 显示需求量 */
|
||||
statusClass = 'demand-chip__status--pending';
|
||||
statusIcon = '○';
|
||||
weightText = d.qty + 'g';
|
||||
} else if (slotW === 0) {
|
||||
/* 已分配但未称重 → 黄色圆点,重量显示为 0 */
|
||||
chip.classList.add('demand-chip--warning');
|
||||
statusClass = 'demand-chip__status--warning';
|
||||
statusIcon = '●';
|
||||
weightText = '0g';
|
||||
} else {
|
||||
/* 已分配且已称重 → 绿色对号,显示实际重量 */
|
||||
chip.classList.add('demand-chip--placed');
|
||||
statusClass = 'demand-chip__status--done';
|
||||
statusIcon = '✓';
|
||||
weightText = slotW + 'g';
|
||||
}
|
||||
|
||||
chip.innerHTML =
|
||||
'<span class="demand-chip__name">' + d.name + '</span>' +
|
||||
'<span class="demand-chip__qty">' + weightText + '</span>' +
|
||||
'<span class="demand-chip__status ' + statusClass + '">' + statusIcon + '</span>';
|
||||
container.appendChild(chip);
|
||||
});
|
||||
|
||||
/* 折叠/展开按钮 */
|
||||
if (needsCollapse) {
|
||||
var toggleChip = document.createElement('span');
|
||||
toggleChip.className = 'demand-chip demand-chip--toggle';
|
||||
toggleChip.textContent = demandExpanded ? '收起 ▲' : '展开全部 (' + total + ')';
|
||||
toggleChip.onclick = toggleDemandExpand;
|
||||
container.appendChild(toggleChip);
|
||||
}
|
||||
}
|
||||
|
||||
/* 一键分配:按需求量降序自动填充空闲格子 */
|
||||
function autoAssignAll() {
|
||||
if (!confirm('确定一键分配?将按需求量从大到小自动填充空闲格子。')) return;
|
||||
var sorted = MOCK_DEMAND.slice().sort(function(a, b) { return b.qty - a.qty; });
|
||||
var slotIndex = 0;
|
||||
var assigned = 0;
|
||||
for (var pos = 0; pos <= 11 && slotIndex < sorted.length; pos++) {
|
||||
if (config[pos] && config[pos].name) continue;
|
||||
var item = sorted[slotIndex];
|
||||
config[pos] = { name: item.name, weight: 0 };
|
||||
slotIndex++;
|
||||
assigned++;
|
||||
}
|
||||
if (assigned === 0) {
|
||||
showToast('没有空闲格子可分配', 2000, 'error');
|
||||
return;
|
||||
}
|
||||
renderGrid();
|
||||
renderDemandChips();
|
||||
showToast('已自动分配 ' + assigned + ' 个调料到空闲格子', 2000, 'success');
|
||||
}
|
||||
|
||||
/* 初始化 */
|
||||
renderGrid();
|
||||
renderDemandChips();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -198,6 +198,15 @@
|
||||
100% { border-color: rgba(255,255,255,0.06); box-shadow: none; background: #1a2b4a; }
|
||||
}
|
||||
|
||||
/* 新增任务按钮 */
|
||||
.add-task-btn {
|
||||
padding: 8px 18px; border-radius: 8px; cursor: pointer;
|
||||
background: #4a90d9; color: #fff; font-size: 13px; font-weight: 600;
|
||||
border: none; transition: all 0.2s; font-family: inherit; flex-shrink: 0;
|
||||
}
|
||||
.add-task-btn:hover { background: #5ba0e9; }
|
||||
.add-task-btn:active { transform: scale(0.96); }
|
||||
|
||||
/* 顶部操作区 */
|
||||
.tabs-spacer { flex: 1; }
|
||||
.logout-btn {
|
||||
@@ -207,6 +216,185 @@
|
||||
}
|
||||
.logout-btn:hover { color: #fff; border-color: rgba(255,255,255,0.3); }
|
||||
|
||||
/* ── 新增任务弹窗 ── */
|
||||
.dialog-overlay {
|
||||
position: fixed; inset: 0; background: rgba(0,0,0,0.55);
|
||||
z-index: 100; display: none; align-items: center; justify-content: center;
|
||||
}
|
||||
.dialog-overlay.show { display: flex; }
|
||||
.dialog-panel {
|
||||
background: #0e1326; border-radius: 14px; border: 1px solid rgba(255,255,255,0.08);
|
||||
padding: 0; width: 900px; height: 560px; display: flex; flex-direction: column; gap: 0;
|
||||
box-shadow: 0 20px 48px rgba(0,0,0,0.5); overflow: hidden;
|
||||
}
|
||||
/* 弹窗顶栏 — 与 top-bar 一致 */
|
||||
.dialog-panel__top {
|
||||
display: flex; align-items: center; height: 44px;
|
||||
background: #1a2b4a; padding: 0 20px; flex-shrink: 0;
|
||||
}
|
||||
.dialog-panel__title {
|
||||
flex: 1; font-size: 15px; font-weight: 600; color: rgba(255,255,255,0.85);
|
||||
}
|
||||
/* 弹窗主内容 — 仿 02 页 main-content 左右分栏 */
|
||||
.dialog-body {
|
||||
flex: 1; padding: 14px 20px; display: flex; gap: 16px; overflow: hidden;
|
||||
}
|
||||
|
||||
/* ===== 左侧:任务号选择 ===== */
|
||||
.dialog-left {
|
||||
flex: 0 0 300px; display: flex; flex-direction: column; gap: 8px; overflow: hidden;
|
||||
}
|
||||
.dialog-section__label {
|
||||
font-size: 11px; color: rgba(255,255,255,0.4); font-weight: 500;
|
||||
}
|
||||
.dialog-task-list {
|
||||
flex: 1; display: flex; flex-direction: column; gap: 6px; overflow-y: auto;
|
||||
scrollbar-width: thin; scrollbar-color: rgba(255,255,255,0.1) transparent;
|
||||
}
|
||||
.dialog-task-list::-webkit-scrollbar { width: 4px; }
|
||||
.dialog-task-list::-webkit-scrollbar-track { background: transparent; }
|
||||
.dialog-task-list::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 2px; }
|
||||
.task-option {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
padding: 10px 12px; border-radius: 8px; cursor: pointer;
|
||||
background: rgba(74,144,217,0.04); border: 1px solid rgba(74,144,217,0.08);
|
||||
transition: all 0.2s; flex-shrink: 0;
|
||||
}
|
||||
.task-option:hover {
|
||||
border-color: rgba(74,144,217,0.25); background: rgba(74,144,217,0.08);
|
||||
}
|
||||
.task-option--selected {
|
||||
border-color: #4a90d9; background: rgba(74,144,217,0.1);
|
||||
}
|
||||
.task-option__radio {
|
||||
width: 16px; height: 16px; border-radius: 50%; flex-shrink: 0;
|
||||
border: 2px solid rgba(255,255,255,0.2);
|
||||
display: flex; align-items: center; justify-content: center; transition: all 0.2s;
|
||||
}
|
||||
.task-option--selected .task-option__radio {
|
||||
border-color: #4a90d9; background: #4a90d9;
|
||||
}
|
||||
.task-option--selected .task-option__radio::after {
|
||||
content: ''; width: 5px; height: 5px; border-radius: 50%; background: #fff;
|
||||
}
|
||||
.task-option__no {
|
||||
font-size: 13px; font-weight: 600; color: rgba(255,255,255,0.85);
|
||||
font-family: "Courier New", monospace;
|
||||
}
|
||||
.task-option__desc {
|
||||
font-size: 11px; color: rgba(255,255,255,0.35); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ===== 右侧:食材表格(仿 batch-panel) ===== */
|
||||
.dialog-right {
|
||||
flex: 1; display: flex; flex-direction: column; gap: 10px; overflow: hidden;
|
||||
}
|
||||
/* 汇总 — 仿 batch-summary */
|
||||
.dialog-summary {
|
||||
background: #1a2b4a; border-radius: 12px; padding: 10px 16px;
|
||||
display: flex; gap: 16px; flex-shrink: 0;
|
||||
}
|
||||
.dialog-stat { flex: 1; text-align: center; }
|
||||
.dialog-stat__value { font-size: 20px; font-weight: 700; color: #fff; }
|
||||
.dialog-stat__label { font-size: 11px; color: rgba(255,255,255,0.5); }
|
||||
|
||||
/* 表格区 — 仿 batch-list-section */
|
||||
.ingredient-table-section {
|
||||
flex: 1; background: #1a2b4a; border-radius: 12px;
|
||||
padding: 12px 16px; display: flex; flex-direction: column; overflow: hidden;
|
||||
}
|
||||
.ingredient-table-section.hide {
|
||||
display: none;
|
||||
}
|
||||
.ingredient-table-header {
|
||||
display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ingredient-table-title { font-size: 14px; font-weight: 600; color: rgba(255,255,255,0.8); }
|
||||
.ingredient-table-count { font-size: 12px; color: rgba(255,255,255,0.4); }
|
||||
/* 表头列 — 仿 batch-list__columns */
|
||||
.ingredient-table-cols {
|
||||
display: flex; align-items: center; padding: 0 12px 6px;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.08); flex-shrink: 0;
|
||||
}
|
||||
.ing-col {
|
||||
font-size: 11px; color: rgba(255,255,255,0.4); white-space: nowrap;
|
||||
}
|
||||
.ing-col--name { flex: 1; }
|
||||
.ing-col--actual { width: 72px; text-align: right; }
|
||||
.ing-col--status { width: 64px; text-align: center; }
|
||||
|
||||
.ingredient-table-list {
|
||||
flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 6px;
|
||||
scrollbar-width: thin; scrollbar-color: rgba(255,255,255,0.1) transparent;
|
||||
}
|
||||
.ingredient-table-list::-webkit-scrollbar { width: 4px; }
|
||||
.ingredient-table-list::-webkit-scrollbar-track { background: transparent; }
|
||||
.ingredient-table-list::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 2px; }
|
||||
|
||||
/* 食材行 — 仿 batch-item */
|
||||
.ing-row {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
padding: 9px 12px; background: rgba(0,0,0,0.15); border-radius: 8px;
|
||||
cursor: pointer; transition: all 0.2s;
|
||||
}
|
||||
.ing-row:hover { background: rgba(0,0,0,0.25); }
|
||||
.ing-row--checked {
|
||||
background: rgba(52,196,26,0.06); border: 1px solid rgba(82,196,26,0.18);
|
||||
}
|
||||
.ing-row__checkbox {
|
||||
width: 16px; height: 16px; border-radius: 3px; flex-shrink: 0;
|
||||
border: 2px solid rgba(255,255,255,0.2);
|
||||
display: flex; align-items: center; justify-content: center; transition: all 0.2s;
|
||||
font-size: 10px; color: transparent;
|
||||
}
|
||||
.ing-row--checked .ing-row__checkbox {
|
||||
border-color: #52c41a; background: #52c41a; color: #fff;
|
||||
}
|
||||
.ing-row__icon {
|
||||
width: 34px; height: 34px; border-radius: 8px; font-size: 18px;
|
||||
display: flex; align-items: center; justify-content: center; flex-shrink: 0;
|
||||
background: rgba(74,144,217,0.15);
|
||||
}
|
||||
.ing-row__icon.icon--potato { background: rgba(250,173,22,0.15); }
|
||||
.ing-row__icon.icon--tomato { background: rgba(255,77,79,0.15); }
|
||||
.ing-row__icon.icon--cabbage { background: rgba(82,196,26,0.15); }
|
||||
.ing-row__icon.icon--carrot { background: rgba(250,140,22,0.15); }
|
||||
.ing-row__icon.icon--cucumber { background: rgba(20,184,166,0.15); }
|
||||
.ing-row__name { flex: 1; font-size: 13px; font-weight: 500; color: #fff; }
|
||||
.ing-row__actual {
|
||||
font-size: 13px; color: rgba(255,255,255,0.25); width: 72px; text-align: right;
|
||||
}
|
||||
.ing-row__status {
|
||||
font-size: 11px; font-weight: 500; width: 64px; text-align: center;
|
||||
}
|
||||
.ing-row__status--pending { color: rgba(255,255,255,0.3); }
|
||||
.ing-row__status--checked { color: #52c41a; }
|
||||
|
||||
/* 弹窗底部 — 仿 submit-bar */
|
||||
.dialog-panel__footer {
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
padding: 10px 20px; background: #1a2b4a; flex-shrink: 0;
|
||||
}
|
||||
.dialog-hint {
|
||||
flex: 1; font-size: 12px; color: rgba(255,255,255,0.4);
|
||||
}
|
||||
.dialog-btn {
|
||||
padding: 10px 28px; border-radius: 8px; font-size: 14px; font-weight: 600;
|
||||
cursor: pointer; border: none; font-family: inherit; transition: all 0.2s;
|
||||
}
|
||||
.dialog-btn--cancel {
|
||||
background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.5);
|
||||
}
|
||||
.dialog-btn--cancel:hover { background: rgba(255,255,255,0.1); color: #fff; }
|
||||
.dialog-btn--confirm {
|
||||
background: #52c41a; color: #fff;
|
||||
}
|
||||
.dialog-btn--confirm:hover { background: #62d42a; }
|
||||
.dialog-btn--confirm:disabled {
|
||||
background: rgba(82,196,26,0.3); cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Toast */
|
||||
.toast {
|
||||
position: fixed; top: 60px; left: 50%; transform: translateX(-50%) translateY(-20px);
|
||||
@@ -222,7 +410,7 @@
|
||||
|
||||
<div class="top-bar">
|
||||
|
||||
<a class="back-btn" id="backBtn" href="javascript:void(0)">◀ 返回</a> <span class="top-bar__title">今日清洗任务</span>
|
||||
<a class="back-btn" id="backBtn" href="javascript:void(0)">◀ 返回</a> <span class="top-bar__title">毛菜加工任务</span>
|
||||
<span class="top-bar__user" id="topUser">--</span>
|
||||
<button class="logout-btn" onclick="handleLogout()">退出登录</button>
|
||||
</div>
|
||||
@@ -239,6 +427,7 @@
|
||||
<span class="status-tab__count" id="doneCount">1</span>
|
||||
</div>
|
||||
<span class="tabs-spacer"></span>
|
||||
<button class="add-task-btn" onclick="openAddTaskDialog()">+ 新增毛菜加工任务</button>
|
||||
</div>
|
||||
|
||||
<!-- 任务列表区 -->
|
||||
@@ -260,22 +449,22 @@
|
||||
<div class="ingredient-row">
|
||||
<div class="ingredient-row__icon icon--cucumber">🥒</div>
|
||||
<span class="ingredient-row__name">黄瓜</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="2000">需 4 斤</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="2000">已录 4 斤</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="2000">需 2000g</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="2000">已录 2000g</span>
|
||||
<span class="ingredient-row__deadline">截止 10:00</span>
|
||||
</div>
|
||||
<div class="ingredient-row">
|
||||
<div class="ingredient-row__icon icon--potato"></div>
|
||||
<span class="ingredient-row__name">土豆</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="2500">需 5 斤</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="2500">已录 5 斤</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="2500">需 2500g</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="2500">已录 2500g</span>
|
||||
<span class="ingredient-row__deadline">截止 10:30</span>
|
||||
</div>
|
||||
<div class="ingredient-row">
|
||||
<div class="ingredient-row__icon icon--tomato">🍅</div>
|
||||
<span class="ingredient-row__name">西红柿</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="1750">需 3.5 斤</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="1750">已录 3.5 斤</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="1750">需 1750g</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="1750">已录 1750g</span>
|
||||
<span class="ingredient-row__deadline">截止 11:00</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -296,15 +485,15 @@
|
||||
<div class="ingredient-row">
|
||||
<div class="ingredient-row__icon icon--carrot"></div>
|
||||
<span class="ingredient-row__name">胡萝卜</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="1000">需 2 斤</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="1000">已录 2 斤</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="1000">需 1000g</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="1000">已录 1000g</span>
|
||||
<span class="ingredient-row__deadline">截止 11:30</span>
|
||||
</div>
|
||||
<div class="ingredient-row">
|
||||
<div class="ingredient-row__icon icon--tomato">🍅</div>
|
||||
<span class="ingredient-row__name">小番茄</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="750">需 1.5 斤</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="750">已录 1.5 斤</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="750">需 750g</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="750">已录 750g</span>
|
||||
<span class="ingredient-row__deadline">截止 14:00</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -324,22 +513,22 @@
|
||||
<div class="ingredient-row">
|
||||
<div class="ingredient-row__icon icon--cabbage">🥬</div>
|
||||
<span class="ingredient-row__name">大白菜</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="4000">需 8 斤</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="4000">已录 8 斤</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="4000">需 4000g</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="4000">已录 4000g</span>
|
||||
<span class="ingredient-row__deadline ingredient-row__deadline--overdue">截止 09:30</span>
|
||||
</div>
|
||||
<div class="ingredient-row">
|
||||
<div class="ingredient-row__icon icon--cabbage">🥬</div>
|
||||
<span class="ingredient-row__name">娃娃菜</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="1250">需 2.5 斤</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="1250">已录 2.5 斤</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="1250">需 1250g</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="1250">已录 1250g</span>
|
||||
<span class="ingredient-row__deadline">截止 10:00</span>
|
||||
</div>
|
||||
<div class="ingredient-row">
|
||||
<div class="ingredient-row__icon icon--potato"></div>
|
||||
<span class="ingredient-row__name">土豆(晚餐)</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="1500">需 3 斤</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="1500">已录 3 斤</span>
|
||||
<span class="ingredient-row__weight" data-weight-g="1500">需 1500g</span>
|
||||
<span class="ingredient-row__recorded" data-weight-g="1500">已录 1500g</span>
|
||||
<span class="ingredient-row__deadline">截止 15:00</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -350,6 +539,67 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 新增任务弹窗 — 仿 02-batch-weighing 左右分栏布局 -->
|
||||
<div class="dialog-overlay" id="addTaskOverlay">
|
||||
<div class="dialog-panel">
|
||||
<!-- 弹窗顶栏 -->
|
||||
<div class="dialog-panel__top">
|
||||
<span class="dialog-panel__title">新增毛菜加工任务</span>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗主体:左右分栏 -->
|
||||
<div class="dialog-body">
|
||||
<!-- 左侧:任务号选择 -->
|
||||
<div class="dialog-left">
|
||||
<div class="dialog-section__label">选择关联任务号</div>
|
||||
<div class="dialog-task-list" id="upstreamTaskList"></div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:食材表格 + 统计 -->
|
||||
<div class="dialog-right" id="dialogRight">
|
||||
<!-- 汇总统计 — 仿 batch-summary -->
|
||||
<div class="dialog-summary">
|
||||
<div class="dialog-stat">
|
||||
<div class="dialog-stat__value" id="footerKindCount">—</div>
|
||||
<div class="dialog-stat__label">品类数</div>
|
||||
</div>
|
||||
<div class="dialog-stat">
|
||||
<div class="dialog-stat__value" id="footerTotalWeight">—</div>
|
||||
<div class="dialog-stat__label">总重量</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 食材表格 — 仿 batch-list-section -->
|
||||
<div class="ingredient-table-section hide" id="ingredientTableSection">
|
||||
<div class="ingredient-table-header">
|
||||
<span class="ingredient-table-title">选择食材</span>
|
||||
<span class="ingredient-table-count" id="ingTableCount">共 0 种,已选 0 种</span>
|
||||
</div>
|
||||
<div class="ingredient-table-cols">
|
||||
<span class="ing-col ing-col--name">食材名称</span>
|
||||
<span class="ing-col ing-col--actual">实取量</span>
|
||||
<span class="ing-col ing-col--status">状态</span>
|
||||
</div>
|
||||
<div class="ingredient-table-list" id="ingredientTableList"></div>
|
||||
</div>
|
||||
|
||||
<!-- 未选择任务号时展示占位 -->
|
||||
<div class="ingredient-table-section" id="ingredientPlaceholder" style="align-items:center;justify-content:center;">
|
||||
<div style="font-size:32px;opacity:0.2;margin-bottom:8px;">📭</div>
|
||||
<div style="font-size:12px;color:rgba(255,255,255,0.25);">请在左侧选择关联任务号</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗底部 — 仿 submit-bar -->
|
||||
<div class="dialog-panel__footer">
|
||||
<span class="dialog-hint" id="dialogHint">请选择任务号并勾选食材后完成生成</span>
|
||||
<button class="dialog-btn dialog-btn--cancel" onclick="closeAddTaskDialog()">取消</button>
|
||||
<button class="dialog-btn dialog-btn--confirm" id="confirmAddBtn" onclick="confirmAddTask()" disabled>完成生成</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
@@ -369,6 +619,11 @@
|
||||
if (g % 500 === 0) return (g / 500) + '斤';
|
||||
return formatGram(g);
|
||||
}
|
||||
/* 纯克展示:始终以 g 为单位 */
|
||||
function formatGramOnly(g) {
|
||||
if (g === undefined || g === null || g === '' || isNaN(g)) return '—';
|
||||
return Number(g) + 'g';
|
||||
}
|
||||
|
||||
// 获取 URL 参数
|
||||
function getUrlParam(name) {
|
||||
@@ -421,6 +676,223 @@
|
||||
el._timer = setTimeout(function() { el.classList.remove('show'); }, duration || 2000);
|
||||
}
|
||||
|
||||
|
||||
/* ==================== 新增任务弹窗逻辑 ==================== */
|
||||
/* Mock: 上游任务数据 */
|
||||
var UPSTREAM_TASKS = [
|
||||
{
|
||||
taskNo: 'PO-20260810-001',
|
||||
ingredients: [
|
||||
{ name: '土豆', icon: '🥔', iconClass: 'icon--potato', weight: 3000 },
|
||||
{ name: '黄瓜', icon: '🥒', iconClass: 'icon--cucumber', weight: 2000 },
|
||||
{ name: '西红柿', icon: '🍅', iconClass: 'icon--tomato', weight: 2500 },
|
||||
{ name: '胡萝卜', icon: '🥕', iconClass: 'icon--carrot', weight: 1500 },
|
||||
{ name: '大白菜', icon: '🥬', iconClass: 'icon--cabbage', weight: 4000 }
|
||||
]
|
||||
},
|
||||
{
|
||||
taskNo: 'PO-20260810-002',
|
||||
ingredients: [
|
||||
{ name: '芹菜', icon: '🥬', iconClass: 'icon--cabbage', weight: 1500 },
|
||||
{ name: '青椒', icon: '🫑', iconClass: 'icon--cucumber', weight: 1200 },
|
||||
{ name: '洋葱', icon: '🧅', iconClass: 'icon--potato', weight: 2000 },
|
||||
{ name: '小番茄', icon: '🍅', iconClass: 'icon--tomato', weight: 800 }
|
||||
]
|
||||
},
|
||||
{
|
||||
taskNo: 'PO-20260810-003',
|
||||
ingredients: [
|
||||
{ name: '西兰花', icon: '🥦', iconClass: 'icon--cabbage', weight: 1800 },
|
||||
{ name: '娃娃菜', icon: '🥬', iconClass: 'icon--cabbage', weight: 1200 },
|
||||
{ name: '土豆', icon: '🥔', iconClass: 'icon--potato', weight: 2500 },
|
||||
{ name: '黄瓜', icon: '🥒', iconClass: 'icon--cucumber', weight: 1500 },
|
||||
{ name: '西红柿', icon: '🍅', iconClass: 'icon--tomato', weight: 2000 },
|
||||
{ name: '胡萝卜', icon: '🥕', iconClass: 'icon--carrot', weight: 1000 }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
var selectedUpstreamTask = null; /* 当前选中的上游任务号 */
|
||||
var checkedIngredients = {}; /* 勾选的食材: {name: true/false} */
|
||||
var taskCounter = 0; /* 任务编号自增 */
|
||||
|
||||
/* 打开弹窗 */
|
||||
function openAddTaskDialog() {
|
||||
selectedUpstreamTask = null;
|
||||
checkedIngredients = {};
|
||||
renderUpstreamTasks();
|
||||
document.getElementById('ingredientTableSection').classList.add('hide');
|
||||
document.getElementById('ingredientPlaceholder').style.display = 'flex';
|
||||
document.getElementById('confirmAddBtn').disabled = true;
|
||||
document.getElementById('dialogHint').textContent = '请选择任务号并勾选食材后完成生成';
|
||||
document.getElementById('footerKindCount').textContent = '—';
|
||||
document.getElementById('footerTotalWeight').textContent = '—';
|
||||
document.getElementById('addTaskOverlay').classList.add('show');
|
||||
}
|
||||
|
||||
/* 关闭弹窗 */
|
||||
function closeAddTaskDialog() {
|
||||
document.getElementById('addTaskOverlay').classList.remove('show');
|
||||
}
|
||||
|
||||
/* 生成食材摘要文本 */
|
||||
function ingredientSummary(ings) {
|
||||
var names = ings.slice(0, 3).map(function(i) { return i.name; });
|
||||
var tail = ings.length > 3 ? '…' : '';
|
||||
return names.join('、') + tail + ' 等' + ings.length + '种食材';
|
||||
}
|
||||
|
||||
/* 渲染上游任务号列表 */
|
||||
function renderUpstreamTasks() {
|
||||
var container = document.getElementById('upstreamTaskList');
|
||||
container.innerHTML = '';
|
||||
UPSTREAM_TASKS.forEach(function(t) {
|
||||
var el = document.createElement('div');
|
||||
el.className = 'task-option';
|
||||
if (selectedUpstreamTask === t.taskNo) el.classList.add('task-option--selected');
|
||||
el.innerHTML =
|
||||
'<span class="task-option__radio"></span>' +
|
||||
'<span class="task-option__no">' + t.taskNo + '</span>' +
|
||||
'<span class="task-option__desc">' + ingredientSummary(t.ingredients) + '</span>';
|
||||
el.onclick = function() { selectUpstreamTask(t.taskNo); };
|
||||
container.appendChild(el);
|
||||
});
|
||||
}
|
||||
|
||||
/* 选择任务号 */
|
||||
function selectUpstreamTask(taskNo) {
|
||||
selectedUpstreamTask = taskNo;
|
||||
checkedIngredients = {};
|
||||
renderUpstreamTasks();
|
||||
renderIngredientTable();
|
||||
document.getElementById('ingredientTableSection').classList.remove('hide');
|
||||
document.getElementById('ingredientPlaceholder').style.display = 'none';
|
||||
updateConfirmBtn();
|
||||
}
|
||||
|
||||
/* 渲染食材表格 */
|
||||
function renderIngredientTable() {
|
||||
var container = document.getElementById('ingredientTableList');
|
||||
container.innerHTML = '';
|
||||
var task = UPSTREAM_TASKS.find(function(t) { return t.taskNo === selectedUpstreamTask; });
|
||||
if (!task) return;
|
||||
task.ingredients.forEach(function(ing) {
|
||||
var isChecked = checkedIngredients[ing.name];
|
||||
var el = document.createElement('div');
|
||||
el.className = 'ing-row';
|
||||
if (isChecked) el.classList.add('ing-row--checked');
|
||||
el.innerHTML =
|
||||
'<span class="ing-row__checkbox">✓</span>' +
|
||||
'<span class="ing-row__icon ' + ing.iconClass + '">' + ing.icon + '</span>' +
|
||||
'<span class="ing-row__name">' + ing.name + '</span>' +
|
||||
'<span class="ing-row__actual">' + (isChecked ? formatGramOnly(ing.weight) : '—') + '</span>' +
|
||||
'<span class="ing-row__status' + (isChecked ? ' ing-row__status--checked' : ' ing-row__status--pending') + '">' +
|
||||
(isChecked ? '已选择' : '未选择') + '</span>';
|
||||
el.onclick = function() { toggleIngredient(ing.name); };
|
||||
container.appendChild(el);
|
||||
});
|
||||
|
||||
/* 更新计数 */
|
||||
var total = task.ingredients.length;
|
||||
var selected = Object.values(checkedIngredients).filter(function(v) { return v; }).length;
|
||||
document.getElementById('ingTableCount').textContent = '共 ' + total + ' 种,已选 ' + selected + ' 种';
|
||||
}
|
||||
|
||||
/* 勾选/取消食材 */
|
||||
function toggleIngredient(name) {
|
||||
checkedIngredients[name] = !checkedIngredients[name];
|
||||
renderIngredientTable();
|
||||
updateConfirmBtn();
|
||||
}
|
||||
|
||||
/* 更新确认按钮状态 + 底部统计 */
|
||||
function updateConfirmBtn() {
|
||||
var hasChecked = Object.values(checkedIngredients).some(function(v) { return v; });
|
||||
document.getElementById('confirmAddBtn').disabled = !(selectedUpstreamTask && hasChecked);
|
||||
updateFooterStats();
|
||||
}
|
||||
|
||||
/* 更新底部统计 */
|
||||
function updateFooterStats() {
|
||||
var task = selectedUpstreamTask ? UPSTREAM_TASKS.find(function(t) { return t.taskNo === selectedUpstreamTask; }) : null;
|
||||
var selectedNames = Object.keys(checkedIngredients).filter(function(k) { return checkedIngredients[k]; });
|
||||
var totalW = 0;
|
||||
if (task) {
|
||||
task.ingredients.forEach(function(ing) {
|
||||
if (checkedIngredients[ing.name]) totalW += ing.weight;
|
||||
});
|
||||
}
|
||||
document.getElementById('footerKindCount').textContent = selectedNames.length;
|
||||
document.getElementById('footerTotalWeight').textContent = selectedNames.length > 0 ? formatGramOnly(totalW) : '—';
|
||||
var hint = selectedNames.length > 0
|
||||
? '已选 ' + selectedNames.length + ' 种食材,共 ' + formatGramOnly(totalW)
|
||||
: '请勾选需要加工的食材';
|
||||
document.getElementById('dialogHint').textContent = hint;
|
||||
}
|
||||
|
||||
/* 确认新增任务 */
|
||||
function confirmAddTask() {
|
||||
if (!selectedUpstreamTask) return;
|
||||
var selectedNames = Object.keys(checkedIngredients).filter(function(k) { return checkedIngredients[k]; });
|
||||
if (selectedNames.length === 0) return;
|
||||
|
||||
var task = UPSTREAM_TASKS.find(function(t) { return t.taskNo === selectedUpstreamTask; });
|
||||
var selectedIngs = task.ingredients.filter(function(ing) { return checkedIngredients[ing.name]; });
|
||||
|
||||
/* 生成清洗任务编号 */
|
||||
taskCounter++;
|
||||
var today = new Date();
|
||||
var dateStr = today.getFullYear() +
|
||||
('0' + (today.getMonth() + 1)).slice(-2) +
|
||||
('0' + today.getDate()).slice(-2);
|
||||
var taskNo = 'RW-' + dateStr + '-' + ('00' + taskCounter).slice(-3);
|
||||
|
||||
/* 构建食材行 HTML */
|
||||
var rowsHtml = '';
|
||||
selectedIngs.forEach(function(ing) {
|
||||
rowsHtml +=
|
||||
'<div class="ingredient-row">' +
|
||||
'<div class="ingredient-row__icon ' + ing.iconClass + '">' + ing.icon + '</div>' +
|
||||
'<span class="ingredient-row__name">' + ing.name + '</span>' +
|
||||
'<span class="ingredient-row__weight" data-weight-g="' + ing.weight + '">需 ' + formatGramOnly(ing.weight) + '</span>' +
|
||||
'<span class="ingredient-row__recorded ingredient-row__recorded--none">未录入</span>' +
|
||||
'<span class="ingredient-row__deadline">—</span>' +
|
||||
'</div>';
|
||||
});
|
||||
|
||||
/* 构建任务卡片(直接生成已完成状态) */
|
||||
var card = document.createElement('div');
|
||||
card.className = 'order-card order-card--done';
|
||||
card.dataset.status = 'done';
|
||||
card.innerHTML =
|
||||
'<div class="order-card__header">' +
|
||||
'<div class="order-card__header-left">' +
|
||||
'<span class="order-card__no">' + taskNo + '</span>' +
|
||||
'</div>' +
|
||||
'<span class="order-card__done-mark">✓ 已完成</span>' +
|
||||
'</div>' +
|
||||
'<div class="order-card__divider"></div>' +
|
||||
'<div class="order-card__body">' + rowsHtml + '</div>' +
|
||||
'<div class="order-card__divider"></div>';
|
||||
|
||||
var taskList = document.getElementById('taskList');
|
||||
taskList.insertBefore(card, taskList.firstChild);
|
||||
|
||||
/* 更新已完成计数 */
|
||||
var countEl = document.getElementById('doneCount');
|
||||
countEl.textContent = (parseInt(countEl.textContent) + 1) + '';
|
||||
|
||||
/* 新增任务后强制切到已完成标签页,确保新任务可见 */
|
||||
var doneTab = document.querySelector('[data-filter="done"]');
|
||||
if (doneTab) {
|
||||
filterTasks('done', doneTab);
|
||||
}
|
||||
|
||||
/* 关闭弹窗并提示 */
|
||||
closeAddTaskDialog();
|
||||
showToast('任务单已生成:' + taskNo + ',关联 ' + selectedUpstreamTask, 2500);
|
||||
}
|
||||
|
||||
// ── 模拟新任务单到达(15 秒后推送一个新任务单)──
|
||||
setTimeout(function() {
|
||||
var taskList = document.getElementById('taskList');
|
||||
@@ -440,20 +912,27 @@
|
||||
'<div class="ingredient-row">' +
|
||||
'<div class="ingredient-row__icon icon--cabbage">🥦</div>' +
|
||||
'<span class="ingredient-row__name">西兰花</span>' +
|
||||
'<span class="ingredient-row__weight" data-weight-g="1500">需 3 斤</span>' +
|
||||
'<span class="ingredient-row__weight" data-weight-g="1500">需 1500g</span>' +
|
||||
'<span class="ingredient-row__recorded ingredient-row__recorded--none">未录入</span>' +
|
||||
'<span class="ingredient-row__deadline">截止 13:00</span>' +
|
||||
'</div>' +
|
||||
'<div class="ingredient-row">' +
|
||||
'<div class="ingredient-row__icon icon--carrot">🥕</div>' +
|
||||
'<span class="ingredient-row__name">芹菜</span>' +
|
||||
'<span class="ingredient-row__weight" data-weight-g="1000">需 2 斤</span>' +
|
||||
'<span class="ingredient-row__weight" data-weight-g="1000">需 1000g</span>' +
|
||||
'<span class="ingredient-row__recorded ingredient-row__recorded--none">未录入</span>' +
|
||||
'<span class="ingredient-row__deadline">截止 13:30</span>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="order-card__divider"></div>';
|
||||
taskList.insertBefore(newCard, taskList.firstChild);
|
||||
|
||||
/* 重新应用当前筛选状态 */
|
||||
var activeTab = document.querySelector('.status-tab.active--pending, .status-tab.active--done');
|
||||
if (activeTab) {
|
||||
filterTasks(activeTab.dataset.filter, activeTab);
|
||||
}
|
||||
|
||||
showToast('⚡ 新任务单已到达:RW-20260613-004', 2500);
|
||||
// 更新待处理计数
|
||||
document.getElementById('pendingCount').textContent = '3';
|
||||
|
||||
Reference in New Issue
Block a user