附录A全接入:7新页面+路由菜单+库存大盘抽屉 / P1-2真机非法值拦截全绿 / 文档终版510+514
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user