Skip to content

Commit be5a65c

Browse files
author
gemini2035
committed
feat(sheet): fav Operator completed
1 parent 1da5314 commit be5a65c

File tree

5 files changed

+215
-60
lines changed

5 files changed

+215
-60
lines changed

src/components/editor/operator/sheet/SheetGroup.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ const SheetGroup = ({
158158
{ ...value },
159159
])
160160

161-
const groupAddHandle = (value: Group) => {
161+
const groupAddHandle: GroupListModifyProp['groupAddHandle'] = (value) => {
162162
if (checkGroupExisted(value.name)) {
163163
AppToaster.show({
164164
message: '干员组已存在!',
@@ -169,18 +169,20 @@ const SheetGroup = ({
169169
submitGroup(value, undefined, true)
170170
}
171171
}
172-
const groupRemoveHandle = (_id: string) => {
172+
const groupRemoveHandle: GroupListModifyProp['groupRemoveHandle'] = (_id) => {
173173
removeGroup(existedGroups.findIndex((item) => item._id === _id))
174174
}
175-
const groupPinHandle = (value: Group) => {
175+
const groupPinHandle: GroupListModifyProp['groupPinHandle'] = (value) => {
176176
if (checkGroupPinned(value))
177177
setFavGroups([...favGroups].filter(({ name }) => name !== value.name))
178178
else {
179179
if (checkSamePinned(value.name)) setCoverGroup(value)
180180
else updateFavGroup(value)
181181
}
182182
}
183-
const groupUpdateHandle = (value: Group) => {
183+
const groupUpdateHandle: GroupListModifyProp['groupUpdateHandle'] = (
184+
value,
185+
) => {
184186
changeOperatorOfOtherGroups(value.opers)
185187
submitGroup(value, undefined, true)
186188
}

src/components/editor/operator/sheet/SheetOperator.tsx

Lines changed: 133 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
import { Button, Divider, H4, H5, H6, Intent } from '@blueprintjs/core'
1+
import { Alert, Button, Divider, H4, H5, H6, Intent } from '@blueprintjs/core'
22

33
import clsx from 'clsx'
4+
import { useAtom } from 'jotai'
5+
import { isEqual, omit } from 'lodash'
46
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
57
import { UseFieldArrayRemove } from 'react-hook-form'
68

79
import { AppToaster } from 'components/Toaster'
810
import { OPERATORS, PROFESSIONS } from 'models/operator'
11+
import { ignoreKeyDic } from 'store/useFavGroups'
12+
import { favOperatorAtom } from 'store/useFavOperators'
913

1014
import { EditorPerformerOperatorProps } from '../EditorPerformerOperator'
1115
import { Group, Operator } from '../EditorSheet'
@@ -20,12 +24,23 @@ export interface SheetOperatorProps {
2024
removeOperator: UseFieldArrayRemove
2125
}
2226

27+
export interface OperatorModifyProps {
28+
operatorPinHandle?: (value: Operator) => void
29+
operatorSelectHandle?: (value: string) => void
30+
operatorSkillHandle?: (value: Operator) => void
31+
}
32+
2333
const defaultProf = [
2434
{
2535
id: 'all',
2636
name: '全部',
2737
sub: [],
2838
},
39+
{
40+
id: 'fav',
41+
name: '收藏',
42+
sub: [],
43+
},
2944
{
3045
id: 'others',
3146
name: '其它',
@@ -39,9 +54,9 @@ const defaultSubProf = [
3954
]
4055

4156
const formattedProfessions = [
42-
defaultProf[0],
57+
...defaultProf.slice(0, defaultProf.length - 1),
4358
...PROFESSIONS,
44-
...defaultProf.slice(1),
59+
...defaultProf.slice(defaultProf.length - 1),
4560
]
4661

4762
const paginationSize = 60
@@ -56,6 +71,12 @@ const SheetOperator = ({
5671

5772
const [selectedProf, setSelectedProf] = useState(formattedProfessions[0])
5873
const [selectedSubProf, setSelectedSubProf] = useState(defaultSubProf[0])
74+
const [favOperators, setFavOperators] = useAtom(favOperatorAtom)
75+
const [coverOperator, setCoverOperator] = useState<Operator>()
76+
77+
const favOperatorFindByName = (target: string) => {
78+
return !!favOperators.find(({ name }) => name === target)
79+
}
5980

6081
const [formattedSubProfessions, operatorsGroupedByProf] = useMemo(
6182
() => [
@@ -73,12 +94,14 @@ const SheetOperator = ({
7394
...OPERATORS,
7495
].filter((item) => {
7596
if (selectedProf.id === defaultProf[0].id) return true
76-
else if (selectedProf.id === defaultProf[1].id) {
97+
if (selectedProf.id === defaultProf[1].id)
98+
return favOperatorFindByName(item.name)
99+
else if (selectedProf.id === defaultProf[2].id) {
77100
return item.subProf === 'notchar1' || !item.subProf
78101
} else return !!selectedProf.sub?.find((op) => op.id === item.subProf)
79102
}),
80103
],
81-
[selectedProf, existedOperators],
104+
[selectedProf, existedOperators, favOperators],
82105
)
83106

84107
const checkOperatorSelected = useCallback(
@@ -93,6 +116,34 @@ const SheetOperator = ({
93116
[existedOperators, existedGroups],
94117
)
95118

119+
const checkOperatorPinned = (target: Operator, ignoreKey = ignoreKeyDic) =>
120+
isEqual(
121+
omit(target, [...ignoreKey]),
122+
omit(
123+
favOperators.find(({ name }) => name === target.name),
124+
[...ignoreKey],
125+
),
126+
)
127+
128+
const updateFavOperator = (value: Operator) =>
129+
setFavOperators([
130+
...[...favOperators].filter(({ name }) => name !== value.name),
131+
{ ...value },
132+
])
133+
134+
const operatorPinHandle: OperatorModifyProps['operatorPinHandle'] = (
135+
value,
136+
) => {
137+
if (checkOperatorPinned(value))
138+
setFavOperators(
139+
[...favOperators].filter(({ name }) => name !== value.name),
140+
)
141+
else {
142+
if (favOperatorFindByName(value.name)) setCoverOperator(value)
143+
else updateFavOperator(value)
144+
}
145+
}
146+
96147
const operatorsGroupedBySubProf = useMemo(() => {
97148
if (selectedSubProf.id === 'all') return operatorsGroupedByProf
98149
else if (selectedSubProf.id === 'selected')
@@ -105,7 +156,9 @@ const SheetOperator = ({
105156
)
106157
}, [selectedSubProf, operatorsGroupedByProf, checkOperatorSelected])
107158

108-
const operatorSelectHandle = (operatorName: string) => {
159+
const operatorSelectHandle: OperatorModifyProps['operatorSelectHandle'] = (
160+
operatorName,
161+
) => {
109162
if (checkOperatorSelected(operatorName))
110163
if (existedOperators.find((item) => item.name === operatorName))
111164
removeOperator(
@@ -116,10 +169,19 @@ const SheetOperator = ({
116169
message: `干员 ${operatorName} 已被编组`,
117170
intent: Intent.DANGER,
118171
})
119-
else submitOperator({ name: operatorName }, undefined, true)
172+
else
173+
submitOperator(
174+
favOperators.find(({ name }) => name === operatorName) || {
175+
name: operatorName,
176+
},
177+
undefined,
178+
true,
179+
)
120180
}
121181

122-
const operatorSkillHandle = (value: Operator) => {
182+
const operatorSkillHandle: OperatorModifyProps['operatorSkillHandle'] = (
183+
value,
184+
) => {
123185
submitOperator(value, undefined, true)
124186
}
125187

@@ -259,44 +321,70 @@ const SheetOperator = ({
259321
)
260322

261323
return (
262-
<div className="flex h-full">
263-
<div className="flex-auto px-1" ref={operatorScrollRef}>
264-
{operatorsGroupedBySubProf.length ? (
265-
<>
266-
<div
267-
key="operatorContainer"
268-
className="flex flex-wrap items-start content-start overscroll-contain relative"
269-
>
270-
{operatorsGroupedBySubProf
271-
.slice(0, lastIndex)
272-
.map(({ name: operatorInfoName }, index) => {
273-
const operatorDetail = existedOperators.find(
274-
({ name }) => name === operatorInfoName,
275-
)
276-
return (
277-
<div
278-
className="flex items-center w-32 h-32 flex-0"
279-
key={index}
280-
>
281-
<OperatorItem
282-
selected={checkOperatorSelected(operatorInfoName)}
283-
onSkillChange={operatorSkillHandle}
284-
operator={operatorDetail}
285-
name={operatorInfoName}
286-
onClick={() => operatorSelectHandle(operatorInfoName)}
287-
/>
288-
</div>
289-
)
290-
})}
291-
</div>
292-
{ShowMoreButton}
293-
</>
294-
) : (
295-
OperatorNoData
296-
)}
324+
<>
325+
<div className="flex h-full">
326+
<div className="flex-auto px-1" ref={operatorScrollRef}>
327+
{operatorsGroupedBySubProf.length ? (
328+
<>
329+
<div
330+
key="operatorContainer"
331+
className="flex flex-wrap items-start content-start overscroll-contain relative"
332+
>
333+
{operatorsGroupedBySubProf
334+
.slice(0, lastIndex)
335+
.map(({ name: operatorInfoName }, index) => {
336+
const operatorDetail = existedOperators.find(
337+
({ name }) => name === operatorInfoName,
338+
)
339+
return (
340+
<div
341+
className="flex items-center w-32 h-32 flex-0"
342+
key={index}
343+
>
344+
<OperatorItem
345+
selected={checkOperatorSelected(operatorInfoName)}
346+
pinned={checkOperatorPinned(
347+
operatorDetail || { name: operatorInfoName },
348+
)}
349+
onSkillChange={operatorSkillHandle}
350+
operator={operatorDetail}
351+
name={operatorInfoName}
352+
onClick={() => operatorSelectHandle(operatorInfoName)}
353+
onPinHandle={
354+
existedOperators.find(
355+
({ name }) => name === operatorInfoName,
356+
)
357+
? operatorPinHandle
358+
: undefined
359+
}
360+
/>
361+
</div>
362+
)
363+
})}
364+
</div>
365+
{ShowMoreButton}
366+
</>
367+
) : (
368+
OperatorNoData
369+
)}
370+
</div>
371+
{ProfSelect}
297372
</div>
298-
{ProfSelect}
299-
</div>
373+
<Alert
374+
isOpen={!!coverOperator}
375+
confirmButtonText="是"
376+
cancelButtonText="否"
377+
icon="error"
378+
intent={Intent.DANGER}
379+
onConfirm={() => updateFavOperator(coverOperator as Group)}
380+
onClose={() => setCoverOperator(undefined)}
381+
>
382+
<div>
383+
<H5>收藏: </H5>
384+
<p>检测到同名的已收藏干员 {coverOperator?.name},是否覆盖?</p>
385+
</div>
386+
</Alert>
387+
</>
300388
)
301389
}
302390

src/components/editor/operator/sheet/SheetOperatorItem.tsx

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import { Card, CardProps } from '@blueprintjs/core'
1+
import { Button, Card, CardProps, Icon } from '@blueprintjs/core'
2+
import { Popover2 } from '@blueprintjs/popover2'
23

34
import clsx from 'clsx'
45

56
import { OperatorAvatar } from '../EditorOperator'
7+
import { Operator } from '../EditorSheet'
8+
import { OperatorModifyProps } from './SheetOperator'
69
import { SkillAboutProps, SkillAboutTrigger } from './SheetOperatorSkillAbout'
710

811
export interface OperatorItemPorps extends CardProps, SkillAboutProps {
@@ -11,6 +14,8 @@ export interface OperatorItemPorps extends CardProps, SkillAboutProps {
1114
horizontal?: boolean
1215
scaleDisable?: boolean
1316
readOnly?: boolean
17+
pinned?: boolean
18+
onPinHandle?: OperatorModifyProps['operatorPinHandle']
1419
}
1520

1621
export const OperatorItem = ({
@@ -21,6 +26,8 @@ export const OperatorItem = ({
2126
scaleDisable,
2227
readOnly,
2328
onSkillChange,
29+
onPinHandle,
30+
pinned,
2431
...cardProps
2532
}: OperatorItemPorps) => (
2633
<Card
@@ -33,15 +40,45 @@ export const OperatorItem = ({
3340
{...cardProps}
3441
>
3542
<>
36-
<OperatorAvatar name={name} size="large" />
37-
<p
38-
className={clsx(
39-
'font-bold leading-none text-center mt-3 truncate',
40-
horizontal && 'mt-0 ml-1 mr-auto',
41-
)}
42-
>
43-
{name}
44-
</p>
43+
<>
44+
<OperatorAvatar name={name} size="large" />
45+
<p
46+
className={clsx(
47+
'font-bold leading-none text-center mt-3 truncate',
48+
horizontal && 'mt-0 ml-1 mr-auto',
49+
)}
50+
>
51+
{name}
52+
</p>
53+
</>
54+
{!horizontal && selected && !!onPinHandle && (
55+
<div
56+
className="absolute top-2 right-2"
57+
onClick={(e) => e.stopPropagation()}
58+
role="presentation"
59+
>
60+
<Popover2
61+
content={
62+
<Button
63+
minimal
64+
onClick={() => onPinHandle?.(operator as Operator)}
65+
>
66+
<Icon icon="pin" className="-rotate-45" />
67+
<span>移出收藏</span>
68+
</Button>
69+
}
70+
disabled={!pinned}
71+
>
72+
<Icon
73+
icon={pinned ? 'pin' : 'unpin'}
74+
className={clsx(pinned && '-rotate-45')}
75+
onClick={
76+
pinned ? undefined : () => onPinHandle?.(operator as Operator)
77+
}
78+
/>
79+
</Popover2>
80+
</div>
81+
)}
4582
</>
4683
{!readOnly && selected && (
4784
<SkillAboutTrigger {...{ operator, onSkillChange }} />

src/components/editor/operator/sheet/SheetOperatorSkillAbout.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ import { EditorOperatorSkill } from '../EditorOperatorSkill'
1313
import { EditorOperatorSkillTimes } from '../EditorOperatorSkillTimes'
1414
import { EditorOperatorSkillUsage } from '../EditorOperatorSkillUsage'
1515
import { Operator } from '../EditorSheet'
16+
import { OperatorModifyProps } from './SheetOperator'
1617

1718
const needSkillTimeType = CopilotDocV1.SkillUsageType.ReadyToUseTimes
1819

1920
export interface SkillAboutProps {
2021
operator?: Operator
21-
onSkillChange?: (value: Operator) => void
22+
onSkillChange?: OperatorModifyProps['operatorSkillHandle']
2223
}
2324

2425
const skillDic = operatorSkillUsages as DetailedSelectChoice[]

0 commit comments

Comments
 (0)