fix: 删除类型

This commit is contained in:
王天骄
2026-06-18 14:53:49 +08:00
parent 88131781bb
commit 58c2764e06
5 changed files with 147 additions and 45 deletions
+2 -2
View File
@@ -390,9 +390,9 @@ function normalizeCase(item: unknown, index: number): CaseListItem {
title,
caseType: getString(record, ['case_type', 'caseType', 'type']),
publishStatus,
institutionId: getRelatedId(record, ['institution_id', 'institutionId'], ['institution', 'institution_info', 'institutionInfo']),
institutionId: getRelatedId(record, ['institution_id', 'institutionId', 'institution'], ['institution_info', 'institutionInfo']),
institutionName: getRelatedName(record, ['institution_name', 'institutionName', 'organization_name', 'organizationName'], ['institution', 'institution_info', 'institutionInfo']),
departmentId: getRelatedId(record, ['department_id', 'departmentId'], ['department', 'department_info', 'departmentInfo']),
departmentId: getRelatedId(record, ['department_id', 'departmentId', 'department'], ['department_info', 'departmentInfo']),
departmentName: getRelatedName(record, ['department_name', 'departmentName'], ['department', 'department_info', 'departmentInfo']),
difficulty: getString(record, ['difficulty']),
chiefComplaint: getString(record, ['chief_complaint', 'chiefComplaint']),
+31 -2
View File
@@ -134,6 +134,28 @@ function getBannerUrlFromResponse(data: unknown): string {
return ''
}
function getInstitutionIdFromResponse(data: unknown): number {
if (!data || typeof data !== 'object') {
return 0
}
const record = data as Record<string, unknown>
const id = record.id || record.institution_id || record.institutionId
if (typeof id === 'number' && Number.isFinite(id)) {
return id
}
if (typeof id === 'string' && Number.isFinite(Number(id))) {
return Number(id)
}
const nested = record.data || record.result || record.payload || record.institution
if (nested && typeof nested === 'object') {
return getInstitutionIdFromResponse(nested)
}
return 0
}
function normalizeInstitution(item: unknown): InstitutionListItem {
const record = item && typeof item === 'object' ? (item as Record<string, unknown>) : {}
const id = record.id
@@ -283,7 +305,7 @@ export async function fetchInstitutions(params: InstitutionListParams): Promise<
}
}
export async function createInstitution(params: InstitutionMutationParams): Promise<unknown> {
export async function createInstitution(params: InstitutionMutationParams): Promise<InstitutionListItem> {
const response = await fetch('/server/api/cms/institutions/', {
method: 'POST',
headers: {
@@ -294,7 +316,14 @@ export async function createInstitution(params: InstitutionMutationParams): Prom
body: JSON.stringify(params.payload)
})
return parseMutationResponse(response, '新增机构失败')
const data = await parseMutationResponse(response, '新增机构失败')
const normalized = normalizeInstitution(data)
const id = normalized.id || getInstitutionIdFromResponse(data)
return {
...normalized,
id
}
}
export async function updateInstitution(params: UpdateInstitutionParams): Promise<unknown> {
+2 -2
View File
@@ -490,8 +490,8 @@ function fillDetailForm(row: CaseListItem, fullData: unknown) {
detailForm.title = getString(record, ['title', 'name', 'case_title', 'caseTitle'], row.title)
detailForm.case_type = normalizeCaseType(getString(record, ['case_type', 'caseType'], row.caseType), normalizeCaseType(row.caseType, 'traditional'))
detailForm.institution_name = getString(record, ['institution_name', 'institutionName'], row.institutionName || row.institutionId)
detailForm.department_name = getString(record, ['department_name', 'departmentName'], row.departmentName || row.departmentId)
detailForm.institution_name = getString(record, ['institution_name', 'institutionName'], row.institutionName || row.institutionId || getString(record, ['institution']))
detailForm.department_name = getString(record, ['department_name', 'departmentName'], row.departmentName || row.departmentId || getString(record, ['department']))
detailForm.difficulty = getString(record, ['difficulty'], row.difficulty)
detailForm.chief_complaint = getString(record, ['chief_complaint', 'chiefComplaint'], row.chiefComplaint)
detailForm.description = getString(record, ['description', 'summary', 'content'])
+20 -3
View File
@@ -420,6 +420,7 @@
<el-form-item label="机构">
<el-select
v-model="detailForm.institution_id"
:disabled="!canEditDetailCase"
:loading="loadingInstitutions"
clearable
filterable
@@ -440,7 +441,7 @@
<el-form-item label="科室">
<el-select
v-model="detailForm.department_id"
:disabled="canManageInstitution && !detailForm.institution_id"
:disabled="!canEditDetailCase || (canManageInstitution && !detailForm.institution_id)"
:loading="loadingDepartments"
clearable
filterable
@@ -987,12 +988,20 @@ async function loadDepartmentOptions(institutionId?: number) {
}
function handleInstitutionVisibleChange(visible: boolean) {
if (detailDrawerVisible.value && !canEditDetailCase.value) {
return
}
if (visible) {
loadInstitutionOptions()
}
}
function handleDepartmentVisibleChange(visible: boolean) {
if (detailDrawerVisible.value && !canEditDetailCase.value) {
return
}
if (visible) {
loadDepartmentOptions(activeCaseForm().institution_id)
}
@@ -1005,6 +1014,10 @@ function handleCaseInstitutionChange() {
}
function handleDetailInstitutionChange() {
if (!canEditDetailCase.value) {
return
}
detailForm.department_id = undefined
detailForm.department_name = ''
loadDepartmentOptions(detailForm.institution_id)
@@ -1015,6 +1028,10 @@ function handleCaseDepartmentChange(value?: number) {
}
function handleDetailDepartmentChange(value?: number) {
if (!canEditDetailCase.value) {
return
}
detailForm.department_name = getDepartmentName(value)
}
@@ -1574,8 +1591,8 @@ function fillDetailForm(row: CaseListItem, fullData: unknown) {
detailForm.title = getImportString(record, ['title', 'name', 'case_title', 'caseTitle'], row.title)
detailForm.case_type = normalizeImportCaseType(getImportString(record, ['case_type', 'caseType'], row.caseType), normalizeImportCaseType(row.caseType, 'traditional'))
detailForm.institution_id = getImportNumber(record, ['institution_id', 'institutionId']) ?? undefined
detailForm.department_id = getImportNumber(record, ['department_id', 'departmentId']) ?? undefined
detailForm.institution_id = getImportNumber(record, ['institution_id', 'institutionId', 'institution']) ?? undefined
detailForm.department_id = getImportNumber(record, ['department_id', 'departmentId', 'department']) ?? undefined
detailForm.department_name = getImportString(record, ['department_name', 'departmentName'], row.departmentName)
detailForm.difficulty = getImportString(record, ['difficulty'], row.difficulty)
detailForm.chief_complaint = getImportString(record, ['chief_complaint', 'chiefComplaint'], row.chiefComplaint)
+92 -36
View File
@@ -3,7 +3,7 @@
<section class="page-toolbar">
<div>
<h1>医院管理</h1>
<p>维护医院列表支持按名称编码类型和地区查询</p>
<p>维护医院列表支持按名称编码和地区查询</p>
</div>
<div class="toolbar-actions">
<el-button :icon="Download" :loading="downloadingTemplate" @click="downloadTemplate">导入模板</el-button>
@@ -15,11 +15,6 @@
<section class="filter-bar institution-filter">
<el-input v-model="filters.search" :prefix-icon="Search" clearable placeholder="搜索医院名称/编码" @keyup.enter="loadInstitutions" />
<el-select v-model="filters.type" clearable placeholder="类型">
<el-option label="医院" value="hospital" />
<el-option label="医学院校" value="school" />
<el-option label="基层机构" value="primary" />
</el-select>
<el-input v-model="filters.province" clearable placeholder="省份" @keyup.enter="loadInstitutions" />
<el-input v-model="filters.city" clearable placeholder="城市" @keyup.enter="loadInstitutions" />
<el-button :icon="Search" type="primary" @click="handleSearch">查询</el-button>
@@ -89,13 +84,6 @@
<el-input v-model="institutionForm.name" placeholder="请输入机构名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="类型" prop="type">
<el-select v-model="institutionForm.type" allow-create filterable default-first-option placeholder="请选择或输入类型">
<el-option v-for="item in institutionTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="等级" prop="level">
<el-input v-model="institutionForm.level" placeholder="例如:三甲、二甲" />
@@ -103,12 +91,31 @@
</el-col>
<el-col :span="12">
<el-form-item label="省" prop="province">
<el-input v-model="institutionForm.province" placeholder="请输入省份" />
<el-select
v-model="institutionForm.province"
allow-create
clearable
filterable
default-first-option
placeholder="请选择省/直辖市"
@change="handleProvinceChange"
>
<el-option v-for="item in provinceOptions" :key="item.name" :label="item.name" :value="item.name" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="市" prop="city">
<el-input v-model="institutionForm.city" placeholder="请输入城市" />
<el-select
v-model="institutionForm.city"
allow-create
clearable
filterable
default-first-option
placeholder="请选择城市"
>
<el-option v-for="item in cityOptions" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
@@ -135,7 +142,7 @@
</el-upload>
<el-button :icon="Delete" @click="clearInstitutionBanner">清空背景图</el-button>
</div>
<p class="institution-banner-tip">编辑时选择图片会先上传背景图再保存机构信息支持 png/jpg/jpeg/webp最大 5MB</p>
<p class="institution-banner-tip">选择图片后保存会自动上传背景图支持 png/jpg/jpeg/webp最大 5MB</p>
</div>
</div>
</el-form-item>
@@ -215,7 +222,6 @@ const bannerFile = ref<File | null>(null)
const institutions = ref<InstitutionListItem[]>([])
const filters = reactive({
search: '',
type: '',
province: '',
city: ''
})
@@ -233,10 +239,41 @@ const institutionForm = reactive({
bannerUrl: ''
})
const institutionTypeOptions = [
{ label: '医院 hospital', value: 'hospital' },
{ label: '医学院校 school', value: 'school' },
{ label: '基层机构 primary', value: 'primary' }
const provinceOptions = [
{ name: '北京市', cities: ['北京市'] },
{ name: '天津市', cities: ['天津市'] },
{ name: '上海市', cities: ['上海市'] },
{ name: '重庆市', cities: ['重庆市'] },
{ name: '河北省', cities: ['石家庄市', '唐山市', '秦皇岛市', '邯郸市', '邢台市', '保定市', '张家口市', '承德市', '沧州市', '廊坊市', '衡水市'] },
{ name: '山西省', cities: ['太原市', '大同市', '阳泉市', '长治市', '晋城市', '朔州市', '晋中市', '运城市', '忻州市', '临汾市', '吕梁市'] },
{ name: '内蒙古自治区', cities: ['呼和浩特市', '包头市', '乌海市', '赤峰市', '通辽市', '鄂尔多斯市', '呼伦贝尔市', '巴彦淖尔市', '乌兰察布市'] },
{ name: '辽宁省', cities: ['沈阳市', '大连市', '鞍山市', '抚顺市', '本溪市', '丹东市', '锦州市', '营口市', '阜新市', '辽阳市', '盘锦市', '铁岭市', '朝阳市', '葫芦岛市'] },
{ name: '吉林省', cities: ['长春市', '吉林市', '四平市', '辽源市', '通化市', '白山市', '松原市', '白城市'] },
{ name: '黑龙江省', cities: ['哈尔滨市', '齐齐哈尔市', '鸡西市', '鹤岗市', '双鸭山市', '大庆市', '伊春市', '佳木斯市', '七台河市', '牡丹江市', '黑河市', '绥化市'] },
{ name: '江苏省', cities: ['南京市', '无锡市', '徐州市', '常州市', '苏州市', '南通市', '连云港市', '淮安市', '盐城市', '扬州市', '镇江市', '泰州市', '宿迁市'] },
{ name: '浙江省', cities: ['杭州市', '宁波市', '温州市', '嘉兴市', '湖州市', '绍兴市', '金华市', '衢州市', '舟山市', '台州市', '丽水市'] },
{ name: '安徽省', cities: ['合肥市', '芜湖市', '蚌埠市', '淮南市', '马鞍山市', '淮北市', '铜陵市', '安庆市', '黄山市', '滁州市', '阜阳市', '宿州市', '六安市', '亳州市', '池州市', '宣城市'] },
{ name: '福建省', cities: ['福州市', '厦门市', '莆田市', '三明市', '泉州市', '漳州市', '南平市', '龙岩市', '宁德市'] },
{ name: '江西省', cities: ['南昌市', '景德镇市', '萍乡市', '九江市', '新余市', '鹰潭市', '赣州市', '吉安市', '宜春市', '抚州市', '上饶市'] },
{ name: '山东省', cities: ['济南市', '青岛市', '淄博市', '枣庄市', '东营市', '烟台市', '潍坊市', '济宁市', '泰安市', '威海市', '日照市', '临沂市', '德州市', '聊城市', '滨州市', '菏泽市'] },
{ name: '河南省', cities: ['郑州市', '开封市', '洛阳市', '平顶山市', '安阳市', '鹤壁市', '新乡市', '焦作市', '濮阳市', '许昌市', '漯河市', '三门峡市', '南阳市', '商丘市', '信阳市', '周口市', '驻马店市'] },
{ name: '湖北省', cities: ['武汉市', '黄石市', '十堰市', '宜昌市', '襄阳市', '鄂州市', '荆门市', '孝感市', '荆州市', '黄冈市', '咸宁市', '随州市'] },
{ name: '湖南省', cities: ['长沙市', '株洲市', '湘潭市', '衡阳市', '邵阳市', '岳阳市', '常德市', '张家界市', '益阳市', '郴州市', '永州市', '怀化市', '娄底市'] },
{ name: '广东省', cities: ['广州市', '韶关市', '深圳市', '珠海市', '汕头市', '佛山市', '江门市', '湛江市', '茂名市', '肇庆市', '惠州市', '梅州市', '汕尾市', '河源市', '阳江市', '清远市', '东莞市', '中山市', '潮州市', '揭阳市', '云浮市'] },
{ name: '广西壮族自治区', cities: ['南宁市', '柳州市', '桂林市', '梧州市', '北海市', '防城港市', '钦州市', '贵港市', '玉林市', '百色市', '贺州市', '河池市', '来宾市', '崇左市'] },
{ name: '海南省', cities: ['海口市', '三亚市', '三沙市', '儋州市'] },
{ name: '四川省', cities: ['成都市', '自贡市', '攀枝花市', '泸州市', '德阳市', '绵阳市', '广元市', '遂宁市', '内江市', '乐山市', '南充市', '眉山市', '宜宾市', '广安市', '达州市', '雅安市', '巴中市', '资阳市'] },
{ name: '贵州省', cities: ['贵阳市', '六盘水市', '遵义市', '安顺市', '毕节市', '铜仁市'] },
{ name: '云南省', cities: ['昆明市', '曲靖市', '玉溪市', '保山市', '昭通市', '丽江市', '普洱市', '临沧市'] },
{ name: '西藏自治区', cities: ['拉萨市', '日喀则市', '昌都市', '林芝市', '山南市', '那曲市'] },
{ name: '陕西省', cities: ['西安市', '铜川市', '宝鸡市', '咸阳市', '渭南市', '延安市', '汉中市', '榆林市', '安康市', '商洛市'] },
{ name: '甘肃省', cities: ['兰州市', '嘉峪关市', '金昌市', '白银市', '天水市', '武威市', '张掖市', '平凉市', '酒泉市', '庆阳市', '定西市', '陇南市'] },
{ name: '青海省', cities: ['西宁市', '海东市'] },
{ name: '宁夏回族自治区', cities: ['银川市', '石嘴山市', '吴忠市', '固原市', '中卫市'] },
{ name: '新疆维吾尔自治区', cities: ['乌鲁木齐市', '克拉玛依市', '吐鲁番市', '哈密市'] },
{ name: '香港特别行政区', cities: ['香港特别行政区'] },
{ name: '澳门特别行政区', cities: ['澳门特别行政区'] },
{ name: '台湾省', cities: ['台北市', '新北市', '桃园市', '台中市', '台南市', '高雄市'] }
]
const institutionRules = computed<FormRules>(() => {
@@ -251,6 +288,7 @@ const institutionRules = computed<FormRules>(() => {
})
const institutionDialogTitle = computed(() => (institutionMode.value === 'create' ? '新增机构' : '编辑机构'))
const institutionBannerPreview = computed(() => bannerPreviewUrl.value || institutionForm.bannerUrl.trim())
const cityOptions = computed(() => provinceOptions.find(item => item.name === institutionForm.province)?.cities || [])
async function loadInstitutions() {
if (!appStore.token) {
@@ -263,7 +301,6 @@ async function loadInstitutions() {
const result = await fetchInstitutions({
token: appStore.token,
search: filters.search,
type: filters.type,
province: filters.province,
city: filters.city,
page: pagination.page
@@ -284,7 +321,6 @@ function handleSearch() {
function resetFilters() {
filters.search = ''
filters.type = ''
filters.province = ''
filters.city = ''
pagination.page = 1
@@ -338,6 +374,23 @@ function resetInstitutionForm() {
institutionFormRef.value?.clearValidate()
}
function handleProvinceChange(value: string) {
const matched = provinceOptions.find(item => item.name === value)
if (!matched) {
institutionForm.city = ''
return
}
if (matched.cities.length === 1) {
institutionForm.city = matched.cities[0]
return
}
if (!matched.cities.includes(institutionForm.city)) {
institutionForm.city = ''
}
}
function buildCreatePayload(): CreateInstitutionPayload {
const payload: CreateInstitutionPayload = {
code: institutionForm.code.trim(),
@@ -384,14 +437,6 @@ function buildUpdatePayload(): InstitutionPayload {
}
function setInstitutionBannerFile(file: UploadRawFile) {
if (institutionMode.value === 'create') {
bannerFileList.value = []
bannerFile.value = null
bannerUploadRef.value?.clearFiles()
ElMessage.warning('请先新增机构,保存后编辑时再上传背景图')
return
}
const allowedTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/webp']
if (!allowedTypes.includes(file.type)) {
bannerFileList.value = []
@@ -448,14 +493,15 @@ function clearInstitutionBanner() {
bannerUploadRef.value?.clearFiles()
}
async function uploadPendingBanner() {
if (!bannerFile.value || !editingInstitution.value || !appStore.token) {
async function uploadPendingBanner(institutionId?: number) {
const id = institutionId ?? editingInstitution.value?.id
if (!bannerFile.value || !id || !appStore.token) {
return ''
}
const result = await uploadInstitutionBanner({
token: appStore.token,
id: editingInstitution.value.id,
id,
file: bannerFile.value
})
if (!result.bannerUrl) {
@@ -479,10 +525,21 @@ async function submitInstitutionForm() {
try {
savingInstitution.value = true
if (institutionMode.value === 'create') {
await createInstitution({
const createdInstitution = await createInstitution({
token: appStore.token,
payload: buildCreatePayload()
})
if (bannerFile.value && !createdInstitution.id) {
throw new Error('新增机构成功但未返回机构ID,无法上传背景图')
}
const uploadedBannerUrl = await uploadPendingBanner(createdInstitution.id)
if (uploadedBannerUrl) {
await updateInstitution({
token: appStore.token,
id: createdInstitution.id,
payload: { banner_url: uploadedBannerUrl }
})
}
ElMessage.success('机构已新增')
pagination.page = 1
} else if (editingInstitution.value) {
@@ -607,7 +664,6 @@ async function exportCurrentInstitutions() {
await exportInstitutions({
token: appStore.token,
search: filters.search,
type: filters.type,
province: filters.province,
city: filters.city
})