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

This commit is contained in:
李琦
2026-07-03 10:41:52 +08:00
parent 949167217f
commit 92e145f366
25 changed files with 1616 additions and 105 deletions

View File

@@ -5,7 +5,7 @@ import { computed, ref } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui';
import { Button, Image, message } from 'ant-design-vue';
import { Button, Image, message, Avatar } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
@@ -26,6 +26,7 @@ import { formatAddressDisplay } from '#/util/address-index';
import { createAdminGridOptions } from './table-config';
import { getRoleMeta } from './role-meta';
import DoctorCardModal from '#/views/doctor/doctor/components/DoctorCardModal.vue';
import { resolveAvatarUrl } from '#/views/system/store-input/utils/inputUser';
function formatAdminRegion(row: {
province_id?: number;
@@ -255,6 +256,50 @@ const copyToClipboard = async (text: string) => {
<template #region="{ row }">
{{ formatAdminRegion(row) }}
</template>
<template #store_name="{ row }">
<div v-if="row.store?.name" class="flex items-center gap-2">
<Avatar
:src="resolveAvatarUrl(row.store?.pic)"
:size="28"
shape="square"
>
{{ (row.store.name || '?').charAt(0) }}
</Avatar>
<div class="min-w-0">
<div class="truncate">{{ row.store.name }}</div>
<div class="text-xs text-gray-400">ID: {{ row.store_id }}</div>
</div>
</div>
<span v-else-if="row.store_id">诊所 #{{ row.store_id }}</span>
<span v-else>-</span>
</template>
<template #doctor_profile="{ row }">
<Button
v-if="row.doctor_profile?.name || row.doctor_id"
type="link"
size="small"
class="!h-auto !p-0"
@click="openDoctorCard(row)"
>
<div class="flex items-center gap-2 text-left">
<Avatar
:src="resolveAvatarUrl(row.doctor_profile?.avatar)"
:size="28"
>
{{ (row.doctor_profile?.name || '?').charAt(0) }}
</Avatar>
<div class="min-w-0">
<div class="truncate text-[#1677ff]">
{{ row.doctor_profile?.name || `su_id: ${row.doctor_id}` }}
</div>
<div v-if="row.doctor_profile?.mobile" class="text-xs text-gray-400">
{{ row.doctor_profile.mobile }}
</div>
</div>
</div>
</Button>
<span v-else>-</span>
</template>
<template #login_account="{ row }">
<span v-if="row.login_account">
<Button

View File

@@ -3,7 +3,6 @@ import type { VbenFormProps } from '#/adapter/form';
import { useUserStore } from '@vben/stores';
import { z } from '#/adapter/form';
import { getStoreOption } from '#/views/system/store/api';
import { getSupplierOption } from '#/views/system/supplier/api';
import type { AdminFormType } from './role-meta';
@@ -180,21 +179,7 @@ export function createAdminModalFormProps(
if (formType === 'clinic' || formType === 'doctor' || formType === 'pharmacist') {
schema.push({
component: 'ApiSelect',
componentProps: {
allowClear: true,
filterOption: (input: string, option: { label?: string }) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase()),
showSearch: true,
afterFetch: (data: { id: number; name: string }[]) => {
return data.map((item) => ({
label: item.name,
value: item.id,
}));
},
api: getStoreOption,
placeholder: '请选择诊所',
},
component: 'StorePicker',
fieldName: 'store_id',
formItemClass: 'col-span-6',
label: '所属诊所',
@@ -204,12 +189,18 @@ export function createAdminModalFormProps(
if (formType === 'doctor') {
schema.push({
component: 'VbenInput',
componentProps: {
placeholder: '关联医生档案 ID(可选,建议在医生管理中创建)',
component: 'DoctorPicker',
componentProps: (values: { store_id?: number }) => ({
storeId: values.store_id,
}),
dependencies: {
triggerFields: ['store_id'],
componentProps: (values: { store_id?: number }) => ({
storeId: values.store_id,
}),
},
fieldName: 'doctor_id',
label: '医生ID',
label: '关联医生',
formItemClass: 'col-span-6',
});
}

View File

@@ -0,0 +1,20 @@
export type PlatformAdminUserInfo = {
role_id?: number;
roles?: { id?: number };
} | null | undefined;
/** 超级管理员、系统管理员(role_id 1/2) */
export function isPlatformSuperAdmin(userInfo: PlatformAdminUserInfo): boolean {
const roleId = Number(userInfo?.role_id ?? userInfo?.roles?.id);
return roleId === 1 || roleId === 2;
}
/** 是否可编辑医生卡片中的 service_user 及资料写操作 */
export function canEditDoctorServiceUser(userInfo: PlatformAdminUserInfo): boolean {
return isPlatformSuperAdmin(userInfo);
}
/** 是否可管理诊所银行卡报备入口 */
export function canManageStoreBankCard(userInfo: PlatformAdminUserInfo): boolean {
return isPlatformSuperAdmin(userInfo);
}

View File

@@ -18,6 +18,13 @@ interface RowType {
store_id?: number;
doctor_id?: number;
pharmacist_id?: number;
store?: { id?: number; name?: string; pic?: string; mobile?: string };
doctor_profile?: {
su_id?: number;
name?: string;
avatar?: string;
mobile?: string;
} | null;
province_id?: number;
city_id?: number;
}
@@ -55,11 +62,21 @@ function buildColumns(formType: AdminFormType) {
}
if (formType === 'clinic' || formType === 'doctor' || formType === 'pharmacist') {
cols.push({ field: 'store_id', title: '诊所ID', width: 100 });
cols.push({
field: 'store_id',
title: '所属诊所',
minWidth: 180,
slots: { default: 'store_name' },
});
}
if (formType === 'doctor') {
cols.push({ field: 'doctor_id', title: '医生ID', width: 100 });
cols.push({
field: 'doctor_id',
title: '关联医生',
minWidth: 180,
slots: { default: 'doctor_profile' },
});
}
if (formType === 'pharmacist') {