Files
dealerhub/frontend/src/pages/AlertRules.vue
T

159 lines
5.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<el-card shadow="never">
<div class="toolbar">
<el-input v-model="search" placeholder="搜索规则编码/名称" style="width: 240px" clearable @keyup.enter="load" />
<el-button type="primary" @click="load">查询</el-button>
<el-button @click="initDefault" :loading="initting">初始化默认规则</el-button>
<el-button type="primary" @click="openCreate">新建规则</el-button>
</div>
<el-table :data="rows" v-loading="loading" size="small" stripe>
<el-table-column prop="code" label="规则编码" width="150" />
<el-table-column prop="name" label="规则名称" min-width="160" />
<el-table-column prop="rule_type_name" label="类型" width="200" />
<el-table-column prop="threshold" label="阈值" width="110" />
<el-table-column label="启用" width="90">
<template #default="{ row }">
<el-switch v-model="row.is_enabled" @change="toggle(row)" />
</template>
</el-table-column>
<el-table-column label="操作" width="150">
<template #default="{ row }">
<el-button link type="primary" size="small" @click="openEdit(row)">编辑</el-button>
<el-button link type="danger" size="small" @click="remove(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
style="margin-top: 14px"
layout="prev, pager, next, total"
:total="count"
:page-size="pageSize"
v-model:current-page="page"
@current-change="load"
/>
<el-dialog v-model="dialogVisible" :title="editing ? '编辑预警规则' : '新建预警规则'" width="520px">
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="规则编码" prop="code"><el-input v-model="form.code" /></el-form-item>
<el-form-item label="规则名称" prop="name"><el-input v-model="form.name" /></el-form-item>
<el-form-item label="规则类型" prop="rule_type">
<el-select v-model="form.rule_type" style="width: 100%">
<el-option label="库存缺货/下限预警" value="inventory_low" />
<el-option label="应收账款逾期催款预警" value="receivable_overdue" />
<el-option label="商品呆滞积压预警" value="stock_backlog" />
<el-option label="批次近效期预警" value="batch_expiry" />
<el-option label="AI 应收风险预警" value="risk_score" />
</el-select>
</el-form-item>
<el-form-item label="阈值" prop="threshold">
<el-input-number v-model="form.threshold" :min="0" :precision="2" style="width: 100%" />
</el-form-item>
<el-form-item label="启用" prop="is_enabled"><el-switch v-model="form.is_enabled" /></el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="saving" @click="save">保存</el-button>
</template>
</el-dialog>
</el-card>
</template>
<script setup>
import { onMounted, ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import api from '../api/client'
const rows = ref([])
const count = ref(0)
const page = ref(1)
const pageSize = 20
const search = ref('')
const loading = ref(false)
const initting = ref(false)
const saving = ref(false)
const dialogVisible = ref(false)
const editing = ref(null)
const formRef = ref(null)
const form = reactive({ code: '', name: '', rule_type: 'inventory_low', threshold: 10, is_enabled: true })
const rules = {
code: [{ required: true, message: '请输入规则编码', trigger: 'blur' }],
name: [{ required: true, message: '请输入规则名称', trigger: 'blur' }],
rule_type: [{ required: true, message: '请选择规则类型', trigger: 'change' }],
threshold: [{ required: true, message: '请输入阈值', trigger: 'blur' }],
}
async function load() {
loading.value = true
try {
const data = await api.get('/notify/rules/', {
params: { page: page.value, page_size: pageSize, search: search.value },
})
rows.value = data.results || []
count.value = data.count || 0
} finally {
loading.value = false
}
}
async function initDefault() {
initting.value = true
try {
const data = await api.post('/notify/rules/init-default/', {})
ElMessage.success(`已初始化 ${data.created_count} 条默认规则`)
await load()
} finally {
initting.value = false
}
}
function openCreate() {
editing.value = null
Object.assign(form, { code: '', name: '', rule_type: 'inventory_low', threshold: 10, is_enabled: true })
dialogVisible.value = true
}
function openEdit(row) {
editing.value = row
Object.assign(form, { code: row.code, name: row.name, rule_type: row.rule_type, threshold: Number(row.threshold), is_enabled: row.is_enabled })
dialogVisible.value = true
}
async function save() {
const ok = await formRef.value.validate().catch(() => false)
if (!ok) return
saving.value = true
try {
if (editing.value) await api.patch(`/notify/rules/${editing.value.id}/`, { ...form })
else await api.post('/notify/rules/', { ...form })
ElMessage.success('已保存')
dialogVisible.value = false
await load()
} finally {
saving.value = false
}
}
async function toggle(row) {
try {
await api.patch(`/notify/rules/${row.id}/`, { is_enabled: row.is_enabled })
} catch (e) { row.is_enabled = !row.is_enabled }
}
async function remove(row) {
try {
await ElMessageBox.confirm(`删除规则 ${row.code}(${row.name})?`, '删除确认', { type: 'warning' })
} catch (e) { return }
await api.delete(`/notify/rules/${row.id}/`)
ElMessage.success('已删除')
await load()
}
onMounted(load)
</script>
<style scoped>
.toolbar { display: flex; gap: 10px; margin-bottom: 14px; align-items: center; }
</style>