mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-27 11:19:45 +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 } = {
|
||||
wechat: t('notification.wechat.name'),
|
||||
telegram: t('notification.telegram.name'),
|
||||
qqbot: t('notification.qqbot.name'),
|
||||
vocechat: t('notification.vocechat.name'),
|
||||
synologychat: t('notification.synologychat.name'),
|
||||
slack: t('notification.slack.name'),
|
||||
@@ -97,6 +98,8 @@ const getIcon = computed(() => {
|
||||
return getLogoUrl('wechat')
|
||||
case 'telegram':
|
||||
return getLogoUrl('telegram')
|
||||
case 'qqbot':
|
||||
return getLogoUrl('notification')
|
||||
case 'vocechat':
|
||||
return getLogoUrl('vocechat')
|
||||
case 'synologychat':
|
||||
@@ -464,6 +467,56 @@ function onClose() {
|
||||
/>
|
||||
</VCol>
|
||||
</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'">
|
||||
<VCol cols="12" md="6">
|
||||
<VTextField
|
||||
|
||||
@@ -487,6 +487,16 @@ export function useSetupWizard() {
|
||||
validationErrors.value.notification.VOCECHAT_API_KEY = true
|
||||
}
|
||||
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 {
|
||||
|
||||
@@ -521,6 +521,21 @@ export default {
|
||||
usernameHint: 'Only push messages to the corresponding logged-in user',
|
||||
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: {
|
||||
title: 'Shortcuts',
|
||||
@@ -1597,6 +1612,7 @@ export default {
|
||||
synologyChat: 'SynologyChat',
|
||||
voceChat: 'VoceChat',
|
||||
webPush: 'WebPush',
|
||||
qq: 'QQ',
|
||||
custom: 'Custom Notification',
|
||||
},
|
||||
words: {
|
||||
|
||||
@@ -518,6 +518,21 @@ export default {
|
||||
usernameHint: '只有对应的用户登录后才会推送消息',
|
||||
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: {
|
||||
title: '捷径',
|
||||
@@ -1581,6 +1596,7 @@ export default {
|
||||
synologyChat: 'SynologyChat',
|
||||
voceChat: 'VoceChat',
|
||||
webPush: 'WebPush',
|
||||
qq: 'QQ',
|
||||
custom: '自定义通知',
|
||||
},
|
||||
words: {
|
||||
|
||||
@@ -518,6 +518,21 @@ export default {
|
||||
usernameHint: '只有對應的用戶登錄後才會推送消息',
|
||||
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: {
|
||||
title: '捷徑',
|
||||
@@ -1582,6 +1597,7 @@ export default {
|
||||
synologyChat: 'SynologyChat',
|
||||
voceChat: 'VoceChat',
|
||||
webPush: 'WebPush',
|
||||
qq: 'QQ',
|
||||
custom: '自定義通知',
|
||||
},
|
||||
words: {
|
||||
|
||||
@@ -300,6 +300,9 @@ onMounted(() => {
|
||||
<VListItem @click="addNotification('synologychat')">
|
||||
<VListItemTitle>{{ t('setting.notification.synologyChat') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem @click="addNotification('qqbot')">
|
||||
<VListItemTitle>{{ t('setting.notification.qq') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem @click="addNotification('vocechat')">
|
||||
<VListItemTitle>{{ t('setting.notification.voceChat') }}</VListItemTitle>
|
||||
</VListItem>
|
||||
|
||||
@@ -91,6 +91,19 @@ const notificationTypes = [
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</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">
|
||||
<VCard
|
||||
:color="wizardData.notification.type === 'vocechat' ? 'primary' : 'default'"
|
||||
@@ -312,6 +325,59 @@ const notificationTypes = [
|
||||
/>
|
||||
</VCol>
|
||||
</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'">
|
||||
<VCol cols="12" md="6">
|
||||
<VTextField
|
||||
|
||||
Reference in New Issue
Block a user