Skip to content

Commit 3f43a49

Browse files
author
sheepzh
committed
Support password and verification for daily limit (#199)
1 parent 9c78213 commit 3f43a49

File tree

32 files changed

+1017
-342
lines changed

32 files changed

+1017
-342
lines changed

src/app/components/limit/filter.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,22 @@
55
* https://opensource.org/licenses/MIT
66
*/
77

8-
import { Operation, Plus } from "@element-plus/icons-vue"
8+
import { Operation, Plus, SetUp } from "@element-plus/icons-vue"
99
import { Ref, h, defineComponent, ref } from "vue"
1010
import InputFilterItem from "@app/components/common/input-filter-item"
1111
import SwitchFilterItem from "@app/components/common/switch-filter-item"
1212
import ButtonFilterItem from "@app/components/common/button-filter-item"
1313
import { t } from "@app/locale"
14+
import { getAppPageUrl } from "@util/constant/url"
15+
import { OPTION_ROUTE } from "@app/router/constants"
16+
import { createTabAfterCurrent } from "@api/chrome/tab"
1417

1518
const urlPlaceholder = t(msg => msg.limit.conditionFilter)
1619
const onlyEnabledLabel = t(msg => msg.limit.filterDisabled)
1720
const addButtonText = t(msg => msg.button.create)
1821
const testButtonText = t(msg => msg.limit.button.test)
22+
const optionButtonText = t(msg => msg.limit.button.option)
23+
const optionPageUrl = getAppPageUrl(false, OPTION_ROUTE, { i: 'dailyLimit' })
1924

2025
const emits = {
2126
create: () => true,
@@ -60,6 +65,12 @@ const _default = defineComponent({
6065
icon: Operation,
6166
onClick: () => ctx.emit('test')
6267
}),
68+
h(ButtonFilterItem, {
69+
text: optionButtonText,
70+
icon: SetUp,
71+
type: 'primary',
72+
onClick: () => createTabAfterCurrent(optionPageUrl)
73+
}),
6374
h(ButtonFilterItem, {
6475
text: addButtonText,
6576
type: "success",
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { t, tN } from "@app/locale"
2+
import { locale } from "@i18n"
3+
import { VerificationPair } from "@service/limit-service/verification/common"
4+
import verificationProcessor from "@service/limit-service/verification/processor"
5+
import { ElMessageBox, ElMessage } from "element-plus"
6+
import { h, VNode } from "vue"
7+
8+
/**
9+
* Judge wether verification is required
10+
*
11+
* @returns T/F
12+
*/
13+
export function judgeVerificationRequired(item: timer.limit.Item): boolean {
14+
const { waste, time } = item || {}
15+
return !!(waste > time * 1000)
16+
}
17+
18+
const PROMT_TXT_CSS: Partial<CSSStyleDeclaration> = {
19+
userSelect: 'none',
20+
}
21+
22+
/**
23+
* @returns null if verification not required,
24+
* or promise with resolve invocked only if verification code or password correct
25+
*/
26+
export async function processVerification(option: timer.option.DailyLimitOption): Promise<void> {
27+
const { limitLevel, limitPassword, limitVerifyDifficulty } = option
28+
let answerValue: string
29+
let messageNodes: (VNode | string)[]
30+
let incrorectMessage: string
31+
if (limitLevel === 'password' && limitPassword) {
32+
answerValue = limitPassword
33+
messageNodes = [t(msg => msg.limit.verification.pswInputTip)]
34+
incrorectMessage = t(msg => msg.limit.verification.incorrectPsw)
35+
} else if (limitLevel === 'verification') {
36+
const pair: VerificationPair = verificationProcessor.generate(limitVerifyDifficulty, locale)
37+
const { prompt, promptParam, answer } = pair || {}
38+
answerValue = typeof answer === 'function' ? t(msg => answer(msg.limit.verification)) : answer
39+
incrorectMessage = t(msg => msg.limit.verification.incorrectAnswer)
40+
if (prompt) {
41+
const promptTxt = typeof prompt === 'function'
42+
? t(msg => prompt(msg.limit.verification), { ...promptParam, answer: answerValue })
43+
: prompt
44+
messageNodes = tN(msg => msg.limit.verification.inputTip, { prompt: h('b', promptTxt) })
45+
} else {
46+
messageNodes = tN(msg => msg.limit.verification.inputTip2, { answer: h('b', answerValue) })
47+
}
48+
}
49+
return messageNodes?.length && answerValue
50+
? new Promise(resolve =>
51+
ElMessageBox({
52+
boxType: 'prompt',
53+
type: 'warning',
54+
title: '',
55+
message: h('div', { style: PROMT_TXT_CSS }, messageNodes),
56+
showInput: true,
57+
showCancelButton: true,
58+
showClose: true,
59+
}).then(data => {
60+
const { value } = data
61+
if (value === answerValue) {
62+
return resolve()
63+
}
64+
ElMessage.error(incrorectMessage)
65+
})
66+
)
67+
: null
68+
}

src/app/components/limit/table/column/delay.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,24 @@ import { InfoFilled } from "@element-plus/icons-vue"
99
import { ElIcon, ElSwitch, ElTableColumn, ElTooltip } from "element-plus"
1010
import { defineComponent, h } from "vue"
1111
import { t } from "@app/locale"
12+
import { judgeVerificationRequired, processVerification } from "./common"
13+
import optionService from "@service/option-service"
1214

1315
const label = t(msg => msg.limit.item.delayAllowed)
1416
const tooltip = t(msg => msg.limit.item.delayAllowedInfo)
1517

18+
async function handleChange(row: timer.limit.Item, newVal: boolean, callback: () => void) {
19+
let promise: Promise<void> = null
20+
if (newVal && judgeVerificationRequired(row)) {
21+
// Open delay for limited rules, so verification is required
22+
const option = await optionService.getAllOption()
23+
promise = processVerification(option)
24+
}
25+
promise
26+
? promise.then(callback).catch(() => { })
27+
: callback()
28+
}
29+
1630
const _default = defineComponent({
1731
name: "LimitDelayColumn",
1832
emits: {
@@ -26,10 +40,10 @@ const _default = defineComponent({
2640
}, {
2741
default: ({ row }: { row: timer.limit.Item }) => h(ElSwitch, {
2842
modelValue: row.allowDelay,
29-
onChange(val: boolean) {
43+
onChange: (val: boolean) => handleChange(row, val, () => {
3044
row.allowDelay = val
3145
ctx.emit("rowChange", row, val)
32-
}
46+
})
3347
}),
3448
header: () => h('div', [
3549
label,

src/app/components/limit/table/column/enabled.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,23 @@
88
import { ElSwitch, ElTableColumn } from "element-plus"
99
import { defineComponent, h } from "vue"
1010
import { t } from "@app/locale"
11+
import { judgeVerificationRequired, processVerification } from "./common"
12+
import optionService from "@service/option-service"
1113

1214
const label = t(msg => msg.limit.item.enabled)
1315

16+
async function handleChange(row: timer.limit.Item, newVal: boolean, callback: () => void) {
17+
let promise: Promise<void> = null
18+
if (!newVal && judgeVerificationRequired(row)) {
19+
// Disable limited rules, so verification is required
20+
const option = await optionService.getAllOption()
21+
promise = processVerification(option)
22+
}
23+
promise
24+
? promise.then(callback).catch(() => { })
25+
: callback()
26+
}
27+
1428
const _default = defineComponent({
1529
name: "LimitEnabledColumn",
1630
emits: {
@@ -25,10 +39,10 @@ const _default = defineComponent({
2539
}, {
2640
default: ({ row }: { row: timer.limit.Item }) => h(ElSwitch, {
2741
modelValue: row.enabled,
28-
onChange(val: boolean) {
42+
onChange: (val: boolean) => handleChange(row, val, () => {
2943
row.enabled = val
3044
ctx.emit("rowChange", row, val)
31-
}
45+
})
3246
})
3347
})
3448
}

src/app/components/limit/table/column/operation.ts

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,40 @@ import { Delete, Edit } from "@element-plus/icons-vue"
99
import { ElButton, ElMessageBox, ElTableColumn } from "element-plus"
1010
import { defineComponent, h } from "vue"
1111
import { t } from "@app/locale"
12+
import optionService from "@service/option-service"
13+
import { judgeVerificationRequired, processVerification } from "./common"
1214

1315
const label = t(msg => msg.limit.item.operation)
1416
const deleteButtonText = t(msg => msg.button.delete)
1517
const modifyButtonText = t(msg => msg.button.modify)
18+
19+
async function handleDelete(row: timer.limit.Item, callback: () => void) {
20+
let promise = undefined
21+
if (judgeVerificationRequired(row)) {
22+
const option = await optionService.getAllOption() as timer.option.DailyLimitOption
23+
promise = processVerification(option)
24+
}
25+
if (!promise) {
26+
const message = t(msg => msg.limit.message.deleteConfirm, { cond: row.cond })
27+
promise = ElMessageBox.confirm(message, { type: 'warning' })
28+
}
29+
promise.then(callback).catch(() => { /** Do nothing */ })
30+
}
31+
32+
async function handleModify(row: timer.limit.Item, callback: () => void) {
33+
let promise: Promise<void> = undefined
34+
if (judgeVerificationRequired(row)) {
35+
const option = await optionService.getAllOption() as timer.option.DailyLimitOption
36+
promise = processVerification(option)
37+
promise
38+
? promise.then(callback).catch(() => { })
39+
: callback()
40+
} else {
41+
callback()
42+
}
43+
}
44+
1645
const _default = defineComponent({
17-
name: "LimitOperationColumn",
1846
emits: {
1947
rowDelete: (_row: timer.limit.Item, _cond: string) => true,
2048
rowModify: (_row: timer.limit.Item) => true,
@@ -31,19 +59,13 @@ const _default = defineComponent({
3159
type: 'danger',
3260
size: 'small',
3361
icon: Delete,
34-
onClick() {
35-
const { cond } = row
36-
const message = t(msg => msg.limit.message.deleteConfirm, { cond })
37-
ElMessageBox.confirm(message, { type: 'warning' })
38-
.then(() => ctx.emit("rowDelete", row, cond))
39-
.catch(() => { /** Do nothing */ })
40-
}
62+
onClick: () => handleDelete(row, () => ctx.emit("rowDelete", row, row.cond))
4163
}, () => deleteButtonText),
4264
h(ElButton, {
4365
type: 'primary',
4466
size: 'small',
4567
icon: Edit,
46-
onClick: () => ctx.emit('rowModify', row),
68+
onClick: () => handleModify(row, () => ctx.emit('rowModify', row)),
4769
}, () => modifyButtonText)
4870
]
4971
})

src/app/components/limit/table/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import LimitEnabledColumn from "./column/enabled"
1515
import LimitOperationColumn from "./column/operation"
1616

1717
const _default = defineComponent({
18-
name: "LimitTable",
1918
props: {
2019
data: Array as PropType<timer.limit.Item[]>
2120
},

0 commit comments

Comments
 (0)