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
CI / CI OK (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
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-06-04 16:05:02 +08:00
parent ee25ed00fb
commit b40c7402aa
62 changed files with 4373 additions and 467 deletions

View File

@@ -0,0 +1,27 @@
import { requestClient } from '#/api/request';
const prefix = 'doctor-input/';
export async function createDoctorInput(data: Record<string, any>) {
return requestClient.post<any>(`${prefix}create`, data);
}
export async function getDoctorInputList(data: any) {
return requestClient.get<any>(`${prefix}list`, { params: data });
}
export async function getDoctorInputDetail(id: number) {
return requestClient.get<any>(`${prefix}detail`, { params: { id } });
}
export async function updateDoctorInput(data: Record<string, any>) {
return requestClient.post<any>(`${prefix}update`, data);
}
export async function auditDoctorInput(data: {
id: number;
status: number;
audit_remark?: string;
}) {
return requestClient.post<any>(`${prefix}audit`, data);
}

View File

@@ -0,0 +1,128 @@
<script lang="ts" setup>
import type { VxeGridListeners } from '#/adapter/vxe-table';
import { computed, ref } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui';
import { useUserStore } from '@vben/stores';
import { Tag } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { TableAction } from '#/components/table-action';
import AuditModal from './components/AuditModal.vue';
import DetailModal from './components/DetailModal.vue';
import { auditFormOptions } from './config/search';
import { auditGridOptions } from './config/table';
const userStore = useUserStore();
const isPlatformAdmin = computed(() => {
return userStore?.userInfo?.roles?.user_type === 2;
});
const hasTopTableDropDownActions = ref(false);
const gridEvents: VxeGridListeners<any> = {
checkboxChange() {
const records = gridApi.grid.getCheckboxRecords();
hasTopTableDropDownActions.value = records.length > 0;
},
checkboxAll() {
const records = gridApi.grid.getCheckboxRecords();
hasTopTableDropDownActions.value = records.length > 0;
},
};
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: auditFormOptions,
gridOptions: auditGridOptions,
gridEvents,
});
const [DetailModalComponent, detailModalApi] = useVbenModal({
connectedComponent: DetailModal,
});
const [AuditModalComponent, auditModalApi] = useVbenModal({
connectedComponent: AuditModal,
});
const showDetail = (row: any) => {
detailModalApi.setData({
values: row,
});
detailModalApi.open();
};
const showAudit = (row: any) => {
auditModalApi.setData({
values: row,
gridApi,
});
auditModalApi.open();
};
const getTypeText = (type: number) => {
if (type === 1) return '中医医生';
if (type === 2) return '西医医生';
return '-';
};
const getStatusColor = (status: number) => {
if (status === 0) return 'orange';
if (status === 1) return 'success';
return 'error';
};
const getStatusText = (status: number) => {
if (status === 0) return '待审核';
if (status === 1) return '审核通过';
return '审核拒绝';
};
</script>
<template>
<Page auto-content-height title="医生信息审核">
<DetailModalComponent />
<AuditModalComponent />
<Grid>
<template #type="{ row }">
<Tag>{{ getTypeText(row.type) }}</Tag>
</template>
<template #status="{ row }">
<Tag :color="getStatusColor(row.status)">
{{ getStatusText(row.status) }}
</Tag>
</template>
<template #audit_time="{ row }">
<span v-if="row.audit_time">
{{ new Date(row.audit_time * 1000).toLocaleString() }}
</span>
<span v-else>-</span>
</template>
<template #action="{ row }">
<TableAction
:actions="[
{
label: '查看详情',
type: 'link',
icon: 'uil:eye',
size: 'small',
onClick: showDetail.bind(null, row),
},
{
label: '审核',
type: 'link',
icon: 'uil:check',
size: 'small',
ifShow: row.status === 0 && isPlatformAdmin,
onClick: showAudit.bind(null, row),
},
]"
/>
</template>
</Grid>
</Page>
</template>

View File

