Files
zcglxt/src/views/allocation/components/CreateAllocationDialog.vue
Claude e48975f9d5 fix: 修复前端登录体验和API调用问题
- 修复路由守卫:未登录时直接跳转,不显示提示信息
- 修复API拦截器:401错误直接跳转,无需确认
- 移除不必要的ElMessageBox确认框
- 优化Token过期处理逻辑
- 修复文件管理API引入路径和URL前缀
- 修复调拨/回收管理API端点不匹配问题
- 修复通知管理API方法不匹配问题
- 统一系统配置API路径为单数形式

影响文件:
- src/router/index.ts
- src/api/request.ts
- src/api/file.ts
- src/api/index.ts

测试状态:
- 前端构建通过
- 所有API路径已验证
- 登录流程测试通过

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-25 00:26:33 +08:00

344 lines
8.7 KiB
Vue

<template>
<el-dialog
v-model="visible"
:title="isEdit ? '编辑分配单' : '新建分配单'"
width="900px"
:close-on-click-modal="false"
@close="handleClose"
>
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="单据类型" prop="orderType">
<el-select
v-model="formData.orderType"
placeholder="请选择"
:disabled="isEdit"
>
<el-option
v-for="(item, key) in ALLOCATION_ORDER_TYPE"
:key="key"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="目标机构" prop="targetOrganizationId">
<el-select
v-model="formData.targetOrganizationId"
placeholder="请选择"
filterable
>
<el-option
v-for="org in organizations"
:key="org.id"
:label="org.orgName"
:value="org.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="标题" prop="title">
<el-input
v-model="formData.title"
placeholder="请输入分配单标题"
maxlength="100"
show-word-limit
/>
</el-form-item>
</el-col>
</el-row>
<!-- 资产选择 -->
<el-form-item label="选择资产">
<div class="asset-selector">
<el-button type="primary" :icon="Plus" @click="showAssetSelector">
添加资产
</el-button>
<span class="selected-count">
已选 {{ selectedAssets.length }}
</span>
</div>
<!-- 已选资产列表 -->
<el-table
:data="selectedAssets"
border
max-height="300"
class="selected-assets-table"
>
<el-table-column prop="assetCode" label="资产编码" width="180" />
<el-table-column prop="assetName" label="资产名称" min-width="150" />
<el-table-column prop="deviceType.typeName" label="设备类型" width="120" />
<el-table-column prop="organization.orgName" label="当前机构" width="150" />
<el-table-column prop="status" label="状态" width="100">
<template #default="{ row }">
<el-tag :type="getStatusType(row.status)">
{{ getStatusName(row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="80" fixed="right">
<template #default="{ $index }">
<el-button
link
type="danger"
@click="removeAsset($index)"
>
移除
</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="formData.remark"
type="textarea"
:rows="3"
placeholder="请输入备注信息"
maxlength="500"
show-word-limit
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button @click="handleSaveDraft">
保存草稿
</el-button>
<el-button type="primary" :loading="submitting" @click="handleSubmit">
提交审批
</el-button>
</div>
</template>
<!-- 资产选择器对话框 -->
<AssetSelectorDialog
v-model="assetSelectorVisible"
:exclude-ids="selectedAssetIds"
@confirm="handleAssetSelect"
/>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import { createAllocationOrder, updateAllocationOrder, getOrganizationTree } from '@/api'
import { ALLOCATION_ORDER_TYPE, ASSET_STATUS } from '@/utils/constants'
import AssetSelectorDialog from './AssetSelectorDialog.vue'
interface Props {
modelValue: boolean
orderId?: number | null
}
interface Emits {
(e: 'update:modelValue', value: boolean): void
(e: 'success'): void
}
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
const visible = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val)
})
const isEdit = computed(() => !!props.orderId)
const formRef = ref()
const submitting = ref(false)
const organizations = ref<any[]>([])
const assetSelectorVisible = ref(false)
const selectedAssets = ref<any[]>([])
const formData = reactive({
orderType: 'allocation',
targetOrganizationId: undefined,
title: '',
remark: ''
})
const formRules = {
orderType: [
{ required: true, message: '请选择单据类型', trigger: 'change' }
],
targetOrganizationId: [
{ required: true, message: '请选择目标机构', trigger: 'change' }
],
title: [
{ required: true, message: '请输入标题', trigger: 'blur' },
{ min: 2, max: 100, message: '标题长度在 2 到 100 个字符', trigger: 'blur' }
]
}
// 已选资产ID列表
const selectedAssetIds = computed(() => {
return selectedAssets.value.map(asset => asset.id)
})
// 获取网点列表
const fetchOrganizations = async () => {
try {
const tree = await getOrganizationTree()
const flatten = (nodes: any[]) => {
const result: any[] = []
nodes.forEach(node => {
result.push(node)
if (node.children) {
result.push(...flatten(node.children))
}
})
return result
}
organizations.value = flatten(tree)
} catch (error) {
console.error('获取网点失败', error)
}
}
// 显示资产选择器
const showAssetSelector = () => {
assetSelectorVisible.value = true
}
// 处理资产选择
const handleAssetSelect = (assets: any[]) => {
selectedAssets.value = [...selectedAssets.value, ...assets]
}
// 移除资产
const removeAsset = (index: number) => {
selectedAssets.value.splice(index, 1)
}
// 获取状态标签类型
const getStatusType = (status: string) => {
const item = Object.values(ASSET_STATUS).find(item => item.value === status)
return item?.type || ''
}
// 获取状态名称
const getStatusName = (status: string) => {
const item = Object.values(ASSET_STATUS).find(item => item.value === status)
return item?.label || status
}
// 保存草稿
const handleSaveDraft = async () => {
if (selectedAssets.value.length === 0) {
ElMessage.warning('请至少选择一项资产')
return
}
await submitForm(false)
}
// 提交审批
const handleSubmit = async () => {
// 验证表单
const valid = await formRef.value?.validate().catch(() => false)
if (!valid) return
if (selectedAssets.value.length === 0) {
ElMessage.warning('请至少选择一项资产')
return
}
await submitForm(true)
}
// 提交表单
const submitForm = async (submitForApproval: boolean) => {
submitting.value = true
try {
const data = {
...formData,
assetIds: selectedAssets.value.map(asset => asset.id),
submitForApproval
}
if (isEdit.value) {
await updateAllocationOrder(props.orderId!, data)
ElMessage.success(submitForApproval ? '提交成功' : '保存成功')
} else {
await createAllocationOrder(data)
ElMessage.success(submitForApproval ? '提交成功' : '保存成功')
}
emit('success')
handleClose()
} catch (error) {
ElMessage.error('操作失败')
} finally {
submitting.value = false
}
}
// 关闭对话框
const handleClose = () => {
visible.value = false
// 重置表单
setTimeout(() => {
formRef.value?.resetFields()
selectedAssets.value = []
Object.assign(formData, {
orderType: 'allocation',
targetOrganizationId: undefined,
title: '',
remark: ''
})
}, 300)
}
// 如果是编辑模式,加载数据
watch(
() => props.orderId,
(orderId) => {
if (orderId && props.modelValue) {
// TODO: 加载分配单详情
}
}
)
// 初始化
fetchOrganizations()
</script>
<style scoped lang="scss">
.asset-selector {
display: flex;
align-items: center;
gap: 12px;
.selected-count {
font-size: 14px;
color: #909399;
}
}
.selected-assets-table {
margin-top: 12px;
}
</style>