| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647 |
- import type { TransformList, TransformRecord } from '#/api';
- /** 岗位人员资质(接口就绪后替换为真实请求) */
- export namespace PersonnelQualificationModel {
- export type QualificationStatus = 'valid' | 'expiring' | 'expired';
- export interface CertificateAttachment {
- id: string;
- name: string;
- url: string;
- type: 'image' | 'pdf';
- }
- export interface Certificate {
- id: string;
- name: string;
- type?: string;
- number: string;
- expiryDate: string;
- longTerm?: boolean;
- status: QualificationStatus;
- attachments: CertificateAttachment[];
- }
- export type OrganizationType = 'enterprise' | 'medicalInstitution';
- export interface Personnel extends TransformRecord {
- organizationType?: OrganizationType;
- enterpriseId?: string;
- enterpriseName: string;
- decoctionCenterId?: string;
- decoctionCenterName: string;
- name: string;
- positions: string[];
- employeeNo: string;
- idNumber: string;
- certificateNames: string;
- qualificationStatus: QualificationStatus;
- certificates: Certificate[];
- }
- export interface PersonnelForm {
- id?: string;
- decoctionCenterId: string;
- decoctionCenterName?: string;
- name: string;
- positions: string[];
- employeeNo: string;
- idNumber: string;
- certificates: Certificate[];
- }
- export interface ListQuery {
- organizationType?: OrganizationType;
- organizationId?: string;
- enterpriseId?: string;
- decoctionCenterId?: string;
- position?: string;
- qualificationStatus?: QualificationStatus;
- keyword?: string;
- }
- export interface ExpirySummary {
- expiredCount: number;
- expiringCount: number;
- }
- }
- export const POSITION_OPTIONS = [
- { label: '接方、审方', value: '接方、审方' },
- { label: '审方', value: '审方' },
- { label: '配药', value: '配药' },
- { label: '复核', value: '复核' },
- { label: '煎煮', value: '煎煮' },
- { label: '打包', value: '打包' },
- ];
- export const CERTIFICATE_NAME_OPTIONS = [
- { label: '健康证', value: '健康证' },
- { label: '中药调剂员', value: '中药调剂员' },
- { label: '中药保管员', value: '中药保管员' },
- { label: '执业中药师', value: '执业中药师' },
- ];
- export const QUALIFICATION_STATUS_OPTIONS = [
- { label: '有效', value: 'valid' },
- { label: '即将过期', value: 'expiring' },
- { label: '过期', value: 'expired' },
- ];
- export const ORGANIZATION_TYPE_OPTIONS: Array<{
- label: string;
- value: PersonnelQualificationModel.OrganizationType;
- }> = [
- { label: '煎药企业', value: 'enterprise' },
- { label: '医疗机构', value: 'medicalInstitution' },
- ];
- export const QUALIFICATION_STATUS_LABELS: Record<
- PersonnelQualificationModel.QualificationStatus,
- string
- > = {
- valid: '有效',
- expiring: '即将过期',
- expired: '过期',
- };
- /** 各证书类型独立的 mock 附件,避免多证共用同一套图片 */
- function getDefaultAttachments(
- certName: string,
- index: number,
- ): PersonnelQualificationModel.CertificateAttachment[] {
- const attachmentSets: Record<
- string,
- PersonnelQualificationModel.CertificateAttachment[]
- > = {
- 健康证: [
- {
- id: `health-${index}-1`,
- name: '健康证正面',
- url: 'https://fastly.jsdelivr.net/npm/@vant/assets/apple-8.jpeg',
- type: 'image',
- },
- {
- id: `health-${index}-2`,
- name: '健康证反面',
- url: 'https://fastly.jsdelivr.net/npm/@vant/assets/apple-7.jpeg',
- type: 'image',
- },
- ],
- 中药保管员: [
- {
- id: `custodian-${index}-1`,
- name: '保管员资格证',
- url: 'https://fastly.jsdelivr.net/npm/@vant/assets/apple-6.jpeg',
- type: 'image',
- },
- {
- id: `custodian-${index}-2`,
- name: '保管员证书扫描件',
- url: 'https://fastly.jsdelivr.net/npm/@vant/assets/apple-5.jpeg',
- type: 'image',
- },
- ],
- 执业中药师: [
- {
- id: `pharmacist-${index}-1`,
- name: '执业药师资格证',
- url: 'https://fastly.jsdelivr.net/npm/@vant/assets/apple-4.jpeg',
- type: 'image',
- },
- {
- id: `pharmacist-${index}-2`,
- name: '执业药师注册证',
- url: 'https://fastly.jsdelivr.net/npm/@vant/assets/apple-3.jpeg',
- type: 'pdf',
- },
- ],
- 中药调剂员: [
- {
- id: `dispenser-${index}-1`,
- name: '调剂员资格证',
- url: 'https://fastly.jsdelivr.net/npm/@vant/assets/apple-2.jpeg',
- type: 'image',
- },
- {
- id: `dispenser-${index}-2`,
- name: '调剂员证书扫描件',
- url: 'https://fastly.jsdelivr.net/npm/@vant/assets/apple-1.jpeg',
- type: 'image',
- },
- ],
- };
- return (
- attachmentSets[certName] ?? [
- {
- id: `cert-${index}-1`,
- name: '证书附件',
- url: 'https://fastly.jsdelivr.net/npm/@vant/assets/apple-8.jpeg',
- type: 'image',
- },
- ]
- );
- }
- function buildCertificates(
- items: Array<
- Omit<PersonnelQualificationModel.Certificate, 'id' | 'attachments'> & {
- attachments?: PersonnelQualificationModel.CertificateAttachment[];
- }
- >,
- ): PersonnelQualificationModel.Certificate[] {
- return items.map((item, index) => ({
- ...item,
- id: `cert-${index + 1}`,
- attachments: item.attachments ?? getDefaultAttachments(item.name, index),
- }));
- }
- function resolveWorstStatus(
- certificates: PersonnelQualificationModel.Certificate[],
- ): PersonnelQualificationModel.QualificationStatus {
- if (certificates.some((item) => item.status === 'expired')) return 'expired';
- if (certificates.some((item) => item.status === 'expiring')) return 'expiring';
- return 'valid';
- }
- function buildPersonnel(
- data: Omit<
- PersonnelQualificationModel.Personnel,
- 'certificateNames' | 'qualificationStatus'
- >,
- ): PersonnelQualificationModel.Personnel {
- const certificateNames = data.certificates.map((item) => item.name).join('、');
- return {
- ...data,
- certificateNames,
- qualificationStatus: resolveWorstStatus(data.certificates),
- };
- }
- const MOCK_PERSONNEL: PersonnelQualificationModel.Personnel[] = [
- buildPersonnel({
- id: '1',
- organizationType: 'enterprise',
- enterpriseId: 'e1',
- enterpriseName: '重药煎药中心',
- decoctionCenterId: 'c1',
- decoctionCenterName: '重药华东煎药中心2',
- name: '孙明1',
- positions: ['接方、审方'],
- employeeNo: '28473',
- idNumber: '330102199001012839',
- certificates: buildCertificates([
- {
- name: '健康证',
- number: '944895756806594342',
- expiryDate: '2027-3-20',
- status: 'valid',
- type: '健康证',
- },
- {
- name: '中药保管员',
- number: '944895756806594343',
- expiryDate: '2026-4-15',
- status: 'expiring',
- type: '保管员',
- },
- {
- name: '执业中药师',
- number: '944895756806594344',
- expiryDate: '2028-6-30',
- status: 'valid',
- type: '执业药师',
- },
- ]),
- }),
- buildPersonnel({
- id: '2',
- enterpriseId: 'e1',
- enterpriseName: '重药煎药中心',
- decoctionCenterId: 'c1',
- decoctionCenterName: '重药华东煎药中心2',
- name: '孙明2',
- positions: ['审方'],
- employeeNo: '28474',
- idNumber: '330103198802022840',
- certificates: buildCertificates([
- {
- name: '健康证',
- number: '944895756806594345',
- expiryDate: '2025-1-10',
- status: 'expired',
- },
- {
- name: '执业中药师',
- number: '944895756806594346',
- expiryDate: '2027-8-20',
- status: 'valid',
- },
- ]),
- }),
- buildPersonnel({
- id: '3',
- enterpriseId: 'e1',
- enterpriseName: '重药煎药中心',
- decoctionCenterId: 'c1',
- decoctionCenterName: '重药华东煎药中心2',
- name: '孙明3',
- positions: ['配药'],
- employeeNo: '28475',
- idNumber: '330104199203033841',
- certificates: buildCertificates([
- {
- name: '中药调剂员',
- number: '944895756806594347',
- expiryDate: '2026-5-1',
- status: 'expiring',
- },
- {
- name: '健康证',
- number: '944895756806594348',
- expiryDate: '2027-2-18',
- status: 'valid',
- },
- ]),
- }),
- buildPersonnel({
- id: '4',
- enterpriseId: 'e1',
- enterpriseName: '重药煎药中心',
- decoctionCenterId: 'c1',
- decoctionCenterName: '重药华东煎药中心2',
- name: '孙明4',
- positions: ['复核'],
- employeeNo: '28476',
- idNumber: '330105199504044842',
- certificates: buildCertificates([
- {
- name: '健康证',
- number: '944895756806594349',
- expiryDate: '2027-12-31',
- status: 'valid',
- },
- ]),
- }),
- buildPersonnel({
- id: '5',
- enterpriseId: 'e1',
- enterpriseName: '重药煎药中心',
- decoctionCenterId: 'c1',
- decoctionCenterName: '重药华东煎药中心2',
- name: '孙明5',
- positions: ['煎煮'],
- employeeNo: '28477',
- idNumber: '330106199605055843',
- certificates: buildCertificates([
- {
- name: '健康证',
- number: '944895756806594350',
- expiryDate: '2024-12-1',
- status: 'expired',
- },
- ]),
- }),
- buildPersonnel({
- id: '6',
- enterpriseId: 'e1',
- enterpriseName: '重药煎药中心',
- decoctionCenterId: 'c1',
- decoctionCenterName: '重药华东煎药中心2',
- name: '孙明6',
- positions: ['打包'],
- employeeNo: '28478',
- idNumber: '330107199706066844',
- certificates: buildCertificates([
- {
- name: '健康证',
- number: '944895756806594351',
- expiryDate: '2027-9-10',
- status: 'valid',
- },
- ]),
- }),
- buildPersonnel({
- id: '7',
- enterpriseId: 'e2',
- enterpriseName: '杭州中药煎配中心',
- decoctionCenterId: 'c2',
- decoctionCenterName: '西湖煎药中心',
- name: '李明1',
- positions: ['接方、审方'],
- employeeNo: '38473',
- idNumber: '330108199807077845',
- certificates: buildCertificates([
- {
- name: '执业中药师',
- number: '944895756806594352',
- expiryDate: '2026-3-20',
- status: 'expiring',
- },
- ]),
- }),
- buildPersonnel({
- id: '8',
- organizationType: 'enterprise',
- enterpriseId: 'e2',
- enterpriseName: '杭州中药煎配中心',
- decoctionCenterId: 'c2',
- decoctionCenterName: '西湖煎药中心',
- name: '李明2',
- positions: ['配药'],
- employeeNo: '38474',
- idNumber: '330109199908088846',
- certificates: buildCertificates([
- {
- name: '中药调剂员',
- number: '944895756806594353',
- expiryDate: '2027-6-15',
- status: 'valid',
- },
- ]),
- }),
- buildPersonnel({
- id: '9',
- organizationType: 'medicalInstitution',
- enterpriseId: 'm1',
- enterpriseName: '蒋村社区卫生服务中心',
- decoctionCenterId: 'c3',
- decoctionCenterName: '蒋村煎药中心',
- name: '王芳',
- positions: ['接方、审方'],
- employeeNo: '48473',
- idNumber: '330110199001011234',
- certificates: buildCertificates([
- {
- name: '健康证',
- number: '944895756806594360',
- expiryDate: '2027-5-20',
- status: 'valid',
- },
- {
- name: '执业中药师',
- number: '944895756806594361',
- expiryDate: '2026-2-10',
- status: 'expiring',
- },
- ]),
- }),
- buildPersonnel({
- id: '10',
- organizationType: 'medicalInstitution',
- enterpriseId: 'm2',
- enterpriseName: '西湖区中医院',
- decoctionCenterId: 'c4',
- decoctionCenterName: '西湖区中医院煎药室',
- name: '赵强',
- positions: ['配药'],
- employeeNo: '48474',
- idNumber: '330111198803022345',
- certificates: buildCertificates([
- {
- name: '中药调剂员',
- number: '944895756806594362',
- expiryDate: '2027-8-1',
- status: 'valid',
- },
- ]),
- }),
- ];
- let mockStore = [...MOCK_PERSONNEL];
- function filterPersonnel(
- list: PersonnelQualificationModel.Personnel[],
- query?: PersonnelQualificationModel.ListQuery,
- ) {
- if (!query) return list;
- return list.filter((item) => {
- const organizationId = query.organizationId ?? query.enterpriseId;
- const organizationType = query.organizationType ?? 'enterprise';
- if (organizationId) {
- const itemType = item.organizationType ?? 'enterprise';
- if (itemType !== organizationType) {
- return false;
- }
- if (item.enterpriseId !== organizationId) {
- return false;
- }
- }
- if (
- query.decoctionCenterId &&
- item.decoctionCenterId !== query.decoctionCenterId
- ) {
- return false;
- }
- if (query.position && !item.positions.includes(query.position)) {
- return false;
- }
- if (
- query.qualificationStatus &&
- item.qualificationStatus !== query.qualificationStatus
- ) {
- return false;
- }
- if (query.keyword) {
- const keyword = query.keyword.trim();
- if (
- !item.name.includes(keyword) &&
- !item.employeeNo.includes(keyword)
- ) {
- return false;
- }
- }
- return true;
- });
- }
- function computeExpirySummary(): PersonnelQualificationModel.ExpirySummary {
- let expiredCount = 0;
- let expiringCount = 0;
- for (const person of mockStore) {
- if (person.qualificationStatus === 'expired') expiredCount += 1;
- else if (person.qualificationStatus === 'expiring') expiringCount += 1;
- }
- return { expiredCount, expiringCount };
- }
- /** 岗位人员资质列表(当前为本地 mock,后期对接后端接口) */
- export function listPersonnelQualificationsMethod(
- page = 1,
- size = 10,
- query?: PersonnelQualificationModel.ListQuery,
- ): Promise<TransformList<PersonnelQualificationModel.Personnel>> {
- const filtered = filterPersonnel(mockStore, query);
- const start = (page - 1) * size;
- const items = filtered.slice(start, start + size);
- return Promise.resolve({
- items,
- total: filtered.length,
- data: { page, size, total: filtered.length },
- });
- }
- /** 资质到期统计(当前为本地 mock) */
- export function getPersonnelQualificationSummaryMethod(): Promise<PersonnelQualificationModel.ExpirySummary> {
- return Promise.resolve(computeExpirySummary());
- }
- /** 岗位人员资质详情(当前为本地 mock) */
- export function getPersonnelQualificationMethod(id: string) {
- const item = mockStore.find((row) => row.id === id);
- if (!item) {
- return Promise.reject(new Error('人员记录不存在'));
- }
- return Promise.resolve({ ...item });
- }
- /** 新增/修改岗位人员资质(当前为本地 mock) */
- export function editPersonnelQualificationMethod(
- data: PersonnelQualificationModel.PersonnelForm,
- ) {
- const certificates = data.certificates.map((cert, index) => ({
- ...cert,
- id: cert.id || `cert-${Date.now()}-${index}`,
- status: cert.status ?? 'valid',
- attachments: cert.attachments ?? [],
- }));
- const enterpriseName =
- mockStore.find((item) => item.decoctionCenterId === data.decoctionCenterId)
- ?.enterpriseName ?? '重药煎药中心';
- const decoctionCenterName =
- data.decoctionCenterName ??
- mockStore.find((item) => item.decoctionCenterId === data.decoctionCenterId)
- ?.decoctionCenterName ??
- '重药华东煎药中心2';
- const payload = buildPersonnel({
- id: data.id ?? String(Date.now()),
- enterpriseId: mockStore.find(
- (item) => item.decoctionCenterId === data.decoctionCenterId,
- )?.enterpriseId,
- enterpriseName,
- decoctionCenterId: data.decoctionCenterId,
- decoctionCenterName,
- name: data.name,
- positions: data.positions,
- employeeNo: data.employeeNo,
- idNumber: data.idNumber,
- certificates,
- });
- if (data.id) {
- const index = mockStore.findIndex((item) => item.id === data.id);
- if (index === -1) {
- return Promise.reject(new Error('人员记录不存在'));
- }
- mockStore[index] = payload;
- } else {
- mockStore = [payload, ...mockStore];
- }
- return Promise.resolve(payload);
- }
- /** 删除岗位人员资质(当前为本地 mock) */
- export function deletePersonnelQualificationMethod(id: string) {
- const index = mockStore.findIndex((item) => item.id === id);
- if (index === -1) {
- return Promise.reject(new Error('人员记录不存在'));
- }
- mockStore.splice(index, 1);
- return Promise.resolve(true);
- }
- /** 煎药企业选项(mock) */
- export function optionsPersonnelEnterpriseMethod() {
- const map = new Map<string, string>();
- for (const item of mockStore) {
- if ((item.organizationType ?? 'enterprise') !== 'enterprise') continue;
- if (item.enterpriseId) {
- map.set(item.enterpriseId, item.enterpriseName);
- }
- }
- return Promise.resolve(
- [...map.entries()].map(([value, label]) => ({ label, value })),
- );
- }
- /** 医疗机构选项(mock) */
- export function optionsPersonnelMedicalInstitutionMethod() {
- const map = new Map<string, string>();
- for (const item of mockStore) {
- if (item.organizationType !== 'medicalInstitution') continue;
- if (item.enterpriseId) {
- map.set(item.enterpriseId, item.enterpriseName);
- }
- }
- return Promise.resolve(
- [...map.entries()].map(([value, label]) => ({ label, value })),
- );
- }
- /** 煎药中心选项(mock) */
- export function optionsPersonnelDecoctionCenterMethod(
- organizationId?: string,
- organizationType: PersonnelQualificationModel.OrganizationType = 'enterprise',
- ) {
- const map = new Map<string, string>();
- for (const item of mockStore) {
- const itemType = item.organizationType ?? 'enterprise';
- if (itemType !== organizationType) continue;
- if (organizationId && item.enterpriseId !== organizationId) continue;
- if (item.decoctionCenterId) {
- map.set(item.decoctionCenterId, item.decoctionCenterName);
- }
- }
- return Promise.resolve(
- [...map.entries()].map(([value, label]) => ({ label, value })),
- );
- }
|