@@ -0,0 +1,86 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message, Radio, RadioGroup, Textarea } from 'ant-design-vue';
import { auditDoctorInput } from '../api';
const [ModalComponent, modalApi] = useVbenModal({
fullscreenButton: false,
draggable: true,
onCancel() {
modalApi.close();
},
});
const auditStatus = ref<number>(1);
const auditRemark = ref<string>('');
const currentRow = ref<any>(null);
const gridApi = ref<any>(null);
const loading = ref(false);
const handleAudit = async () => {
if (!currentRow.value) {
message.error('数据错误');
return;
}
loading.value = true;
try {
await auditDoctorInput({
id: currentRow.value.id,
status: auditStatus.value,
audit_remark: auditRemark.value,
});
message.success('审核成功');
gridApi.value?.reload();
modalApi.close();
auditStatus.value = 1;
auditRemark.value = '';
} catch (error) {
console.error('审核失败:', error);
message.error('审核失败,请稍后重试');
} finally {
loading.value = false;
}
};
modalApi.onOpenChange = (isOpen: boolean) => {
if (isOpen) {
const { values, gridApi: api } = modalApi.getData<Record<string, any>>();
currentRow.value = values;
gridApi.value = api;
auditStatus.value = 1;
auditRemark.value = '';
}
};
</script>
<template>
<ModalComponent
title="审核医生预填"
class="w-[500px]"
:confirm-loading="loading"
@confirm="handleAudit"
>
<div class="space-y-4 p-4">
<div>
<div class="mb-2 font-semibold">审核结果:</div>
<RadioGroup v-model:value="auditStatus">
<Radio :value="1">审核通过</Radio>
<Radio :value="2">审核拒绝</Radio>
</RadioGroup>
</div>
<div>
<div class="mb-2 font-semibold">审核备注:</div>
<Textarea
v-model:value="auditRemark"
:rows="4"
placeholder="请输入审核备注(可选)"
/>
</div>
</div>
</ModalComponent>
</template>

View File

@@ -0,0 +1,146 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { Avatar, Descriptions, DescriptionsItem, Image, Spin, message } from 'ant-design-vue';
import { getDoctorInputDetail } from '../api';
import {
inputUserDisplayName,
normalizeInputUser,
resolveAvatarUrl,
} from '../../store-input/utils/inputUser';
const detailData = ref<any>(null);
const loading = ref(false);
const getTypeText = (type: number) => {
if (type === 1) return '中医医生';
if (type === 2) return '西医医生';
return '-';
};
const getSignTypeText = (signType: number) => {
if (signType === 1) return '电子签名';
if (signType === 2) return '手写签名';
return '-';
};
const loadDetail = async (id: number) => {
loading.value = true;
detailData.value = null;
try {
const res = await getDoctorInputDetail(id);
detailData.value = res;
normalizeInputUser(detailData.value);
} catch (error) {
console.error('获取详情失败:', error);
message.error('获取详情失败');
} finally {
loading.value = false;
}
};
const [Modal, modalApi] = useVbenModal({
fullscreenButton: false,
draggable: true,
onCancel() {
modalApi.close();
},
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
detailData.value = null;
loading.value = false;
return;
}
const { values } = modalApi.getData<Record<string, any>>();
if (values?.id) {
await loadDetail(values.id);
} else {
detailData.value = values || null;
normalizeInputUser(detailData.value);
}
},
});
</script>
<template>
<Modal title="医生预填详情" class="w-[70%]">
<Spin :spinning="loading">
<div v-if="detailData" class="p-4">
<Descriptions :column="2" bordered>
<DescriptionsItem label="ID">{{ detailData.id }}</DescriptionsItem>
<DescriptionsItem label="医生姓名">{{ detailData.name }}</DescriptionsItem>
<DescriptionsItem label="手机号">{{ detailData.mobile }}</DescriptionsItem>
<DescriptionsItem label="身份证">{{ detailData.idcard }}</DescriptionsItem>
<DescriptionsItem label="身份">{{ getTypeText(detailData.type) }}</DescriptionsItem>
<DescriptionsItem label="签名类型">{{ getSignTypeText(detailData.sign_type) }}</DescriptionsItem>
<DescriptionsItem label="科室">{{ detailData.depart?.name || '-' }}</DescriptionsItem>
<DescriptionsItem label="职称">{{ detailData.titleInfo?.name || '-' }}</DescriptionsItem>
<DescriptionsItem label="擅长" :span="2">{{ detailData.good_at }}</DescriptionsItem>
<DescriptionsItem label="简介" :span="2">{{ detailData.intro }}</DescriptionsItem>
<DescriptionsItem label="录入人">
<div class="flex items-center gap-2">
<Avatar
v-if="resolveAvatarUrl(detailData.inputUser?.avatar)"
:src="resolveAvatarUrl(detailData.inputUser?.avatar)"
:size="40"
/>
<Avatar v-else :size="40">{{ inputUserDisplayName(detailData.inputUser).charAt(0) }}</Avatar>
<span>{{ inputUserDisplayName(detailData.inputUser) }}</span>
</div>
</DescriptionsItem>
<DescriptionsItem label="审核状态">
<span
:class="{
'text-orange-500': detailData.status === 0,
'text-green-500': detailData.status === 1,
'text-red-500': detailData.status === 2,
}"
>
{{
detailData.status === 0
? '待审核'
: detailData.status === 1
? '审核通过'
: '审核拒绝'
}}
</span>
</DescriptionsItem>
<DescriptionsItem v-if="detailData.auditAdmin" label="审核人">
{{ detailData.auditAdmin.nick_name }}
</DescriptionsItem>
<DescriptionsItem v-if="detailData.audit_time" label="审核时间">
{{ new Date(detailData.audit_time * 1000).toLocaleString() }}
</DescriptionsItem>
<DescriptionsItem v-if="detailData.audit_remark" label="审核备注" :span="2">
{{ detailData.audit_remark }}
</DescriptionsItem>
<DescriptionsItem v-if="detailData.avatar" label="头像" :span="2">
<Image :src="detailData.avatar" :width="100" :height="100" :preview="true" />
</DescriptionsItem>
<DescriptionsItem v-if="detailData.qualification" label="资格证书" :span="2">
<Image :src="detailData.qualification" :width="100" :height="100" :preview="true" />
</DescriptionsItem>
<DescriptionsItem v-if="detailData.practicing" label="执业证书" :span="2">
<Image :src="detailData.practicing" :width="100" :height="100" :preview="true" />
</DescriptionsItem>
<DescriptionsItem v-if="detailData.title" label="职称证书" :span="2">
<Image :src="detailData.title" :width="100" :height="100" :preview="true" />
</DescriptionsItem>
<DescriptionsItem v-if="detailData.card_up" label="身份证正面" :span="2">
<Image :src="detailData.card_up" :width="100" :height="100" :preview="true" />
</DescriptionsItem>
<DescriptionsItem v-if="detailData.card_down" label="身份证反面" :span="2">
<Image :src="detailData.card_down" :width="100" :height="100" :preview="true" />
</DescriptionsItem>
<DescriptionsItem v-if="detailData.sign_image" label="签名图片" :span="2">
<Image :src="detailData.sign_image" :width="100" :height="100" :preview="true" />
</DescriptionsItem>
</Descriptions>
</div>
<div v-else-if="!loading" class="p-8 text-center text-gray-400">暂无详情数据</div>
</Spin>
</Modal>
</template>

