| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- <!-- 组件:RuleView;功能:七类规则配置与独立试算;props:无;emit:无。核心规则不可关闭,试算不修改业务单据。 -->
- <script setup lang="ts">
- import { onMounted, ref } from "vue";
- import { ElMessage } from "element-plus";
- import { api, jsonObject, pretty, type Row, type Page } from "../api";
- import { useSession } from "../store";
- import PageHeading from "../components/PageHeading.vue";
- import StatusBadge from "../components/StatusBadge.vue";
- import JsonEvidence from "../components/JsonEvidence.vue";
- const session = useSession(),
- rows = ref<Row[]>([]),
- busy = ref(false),
- dialog = ref(false),
- testDialog = ref(false),
- saving = ref(false),
- current = ref<Row>({}),
- history = ref<Row[]>([]);
- const params = ref("{}"),
- scope = ref("{}"),
- enabled = ref(true),
- severity = ref("error"),
- invoice = ref("{}"),
- context = ref("{}"),
- result = ref<Row | null>(null);
- async function load() {
- busy.value = true;
- try {
- rows.value = (await api<Page>("/rules?page_size=100")).items;
- } catch (error) {
- ElMessage.error((error as Error).message);
- } finally {
- busy.value = false;
- }
- }
- async function edit(row: Row) {
- try {
- const data = await api(`/rules/${row.code}`);
- current.value = data.current;
- history.value = data.history;
- params.value = pretty(data.current.params);
- scope.value = pretty(data.current.scope);
- enabled.value = data.current.enabled;
- severity.value = data.current.severity;
- dialog.value = true;
- } catch (error) {
- ElMessage.error((error as Error).message);
- }
- }
- async function save() {
- saving.value = true;
- try {
- await api(`/rules/${current.value.code}`, "PATCH", {
- expected_version: current.value.version,
- params: jsonObject(params.value),
- scope: jsonObject(scope.value),
- enabled: enabled.value,
- severity: severity.value,
- });
- dialog.value = false;
- await load();
- ElMessage.success("规则新版本已保存");
- } catch (error) {
- ElMessage.error((error as Error).message);
- } finally {
- saving.value = false;
- }
- }
- function openTest(row: Row) {
- current.value = row;
- invoice.value = "{}";
- context.value = "{}";
- result.value = null;
- testDialog.value = true;
- }
- async function test() {
- saving.value = true;
- try {
- result.value = await api(`/rules/${current.value.code}/test`, "POST", {
- invoice: jsonObject(invoice.value),
- context: jsonObject(context.value),
- });
- } catch (error) {
- ElMessage.error((error as Error).message);
- } finally {
- saving.value = false;
- }
- }
- onMounted(load);
- </script>
- <template>
- <PageHeading
- title="审计规则"
- description="参数、严重程度与适用范围均版本化;核心检查不能被关闭或绕过。"
- ><el-button @click="load">刷新</el-button></PageHeading
- ><el-alert
- :closable="false"
- type="info"
- title="税额检查使用发票声明税率;税号长度仅作演示格式检查,不代表税务平台验真。政策合规需要真实制度片段和模型结论。"
- />
- <section class="card">
- <el-table :data="rows" v-loading="busy"
- ><el-table-column
- prop="name"
- label="规则"
- min-width="150"
- /><el-table-column
- prop="code"
- label="标识"
- min-width="230"
- class-name="mono"
- /><el-table-column
- prop="version"
- label="版本"
- width="65"
- /><el-table-column label="严重程度" width="100"
- ><template #default="{ row }"
- ><StatusBadge :value="row.severity" /></template></el-table-column
- ><el-table-column label="启用" width="85"
- ><template #default="{ row }"
- ><el-tag :type="row.enabled ? 'success' : 'info'">{{
- row.enabled ? "生效" : "停用"
- }}</el-tag></template
- ></el-table-column
- ><el-table-column label="参数" min-width="155"
- ><template #default="{ row }"
- ><JsonEvidence
- :value="{ params: row.params, scope: row.scope }"
- title="配置详情" /></template></el-table-column
- ><el-table-column label="操作" min-width="160"
- ><template #default="{ row }"
- ><el-button link type="primary" @click="edit(row)">{{
- session.level >= 4 ? "编辑" : "版本"
- }}</el-button
- ><el-button link type="primary" @click="openTest(row)"
- >试算</el-button
- ></template
- ></el-table-column
- ></el-table
- >
- </section>
- <el-dialog
- v-model="dialog"
- :title="`${current.name || ''} · v${current.version || ''}`"
- width="min(690px,94vw)"
- ><el-form label-position="top"
- ><el-form-item label="生效"
- ><el-switch
- v-model="enabled"
- :disabled="session.level < 4" /></el-form-item
- ><el-form-item label="严重程度"
- ><el-select v-model="severity" :disabled="session.level < 4"
- ><el-option label="警告" value="warning" /><el-option
- label="错误"
- value="error" /><el-option
- label="严重"
- value="critical" /></el-select></el-form-item
- ><el-form-item label="参数(仅允许该规则的白名单字段)"
- ><el-input
- v-model="params"
- class="json-editor"
- type="textarea"
- :rows="7"
- :readonly="session.level < 4" /></el-form-item
- ><el-form-item label="适用范围(departments / types,空对象表示全部)"
- ><el-input
- v-model="scope"
- class="json-editor"
- type="textarea"
- :rows="4"
- :readonly="session.level < 4" /></el-form-item></el-form
- ><JsonEvidence :value="history" title="历史版本" /><template #footer
- ><el-button @click="dialog = false">关闭</el-button
- ><el-button
- v-if="session.level >= 4"
- type="primary"
- :loading="saving"
- @click="save"
- >发布新规则版本</el-button
- ></template
- ></el-dialog
- >
- <el-dialog
- v-model="testDialog"
- :title="`规则试算:${current.name || ''}`"
- width="min(750px,94vw)"
- ><el-alert
- :closable="false"
- title="上下文显式提供 today、existing_hashes、type 等字段;缺少输入时返回未完成或不通过,试算不写正式审核。"
- type="info"
- /><el-form label-position="top"
- ><el-form-item label="发票字段 JSON"
- ><el-input
- v-model="invoice"
- class="json-editor"
- type="textarea"
- :rows="8" /></el-form-item
- ><el-form-item label="上下文 JSON"
- ><el-input
- v-model="context"
- class="json-editor"
- type="textarea"
- :rows="4" /></el-form-item></el-form
- ><JsonEvidence
- v-if="result"
- :value="result"
- title="试算结果(展开)"
- /><template #footer
- ><el-button @click="testDialog = false">关闭</el-button
- ><el-button type="primary" :loading="saving" @click="test"
- >执行试算</el-button
- ></template
- ></el-dialog
- >
- </template>
|