Skip to content

Commit fd20264

Browse files
committed
feat: optimize the error message when setting limit rules (#590)
1 parent f9b5fa0 commit fd20264

File tree

4 files changed

+70
-56
lines changed

4 files changed

+70
-56
lines changed

src/i18n/message/app/limit-resource.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"option": "全局设置"
3232
},
3333
"message": {
34-
"noUrl": "未配置限制网址",
34+
"noUrl": "未添加任何限制网址",
3535
"noRule": "未填写任何规则",
3636
"deleteConfirm": "是否要删除规则 [{name}]?",
3737
"lockConfirm": "锁定后,即使未触发此规则,所有操作也需要验证",
@@ -138,7 +138,7 @@
138138
"test": "Test URL"
139139
},
140140
"message": {
141-
"noUrl": "No restriction URLs configured",
141+
"noUrl": "No URL added",
142142
"noRule": "No rules filled in",
143143
"deleteConfirm": "Do you want to delete the rule [{name}]?",
144144
"lockConfirm": "If locked, all operations will require verification even if the rule is not triggered.",

src/pages/app/components/Limit/LimitModify/Sop/Step2.tsx

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,35 @@ import { useState } from "@hooks"
1111
import Flex from "@pages/components/Flex"
1212
import { EXCLUDING_PREFIX } from '@util/constant/remain-host'
1313
import { cleanCond } from "@util/limit"
14-
import { ElButton, ElDivider, ElIcon, ElInput, ElLink, ElMessage, ElScrollbar, ElText, type ScrollbarInstance } from "element-plus"
15-
import { type StyleValue, defineComponent, ref } from "vue"
16-
import { useSopData } from "./context"
14+
import {
15+
ElButton, ElDivider, ElIcon, ElInput, ElLink, ElMessage, ElScrollbar, ElText,
16+
type InputInstance, type ScrollbarInstance,
17+
} from "element-plus"
18+
import { type StyleValue, defineComponent, ref, watch } from "vue"
19+
import { useSopData, useUrlMiss } from "./context"
1720

1821
const _default = defineComponent(() => {
1922
const data = useSopData()
23+
const urlMiss = useUrlMiss()
2024
const scrollbar = ref<ScrollbarInstance>()
2125

26+
const inputEl = ref<InputInstance>()
27+
watch(urlMiss, v => v && inputEl.value?.focus())
28+
const warnAndFocus = (msg: string) => {
29+
ElMessage.warning(msg)
30+
inputEl.value?.focus()
31+
}
32+
2233
const handleAdd = () => {
2334
let url: string | undefined = inputting.value?.trim?.()?.toLowerCase?.()
24-
if (!url) return ElMessage.warning('URL is blank')
35+
if (!url) return warnAndFocus('URL is blank')
2536
url = cleanCond(url)
26-
if (!url) return ElMessage.warning('URL is invalid')
37+
if (!url) return warnAndFocus('URL is invalid')
2738
const urls = data.cond
28-
if (urls.includes(url)) return ElMessage.warning('Duplicated URL')
39+
if (urls.includes(url)) return warnAndFocus('Duplicated URL')
2940
urls.unshift(url)
41+
42+
urlMiss.value = false
3043
scrollbar.value?.scrollTo(0)
3144

3245
clearInputting()
@@ -40,19 +53,18 @@ const _default = defineComponent(() => {
4053
<Flex column width="100%">
4154
<Flex width="100%" column gap={5}>
4255
<ElInput
56+
ref={inputEl}
4357
modelValue={inputting.value}
4458
onInput={setInputting}
4559
clearable
4660
onClear={clearInputting}
4761
onKeydown={ev => (ev as KeyboardEvent)?.code === "Enter" && handleAdd()}
62+
// change the color of append button
63+
style={{ '--el-color-info': `var(--el-color-${urlMiss.value ? 'danger' : 'primary'}` }}
64+
placeholder="www.demo.com, *.demo.com, demo.com/blog/*, demo.com/**, +www.demo.com/blog/list"
4865
v-slots={{
49-
append: () => (
50-
<ElButton onClick={handleAdd} style={{ display: 'flex' } satisfies StyleValue}>
51-
{t(msg => msg.button.add)}
52-
</ElButton>
53-
)
66+
append: () => <ElButton onClick={handleAdd}>{t(msg => msg.button.add)}</ElButton>
5467
}}
55-
placeholder="www.demo.com, *.demo.com, demo.com/blog/*, demo.com/**, +www.demo.com/blog/list"
5668
/>
5769
<ElText style={{ textAlign: 'start', width: '100%', paddingInlineStart: '10px' } satisfies StyleValue}>
5870
{t(msg => msg.limit.wildcardTip)}

src/pages/app/components/Limit/LimitModify/Sop/context.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ import { t } from "@app/locale"
22
import { useProvide, useProvider } from "@hooks"
33
import { range } from "@util/array"
44
import { ElMessage } from "element-plus"
5-
import { type Reactive, reactive, ref, toRaw } from "vue"
5+
import { type Reactive, reactive, type Ref, ref, toRaw } from "vue"
66

77
type Step = 0 | 1 | 2
88

99
type SopData = Required<Omit<timer.limit.Rule, 'id'>>
1010

1111
type Context = {
1212
data: Reactive<SopData>
13+
urlMiss: Ref<boolean>
1314
}
1415

1516
const createInitial = (): SopData => ({
@@ -36,6 +37,7 @@ const NAMESPACE = 'limit_sop_model'
3637
export const initSop = ({ onSave }: Options) => {
3738
const step = ref<Step>(0)
3839
const data = reactive<SopData>(createInitial())
40+
const urlMiss = ref(false)
3941

4042
const validator: Record<Step, () => Promise<boolean>> = {
4143
0: async () => {
@@ -53,8 +55,10 @@ export const initSop = ({ onSave }: Options) => {
5355
1: async () => {
5456
if (!data.cond?.length) {
5557
ElMessage.error(t(msg => msg.limit.message.noUrl))
58+
urlMiss.value = true
5659
return false
5760
}
61+
urlMiss.value = false
5862
return true
5963
},
6064
2: async () => {
@@ -85,11 +89,13 @@ export const initSop = ({ onSave }: Options) => {
8589
}
8690
}
8791

88-
useProvide<Context>(NAMESPACE, { data })
92+
useProvide<Context>(NAMESPACE, { data, urlMiss })
8993

9094
return {
9195
step, reset, handleNext
9296
}
9397
}
9498

95-
export const useSopData = () => useProvider<Context, 'data'>(NAMESPACE, 'data').data
99+
export const useSopData = () => useProvider<Context, 'data'>(NAMESPACE, 'data').data
100+
101+
export const useUrlMiss = () => useProvider<Context, 'urlMiss'>(NAMESPACE, 'urlMiss').urlMiss

src/pages/app/components/Limit/LimitModify/Sop/index.tsx

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,45 +21,41 @@ export type SopInstance = {
2121
reset: (rule?: timer.limit.Rule) => void
2222
}
2323

24-
const _default = defineComponent({
25-
props: {
26-
condDisabled: Boolean,
27-
},
28-
emits: {
29-
cancel: () => true,
30-
save: (_rule: MakeOptional<timer.limit.Rule, 'id'>) => true,
31-
},
32-
setup(_, ctx) {
33-
const { reset, step, handleNext } = initSop({ onSave: data => ctx.emit('save', data) })
34-
const last = computed(() => step.value === 2)
35-
const first = computed(() => step.value === 0)
36-
ctx.expose({ reset } satisfies SopInstance)
24+
type Props = {
25+
onCancel?: NoArgCallback
26+
onSave?: ArgCallback<MakeOptional<timer.limit.Rule, 'id'>>
27+
}
28+
29+
const _default = defineComponent<Props>(({ onSave, onCancel }, ctx) => {
30+
const { reset, step, handleNext } = initSop({ onSave })
31+
const last = computed(() => step.value === 2)
32+
const first = computed(() => step.value === 0)
33+
ctx.expose({ reset } satisfies SopInstance)
3734

38-
return () => (
39-
<DialogSop
40-
last={last.value}
41-
first={first.value}
42-
onBack={() => step.value--}
43-
onCancel={() => ctx.emit('cancel')}
44-
onNext={handleNext}
45-
onFinish={handleNext}
46-
v-slots={{
47-
steps: () => (
48-
<ElSteps space={200} finishStatus="success" active={step.value} alignCenter>
49-
<ElStep title={t(msg => msg.limit.step.base)} />
50-
<ElStep title={t(msg => msg.limit.step.url)} />
51-
<ElStep title={t(msg => msg.limit.step.rule)} />
52-
</ElSteps>
53-
),
54-
content: () => <>
55-
<Step1 v-show={step.value === 0} />
56-
<Step2 v-show={step.value === 1} />
57-
<Step3 v-show={step.value === 2} />
58-
</>
59-
}}
60-
/>
61-
)
62-
}
63-
})
35+
return () => (
36+
<DialogSop
37+
last={last.value}
38+
first={first.value}
39+
onBack={() => step.value--}
40+
onCancel={onCancel}
41+
onNext={handleNext}
42+
onFinish={handleNext}
43+
v-slots={{
44+
steps: () => (
45+
<ElSteps space={200} finishStatus="success" active={step.value} alignCenter>
46+
<ElStep title={t(msg => msg.limit.step.base)} />
47+
<ElStep title={t(msg => msg.limit.step.url)} />
48+
<ElStep title={t(msg => msg.limit.step.rule)} />
49+
</ElSteps>
50+
),
51+
content: () => <>
52+
<Step1 v-show={step.value === 0} />
53+
<Step2 v-show={step.value === 1} />
54+
<Step3 v-show={step.value === 2} />
55+
</>
56+
}}
57+
/>
58+
)
59+
}, { props: ['onCancel', 'onSave'] })
6460

6561
export default _default

0 commit comments

Comments
 (0)