View File

@@ -0,0 +1,78 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import {
createDoctorInput,
getDoctorInputDetail,
updateDoctorInput,
} from '../api';
import { modalFormProps } from '../config/form';
const isUpdate = ref(false);
const gridApi = ref();
const [Form, formApi] = useVbenForm(modalFormProps);
const [Modal, modalApi] = useVbenModal({
fullscreenButton: false,
draggable: true,
onCancel() {
modalApi.close();
},
onConfirm: async () => {
formApi.validate().then(async (e: any) => {
if (e.valid) {
const values = await formApi.getValues();
modalApi.setState({ loading: true, confirmLoading: true });
const submitApi = isUpdate.value ? updateDoctorInput : createDoctorInput;
submitApi(values)
.then(() => {
message.success(isUpdate.value ? '更新成功' : '预填成功');
gridApi.value?.reload();
modalApi.close();
})
.finally(() => {
modalApi.setState({ loading: false, confirmLoading: false });
});
}
});
await formApi.validateAndSubmitForm();
},
async onOpenChange(isOpen: boolean) {
gridApi.value = isOpen ? modalApi.getData()?.gridApi : null;
if (isOpen) {
const { values, update } = modalApi.getData<Record<string, any>>();
if (values?.id) {
isUpdate.value = update;
if (update) {
const detail = await getDoctorInputDetail(values.id);
formApi.setValues({
...detail,
stores: detail.store_ids || [],
});
} else {
formApi.setValues({
...values,
stores: values.store_ids || [],
});
}
} else {
isUpdate.value = false;
formApi.resetForm();
}
}
},
});
</script>
<template>
<Modal :title="`${isUpdate ? '编辑' : '新增'}医生预填`" class="w-[60%]">
<Form />
</Modal>
</template>

