11 KiB
Coal Feeding Layout Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Replace the right-side <table> in src/views/coalFeeding.vue with a block-based unit-column layout while preserving the current row/column visual structure and existing interactions.
Architecture: Keep all business state and handlers in src/views/coalFeeding.vue, but reorganize the right-side rendering around a fixed parameter label column plus horizontally scrollable unit columns. Use small in-file render configurations for upper rows, lower rows, and fixed-height visual blocks so the new block layout stays aligned with the former table structure.
Tech Stack: Vue 3 <script setup lang="ts">, existing CSS utility classes, @opentiny/vue, Vite build verification
Task 1: Prepare In-File Layout Metadata
Files:
-
Modify:
D:\testProjects\yaodaoxiangmu\vite_vue3_tsproject_change\src\views\coalFeeding.vue -
Step 1: Add typed row metadata for the upper and lower time-setting blocks
Insert these constants near the existing type declarations in src/views/coalFeeding.vue so the new template can loop over block rows instead of repeating hard-coded table rows:
type TimeFieldKey =
| "tmyxsds"
| "tmtzsds"
| "tmljsds"
| "blyxsds"
| "tmyxsdx"
| "tmtzsdx"
| "tmljsdx"
| "blyxsdx";
type DisplayFieldKey =
| "tmljsjs"
| "tmljsjx"
| "tempera1"
| "tempera2"
| "carNumber";
type BlockRowConfig = {
key: TimeFieldKey | DisplayFieldKey;
label: string;
kind: "time" | "display";
idPrefix?: string;
};
const upperBlockRows: BlockRowConfig[] = [
{ key: "tmyxsds", label: "投煤运行时间设定", kind: "time", idPrefix: "tmyxsds" },
{ key: "tmtzsds", label: "投煤停止时间设定", kind: "time", idPrefix: "tmtzsds" },
{ key: "tmljsds", label: "投煤累积时间设定", kind: "time", idPrefix: "tmljsds" },
{ key: "blyxsds", label: "布料运行时间设定", kind: "time", idPrefix: "blyxsds" },
{ key: "tmljsjs", label: "投煤累积时间", kind: "display", idPrefix: "tmljsjs" },
];
const lowerBlockRows: BlockRowConfig[] = [
{ key: "tmyxsdx", label: "投煤运行时间设定", kind: "time", idPrefix: "tmyxsdx" },
{ key: "tmtzsdx", label: "投煤停止时间设定", kind: "time", idPrefix: "tmtzsdx" },
{ key: "tmljsdx", label: "投煤累积时间设定", kind: "time", idPrefix: "tmljsdx" },
{ key: "blyxsdx", label: "布料运行时间设定", kind: "time", idPrefix: "blyxsdx" },
{ key: "tmljsjx", label: "投煤累积时间", kind: "display", idPrefix: "tmljsjx" },
];
- Step 2: Add typed helpers for rendering ids and editable values
Add these helpers below the row metadata so the template can render the new block layout without string duplication:
const getCellId = (prefix: string | undefined, index: number) => {
return prefix ? `${prefix}${index}` : undefined;
};
const getTempDropId = (side: "tempera1" | "tempera2", item: any, index: number) => {
return `${side}_unit${item.unit}_${index + 1}`;
};
const isTimeRow = (row: BlockRowConfig) => row.kind === "time";
- Step 3: Run a quick type sanity scan before touching the template
Run: rg -n "upperBlockRows|lowerBlockRows|getCellId|getTempDropId|isTimeRow" src\views\coalFeeding.vue
Expected: five matches for the newly added metadata/helpers, all inside src/views\coalFeeding.vue
Task 2: Replace the Table Template With a Column Layout
Files:
-
Modify:
D:\testProjects\yaodaoxiangmu\vite_vue3_tsproject_change\src\views\coalFeeding.vue -
Step 1: Replace the
<table>wrapper with a block-based layout shell
Replace the current <table> section with this outer structure inside the existing right-side panel container:
<div class="control-panel">
<div class="control-panel__labels">
<div class="control-panel__corner"></div>
<div class="control-panel__section">
<div
v-for="row in upperBlockRows"
:key="`upper-label-${row.key}`"
class="control-panel__label control-panel__label--row"
>
{{ row.label }}
</div>
<div class="control-panel__label control-panel__label--motor">中间侧</div>
</div>
<div class="control-panel__label control-panel__label--temp">2侧温度</div>
<div class="control-panel__label control-panel__label--car">车位号</div>
<div class="control-panel__label control-panel__label--temp">1侧温度</div>
<div class="control-panel__section">
<div
v-for="row in lowerBlockRows"
:key="`lower-label-${row.key}`"
class="control-panel__label control-panel__label--row"
>
{{ row.label }}
</div>
<div class="control-panel__label control-panel__label--motor">回车侧</div>
</div>
</div>
<div class="control-panel__columns">
<!-- unit columns render here -->
</div>
</div>
- Step 2: Render each unit as one vertical column
Inside control-panel__columns, render one column per dataList item using this structure:
<div
v-for="(item, index) in dataList"
:key="item.team"
class="control-panel__column"
>
<div class="control-panel__column-header">
<span class="inline_flex items_center justify_center h1_25 min_w_6 px0_375 rounded bg_primary text_primary_color fontw700 text_11">
{{ item.team }}
</span>
</div>
<div class="control-panel__section">
<!-- upper rows -->
</div>
<div
:id="getTempDropId('tempera2', item, index)"
class="control-panel__cell control-panel__cell--temp"
@dragover="onDjDragOver"
@drop="onDjDrop($event, item, getTempDropId('tempera2', item, index))"
>
<span class="text_xs fontw700 min_w_2_25 text_right text_red">{{ item.tempera2 }}</span>
<span> °C</span>
</div>
<div class="control-panel__cell control-panel__cell--car">
<span class="inline_flex items_center justify_center h1_25 min_w_1_75 px0_375 rounded_md bg_primary text_primary_color my0_3 fontw700 text_sm shadow_sm">
{{ item.carNumber }}
</span>
</div>
<div
:id="getTempDropId('tempera1', item, index)"
class="control-panel__cell control-panel__cell--temp"
@dragover="onDjDragOver"
@drop="onDjDrop($event, item, getTempDropId('tempera1', item, index))"
>
<span class="text_xs fontw700 min_w_2_25 text_right text_red">{{ item.tempera1 }}</span>
<span> °C</span>
</div>
<div class="control-panel__section">
<!-- lower rows -->
</div>
</div>
- Step 3: Render the upper and lower time/display rows from metadata
Use this pattern in both the upper and lower sections so editable rows and display rows remain consistent:
<div
v-for="row in upperBlockRows"
:key="`upper-${item.team}-${row.key}`"
:id="getCellId(row.idPrefix, index)"
class="control-panel__cell control-panel__cell--row"
>
<span v-if="!isTimeRow(row) || item.statusAuto" class="px0_25 py0_125 text_center text_xs color_base">
{{ item[row.key] }}
</span>
<input
v-else
v-model="item[row.key]"
class="px0_25 py0_125 text_center text_xs color_base control-panel__input"
/>
</div>
For the lower section, switch upperBlockRows to lowerBlockRows and keep the same markup.
- Step 4: Move the middle-side and return-side motor rendering into the new sections
Render the motor groups as fixed-height cells so the old 中间侧 and 回车侧 rows become block elements:
<div class="control-panel__cell control-panel__cell--motor">
<div
v-for="dj in item.dianji"
:id="dj.id"
:key="dj.id"
class="flexs flex_col items_center gap0_25 text_center dianji_status"
@dragover="onDjDragOver"
@drop="onDjDrop($event, dj, 'id')"
>
<!-- preserve existing motor inner markup and click handlers -->
</div>
</div>
For the lower section, keep the same structure but iterate item.dianji2 and continue calling toggleDjStop(dj, item.team, item.statusAuto, 'dianji2').
Task 3: Rebuild Styling for Alignment and Visual Parity
Files:
-
Modify:
D:\testProjects\yaodaoxiangmu\vite_vue3_tsproject_change\src\views\coalFeeding.vue -
Step 1: Add block-layout container styles
Append styles like these near the existing <style> block:
.control-panel {
display: flex;
align-items: flex-start;
min-width: max-content;
}
.control-panel__labels {
flex: 0 0 132px;
}
.control-panel__columns {
display: flex;
align-items: flex-start;
}
.control-panel__column {
min-width: 96px;
border-right: 1px solid rgba(148, 163, 184, 0.6);
}
- Step 2: Add fixed row heights so labels and unit cells stay aligned
Add shared row classes to replace the natural table sizing:
.control-panel__corner,
.control-panel__column-header {
height: 42px;
display: flex;
align-items: center;
justify-content: center;
border-bottom: 1px solid rgba(148, 163, 184, 0.6);
}
.control-panel__label--row,
.control-panel__cell--row {
height: 42px;
}
.control-panel__label--temp,
.control-panel__cell--temp,
.control-panel__label--car,
.control-panel__cell--car {
height: 42px;
}
.control-panel__label--motor,
.control-panel__cell--motor {
min-height: 120px;
}
- Step 3: Restore row backgrounds and dense control-panel styling
Add styling hooks so the new block elements preserve the current visual categories:
.control-panel__label,
.control-panel__cell {
display: flex;
align-items: center;
justify-content: center;
padding: 0.25rem;
border-bottom: 1px solid rgba(148, 163, 184, 0.6);
background: #ffffff;
}
.control-panel__label--temp,
.control-panel__cell--temp {
background: #fff1e8;
}
.control-panel__label--car,
.control-panel__cell--car {
background: #dbeafe;
}
.control-panel__label--motor,
.control-panel__cell--motor {
background: #eff6ff;
}
.control-panel__input {
width: 6rem;
}
- Step 4: Run a targeted selector scan to make sure the old
<table>layout is gone
Run: rg -n "<table|<thead|<tbody|<tr|<td|<th" src\views\coalFeeding.vue
Expected: no matches
Task 4: Verify Build and Behavior
Files:
-
Modify:
D:\testProjects\yaodaoxiangmu\vite_vue3_tsproject_change\src\views\coalFeeding.vue -
Step 1: Run the production build
Run: npm run build
Expected: Vite build completes successfully and outputs the dist bundle without Vue template or TypeScript errors.
- Step 2: Manually verify the right panel structure in the app
Open the page and confirm:
1. The right panel no longer uses a table layout.
2. The left parameter column remains visually aligned with each unit column.
3. Each unit column shows:
- upper block
- 2侧温度
- 车位号
- 1侧温度
- lower block
4. 中间侧 and 回车侧 motor areas still render with the expected controls.
- Step 3: Manually verify preserved interactions
Confirm these behaviors still work:
1. Auto mode shows text; manual mode shows inputs.
2. Clicking a motor still toggles stop/run state as before.
3. Temperature targets still accept drag-and-drop point binding.
4. Bottom manual/auto switch panel still renders and responds.
- Step 4: Record completion status instead of committing
Because this workspace currently has no .git directory, do not run commit commands here.
Instead, record completion by listing the verified items in the final handoff:
- build result
- layout conversion status
- interaction checks completed