feat(settings): AccountSettingNotification

- 增加防抖。
- `card` 从父组件获取到的值改为深复制,解决 `card` 内修改数据,会直接导致在父组件中同步更新的问题。
- 微调图标位置。
This commit is contained in:
Aqr-K
2024-10-31 16:46:05 +08:00
parent c90ed003f7
commit eab2f0df20
2 changed files with 36 additions and 27 deletions
@@ -7,6 +7,7 @@ import synologychat_image from '@images/logos/synologychat.png'
import slack_image from '@images/logos/slack.webp' import slack_image from '@images/logos/slack.webp'
import chrome_image from '@images/logos/chrome.png' import chrome_image from '@images/logos/chrome.png'
import { useToast } from 'vue-toast-notification' import { useToast } from 'vue-toast-notification'
import { cloneDeep } from "lodash"
// 定义输入 // 定义输入
const props = defineProps({ const props = defineProps({
@@ -31,9 +32,6 @@ const $toast = useToast()
// 通知详情弹窗 // 通知详情弹窗
const notificationInfoDialog = ref(false) const notificationInfoDialog = ref(false)
// 通知名称
const notificationName = ref('')
// 通知详情 // 通知详情
const notificationInfo = ref<NotificationConf>({ const notificationInfo = ref<NotificationConf>({
name: '', name: '',
@@ -66,26 +64,26 @@ const notificationTypes = [
// 打开详情弹窗 // 打开详情弹窗
function openNotificationInfoDialog() { function openNotificationInfoDialog() {
notificationInfo.value = props.notification // 替换成深复制,避免修改时影响原数据
notificationName.value = props.notification.name notificationInfo.value = cloneDeep(props.notification)
console.log(`当前卡片的通知信息:${JSON.stringify(notificationInfo.value)}`)
notificationInfoDialog.value = true notificationInfoDialog.value = true
} }
// 保存详情数据 // 保存详情数据
function saveNotificationInfo() { function saveNotificationInfo() {
// 为空不保存,跳出警告框 // 为空不保存,跳出警告框
if (!notificationName.value) { if (!notificationInfo.value.name) {
$toast.error('名称不能为空,请输入后再确定') $toast.error('名称不能为空,请输入后再确定')
return return
} }
// 重名判断 // 重名判断
if (props.notifications.some(item => item.name === notificationName.value && item !== props.notification)) { if (props.notifications.some(item => item.name === notificationInfo.value.name && item !== props.notification)) {
$toast.error(`${notificationName.value}】已存在,请替换为其他名称`) $toast.error(`通知渠道${notificationInfo.value.name}】已存在,请替换`)
return return
} }
notificationInfoDialog.value = false notificationInfoDialog.value = false
notificationInfo.value.name = notificationName.value emit('change', notificationInfo.value, props.notification.name)
emit('change', notificationInfo.value)
emit('done') emit('done')
} }
@@ -131,7 +129,7 @@ function onClose() {
</div> </div>
<div class="text-body-1 mb-3">{{ notificationTypeNames[notification.type] }}</div> <div class="text-body-1 mb-3">{{ notificationTypeNames[notification.type] }}</div>
</div> </div>
<VImg :src="getIcon" cover class="mt-5 me-7" max-width="3rem" /> <VImg :src="getIcon" cover class="mt-7 me-7" max-width="3rem" />
</VCardText> </VCardText>
</VCard> </VCard>
<VDialog v-model="notificationInfoDialog" scrollable max-width="40rem" persistent> <VDialog v-model="notificationInfoDialog" scrollable max-width="40rem" persistent>
@@ -160,7 +158,7 @@ function onClose() {
<VRow v-if="notificationInfo.type == 'wechat'"> <VRow v-if="notificationInfo.type == 'wechat'">
<VCol cols="12" md="6"> <VCol cols="12" md="6">
<VTextField <VTextField
v-model="notificationName" v-model="notificationInfo.name"
label="名称" label="名称"
placeholder="别名" placeholder="别名"
hint="通知渠道的别名" hint="通知渠道的别名"
@@ -228,7 +226,7 @@ function onClose() {
<VRow v-if="notificationInfo.type == 'telegram'"> <VRow v-if="notificationInfo.type == 'telegram'">
<VCol cols="12" md="6"> <VCol cols="12" md="6">
<VTextField <VTextField
v-model="notificationName" v-model="notificationInfo.name"
label="名称" label="名称"
placeholder="别名" placeholder="别名"
hint="通知渠道的别名" hint="通知渠道的别名"
@@ -273,7 +271,7 @@ function onClose() {
<VRow v-if="notificationInfo.type == 'slack'"> <VRow v-if="notificationInfo.type == 'slack'">
<VCol cols="12" md="6"> <VCol cols="12" md="6">
<VTextField <VTextField
v-model="notificationName" v-model="notificationInfo.name"
label="名称" label="名称"
placeholder="别名" placeholder="别名"
hint="通知渠道的别名" hint="通知渠道的别名"
@@ -311,7 +309,7 @@ function onClose() {
<VRow v-if="notificationInfo.type == 'synologychat'"> <VRow v-if="notificationInfo.type == 'synologychat'">
<VCol cols="12" md="6"> <VCol cols="12" md="6">
<VTextField <VTextField
v-model="notificationName" v-model="notificationInfo.name"
label="名称" label="名称"
placeholder="别名" placeholder="别名"
hint="通知渠道的别名" hint="通知渠道的别名"
@@ -338,7 +336,7 @@ function onClose() {
<VRow v-if="notificationInfo.type == 'vocechat'"> <VRow v-if="notificationInfo.type == 'vocechat'">
<VCol cols="12" md="6"> <VCol cols="12" md="6">
<VTextField <VTextField
v-model="notificationName" v-model="notificationInfo.name"
label="名称" label="名称"
placeholder="别名" placeholder="别名"
hint="通知渠道的别名" hint="通知渠道的别名"
@@ -374,7 +372,7 @@ function onClose() {
<VRow v-if="notificationInfo.type == 'webpush'"> <VRow v-if="notificationInfo.type == 'webpush'">
<VCol cols="12" md="6"> <VCol cols="12" md="6">
<VTextField <VTextField
v-model="notificationName" v-model="notificationInfo.name"
label="名称" label="名称"
placeholder="别名" placeholder="别名"
hint="通知渠道的别名" hint="通知渠道的别名"
@@ -4,10 +4,14 @@ import api from '@/api'
import draggable from 'vuedraggable' import draggable from 'vuedraggable'
import type { NotificationConf, NotificationSwitchConf } from '@/api/types' import type { NotificationConf, NotificationSwitchConf } from '@/api/types'
import NotificationChannelCard from '@/components/cards/NotificationChannelCard.vue' import NotificationChannelCard from '@/components/cards/NotificationChannelCard.vue'
import debounce from 'lodash/debounce'
// 所有消息渠道 // 所有消息渠道
const notifications = ref<NotificationConf[]>([]) const notifications = ref<NotificationConf[]>([])
// 防抖时间
const debounceTime = 500
// 提示框 // 提示框
const $toast = useToast() const $toast = useToast()
@@ -58,8 +62,8 @@ async function reloadSystem() {
} }
} }
// 添加媒体服务器 // 添加通知渠道
function addNotification(notification: string) { const addNotification = debounce((notification: string) => {
let name = `通知${notifications.value.length + 1}`; let name = `通知${notifications.value.length + 1}`;
while (notifications.value.some(item => item.name === name)) { while (notifications.value.some(item => item.name === name)) {
name = `通知${parseInt(name.split('通知')[1]) + 1}`; name = `通知${parseInt(name.split('通知')[1]) + 1}`;
@@ -70,15 +74,15 @@ function addNotification(notification: string) {
enabled: false, enabled: false,
config: {}, config: {},
}) })
} }, debounceTime)
// 移除媒体服务器 // 移除通知渠道
function removeNotification(notification: NotificationConf) { function removeNotification(notification: NotificationConf) {
const index = notifications.value.indexOf(notification) const index = notifications.value.indexOf(notification)
if (index > -1) notifications.value.splice(index, 1) if (index > -1) notifications.value.splice(index, 1)
} }
// 调用API查询通知设置 // 调用API查询通知渠道设置
async function loadNotificationSetting() { async function loadNotificationSetting() {
try { try {
const result: { [key: string]: any } = await api.get('system/setting/Notifications') const result: { [key: string]: any } = await api.get('system/setting/Notifications')
@@ -89,7 +93,7 @@ async function loadNotificationSetting() {
} }
// 调用API保存通知设置 // 调用API保存通知设置
async function saveNotificationSetting() { const saveNotificationSetting = debounce(async () => {
try { try {
const result: { [key: string]: any } = await api.post('system/setting/Notifications', notifications.value) const result: { [key: string]: any } = await api.post('system/setting/Notifications', notifications.value)
if (result.success) { if (result.success) {
@@ -99,6 +103,12 @@ async function saveNotificationSetting() {
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} }
}, debounceTime)
// 通知渠道设置变化时赋值
function changNotificationSetting(notification: NotificationConf, name: string) {
const index = notifications.value.findIndex(item => item.name === name)
if (index !== -1) notifications.value[index] = notification
} }
// 加载消息类型开关 // 加载消息类型开关
@@ -112,7 +122,7 @@ async function loadNotificationSwitchs() {
} }
// 保存消息类型开关 // 保存消息类型开关
async function saveNotificationSwitchs() { const saveNotificationSwitchs = debounce(async () => {
try { try {
const result: { [key: string]: any } = await api.post( const result: { [key: string]: any } = await api.post(
'system/setting/NotificationSwitchs', 'system/setting/NotificationSwitchs',
@@ -123,7 +133,7 @@ async function saveNotificationSwitchs() {
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} }
} }, debounceTime)
// 加载数据 // 加载数据
onMounted(() => { onMounted(() => {
@@ -152,6 +162,7 @@ onMounted(() => {
<NotificationChannelCard <NotificationChannelCard
:notification="element" :notification="element"
:notifications="notifications" :notifications="notifications"
@change="changNotificationSetting"
@close="removeNotification(element)" @close="removeNotification(element)"
/> />
</template> </template>
@@ -161,7 +172,7 @@ onMounted(() => {
<VForm @submit.prevent="() => {}"> <VForm @submit.prevent="() => {}">
<div class="d-flex flex-wrap gap-4 mt-4"> <div class="d-flex flex-wrap gap-4 mt-4">
<VBtn mtype="submit" @click="saveNotificationSetting"> 保存 </VBtn> <VBtn mtype="submit" @click="saveNotificationSetting"> 保存 </VBtn>
<VBtn color="success" variant="tonal" @click=""> <VBtn color="success" variant="tonal">
<VIcon icon="mdi-plus" /> <VIcon icon="mdi-plus" />
<VMenu activator="parent" close-on-content-click> <VMenu activator="parent" close-on-content-click>
<VList> <VList>
@@ -225,7 +236,7 @@ onMounted(() => {
<VCardText> <VCardText>
<VForm @submit.prevent="() => {}"> <VForm @submit.prevent="() => {}">
<div class="d-flex flex-wrap gap-4 mt-4"> <div class="d-flex flex-wrap gap-4 mt-4">
<VBtn mtype="submit" @click="saveNotificationSwitchs"> 保存 </VBtn> <VBtn type="submit" @click="saveNotificationSwitchs"> 保存 </VBtn>
</div> </div>
</VForm> </VForm>
</VCardText> </VCardText>