View File

@@ -0,0 +1,228 @@
import type { VbenFormProps } from '#/adapter/form';
import { getDepartOptionApi } from '#/views/doctor/doctor/api';
import { getDoctorTitleOptionApi } from '#/views/doctor/pharmacist/api';
import { getStoreOption } from '#/views/system/store/api';
export const modalFormProps: VbenFormProps = {
wrapperClass: 'grid-cols-12',
commonConfig: {
formItemClass: 'col-span-12',
componentProps: {
class: 'w-full',
},
},
layout: 'horizontal',
schema: [
{
component: 'VbenInput',
fieldName: 'id',
label: 'ID',
formItemClass: 'col-span-6',
dependencies: {
show: false,
triggerFields: ['id'],
},
},
{
component: 'ApiSelect',
componentProps: {
allowClear: true,
filterOption: (input: string, option: any) =>
option?.label.toLowerCase().indexOf(input.toLowerCase()) >= 0,
showSearch: true,
afterFetch: (data: { id: number; name: string }[]) =>
data.map((item: any) => ({
label: item.name,
value: item.id,
})),
api: getStoreOption,
placeholder: '请选择诊所',
mode: 'multiple',
},
fieldName: 'stores',
formItemClass: 'col-span-12',
label: '关联诊所',
rules: 'required',
},
{
component: 'Avatar',
componentProps: {
placeholder: '请上传医生头像',
},
fieldName: 'avatar',
formItemClass: 'col-span-12',
label: '医生头像',
rules: 'required',
},
{
component: 'ApiSelect',
componentProps: {
allowClear: true,
afterFetch: (data: { id: number; name: string }[]) =>
data.map((item: any) => ({
label: item.name,
value: item.id,
})),
api: getDoctorTitleOptionApi,
placeholder: '请选择职称',
},
fieldName: 'title_id',
formItemClass: 'col-span-6',
label: '职称',
},
{
component: 'ApiSelect',
componentProps: {
allowClear: true,
afterFetch: (data: { id: number; name: string }[]) =>
data.map((item: any) => ({
label: item.name,
value: item.id,
})),
api: getDepartOptionApi,
placeholder: '请选择科室',
},
fieldName: 'depart_id',
formItemClass: 'col-span-6',
label: '科室',
rules: 'required',
},
{
component: 'VbenInput',
componentProps: {
placeholder: '请填写医生名称',
},
fieldName: 'name',
formItemClass: 'col-span-6',
label: '医生名称',
rules: 'required',
},
{
component: 'VbenInput',
componentProps: {
placeholder: '请填写手机号码',
},
fieldName: 'mobile',
formItemClass: 'col-span-6',
label: '手机号码',
rules: 'required',
},
{
component: 'VbenInput',
componentProps: {
placeholder: '请填写身份证',
},
fieldName: 'idcard',
formItemClass: 'col-span-6',
label: '身份证',
rules: 'required',
},
{
component: 'VbenSelect',
componentProps: {
placeholder: '请选择身份',
options: [
{ label: '中医医生', value: 1 },
{ label: '西医医生', value: 2 },
],
},
fieldName: 'type',
formItemClass: 'col-span-6',
label: '身份',
rules: 'required',
},
{
component: 'VbenSelect',
componentProps: {
placeholder: '请选择签名类型',
options: [
{ label: '电子签名', value: 1 },
{ label: '手写签名', value: 2 },
],
},
fieldName: 'sign_type',
formItemClass: 'col-span-6',
label: '签名类型',
rules: 'required',
},
{
component: 'Textarea',
componentProps: {
placeholder: '请输入擅长',
},
fieldName: 'good_at',
label: '擅长',
rules: 'required',
},
{
component: 'Textarea',
componentProps: {
placeholder: '请输入简介',
},
fieldName: 'intro',
label: '简介',
rules: 'required',
},
{
component: 'Avatar',
componentProps: {
placeholder: '请上传资格证书',
},
fieldName: 'qualification',
formItemClass: 'col-span-6',
label: '资格证书',
rules: 'required',
},
{
component: 'Avatar',
componentProps: {
placeholder: '请上传执业证书',
},
fieldName: 'practicing',
formItemClass: 'col-span-6',
label: '执业证书',
rules: 'required',
},
{
component: 'Avatar',
componentProps: {
placeholder: '请上传职称证书',
},
fieldName: 'title',
formItemClass: 'col-span-6',
label: '职称证书',
},
{
component: 'Avatar',
componentProps: {
placeholder: '请上传身份证正面',
},
fieldName: 'card_up',
formItemClass: 'col-span-6',
label: '身份证正面',
rules: 'required',
},
{
component: 'Avatar',
componentProps: {
placeholder: '请上传身份证反面',
},
fieldName: 'card_down',
formItemClass: 'col-span-6',
label: '身份证反面',
rules: 'required',
},
{
component: 'Avatar',
componentProps: {
placeholder: '请上传签名图片',
},
fieldName: 'sign_image',
formItemClass: 'col-span-6',
label: '签名图片',
rules: 'required',
},
],
showDefaultActions: false,
};

