Skip to content

Commit a48e58d

Browse files
committed
feat: semi
1 parent 874a789 commit a48e58d

File tree

7 files changed

+115
-63
lines changed

7 files changed

+115
-63
lines changed

src/database/site-cate-database.ts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -77,37 +77,32 @@ class SiteCateDatabase extends BaseDatabase {
7777
return { name, id, autoRules }
7878
}
7979

80-
async update(id: number, name: string): Promise<void> {
81-
if (!name) return
82-
80+
private async updateWithReplacer(id: number, replacer: (exist: Item) => Item): Promise<void> {
8381
const items = await this.getItems()
84-
const existId = Object.entries(items).find(([_, v]) => v.n === name)?.[0]
82+
const exist = items[id]
83+
if (!exist) return
8584

86-
if (existId) {
85+
const replaced = replacer(exist)
86+
87+
if (Object.entries(items).some(([vid, v]) => v.n === replaced.n && parseInt(vid) !== id)) {
88+
// Name exist already
8789
return
8890
}
8991

90-
items[id] = { ...items[id] || {}, n: name }
92+
items[id] = replaced
9193
await this.saveItems(items)
9294
}
9395

94-
async updateFull(edited: timer.site.Cate) {
95-
const { id, name, autoRules } = edited
96-
const items = await this.getItems()
97-
const exist = items[id]
98-
if (!exist) {
99-
throw new Error('Category not exist')
100-
}
101-
102-
const nameDuplicate = Object.entries(items)
103-
.some(([k, v]) => v.n === name && parseInt(k) !== id)
104-
105-
if (nameDuplicate) {
106-
throw new Error('Category name exist')
107-
}
96+
async updateName(id: number, name: string): Promise<void> {
97+
await this.updateWithReplacer(id, exist => ({ ...exist, n: name }))
98+
}
10899

109-
items[id] = { n: name, a: autoRules }
110-
await this.saveItems(items)
100+
async update(cate: timer.site.Cate): Promise<void> {
101+
await this.updateWithReplacer(cate.id, exist => ({
102+
...exist,
103+
n: cate.name,
104+
a: cate.autoRules,
105+
}))
111106
}
112107

113108
async importData(data: any): Promise<void> {

src/pages/app/components/Report/ReportTable/index.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ const _default = defineComponent((_, ctx) => {
108108
() => filter.siteMerge,
109109
], () => table.value?.doLayout?.())
110110

111+
const handleCateChange = (key: timer.site.SiteKey, newCateId: number | undefined) => {
112+
data.value?.list
113+
?.filter(isSite)
114+
?.filter(item => siteEqual(item.siteKey, key))
115+
?.forEach(i => i.cateId = newCateId)
116+
}
117+
111118
return () => (
112119
<ContentCard>
113120
<Flex gap={23} width="100%" height="100%" column>
@@ -138,7 +145,7 @@ const _default = defineComponent((_, ctx) => {
138145
/>
139146
</>}
140147
{visible.value.group && <GroupColumn />}
141-
{visible.value.cate && <CateColumn onChange={refresh} />}
148+
{visible.value.cate && <CateColumn onChange={handleCateChange} />}
142149
<TimeColumn dimension="focus" />
143150
{runColVisible.value && <TimeColumn dimension="run" />}
144151
<VisitColumn />

src/pages/app/components/SiteManage/SiteManageTable/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Flex from "@pages/components/Flex"
1010
import { removeIconUrl, saveSiteRunState } from '@service/site-service'
1111
import { ElSwitch, ElTable, ElTableColumn, type RenderRowData } from "element-plus"
1212
import { defineComponent } from "vue"
13-
import CategoryEditable from "../../common/category/CategoryEditable"
13+
import Category from "../../common/category/CategoryEditable"
1414
import { useSiteManageTable } from '../useSiteManage'
1515
import AliasColumn from "./column/AliasColumn"
1616
import OperationColumn from "./column/OperationColumn"
@@ -70,7 +70,7 @@ const _default = defineComponent<{}>(() => {
7070
minWidth={140}
7171
align="center"
7272
v-slots={({ row }: RenderRowData<timer.site.SiteInfo>) => (
73-
<CategoryEditable siteKey={row} modelValue={row?.cate} onChange={val => row.cate = val} />
73+
<Category siteKey={row} modelValue={row?.cate} onChange={val => row.cate = val} />
7474
)}
7575
/>
7676
<ElTableColumn

src/pages/app/components/common/category/CategoryDialog.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const Component = defineComponent<Props>(props => {
2121
<ElDialog
2222
modelValue={visible.value}
2323
title={props.cate ? t(msg => msg.button.modify) : t(msg => msg.button.create)}
24-
width={600}
24+
width={400}
2525
destroyOnClose
2626
beforeClose={props.onClose}
2727
closeOnClickModal={false}
@@ -37,6 +37,9 @@ const Component = defineComponent<Props>(props => {
3737
<ElFormItem label={t(msg => msg.siteManage.cate.name)} prop="name">
3838
<ElInput v-model={formData.name} />
3939
</ElFormItem>
40+
<ElFormItem label={t(msg => msg.siteManage.cate.name)} prop="name">
41+
<ElInput v-model={formData.name} />
42+
</ElFormItem>
4043
</ElDialog>
4144
)
4245
}, { props: ['cate', 'onClose', 'onSave'] })
Lines changed: 81 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,34 @@
11
import { useCategory } from "@app/context"
22
import { t } from "@app/locale"
3-
import { Delete, Edit } from "@element-plus/icons-vue"
4-
import { useManualRequest, useRequest } from "@hooks"
3+
import { Check, Close, Delete, Edit } from "@element-plus/icons-vue"
4+
import { useManualRequest, useRequest, useState, useSwitch } from "@hooks"
55
import Flex from "@pages/components/Flex"
66
import cateService from "@service/cate-service"
77
import { selectAllSites } from '@service/site-service'
88
import { stopPropagationAfter } from "@util/document"
9-
import { ElButton, ElMessage, ElMessageBox } from "element-plus"
10-
import { defineComponent } from "vue"
9+
import { ElButton, ElInput, ElMessage, ElMessageBox } from "element-plus"
10+
import { defineComponent, ref } from "vue"
1111
import CategoryDialog from '../CategoryDialog'
1212

13-
type Props = {
14-
value: timer.site.Cate
15-
deleteEnable?: boolean
16-
}
17-
18-
const OptionItem = defineComponent<Props>(props => {
13+
const OptionItem = defineComponent<{ value: timer.site.Cate }>(props => {
1914
const cate = useCategory()
2015

16+
const [editing, openEditing, closeEditing] = useSwitch(false)
17+
const [editingName, setEditingName] = useState(props.value.name)
18+
const inputRef = ref<HTMLInputElement>()
19+
20+
const { refresh: saveCate } = useManualRequest((name: string) => cateService.saveName(props.value.id, name), {
21+
onSuccess: () => {
22+
cate.refresh()
23+
closeEditing()
24+
}
25+
})
26+
27+
const onSaveClick = () => {
28+
const name = editingName.value?.trim?.()
29+
name ? saveCate(name) : ElMessage.warning("Name is blank")
30+
}
31+
2132
const { refresh: removeCate } = useManualRequest(() => cateService.remove(props.value.id), {
2233
onSuccess: () => {
2334
cate.refresh()
@@ -42,37 +53,74 @@ const OptionItem = defineComponent<Props>(props => {
4253
}
4354

4455
const onEditClick = async () => {
45-
CategoryDialog.open({ cate: props.value }).then(async (edited) => {
46-
await cateService.save(edited)
47-
cate.refresh()
48-
}).catch(() => { })
56+
const edited = await CategoryDialog.open({ cate: props.value })
57+
await cateService.save(edited)
58+
await cate.refresh()
4959
}
5060

5161
return () => (
5262
<Flex
63+
key={`${editing.value}`}
5364
justify="space-between" align="center" gap={5}
5465
width='100%' height='100%'
66+
onClick={ev => editing.value && ev.stopPropagation()}
5567
>
56-
<Flex flex={1}>{props.value.name}</Flex>
57-
<Flex>
58-
<ElButton
59-
size="small"
60-
link
61-
icon={Edit}
62-
type="primary"
63-
onClick={e => stopPropagationAfter(e, onEditClick)}
64-
/>
65-
<ElButton
66-
size="small"
67-
link
68-
icon={Delete}
69-
type="danger"
70-
disabled={queryingSites.value || !props.deleteEnable}
71-
onClick={onRemoveClick}
72-
/>
73-
</Flex>
68+
{editing.value ? <>
69+
<Flex flex={1}>
70+
<ElInput
71+
ref={inputRef}
72+
size="small"
73+
modelValue={editingName.value}
74+
onInput={setEditingName}
75+
style={{ maxWidth: '120px' }}
76+
onKeydown={ev => {
77+
const { key } = ev as KeyboardEvent
78+
if (key === 'Enter') {
79+
onSaveClick()
80+
} else if (key === 'Escape') {
81+
stopPropagationAfter(ev, closeEditing)
82+
}
83+
}}
84+
/>
85+
</Flex>
86+
<Flex>
87+
<ElButton
88+
size="small"
89+
link
90+
icon={Close}
91+
type="info"
92+
onClick={ev => stopPropagationAfter(ev, closeEditing)}
93+
/>
94+
<ElButton
95+
size="small"
96+
link
97+
icon={Check}
98+
type="primary"
99+
onClick={onSaveClick}
100+
/>
101+
</Flex>
102+
</> : <>
103+
<Flex flex={1}>{props.value.name}</Flex>
104+
<Flex>
105+
<ElButton
106+
size="small"
107+
link
108+
icon={Edit}
109+
type="primary"
110+
onClick={e => stopPropagationAfter(e, onEditClick)}
111+
/>
112+
<ElButton
113+
size="small"
114+
link
115+
icon={Delete}
116+
type="danger"
117+
disabled={queryingSites.value}
118+
onClick={onRemoveClick}
119+
/>
120+
</Flex>
121+
</>}
74122
</Flex>
75123
)
76-
}, { props: ['value', 'deleteEnable'] })
124+
}, { props: ['value'] })
77125

78126
export default OptionItem

src/pages/app/components/common/category/CategorySelect/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const CategorySelect = defineComponent<Props>((props, ctx) => {
4141
>
4242
{cate.all.map(c => (
4343
<ElOption value={c.id} label={c.name}>
44-
<OptionItem value={c} deleteEnable={props.modelValue === c.id} />
44+
<OptionItem value={c} />
4545
</ElOption>
4646
))}
4747
</ElSelect>

src/service/cate-service.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,13 @@ class CateService {
1010
}
1111

1212
saveName(id: number, name: string): Promise<void> {
13-
return siteCateDatabase.update(id, name)
13+
return siteCateDatabase.updateName(id, name)
1414
}
1515

1616
save(edited: timer.site.Cate) {
17-
return siteCateDatabase.updateFull(edited)
17+
return siteCateDatabase.update(edited)
1818
}
1919

20-
2120
remove(id: number): Promise<void> {
2221
return siteCateDatabase.delete(id)
2322
}

0 commit comments

Comments
 (0)