mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 23:56:42 +08:00
feat: add QQ notification channel support with validation and localization
This commit is contained in:
@@ -46,6 +46,7 @@ const notificationInfo = ref<NotificationConf>({
|
|||||||
const notificationTypeNames: { [key: string]: string } = {
|
const notificationTypeNames: { [key: string]: string } = {
|
||||||
wechat: t('notification.wechat.name'),
|
wechat: t('notification.wechat.name'),
|
||||||
telegram: t('notification.telegram.name'),
|
telegram: t('notification.telegram.name'),
|
||||||
|
qqbot: t('notification.qqbot.name'),
|
||||||
vocechat: t('notification.vocechat.name'),
|
vocechat: t('notification.vocechat.name'),
|
||||||
synologychat: t('notification.synologychat.name'),
|
synologychat: t('notification.synologychat.name'),
|
||||||
slack: t('notification.slack.name'),
|
slack: t('notification.slack.name'),
|
||||||
@@ -97,6 +98,8 @@ const getIcon = computed(() => {
|
|||||||
return getLogoUrl('wechat')
|
return getLogoUrl('wechat')
|
||||||
case 'telegram':
|
case 'telegram':
|
||||||
return getLogoUrl('telegram')
|
return getLogoUrl('telegram')
|
||||||
|
case 'qqbot':
|
||||||
|
return getLogoUrl('notification')
|
||||||
case 'vocechat':
|
case 'vocechat':
|
||||||
return getLogoUrl('vocechat')
|
return getLogoUrl('vocechat')
|
||||||
case 'synologychat':
|
case 'synologychat':
|
||||||
@@ -464,6 +467,56 @@ function onClose() {
|
|||||||
/>
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
|
<VRow v-else-if="notificationInfo.type == 'qqbot'">
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VTextField
|
||||||
|
v-model="notificationInfo.name"
|
||||||
|
:label="t('notification.name')"
|
||||||
|
:placeholder="t('notification.name')"
|
||||||
|
:hint="t('notification.nameHint')"
|
||||||
|
persistent-hint
|
||||||
|
prepend-inner-icon="mdi-label"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VTextField
|
||||||
|
v-model="notificationInfo.config.QQ_APP_ID"
|
||||||
|
:label="t('notification.qqbot.appId')"
|
||||||
|
:hint="t('notification.qqbot.appIdHint')"
|
||||||
|
persistent-hint
|
||||||
|
prepend-inner-icon="mdi-application"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VTextField
|
||||||
|
v-model="notificationInfo.config.QQ_APP_SECRET"
|
||||||
|
:label="t('notification.qqbot.appSecret')"
|
||||||
|
:hint="t('notification.qqbot.appSecretHint')"
|
||||||
|
persistent-hint
|
||||||
|
prepend-inner-icon="mdi-key"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VTextField
|
||||||
|
v-model="notificationInfo.config.QQ_OPENID"
|
||||||
|
:label="t('notification.qqbot.openId')"
|
||||||
|
:placeholder="t('notification.qqbot.openIdPlaceholder')"
|
||||||
|
:hint="t('notification.qqbot.openIdHint')"
|
||||||
|
persistent-hint
|
||||||
|
prepend-inner-icon="mdi-account"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VTextField
|
||||||
|
v-model="notificationInfo.config.QQ_GROUP_OPENID"
|
||||||
|
:label="t('notification.qqbot.groupOpenId')"
|
||||||
|
:placeholder="t('notification.qqbot.groupOpenIdPlaceholder')"
|
||||||
|
:hint="t('notification.qqbot.groupOpenIdHint')"
|
||||||
|
persistent-hint
|
||||||
|
prepend-inner-icon="mdi-account-group"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
<VRow v-else-if="notificationInfo.type == 'webpush'">
|
<VRow v-else-if="notificationInfo.type == 'webpush'">
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VTextField
|
<VTextField
|
||||||
|
|||||||
@@ -487,6 +487,16 @@ export function useSetupWizard() {
|
|||||||
validationErrors.value.notification.VOCECHAT_API_KEY = true
|
validationErrors.value.notification.VOCECHAT_API_KEY = true
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case 'qqbot':
|
||||||
|
if (!config.QQ_APP_ID?.trim()) {
|
||||||
|
errors.push(t('notification.qqbot.appIdRequired'))
|
||||||
|
validationErrors.value.notification.QQ_APP_ID = true
|
||||||
|
}
|
||||||
|
if (!config.QQ_APP_SECRET?.trim()) {
|
||||||
|
errors.push(t('notification.qqbot.appSecretRequired'))
|
||||||
|
validationErrors.value.notification.QQ_APP_SECRET = true
|
||||||
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -521,6 +521,21 @@ export default {
|
|||||||
usernameHint: 'Only push messages to the corresponding logged-in user',
|
usernameHint: 'Only push messages to the corresponding logged-in user',
|
||||||
usernameRequired: 'Username cannot be empty',
|
usernameRequired: 'Username cannot be empty',
|
||||||
},
|
},
|
||||||
|
qqbot: {
|
||||||
|
name: 'QQ',
|
||||||
|
appId: 'App ID',
|
||||||
|
appIdHint: 'QQ Open Platform bot App ID',
|
||||||
|
appIdRequired: 'App ID cannot be empty',
|
||||||
|
appSecret: 'App Secret',
|
||||||
|
appSecretHint: 'QQ Open Platform bot App Secret',
|
||||||
|
appSecretRequired: 'App Secret cannot be empty',
|
||||||
|
openId: 'User OpenID',
|
||||||
|
openIdHint: 'Default recipient openid (C2C), user must have interacted with bot before',
|
||||||
|
openIdPlaceholder: '32-char hex',
|
||||||
|
groupOpenId: 'Group OpenID',
|
||||||
|
groupOpenIdHint: 'Default group openid (group chat), use either this or User OpenID',
|
||||||
|
groupOpenIdPlaceholder: 'Group openid',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
shortcut: {
|
shortcut: {
|
||||||
title: 'Shortcuts',
|
title: 'Shortcuts',
|
||||||
@@ -1597,6 +1612,7 @@ export default {
|
|||||||
synologyChat: 'SynologyChat',
|
synologyChat: 'SynologyChat',
|
||||||
voceChat: 'VoceChat',
|
voceChat: 'VoceChat',
|
||||||
webPush: 'WebPush',
|
webPush: 'WebPush',
|
||||||
|
qq: 'QQ',
|
||||||
custom: 'Custom Notification',
|
custom: 'Custom Notification',
|
||||||
},
|
},
|
||||||
words: {
|
words: {
|
||||||
|
|||||||
@@ -518,6 +518,21 @@ export default {
|
|||||||
usernameHint: '只有对应的用户登录后才会推送消息',
|
usernameHint: '只有对应的用户登录后才会推送消息',
|
||||||
usernameRequired: '用户名不能为空',
|
usernameRequired: '用户名不能为空',
|
||||||
},
|
},
|
||||||
|
qqbot: {
|
||||||
|
name: 'QQ',
|
||||||
|
appId: 'AppID',
|
||||||
|
appIdHint: 'QQ 开放平台机器人 AppID',
|
||||||
|
appIdRequired: 'AppID 不能为空',
|
||||||
|
appSecret: 'AppSecret',
|
||||||
|
appSecretHint: 'QQ 开放平台机器人 AppSecret',
|
||||||
|
appSecretRequired: 'AppSecret 不能为空',
|
||||||
|
openId: '用户 OpenID',
|
||||||
|
openIdHint: '默认接收者 openid(单聊),用户需曾与机器人交互过',
|
||||||
|
openIdPlaceholder: '32位十六进制',
|
||||||
|
groupOpenId: '群组 OpenID',
|
||||||
|
groupOpenIdHint: '默认群组 openid(群聊),与用户 OpenID 二选一',
|
||||||
|
groupOpenIdPlaceholder: '群组 openid',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
shortcut: {
|
shortcut: {
|
||||||
title: '捷径',
|
title: '捷径',
|
||||||
@@ -1581,6 +1596,7 @@ export default {
|
|||||||
synologyChat: 'SynologyChat',
|
synologyChat: 'SynologyChat',
|
||||||
voceChat: 'VoceChat',
|
voceChat: 'VoceChat',
|
||||||
webPush: 'WebPush',
|
webPush: 'WebPush',
|
||||||
|
qq: 'QQ',
|
||||||
custom: '自定义通知',
|
custom: '自定义通知',
|
||||||
},
|
},
|
||||||
words: {
|
words: {
|
||||||
|
|||||||
@@ -518,6 +518,21 @@ export default {
|
|||||||
usernameHint: '只有對應的用戶登錄後才會推送消息',
|
usernameHint: '只有對應的用戶登錄後才會推送消息',
|
||||||
usernameRequired: '用戶名不能為空',
|
usernameRequired: '用戶名不能為空',
|
||||||
},
|
},
|
||||||
|
qqbot: {
|
||||||
|
name: 'QQ',
|
||||||
|
appId: 'AppID',
|
||||||
|
appIdHint: 'QQ 開放平台機器人 AppID',
|
||||||
|
appIdRequired: 'AppID 不能為空',
|
||||||
|
appSecret: 'AppSecret',
|
||||||
|
appSecretHint: 'QQ 開放平台機器人 AppSecret',
|
||||||
|
appSecretRequired: 'AppSecret 不能為空',
|
||||||
|
openId: '用戶 OpenID',
|
||||||
|
openIdHint: '默認接收者 openid(單聊),用戶需曾與機器人交互過',
|
||||||
|
openIdPlaceholder: '32位十六進制',
|
||||||
|
groupOpenId: '群組 OpenID',
|
||||||
|
groupOpenIdHint: '默認群組 openid(群聊),與用戶 OpenID 二選一',
|
||||||
|
groupOpenIdPlaceholder: '群組 openid',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
shortcut: {
|
shortcut: {
|
||||||
title: '捷徑',
|
title: '捷徑',
|
||||||
@@ -1582,6 +1597,7 @@ export default {
|
|||||||
synologyChat: 'SynologyChat',
|
synologyChat: 'SynologyChat',
|
||||||
voceChat: 'VoceChat',
|
voceChat: 'VoceChat',
|
||||||
webPush: 'WebPush',
|
webPush: 'WebPush',
|
||||||
|
qq: 'QQ',
|
||||||
custom: '自定義通知',
|
custom: '自定義通知',
|
||||||
},
|
},
|
||||||
words: {
|
words: {
|
||||||
|
|||||||
@@ -300,6 +300,9 @@ onMounted(() => {
|
|||||||
<VListItem @click="addNotification('synologychat')">
|
<VListItem @click="addNotification('synologychat')">
|
||||||
<VListItemTitle>{{ t('setting.notification.synologyChat') }}</VListItemTitle>
|
<VListItemTitle>{{ t('setting.notification.synologyChat') }}</VListItemTitle>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
|
<VListItem @click="addNotification('qqbot')">
|
||||||
|
<VListItemTitle>{{ t('setting.notification.qq') }}</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
<VListItem @click="addNotification('vocechat')">
|
<VListItem @click="addNotification('vocechat')">
|
||||||
<VListItemTitle>{{ t('setting.notification.voceChat') }}</VListItemTitle>
|
<VListItemTitle>{{ t('setting.notification.voceChat') }}</VListItemTitle>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
|
|||||||
@@ -91,6 +91,19 @@ const notificationTypes = [
|
|||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VCol>
|
</VCol>
|
||||||
|
<VCol cols="12" md="3">
|
||||||
|
<VCard
|
||||||
|
:color="wizardData.notification.type === 'qqbot' ? 'primary' : 'default'"
|
||||||
|
:variant="wizardData.notification.type === 'qqbot' ? 'tonal' : 'outlined'"
|
||||||
|
class="cursor-pointer"
|
||||||
|
@click="selectNotification('qqbot')"
|
||||||
|
>
|
||||||
|
<VCardText class="text-center">
|
||||||
|
<VImg :src="getLogoUrl('notification')" height="48" width="48" class="mx-auto mb-2" />
|
||||||
|
<div class="text-h6">QQ</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
<VCol cols="12" md="3">
|
<VCol cols="12" md="3">
|
||||||
<VCard
|
<VCard
|
||||||
:color="wizardData.notification.type === 'vocechat' ? 'primary' : 'default'"
|
:color="wizardData.notification.type === 'vocechat' ? 'primary' : 'default'"
|
||||||
@@ -312,6 +325,59 @@ const notificationTypes = [
|
|||||||
/>
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
|
<VRow v-else-if="wizardData.notification.type === 'qqbot'">
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VTextField
|
||||||
|
v-model="wizardData.notification.name"
|
||||||
|
:label="t('notification.name')"
|
||||||
|
:placeholder="t('notification.name')"
|
||||||
|
:hint="t('notification.nameHint')"
|
||||||
|
:error="validationErrors.notification.name"
|
||||||
|
:error-messages="validationErrors.notification.name ? [t('notification.nameRequired')] : []"
|
||||||
|
persistent-hint
|
||||||
|
prepend-inner-icon="mdi-label"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VTextField
|
||||||
|
v-model="wizardData.notification.config.QQ_APP_ID"
|
||||||
|
:label="t('notification.qqbot.appId')"
|
||||||
|
:hint="t('notification.qqbot.appIdHint')"
|
||||||
|
persistent-hint
|
||||||
|
prepend-inner-icon="mdi-application"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VTextField
|
||||||
|
v-model="wizardData.notification.config.QQ_APP_SECRET"
|
||||||
|
:label="t('notification.qqbot.appSecret')"
|
||||||
|
:hint="t('notification.qqbot.appSecretHint')"
|
||||||
|
persistent-hint
|
||||||
|
prepend-inner-icon="mdi-key"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VTextField
|
||||||
|
v-model="wizardData.notification.config.QQ_OPENID"
|
||||||
|
:label="t('notification.qqbot.openId')"
|
||||||
|
:placeholder="t('notification.qqbot.openIdPlaceholder')"
|
||||||
|
:hint="t('notification.qqbot.openIdHint')"
|
||||||
|
persistent-hint
|
||||||
|
prepend-inner-icon="mdi-account"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VTextField
|
||||||
|
v-model="wizardData.notification.config.QQ_GROUP_OPENID"
|
||||||
|
:label="t('notification.qqbot.groupOpenId')"
|
||||||
|
:placeholder="t('notification.qqbot.groupOpenIdPlaceholder')"
|
||||||
|
:hint="t('notification.qqbot.groupOpenIdHint')"
|
||||||
|
persistent-hint
|
||||||
|
prepend-inner-icon="mdi-account-group"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
<VRow v-else-if="wizardData.notification.type === 'slack'">
|
<VRow v-else-if="wizardData.notification.type === 'slack'">
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VTextField
|
<VTextField
|
||||||
|
|||||||
Reference in New Issue
Block a user