View File

@@ -0,0 +1,55 @@
import type { VbenFormProps } from '#/adapter/form';
export const formOptions: VbenFormProps = {
wrapperClass: 'grid-cols-12',
commonConfig: {
formItemClass: 'col-span-12',
componentProps: {
class: 'w-full',
},
},
layout: 'horizontal',
schema: [
{
component: 'VbenInput',
formItemClass: 'col-span-6',
componentProps: {
placeholder: '请输入医生姓名',
},
fieldName: 'name',
label: '医生姓名',
},
{
component: 'VbenInput',
formItemClass: 'col-span-6',
componentProps: {
placeholder: '请输入手机号',
},
fieldName: 'mobile',
label: '手机号',
},
{
component: 'Select',
formItemClass: 'col-span-6',
componentProps: {
placeholder: '请选择审核状态',
options: [
{ label: '待审核', value: 0 },
{ label: '审核通过', value: 1 },
{ label: '审核拒绝', value: 2 },
],
},
fieldName: 'status',
label: '审核状态',
},
],
showDefaultActions: false,
};
/** 审核列表:默认只看待审核 */
export const auditFormOptions: VbenFormProps = {
...formOptions,
schema: formOptions.schema?.map((item) =>
item.fieldName === 'status' ? { ...item, defaultValue: 0 } : item,
),
};

View File

