1
- import { Button , Divider , H4 , H5 , H6 , Intent } from '@blueprintjs/core'
1
+ import { Alert , Button , Divider , H4 , H5 , H6 , Intent } from '@blueprintjs/core'
2
2
3
3
import clsx from 'clsx'
4
+ import { useAtom } from 'jotai'
5
+ import { isEqual , omit } from 'lodash'
4
6
import { useCallback , useEffect , useMemo , useRef , useState } from 'react'
5
7
import { UseFieldArrayRemove } from 'react-hook-form'
6
8
7
9
import { AppToaster } from 'components/Toaster'
10
+ import { CopilotDocV1 } from 'models/copilot.schema'
8
11
import { OPERATORS , PROFESSIONS } from 'models/operator'
12
+ import { ignoreKeyDic } from 'store/useFavGroups'
13
+ import { favOperatorAtom } from 'store/useFavOperators'
9
14
10
15
import { EditorPerformerOperatorProps } from '../EditorPerformerOperator'
11
16
import { Group , Operator } from '../EditorSheet'
@@ -20,12 +25,23 @@ export interface SheetOperatorProps {
20
25
removeOperator : UseFieldArrayRemove
21
26
}
22
27
28
+ export interface OperatorModifyProps {
29
+ operatorPinHandle ?: ( value : Operator ) => void
30
+ operatorSelectHandle ?: ( value : string ) => void
31
+ operatorSkillHandle ?: ( value : Operator ) => void
32
+ }
33
+
23
34
const defaultProf = [
24
35
{
25
36
id : 'all' ,
26
37
name : '全部' ,
27
38
sub : [ ] ,
28
39
} ,
40
+ {
41
+ id : 'fav' ,
42
+ name : '收藏' ,
43
+ sub : [ ] ,
44
+ } ,
29
45
{
30
46
id : 'others' ,
31
47
name : '其它' ,
@@ -39,9 +55,9 @@ const defaultSubProf = [
39
55
]
40
56
41
57
const formattedProfessions = [
42
- defaultProf [ 0 ] ,
58
+ ... defaultProf . slice ( 0 , defaultProf . length - 1 ) ,
43
59
...PROFESSIONS ,
44
- ...defaultProf . slice ( 1 ) ,
60
+ ...defaultProf . slice ( defaultProf . length - 1 ) ,
45
61
]
46
62
47
63
const paginationSize = 60
@@ -56,6 +72,12 @@ const SheetOperator = ({
56
72
57
73
const [ selectedProf , setSelectedProf ] = useState ( formattedProfessions [ 0 ] )
58
74
const [ selectedSubProf , setSelectedSubProf ] = useState ( defaultSubProf [ 0 ] )
75
+ const [ favOperators , setFavOperators ] = useAtom ( favOperatorAtom )
76
+ const [ coverOperator , setCoverOperator ] = useState < Operator > ( )
77
+
78
+ const favOperatorFindByName = ( target : string ) => {
79
+ return ! ! favOperators . find ( ( { name } ) => name === target )
80
+ }
59
81
60
82
const [ formattedSubProfessions , operatorsGroupedByProf ] = useMemo (
61
83
( ) => [
@@ -73,12 +95,14 @@ const SheetOperator = ({
73
95
...OPERATORS ,
74
96
] . filter ( ( item ) => {
75
97
if ( selectedProf . id === defaultProf [ 0 ] . id ) return true
76
- else if ( selectedProf . id === defaultProf [ 1 ] . id ) {
98
+ if ( selectedProf . id === defaultProf [ 1 ] . id )
99
+ return favOperatorFindByName ( item . name )
100
+ else if ( selectedProf . id === defaultProf [ 2 ] . id ) {
77
101
return item . subProf === 'notchar1' || ! item . subProf
78
102
} else return ! ! selectedProf . sub ?. find ( ( op ) => op . id === item . subProf )
79
103
} ) ,
80
104
] ,
81
- [ selectedProf , existedOperators ] ,
105
+ [ selectedProf , existedOperators , favOperators ] ,
82
106
)
83
107
84
108
const checkOperatorSelected = useCallback (
@@ -93,6 +117,46 @@ const SheetOperator = ({
93
117
[ existedOperators , existedGroups ] ,
94
118
)
95
119
120
+ const checkOperatorPinned = ( target : Operator , ignoreKey = ignoreKeyDic ) =>
121
+ isEqual (
122
+ omit ( target , [ ...ignoreKey ] ) ,
123
+ omit (
124
+ favOperators . find ( ( { name } ) => name === target . name ) ,
125
+ [ ...ignoreKey ] ,
126
+ ) ,
127
+ )
128
+
129
+ const updateFavOperator = ( value : Operator ) => {
130
+ const { skill, skillUsage, skillTimes, ...rest } = value
131
+ const formattedValue = {
132
+ ...rest ,
133
+ skill : skill || 1 ,
134
+ skillUsage : skillUsage || 0 ,
135
+ skillTimes :
136
+ skillUsage === CopilotDocV1 . SkillUsageType . ReadyToUseTimes
137
+ ? skillTimes || 1
138
+ : undefined ,
139
+ }
140
+ setFavOperators ( [
141
+ ...[ ...favOperators ] . filter ( ( { name } ) => name !== formattedValue . name ) ,
142
+ { ...formattedValue } ,
143
+ ] )
144
+ submitOperator ( formattedValue , undefined , true )
145
+ }
146
+
147
+ const operatorPinHandle : OperatorModifyProps [ 'operatorPinHandle' ] = (
148
+ value ,
149
+ ) => {
150
+ if ( checkOperatorPinned ( value ) )
151
+ setFavOperators (
152
+ [ ...favOperators ] . filter ( ( { name } ) => name !== value . name ) ,
153
+ )
154
+ else {
155
+ if ( favOperatorFindByName ( value . name ) ) setCoverOperator ( value )
156
+ else updateFavOperator ( value )
157
+ }
158
+ }
159
+
96
160
const operatorsGroupedBySubProf = useMemo ( ( ) => {
97
161
if ( selectedSubProf . id === 'all' ) return operatorsGroupedByProf
98
162
else if ( selectedSubProf . id === 'selected' )
@@ -105,7 +169,9 @@ const SheetOperator = ({
105
169
)
106
170
} , [ selectedSubProf , operatorsGroupedByProf , checkOperatorSelected ] )
107
171
108
- const operatorSelectHandle = ( operatorName : string ) => {
172
+ const operatorSelectHandle : OperatorModifyProps [ 'operatorSelectHandle' ] = (
173
+ operatorName ,
174
+ ) => {
109
175
if ( checkOperatorSelected ( operatorName ) )
110
176
if ( existedOperators . find ( ( item ) => item . name === operatorName ) )
111
177
removeOperator (
@@ -116,10 +182,19 @@ const SheetOperator = ({
116
182
message : `干员 ${ operatorName } 已被编组` ,
117
183
intent : Intent . DANGER ,
118
184
} )
119
- else submitOperator ( { name : operatorName } , undefined , true )
185
+ else
186
+ submitOperator (
187
+ favOperators . find ( ( { name } ) => name === operatorName ) || {
188
+ name : operatorName ,
189
+ } ,
190
+ undefined ,
191
+ true ,
192
+ )
120
193
}
121
194
122
- const operatorSkillHandle = ( value : Operator ) => {
195
+ const operatorSkillHandle : OperatorModifyProps [ 'operatorSkillHandle' ] = (
196
+ value ,
197
+ ) => {
123
198
submitOperator ( value , undefined , true )
124
199
}
125
200
@@ -259,44 +334,70 @@ const SheetOperator = ({
259
334
)
260
335
261
336
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
- ) }
337
+ < >
338
+ < div className = "flex h-full" >
339
+ < div className = "flex-auto px-1" ref = { operatorScrollRef } >
340
+ { operatorsGroupedBySubProf . length ? (
341
+ < >
342
+ < div
343
+ key = "operatorContainer"
344
+ className = "flex flex-wrap items-start content-start overscroll-contain relative"
345
+ >
346
+ { operatorsGroupedBySubProf
347
+ . slice ( 0 , lastIndex )
348
+ . map ( ( { name : operatorInfoName } , index ) => {
349
+ const operatorDetail = existedOperators . find (
350
+ ( { name } ) => name === operatorInfoName ,
351
+ )
352
+ return (
353
+ < div
354
+ className = "flex items-center w-32 h-32 flex-0"
355
+ key = { index }
356
+ >
357
+ < OperatorItem
358
+ selected = { checkOperatorSelected ( operatorInfoName ) }
359
+ pinned = { checkOperatorPinned (
360
+ operatorDetail || { name : operatorInfoName } ,
361
+ ) }
362
+ onSkillChange = { operatorSkillHandle }
363
+ operator = { operatorDetail }
364
+ name = { operatorInfoName }
365
+ onClick = { ( ) => operatorSelectHandle ( operatorInfoName ) }
366
+ onPinHandle = {
367
+ existedOperators . find (
368
+ ( { name } ) => name === operatorInfoName ,
369
+ )
370
+ ? operatorPinHandle
371
+ : undefined
372
+ }
373
+ />
374
+ </ div >
375
+ )
376
+ } ) }
377
+ </ div >
378
+ { ShowMoreButton }
379
+ </ >
380
+ ) : (
381
+ OperatorNoData
382
+ ) }
383
+ </ div >
384
+ { ProfSelect }
297
385
</ div >
298
- { ProfSelect }
299
- </ div >
386
+ < Alert
387
+ isOpen = { ! ! coverOperator }
388
+ confirmButtonText = "是"
389
+ cancelButtonText = "否"
390
+ icon = "error"
391
+ intent = { Intent . DANGER }
392
+ onConfirm = { ( ) => updateFavOperator ( coverOperator as Group ) }
393
+ onClose = { ( ) => setCoverOperator ( undefined ) }
394
+ >
395
+ < div >
396
+ < H5 > 收藏: </ H5 >
397
+ < p > 检测到同名的已收藏干员 { coverOperator ?. name } ,是否覆盖?</ p >
398
+ </ div >
399
+ </ Alert >
400
+ </ >
300
401
)
301
402
}
302
403
0 commit comments