1. 优化一些问题
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled

This commit is contained in:
李琦
2026-05-20 10:12:09 +08:00
parent 90a9bde586
commit 68fd7b0045
14 changed files with 873 additions and 134 deletions

View File

@@ -373,14 +373,8 @@ export const usePrescriptionStore = defineStore('prescription', () => {
selectedStoreId.value = res.delegate_store_id;
sendMode.value = 1; // 使用自定义模式但使用承接方诊所ID
} else if (res && res.store_id) {
// 非转诊挂号,默认选择挂号诊所
selectedStoreId.value = res.store_id;
// 如果挂号诊所与医生当前诊所不同,设置为自定义模式
if (res.can_change) {
sendMode.value = 1;
} else {
sendMode.value = 0;
}
sendMode.value = 1;
}
console.log('获取挂号诊所信息成功:', res);
} catch (error) {

View File

@@ -50,7 +50,6 @@ import WesternModal from '#/views/doctor/doctor-reception/components/WesternModa
import SimpleProductModal from '#/views/doctor/doctor-reception/components/SimpleProductModal.vue';
// 常用方选择弹窗组件
import CommonPrescriptionModal from '#/views/doctor/doctor-reception/components/CommonPrescriptionModal.vue';
import StoreConfirmModal from './StoreConfirmModal.vue';
// 信息提示模态框
import InfoModal from '#/components/modal/InfoModal.vue';
// 药品搜索选择组件
@@ -168,11 +167,6 @@ const [InfoModalComponent, infoModalApi] = useVbenModal({
connectedComponent: InfoModal,
});
// 诊所确认弹窗
const [StoreConfirmModalComponent, storeConfirmModalApi] = useVbenModal({
connectedComponent: StoreConfirmModal,
});
// ==================== 常用方选择弹窗 ====================
const [CommonPrescriptionModals, CommonPrescriptionModalApi] = useVbenModal({
connectedComponent: CommonPrescriptionModal,
@@ -212,27 +206,13 @@ const handleSendPrescription = async (doctorSecondSignValue = 0) => {
// 获取挂号诊所信息
await prescriptionStore.fetchRegisterStoreInfo();
const canChange = prescriptionStore.canChangeStore;
const storeInfo = prescriptionStore.registerStoreInfo;
// 如果是转诊挂号自动使用承接方诊所ID不需要弹出诊所选择弹窗
if (storeInfo?.is_from_transfer === 1 && storeInfo?.delegate_store_id) {
// 转接方开处方时自动使用承接方诊所ID
await executeSendPrescription(doctorSecondSignValue, 1, storeInfo.delegate_store_id);
} else if (canChange) {
// 弹出诊所确认弹窗 - 直接从 registerStoreInfo 获取诊所信息
storeConfirmModalApi.setData({
registerStoreName: storeInfo?.store_name || '挂号诊所',
registerStoreId: storeInfo?.store_id,
currentStoreName: storeInfo?.current_store_name || '当前诊所', // 直接从后端数据获取
canChange: true,
onConfirm: async (mode: number, customStoreId: number | null) => {
await executeSendPrescription(doctorSecondSignValue, mode, customStoreId);
},
});
storeConfirmModalApi.open();
} else if (storeInfo?.store_id) {
await executeSendPrescription(doctorSecondSignValue, 1, storeInfo.store_id);
} else {
// 直接发送
await executeSendPrescription(doctorSecondSignValue, 0, null);
}
};
@@ -1626,7 +1606,6 @@ const cancelSaveCommonPrescription = () => {
<DiagnosisModals />
<DoctorOrderModals />
<PrescriptionDetailModal />
<StoreConfirmModalComponent />
<!-- 常用方选择弹窗 -->
<CommonPrescriptionModals />
</Modal>

View File

@@ -1,104 +0,0 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { Radio, RadioGroup } from 'ant-design-vue';
const selectedMode = ref(0); // 0=当前诊所, 1=挂号诊所
const modalData = ref<any>({});
const [Modal, modalApi] = useVbenModal({
onOpenChange(isOpen) {
if (isOpen) {
modalData.value = modalApi.getData();
// 默认选择挂号诊所(如果可以更改的话)
selectedMode.value = modalData.value.canChange ? 1 : 0;
}
},
onConfirm() {
const customStoreId = selectedMode.value === 1 ? modalData.value.registerStoreId : null;
// #region agent log
fetch('http://127.0.0.1:7242/ingest/3cda25fa-2f46-4a02-889c-2ffb76bc49fe',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'StoreConfirmModal.vue:onConfirm',message:'弹窗确认时的值',data:{selectedMode:selectedMode.value,registerStoreId:modalData.value.registerStoreId,customStoreId:customStoreId},timestamp:Date.now(),sessionId:'debug-session',hypothesisId:'A'})}).catch(()=>{});
// #endregion
modalData.value.onConfirm?.(selectedMode.value, customStoreId);
modalApi.close();
},
});
</script>
<template>
<Modal title="确认发送诊所">
<div class="space-y-4">
<!-- 诊所信息展示 -->
<div class="rounded-lg border border-blue-200 bg-blue-50 p-4 dark:border-blue-800 dark:bg-blue-950">
<div class="mb-2 flex items-center gap-2">
<span class="text-gray-600 dark:text-gray-400">挂号诊所</span>
<span class="font-semibold text-blue-600 dark:text-blue-400">{{
modalData.registerStoreName || '未知'
}}</span>
</div>
<div class="flex items-center gap-2">
<span class="text-gray-600 dark:text-gray-400">当前诊所</span>
<span class="font-semibold text-green-600 dark:text-green-400">{{
modalData.currentStoreName || '未知'
}}</span>
</div>
</div>
<!-- 诊所选择 -->
<div v-if="modalData.canChange" class="mt-4">
<p class="mb-3 text-gray-700 dark:text-gray-300">请选择处方发送到哪个诊所</p>
<RadioGroup v-model:value="selectedMode" class="w-full">
<div class="space-y-3">
<div
class="cursor-pointer rounded-lg border p-3 transition-all"
:class="
selectedMode === 1
? 'border-blue-500 bg-blue-50 dark:border-blue-600 dark:bg-blue-950'
: 'border-gray-200 hover:border-gray-400 dark:border-gray-600 dark:hover:border-gray-500'
"
@click="selectedMode = 1"
>
<Radio :value="1" class="w-full">
<span class="font-medium">发送到挂号诊所</span>
<span class="ml-2 text-sm text-gray-500 dark:text-gray-400"
>{{ modalData.registerStoreName }}</span
>
</Radio>
</div>
<div
class="cursor-pointer rounded-lg border p-3 transition-all"
:class="
selectedMode === 0
? 'border-green-500 bg-green-50 dark:border-green-600 dark:bg-green-950'
: 'border-gray-200 hover:border-gray-400 dark:border-gray-600 dark:hover:border-gray-500'
"
@click="selectedMode = 0"
>
<Radio :value="0" class="w-full">
<span class="font-medium">发送到当前诊所</span>
<span class="ml-2 text-sm text-gray-500 dark:text-gray-400"
>{{ modalData.currentStoreName }}</span
>
</Radio>
</div>
</div>
</RadioGroup>
</div>
<!-- 无法更改时的提示 -->
<div v-else class="mt-4 text-center text-gray-500 dark:text-gray-400">
处方将发送到当前诊所
</div>
</div>
</Modal>
</template>
<style scoped>
/* Radio 组件间距调整 */
:deep(.ant-radio-wrapper) {
margin-right: 0;
}
</style>

View File

@@ -131,6 +131,17 @@ const getImageSource = (imageString) => {
<span>科室: {{ item.content?.doctor.depart?.name }}</span>
<span>诊断: {{ item.content?.clinical_diagnose }}</span>
</div>
<template v-if="item.online_tcm_print?.show">
<div v-if="item.online_tcm_print.tcm_syndrome" class="info-row">
<span>中医证候: {{ item.online_tcm_print.tcm_syndrome }}</span>
</div>
<div v-if="item.online_tcm_print.tcm_method" class="info-row">
<span>中医治法: {{ item.online_tcm_print.tcm_method }}</span>
</div>
<div v-if="item.online_tcm_print.tcm_disease" class="info-row">
<span>中医疾病: {{ item.online_tcm_print.tcm_disease }}</span>
</div>
</template>
</div>
<!-- 药品列表 -->

View File

@@ -0,0 +1,15 @@
import { requestClient } from '#/api/request';
const prefix = 'log/';
export async function getHyTransitBatchList(params: Record<string, any>) {
return requestClient.get<any>(`${prefix}hy-transit-batch-list`, { params });
}
export async function getHyTransitRecordList(params: Record<string, any>) {
return requestClient.get<any>(`${prefix}hy-transit-record-list`, { params });
}
export async function getHyTransitRecordDetail(params: { id: number }) {
return requestClient.get<any>(`${prefix}hy-transit-record-detail`, { params });
}

View File

@@ -0,0 +1,61 @@
import type { VbenFormProps } from '#/adapter/form';
export const formOptions: VbenFormProps = {
collapsed: false,
schema: [
{
component: 'VbenSelect',
fieldName: 'callback_status',
label: '回调状态',
componentProps: {
allowClear: true,
placeholder: '全部',
options: [
{ label: '等待回调', value: 'waiting' },
{ label: '成功', value: 'success' },
{ label: '失败', value: 'failed' },
],
},
},
{
component: 'VbenInput',
fieldName: 'anchor_date',
label: '锚定日',
componentProps: { placeholder: 'YYYY-MM-DD' },
},
{
component: 'VbenInput',
fieldName: 'buss_id',
label: '业务ID',
},
{
component: 'VbenInput',
fieldName: 'batch_id',
label: '批次ID',
},
{
component: 'VbenInput',
fieldName: 'register_id',
label: '挂号ID',
},
{
component: 'VbenInput',
fieldName: 'prescription_id',
label: '处方ID',
},
{
component: 'VbenInput',
fieldName: 'order_id',
label: '订单ID',
},
{
component: 'VbenInput',
fieldName: 'prescription_no',
label: '处方编号',
},
],
showCollapseButton: true,
submitButtonOptions: { content: '查询' },
submitOnChange: false,
submitOnEnter: true,
};

View File

@@ -0,0 +1,47 @@
import type { VxeGridProps } from '#/adapter/vxe-table';
import { getHyTransitRecordList } from '../../api';
export const gridOptions: VxeGridProps = {
columns: [
{ field: 'id', title: 'ID', width: 80 },
{ field: 'batch_id', title: '批次', width: 80 },
{ field: 'step_txt', title: '类型', width: 100 },
{ field: 'register_id', title: '挂号ID', width: 90 },
{ field: 'prescription_id', title: '处方ID', width: 90 },
{ field: 'order_id', title: '订单ID', width: 90 },
{ field: 'prescription_no', title: '处方编号', width: 140 },
{ field: 'patient_name', title: '患者', width: 90 },
{ field: 'push_status_txt', title: '上报', width: 90 },
{ field: 'callback_status_txt', title: '回调', width: 90, slots: { default: 'callback_status' } },
{
field: 'error_summary',
title: '校验/报错',
minWidth: 200,
showOverflow: true,
slots: { default: 'error_summary' },
},
{ field: 'callback_at', title: '回调时间', width: 160, slots: { default: 'callback_at' } },
{ type: 'html', title: '操作', width: 100, slots: { default: 'action' } },
],
keepSource: true,
pagerConfig: {},
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
return await getHyTransitRecordList({
page: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
height: 'auto',
border: false,
toolbarConfig: {
search: true,
refresh: true,
zoom: true,
},
};

View File

@@ -0,0 +1,197 @@
<script lang="ts" setup>
import { Page, useVbenModal } from '@vben/common-ui';
import { Tag } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { TableAction } from '#/components/table-action';
import { getHyTransitRecordList } from '../api';
import FailDetailModal from '../components/fail-detail-modal.vue';
import { formOptions } from './config/search';
import { hasErrorTextClass } from '../utils';
import { gridOptions as baseGridOptions } from './config/table';
function formatTs(ts?: number) {
if (!ts) return '-';
return new Date(ts * 1000).toLocaleString();
}
const statusColor: Record<string, string> = {
waiting: 'orange',
success: 'green',
failed: 'error',
};
function callbackTagColor(status?: string) {
return statusColor[status ?? ''] || 'default';
}
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridOptions: {
...baseGridOptions,
proxyConfig: {
...baseGridOptions.proxyConfig,
ajax: {
query: async ({ page }, formValues) => {
const res = await getHyTransitRecordList({
page: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
const callbackOpts = res?.form_options?.callback_status;
if (callbackOpts?.length) {
gridApi.formApi?.updateSchema([
{
fieldName: 'callback_status',
componentProps: {
allowClear: true,
placeholder: '全部',
options: callbackOpts,
},
},
]);
}
return res;
},
},
},
},
});
const [DetailModal, detailModalApi] = useVbenModal({
connectedComponent: FailDetailModal,
});
const showDetail = (row: { id: number }) => {
detailModalApi.setData({ id: row.id });
detailModalApi.open();
};
</script>
<template>
<Page auto-content-height title="监管回调结果">
<DetailModal />
<Grid>
<template #callback_status="{ row }">
<Tag :color="callbackTagColor(row.callback_status)">
{{ row.callback_status_txt || row.callback_status }}
</Tag>
</template>
<template #error_summary="{ row }">
<span :class="hasErrorTextClass(row.error_summary)">
{{ row.error_summary || '-' }}
</span>
</template>
<template #callback_at="{ row }">
{{ formatTs(row.callback_at) }}
</template>
<template #action="{ row }">
<TableAction
:actions="[
{
label: '查看回调',
type: 'link',
onClick: () => showDetail(row),
},
]"
/>
</template>
</Grid>
</Page>
</template>

View File

@@ -0,0 +1,104 @@
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { Descriptions, Spin } from 'ant-design-vue';
import { getHyTransitRecordDetail } from '../api';
import { hasErrorTextClass } from '../utils';
const loading = ref(false);
const data = ref<Record<string, any>>({});
const payloadText = computed(() => {
const raw = data.value.payload_json;
if (!raw) return '';
try {
return JSON.stringify(JSON.parse(raw), null, 2);
} catch {
return String(raw);
}
});
const responseText = computed(() => {
const raw = data.value.response_body;
if (!raw) return '';
try {
return JSON.stringify(JSON.parse(raw), null, 2);
} catch {
return String(raw);
}
});
const [Modal, modalApi] = useVbenModal({
fullscreenButton: true,
draggable: true,
onCancel() {
modalApi.close();
},
onConfirm() {
modalApi.close();
},
onOpenChange: async (isOpen: boolean) => {
if (!isOpen) return;
const id = modalApi.getData()?.id;
if (!id) return;
loading.value = true;
try {
data.value = (await getHyTransitRecordDetail({ id })) ?? {};
} finally {
loading.value = false;
}
},
});
</script>
<template>
<Modal class="w-[80%]" title="监管回调详情">
<Spin :spinning="loading">
<Descriptions bordered :column="2" class="mb-4">
<Descriptions.Item label="记录ID">{{ data.id }}</Descriptions.Item>
<Descriptions.Item label="批次ID">{{ data.batch_id }}</Descriptions.Item>
<Descriptions.Item label="监管类型">{{ data.step_txt || data.step_label || data.step }}</Descriptions.Item>
<Descriptions.Item label="业务ID">{{ data.buss_id }}</Descriptions.Item>
<Descriptions.Item label="挂号ID">{{ data.register_id || '-' }}</Descriptions.Item>
<Descriptions.Item label="处方ID">{{ data.prescription_id || '-' }}</Descriptions.Item>
<Descriptions.Item label="订单ID">{{ data.order_id || '-' }}</Descriptions.Item>
<Descriptions.Item label="处方编号">{{ data.prescription_no || '-' }}</Descriptions.Item>
<Descriptions.Item label="患者">{{ data.patient_name || '-' }}</Descriptions.Item>
<Descriptions.Item label="文件ID">{{ data.recipe_file_id || '-' }}</Descriptions.Item>
<Descriptions.Item label="接口">{{ data.service_method }}</Descriptions.Item>
<Descriptions.Item label="上报状态">{{ data.push_status_txt || data.push_status_label || data.push_status }}</Descriptions.Item>
<Descriptions.Item label="回调状态">{{ data.callback_status_txt || data.callback_status_label || data.callback_status }}</Descriptions.Item>
<Descriptions.Item label="HTTP">{{ data.http_code }}</Descriptions.Item>
<Descriptions.Item label="msgCode">{{ data.msg_code }}</Descriptions.Item>
<Descriptions.Item label="trace_id" :span="2">{{ data.trace_id }}</Descriptions.Item>
<Descriptions.Item label="校验错误" :span="2">
<span
:class="
hasErrorTextClass(
(data.validation_errors_label || data.validation_errors || []).join('、'),
)
"
>
{{ (data.validation_errors_label || data.validation_errors || []).join('、') || '-' }}
</span>
</Descriptions.Item>
<Descriptions.Item label="错误摘要" :span="2">
<span :class="hasErrorTextClass(data.error_summary || data.error_message)">
{{ data.error_summary || data.error_message || '-' }}
</span>
</Descriptions.Item>
</Descriptions>
<div class="mb-2 font-medium">组包数据 payload_json</div>
<pre
class=" rounded border bg-muted p-3 text-xs dark:bg-[#020817] dark:text-gray-200"
>{{ payloadText }}</pre>
<div class="mb-2 mt-4 font-medium">监管响应 response_body</div>
<pre
class=" rounded border bg-muted p-3 text-xs dark:bg-[#020817] dark:text-gray-200"
>{{ responseText }}</pre>
</Spin>
</Modal>
</template>

View File

@@ -0,0 +1,180 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { TableAction } from '#/components/table-action';
import { getHyTransitRecordList } from '../api';
import { hasErrorTextClass } from '../utils';
import FailDetailModal from './fail-detail-modal.vue';
const batchId = ref(0);
const [Modal, modalApi] = useVbenModal({
fullscreenButton: true,
draggable: true,
onOpenChange(isOpen: boolean) {
if (isOpen) {
batchId.value = modalApi.getData()?.batchId ?? 0;
gridApi.reload();
}
},
});
const [DetailModal, detailModalApi] = useVbenModal({
connectedComponent: FailDetailModal,
});
const showDetail = (row: { id: number }) => {
detailModalApi.setData({ id: row.id });
detailModalApi.open();
};
const [Grid, gridApi] = useVbenVxeGrid({
gridOptions: {
height: 480,
columns: [
{ field: 'id', title: 'ID', width: 70 },
{ field: 'step_txt', title: '类型', width: 100 },
{ field: 'register_id', title: '挂号ID', width: 85 },
{ field: 'prescription_id', title: '处方ID', width: 85 },
{ field: 'order_id', title: '订单ID', width: 85 },
{ field: 'prescription_no', title: '处方编号', width: 130 },
{ field: 'patient_name', title: '患者', width: 80 },
{ field: 'pull_status_txt', title: '拉取', width: 80 },
{ field: 'push_status_txt', title: '上报', width: 80 },
{ field: 'callback_status_txt', title: '回调', width: 80 },
{
field: 'error_summary',
title: '校验/报错',
minWidth: 180,
showOverflow: true,
slots: { default: 'error_summary' },
},
{ type: 'html', title: '操作', width: 100, slots: { default: 'action' } },
],
pagerConfig: {},
proxyConfig: {
ajax: {
query: async ({ page }) => {
return await getHyTransitRecordList({
page: page.currentPage,
pageSize: page.pageSize,
batch_id: batchId.value,
});
},
},
},
},
});
</script>
<template>
<Modal class="w-[90%]" title="批次明细">
<DetailModal />
<Grid>
<template #error_summary="{ row }">
<span :class="hasErrorTextClass(row.error_summary)">
{{ row.error_summary || '-' }}
</span>
</template>
<template #action="{ row }">
<TableAction
:actions="[
{
label: '查看回调',
type: 'link',
onClick: () => showDetail(row),
},
]"
/>
</template>
</Grid>
</Modal>
</template>

View File

@@ -0,0 +1,37 @@
import type { VbenFormProps } from '#/adapter/form';
export const formOptions: VbenFormProps = {
collapsed: false,
schema: [
{
component: 'VbenInput',
fieldName: 'anchor_date',
label: '锚定日',
componentProps: { placeholder: 'YYYY-MM-DD' },
},
{
component: 'VbenSelect',
fieldName: 'step',
label: '接口类型',
componentProps: {
allowClear: true,
options: [
{ label: '咨询', value: 'consult' },
{ label: '复诊', value: 'referral' },
{ label: '处方', value: 'recipe' },
{ label: '核销', value: 'verification' },
{ label: '全部', value: 'all' },
],
},
},
{
component: 'VbenInput',
fieldName: 'batch_id',
label: '批次ID',
},
],
showCollapseButton: true,
submitButtonOptions: { content: '查询' },
submitOnChange: false,
submitOnEnter: true,
};

View File

@@ -0,0 +1,44 @@
import type { VxeGridProps } from '#/adapter/vxe-table';
import { getHyTransitBatchList } from '../../api';
export const gridOptions: VxeGridProps = {
columns: [
{ field: 'id', title: '批次ID', width: 90 },
{ field: 'anchor_date', title: '锚定日', width: 120 },
{ field: 'step_txt', title: '类型', width: 110 },
{ field: 'pull_status_txt', title: '拉取状态', width: 100 },
{ field: 'total_count', title: '总数', width: 80 },
{ field: 'success_count', title: '成功', width: 80 },
{
field: 'failed_count',
title: '失败',
width: 80,
slots: { default: 'failed_count' },
},
{ field: 'skipped_count', title: '跳过', width: 80 },
{ field: 'callback_status_txt', title: '回调状态', width: 100 },
{ field: 'started_at', title: '开始时间', width: 160, slots: { default: 'started_at' } },
{ type: 'html', title: '操作', width: 120, slots: { default: 'action' } },
],
keepSource: true,
pagerConfig: {},
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
return await getHyTransitBatchList({
page: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
height: 'auto',
border: false,
toolbarConfig: {
search: true,
refresh: true,
zoom: true,
},
};

View File

@@ -0,0 +1,165 @@
<script lang="ts" setup>
import { Page, useVbenModal } from '@vben/common-ui';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { TableAction } from '#/components/table-action';
import { getHyTransitBatchList } from '../api';
import RecordModal from '../components/record-list-modal.vue';
import { formOptions } from './config/search';
import { countErrorClass } from '../utils';
import { gridOptions as baseGridOptions } from './config/table';
function formatTs(ts?: number) {
if (!ts) return '-';
return new Date(ts * 1000).toLocaleString();
}
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridOptions: {
...baseGridOptions,
proxyConfig: {
...baseGridOptions.proxyConfig,
ajax: {
query: async ({ page }, formValues) => {
const res = await getHyTransitBatchList({
page: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
const stepOpts = res?.form_options?.step;
if (stepOpts?.length) {
gridApi.formApi?.updateSchema([
{
fieldName: 'step',
componentProps: {
allowClear: true,
options: stepOpts,
},
},
]);
}
return res;
},
},
},
},
});
const [RecordListModal, recordModalApi] = useVbenModal({
connectedComponent: RecordModal,
});
const showRecords = (row: { id: number }) => {
recordModalApi.setData({ batchId: row.id });
recordModalApi.open();
};
</script>
<template>
<Page auto-content-height title="监管拉取记录">
<RecordListModal />
<Grid>
<template #failed_count="{ row }">
<span :class="countErrorClass(row.failed_count)">
{{ row.failed_count }}
</span>
</template>
<template #started_at="{ row }">
{{ formatTs(row.started_at) }}
</template>
<template #action="{ row }">
<TableAction
:actions="[
{
label: '查看明细',
type: 'link',
onClick: () => showRecords(row),
},
]"
/>
</template>
</Grid>
</Page>
</template>

View File

@@ -0,0 +1,9 @@
/** 计数类字段:大于 0 时标红(适配亮/暗主题) */
export function countErrorClass(count?: number) {
return Number(count) > 0 ? 'text-destructive font-semibold' : '';
}
/** 有错误文案时标红 */
export function hasErrorTextClass(text?: string) {
return text?.trim() ? 'text-destructive' : '';
}