@@ -0,0 +1,170 @@
import type { VxeGridProps } from '#/adapter/vxe-table';
import { getDoctorInputList } from '../api';
interface RowType {
id: number;
name: string;
mobile: string;
type: number;
status: number;
input_user_id: number;
inputUser: {
nick_name: string;
};
auditAdmin: {
nick_name: string;
};
depart: {
name: string;
};
titleInfo: {
name: string;
};
audit_time: number;
created_at: string;
}
// 录入列表表格配置
export const inputGridOptions: VxeGridProps<RowType> = {
checkboxConfig: {
highlight: true,
labelField: '',
},
columnConfig: {
useKey: true,
},
rowConfig: {
useKey: true,
},
columns: [
{ type: 'checkbox', width: 60 },
{ field: 'id', align: 'left', title: 'ID', width: 100 },
{ field: 'name', align: 'left', title: '医生姓名' },
{ field: 'mobile', title: '手机号', width: 140 },
{
field: 'type',
align: 'left',
title: '身份',
width: 100,
slots: { default: 'type' },
},
{ field: 'depart.name', title: '科室', width: 120 },
{ field: 'titleInfo.name', title: '职称', width: 120 },
{
field: 'status',
align: 'left',
title: '审核状态',
width: 120,
slots: { default: 'status' },
},
{ field: 'created_at', title: '录入时间' },
{
type: 'html',
title: '操作',
fixed: 'right',
width: 200,
slots: { default: 'action' },
},
],
keepSource: true,
pagerConfig: {},
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
return await getDoctorInputList({
page: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
height: 'auto',
border: false,
toolbarConfig: {
search: true,
refresh: true,
print: false,
export: false,
zoom: true,
slots: {
buttons: 'toolbar-buttons',
},
},
showOverflow: false,
};
// 审核列表表格配置
export const auditGridOptions: VxeGridProps<RowType> = {
checkboxConfig: {
highlight: true,
labelField: '',
},
columnConfig: {
useKey: true,
},
rowConfig: {
useKey: true,
},
columns: [
{ type: 'checkbox', width: 60 },
{ field: 'id', align: 'left', title: 'ID', width: 100 },
{ field: 'name', align: 'left', title: '医生姓名' },
{ field: 'mobile', title: '手机号', width: 140 },
{
field: 'type',
align: 'left',
title: '身份',
width: 100,
slots: { default: 'type' },
},
{ field: 'depart.name', title: '科室', width: 120 },
{ field: 'titleInfo.name', title: '职称', width: 120 },
{
field: 'status',
align: 'left',
title: '审核状态',
width: 120,
slots: { default: 'status' },
},
{
field: 'inputUser',
title: '录入人',
minWidth: 140,
slots: { default: 'inputUser' },
},
{ field: 'auditAdmin.nick_name', title: '审核人' },
{ field: 'audit_time', title: '审核时间', slots: { default: 'audit_time' } },
{ field: 'created_at', title: '录入时间' },
{
type: 'html',
title: '操作',
align: 'right',
slots: { default: 'action' },
},
],
keepSource: true,
pagerConfig: {},
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
return await getDoctorInputList({
page: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
height: 'auto',
border: false,
toolbarConfig: {
search: true,
refresh: true,
print: false,
export: false,
zoom: true,
},
showOverflow: false,
};

View File

@@ -0,0 +1,145 @@
<script lang="ts" setup>
import type { VxeGridListeners } from '#/adapter/vxe-table';
import { ref } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui';
import { Avatar, Tag } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { TableAction } from '#/components/table-action';
import DetailModal from './components/DetailModal.vue';
import FormModalDemo from './components/modal.vue';
import { formOptions } from './config/search';
import { inputGridOptions } from './config/table';
import {
inputUserDisplayName,
normalizeInputUser,
resolveAvatarUrl,
} from '../store-input/utils/inputUser';
const hasTopTableDropDownActions = ref(false);
const gridEvents: VxeGridListeners<any> = {
checkboxChange() {
const records = gridApi.grid.getCheckboxRecords();
hasTopTableDropDownActions.value = records.length > 0;
},
checkboxAll() {
const records = gridApi.grid.getCheckboxRecords();
hasTopTableDropDownActions.value = records.length > 0;
},
};
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridOptions: inputGridOptions,
gridEvents,
});
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: FormModalDemo,
});
const [DetailModalComponent, detailModalApi] = useVbenModal({
connectedComponent: DetailModal,
});
const showDetail = (row: any) => {
detailModalApi.setData({
values: row,
});
detailModalApi.open();
};
const showModal = (data = {}, isUpdate = false) => {
formModalApi.setData({
values: data,
update: isUpdate,
gridApi,
});
formModalApi.open();
};
const getTypeText = (type: number) => {
if (type === 1) return '中医医生';
if (type === 2) return '西医医生';
return '-';
};
const getStatusColor = (status: number) => {
if (status === 0) return 'orange';
if (status === 1) return 'success';
return 'error';
};
const getStatusText = (status: number) => {
if (status === 0) return '待审核';
if (status === 1) return '审核通过';
return '审核拒绝';
};
</script>
<template>
<Page auto-content-height title="医生信息预填">
<FormModal />
<DetailModalComponent />
<Grid>
<template #toolbar-buttons>
<TableAction
:actions="[
{
label: '新增预填',
type: 'primary',
icon: 'ant-design:plus-outlined',
onClick: showModal.bind(null, {}, false),
},
]"
/>
</template>
<template #type="{ row }">
<Tag>{{ getTypeText(row.type) }}</Tag>
</template>
<template #status="{ row }">
<Tag :color="getStatusColor(row.status)">
{{ getStatusText(row.status) }}
</Tag>
</template>
<template #inputUser="{ row }">
<div v-if="normalizeInputUser(row)" class="flex items-center gap-2">
<Avatar
v-if="resolveAvatarUrl(row.inputUser?.avatar)"
:src="resolveAvatarUrl(row.inputUser?.avatar)"
:size="28"
/>
<Avatar v-else :size="28">{{ inputUserDisplayName(row.inputUser).charAt(0) }}</Avatar>
<span>{{ inputUserDisplayName(row.inputUser) }}</span>
</div>
<span v-else>-</span>
</template>
<template #action="{ row }">
<TableAction
:actions="[
{
label: '查看',
type: 'link',
icon: 'uil:eye',
size: 'small',
onClick: showDetail.bind(null, row),
},
{
label: '编辑',
type: 'link',
icon: 'uil:edit',
size: 'small',
ifShow: row.status === 0,
onClick: showModal.bind(null, row, true),
},
]"
/>
</template>
</Grid>
</Page>
</template>