fix(data-ui): 导入类别改为常驻复选框,取消勾选不再从列表消失
之前顶部类别取自服务端返回的「本次已选类别」,取消一个后列表被重算,那一项直接消失 —— 把勾选框做成了单向筛选。现在改为取包头里的全部类别(preview.file.categories)常驻显示, 勾选状态只决定预览与导入范围;取消最后一类时给明确提示,不再静默无响应。
This commit is contained in:
@@ -71,6 +71,7 @@ function DataTransfer() {
|
|||||||
const [result, setResult] = useState(null)
|
const [result, setResult] = useState(null)
|
||||||
const [percent, setPercent] = useState(0)
|
const [percent, setPercent] = useState(0)
|
||||||
const [replanning, setReplanning] = useState(false)
|
const [replanning, setReplanning] = useState(false)
|
||||||
|
const [categoryHint, setCategoryHint] = useState('')
|
||||||
const [dragging, setDragging] = useState(false)
|
const [dragging, setDragging] = useState(false)
|
||||||
const inputRef = useRef(null)
|
const inputRef = useRef(null)
|
||||||
|
|
||||||
@@ -150,6 +151,7 @@ function DataTransfer() {
|
|||||||
setPreview(null)
|
setPreview(null)
|
||||||
setResult(null)
|
setResult(null)
|
||||||
setPercent(0)
|
setPercent(0)
|
||||||
|
setCategoryHint('')
|
||||||
setPhase('checking')
|
setPhase('checking')
|
||||||
setError('')
|
setError('')
|
||||||
|
|
||||||
@@ -175,11 +177,16 @@ function DataTransfer() {
|
|||||||
|
|
||||||
/** 切换类别后重算预览:包已经在服务器上,不用重传 */
|
/** 切换类别后重算预览:包已经在服务器上,不用重传 */
|
||||||
const toggleImport = async key => {
|
const toggleImport = async key => {
|
||||||
if (replanning) return
|
if (replanning || phase === 'applying') return
|
||||||
const next = importPicks.includes(key)
|
const on = importPicks.includes(key)
|
||||||
? importPicks.filter(item => item !== key)
|
/* 全部取消等于「什么都不导」,服务端把空列表当成「全选」——
|
||||||
: [...importPicks, key]
|
所以这里明确挡住,并说明原因,而不是点了没反应 */
|
||||||
if (!next.length) return
|
if (on && importPicks.length === 1) {
|
||||||
|
setCategoryHint('至少要勾一类。想放弃这次导入,点下面的「重新选择」。')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setCategoryHint('')
|
||||||
|
const next = on ? importPicks.filter(item => item !== key) : [...importPicks, key]
|
||||||
setImportPicks(next)
|
setImportPicks(next)
|
||||||
setReplanning(true)
|
setReplanning(true)
|
||||||
setError('')
|
setError('')
|
||||||
@@ -228,6 +235,7 @@ function DataTransfer() {
|
|||||||
setResult(null)
|
setResult(null)
|
||||||
setImportPicks([])
|
setImportPicks([])
|
||||||
setPercent(0)
|
setPercent(0)
|
||||||
|
setCategoryHint('')
|
||||||
setError('')
|
setError('')
|
||||||
if (inputRef.current) inputRef.current.value = ''
|
if (inputRef.current) inputRef.current.value = ''
|
||||||
}
|
}
|
||||||
@@ -241,7 +249,10 @@ function DataTransfer() {
|
|||||||
|
|
||||||
const busy = phase === 'checking' || phase === 'applying' || replanning
|
const busy = phase === 'checking' || phase === 'applying' || replanning
|
||||||
const plan = preview?.plan
|
const plan = preview?.plan
|
||||||
const availableKeys = preview?.availableCategories || preview?.file?.categories || []
|
/* 顶部类别必须取「包里有哪几类」,而不是「这次选了哪几类」——
|
||||||
|
后者会随着取消勾选而缩短,表现就是「点一下那一类就消失了」。
|
||||||
|
preview.file.categories 来自包头,重算预览也不会变。 */
|
||||||
|
const categoriesInFile = preview?.file?.categories || []
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page-container transfer-page">
|
<div className="page-container transfer-page">
|
||||||
@@ -380,24 +391,25 @@ function DataTransfer() {
|
|||||||
|
|
||||||
<div className="transfer-cats">
|
<div className="transfer-cats">
|
||||||
<span className="muted-note">导入类别</span>
|
<span className="muted-note">导入类别</span>
|
||||||
{availableKeys.map(key => {
|
{categoriesInFile.map(key => {
|
||||||
const category = categoryByKey.get(key)
|
const category = categoryByKey.get(key)
|
||||||
const on = importPicks.includes(key)
|
const on = importPicks.includes(key)
|
||||||
return (
|
return (
|
||||||
<button
|
<label key={key} className={`chip-filter transfer-cat${on ? ' is-active' : ''}`}>
|
||||||
key={key}
|
<input
|
||||||
type="button"
|
type="checkbox"
|
||||||
className={`chip-filter${on ? ' is-active' : ''}`}
|
className="transfer-cat-box"
|
||||||
onClick={() => toggleImport(key)}
|
checked={on}
|
||||||
disabled={replanning || phase === 'applying'}
|
disabled={replanning || phase === 'applying'}
|
||||||
aria-pressed={on}
|
onChange={() => toggleImport(key)}
|
||||||
>
|
/>
|
||||||
{category?.label || key}
|
{category?.label || key}
|
||||||
</button>
|
</label>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
{replanning && <span className="spinner" />}
|
{replanning && <span className="spinner" />}
|
||||||
</div>
|
</div>
|
||||||
|
{categoryHint && <p className="help-text transfer-hint">{categoryHint}</p>}
|
||||||
|
|
||||||
<div className="table-wrap transfer-report">
|
<div className="table-wrap transfer-report">
|
||||||
<table className="data-table">
|
<table className="data-table">
|
||||||
|
|||||||
@@ -202,6 +202,29 @@
|
|||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 导入类别是一组常驻的复选框:取消勾选只改「导不导」,不会把它从列表里拿掉 */
|
||||||
|
.transfer-cat {
|
||||||
|
cursor: pointer;
|
||||||
|
gap: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transfer-cat-box {
|
||||||
|
width: 13px;
|
||||||
|
height: 13px;
|
||||||
|
margin: 0;
|
||||||
|
accent-color: var(--primary-light);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transfer-cat-box:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transfer-hint {
|
||||||
|
margin: -4px 0 10px;
|
||||||
|
color: var(--warning);
|
||||||
|
}
|
||||||
|
|
||||||
.transfer-report {
|
.transfer-report {
|
||||||
max-height: 320px;
|
max-height: 320px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user