Files
zkxw/web-admin/src/components/business/ProjectSelect.vue
T
zlwuandCursor 96518c08fb fix(web-admin): 简化项目归属维护调整弹窗 (#52)
展示原项目组/项目,录入新项目组/项目与原因;确认时静默预览并仍级联关联单据。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-05 16:54:22 +08:00

119 lines
3.4 KiB
Vue

<template>
<div style="width: 100%">
<el-select
style="width: 100%"
:model-value="modelValue"
:disabled="disabled"
:loading="loading"
filterable
clearable
:placeholder="team ? '请选择项目组' : '请选择项目'"
@update:model-value="$emit('update:modelValue', $event || '')"
>
<el-option
v-if="modelValue && !displayOptions.some((o) => o.id === modelValue)"
:value="modelValue"
:label="projectName || modelValue"
disabled
/>
<el-option
v-for="option in displayOptions"
:key="option.id"
:value="option.id"
:label="
team
? option.teamName
: teamId
? option.projectName
: `${option.projectName} · ${option.teamName}`
"
:disabled="!filter && option.disabled"
/>
</el-select>
<div v-if="error" class="form-tip"
>项目选项加载失败<el-button link type="primary" @click="retry++"
><el-icon><RefreshRight /></el-icon>重试</el-button
></div
>
</div>
</template>
<script setup lang="ts">
import { projectOptionsParams } from '@/utils/project-management'
import { RefreshRight } from '@element-plus/icons-vue'
import {
fetchProjectOptions,
bizLabels,
type BizType,
type ProjectOption
} from '@/api/project-management'
const props = defineProps<{
filter?: boolean
team?: boolean
/** When selecting projects, keep options under this team. */
teamId?: string
modelValue?: string
bizType?: BizType
disabled?: boolean
projectName?: string
}>()
const emit = defineEmits<{
'update:modelValue': [value: string]
required: [value: boolean]
ready: [value: boolean]
}>()
const options = ref<ProjectOption[]>([])
const displayOptions = computed(() => {
if (props.team) {
return [
...new Map(
options.value.map((option) => [option.teamId, { ...option, id: option.teamId }])
).values()
]
}
return props.teamId
? options.value.filter((option) => option.teamId === props.teamId)
: options.value
})
const loading = ref(false)
const error = ref(false),
retry = ref(0)
let version = 0
watch(
() => [props.bizType, props.disabled, props.filter, retry.value],
async () => {
const requestVersion = ++version
if (props.disabled) {
loading.value = false
return
}
loading.value = true
error.value = false
emit('ready', false)
try {
const results = await Promise.all(
(props.bizType ? [props.bizType] : (Object.keys(bizLabels) as BizType[])).map((bizType) =>
fetchProjectOptions(projectOptionsParams(bizType, props.filter))
)
)
const result = {
list: [
...new Map(
results.flatMap((result) => result.list).map((option) => [option.id, option])
).values()
],
required: results.some((result) => result.required)
}
if (requestVersion !== version) return
options.value = result.list || []
emit('required', result.required)
emit('ready', true)
} catch {
if (requestVersion === version) error.value = true
} finally {
if (requestVersion === version) loading.value = false
}
},
{ immediate: true }
)
</script>