165 lines
3.7 KiB
JavaScript
165 lines
3.7 KiB
JavaScript
/**
|
|
* 通知渠道 Composable
|
|
* 封装列表/统计/详情/CRUD/批量操作,遵循 VNC §5 标准结构。
|
|
*/
|
|
import { ref, computed } from 'vue'
|
|
import {
|
|
getNotificationChannelListApi,
|
|
getNotificationChannelStatsApi,
|
|
getNotificationChannelDetailApi,
|
|
createNotificationChannelApi,
|
|
updateNotificationChannelApi,
|
|
deleteNotificationChannelApi
|
|
} from '@/apis/external-systems/notification_channel_api'
|
|
import { unwrap } from './utils'
|
|
|
|
export function useNotificationChannel() {
|
|
// ===== 响应式状态 =====
|
|
const list = ref([])
|
|
const stats = ref(null)
|
|
const detail = ref(null)
|
|
const total = ref(0)
|
|
const loading = ref(false)
|
|
const detailLoading = ref(false)
|
|
const submitting = ref(false)
|
|
const error = ref(null)
|
|
|
|
// ===== 计算属性 =====
|
|
const isEmpty = computed(() => !loading.value && list.value.length === 0)
|
|
|
|
// ===== 列表与统计 =====
|
|
async function fetchList(params) {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const data = unwrap(await getNotificationChannelListApi(params))
|
|
list.value = data?.items ?? []
|
|
total.value = data?.total ?? list.value.length
|
|
} catch (e) {
|
|
error.value = e
|
|
list.value = []
|
|
total.value = 0
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function fetchStats() {
|
|
error.value = null
|
|
try {
|
|
stats.value = unwrap(await getNotificationChannelStatsApi()) ?? null
|
|
} catch (e) {
|
|
error.value = e
|
|
}
|
|
}
|
|
|
|
// ===== 详情 =====
|
|
async function fetchDetail(id) {
|
|
detailLoading.value = true
|
|
error.value = null
|
|
try {
|
|
detail.value = unwrap(await getNotificationChannelDetailApi(id)) ?? null
|
|
return detail.value
|
|
} catch (e) {
|
|
error.value = e
|
|
throw e
|
|
} finally {
|
|
detailLoading.value = false
|
|
}
|
|
}
|
|
|
|
// ===== CRUD =====
|
|
async function create(data) {
|
|
submitting.value = true
|
|
error.value = null
|
|
try {
|
|
return unwrap(await createNotificationChannelApi(data))
|
|
} catch (e) {
|
|
error.value = e
|
|
throw e
|
|
} finally {
|
|
submitting.value = false
|
|
}
|
|
}
|
|
|
|
async function update(id, data) {
|
|
submitting.value = true
|
|
error.value = null
|
|
try {
|
|
return unwrap(await updateNotificationChannelApi(id, data))
|
|
} catch (e) {
|
|
error.value = e
|
|
throw e
|
|
} finally {
|
|
submitting.value = false
|
|
}
|
|
}
|
|
|
|
async function remove(id) {
|
|
error.value = null
|
|
try {
|
|
await deleteNotificationChannelApi(id)
|
|
} catch (e) {
|
|
error.value = e
|
|
throw e
|
|
}
|
|
}
|
|
|
|
// ===== 批量操作(逐条调用,返回成功/失败明细) =====
|
|
async function batchUpdateEnabled(items, enabled) {
|
|
const results = { success: 0, failed: [] }
|
|
for (const item of items) {
|
|
try {
|
|
await updateNotificationChannelApi(item.id, { enabled })
|
|
results.success += 1
|
|
} catch (e) {
|
|
results.failed.push({ id: item.id, name: item.name, reason: e.message || '更新失败' })
|
|
}
|
|
}
|
|
return results
|
|
}
|
|
|
|
async function batchDelete(items) {
|
|
const results = { success: 0, failed: [] }
|
|
for (const item of items) {
|
|
try {
|
|
await deleteNotificationChannelApi(item.id)
|
|
results.success += 1
|
|
} catch (e) {
|
|
results.failed.push({ id: item.id, name: item.name, reason: e.message || '删除失败' })
|
|
}
|
|
}
|
|
return results
|
|
}
|
|
|
|
function resetDetail() {
|
|
detail.value = null
|
|
}
|
|
|
|
return {
|
|
// 状态
|
|
list,
|
|
stats,
|
|
detail,
|
|
total,
|
|
loading,
|
|
detailLoading,
|
|
submitting,
|
|
error,
|
|
isEmpty,
|
|
// 列表与统计
|
|
fetchList,
|
|
fetchStats,
|
|
// 详情
|
|
fetchDetail,
|
|
resetDetail,
|
|
// CRUD
|
|
create,
|
|
update,
|
|
remove,
|
|
// 批量操作
|
|
batchUpdateEnabled,
|
|
batchDelete
|
|
}
|
|
}
|