888 lines
24 KiB
TypeScript
888 lines
24 KiB
TypeScript
import { Request, Response } from 'express'
|
||
import prisma from '../utils/prisma'
|
||
import { successResponse, errorResponse } from '../utils/response'
|
||
|
||
const parseNumber = (value: any): number | undefined => {
|
||
const num = Number(value)
|
||
return Number.isNaN(num) ? undefined : num
|
||
}
|
||
|
||
const parseDate = (value?: any): Date | null => {
|
||
if (!value) return null
|
||
const date = new Date(value)
|
||
return Number.isNaN(date.getTime()) ? null : date
|
||
}
|
||
|
||
const equipmentInclude = {
|
||
storageLocation: {
|
||
select: {
|
||
id: true,
|
||
name: true,
|
||
code: true,
|
||
status: true
|
||
}
|
||
}
|
||
}
|
||
|
||
const getEquipmentByIdentifier = async (equipmentId?: number, equipmentCode?: string) => {
|
||
if (equipmentId) {
|
||
return prisma.equipment.findUnique({ where: { id: equipmentId }, include: equipmentInclude })
|
||
}
|
||
if (equipmentCode) {
|
||
return prisma.equipment.findUnique({ where: { equipment_code: equipmentCode }, include: equipmentInclude })
|
||
}
|
||
return null
|
||
}
|
||
|
||
const ensurePersonAvailable = async (personId?: number) => {
|
||
if (!personId) {
|
||
throw new Error('使用者ID不能为空')
|
||
}
|
||
const person = await prisma.person.findUnique({ where: { id: personId } })
|
||
if (!person || person.status !== 'active') {
|
||
throw new Error('使用者不存在或已禁用')
|
||
}
|
||
return person
|
||
}
|
||
|
||
const ensureEquipmentBorrowable = (equipment: any) => {
|
||
// 检查报废状态
|
||
if (equipment.status === '待报废' || equipment.status === '已报废') {
|
||
throw new Error('资产已报废或待报废,不可借用')
|
||
}
|
||
// 检查维护状态
|
||
if (equipment.status === '维护中') {
|
||
throw new Error('资产正在维护中,不可借用')
|
||
}
|
||
if (equipment.status !== '可用') {
|
||
throw new Error('资产状态不可借用')
|
||
}
|
||
if (equipment.remaining_quantity <= 0) {
|
||
throw new Error('资产库存不足')
|
||
}
|
||
}
|
||
|
||
const appendLongTermNotes = (notes?: string, isLongTerm?: boolean) => {
|
||
const longTerm = Boolean(isLongTerm)
|
||
return longTerm && notes
|
||
? `${notes};在职长期`
|
||
: longTerm
|
||
? '在职长期'
|
||
: notes || undefined
|
||
}
|
||
|
||
const getChildrenSnapshot = async (equipmentId: number) => {
|
||
const children = await prisma.equipment.findMany({
|
||
where: { parent_id: equipmentId },
|
||
select: {
|
||
id: true,
|
||
equipment_code: true,
|
||
equipment_name: true,
|
||
equipment_model: true,
|
||
equipment_type: true,
|
||
unit_price: true
|
||
}
|
||
})
|
||
|
||
return {
|
||
children,
|
||
snapshot: children.length > 0 ? JSON.stringify(children) : undefined
|
||
}
|
||
}
|
||
|
||
const borrowEquipmentInTransaction = async (
|
||
equipment: any,
|
||
person: any,
|
||
expectedReturn: Date | null,
|
||
combinedNotes?: string,
|
||
isLongTerm?: boolean,
|
||
childrenSnapshot?: string
|
||
) => {
|
||
return prisma.$transaction(async (tx) => {
|
||
const record = await tx.borrowRecord.create({
|
||
data: {
|
||
equipment_id: equipment.id,
|
||
equipment_code: equipment.equipment_code,
|
||
person_id: person.id,
|
||
person_name: person.real_name,
|
||
person_nickname: person.nickname,
|
||
person_identifier: person.id_number,
|
||
expected_return_time: expectedReturn,
|
||
is_long_term: Boolean(isLongTerm),
|
||
notes: combinedNotes,
|
||
status: '已借出',
|
||
children_snapshot: childrenSnapshot
|
||
}
|
||
})
|
||
|
||
const nextStatus = equipment.remaining_quantity === 1 ? '已借出' : '可用'
|
||
const updateResult = await tx.equipment.updateMany({
|
||
where: {
|
||
id: equipment.id,
|
||
status: '可用',
|
||
remaining_quantity: equipment.remaining_quantity
|
||
},
|
||
data: {
|
||
remaining_quantity: { decrement: 1 },
|
||
borrowed_value: { increment: Number(equipment.unit_price) },
|
||
available_value: { decrement: Number(equipment.unit_price) },
|
||
status: nextStatus
|
||
}
|
||
})
|
||
|
||
if (updateResult.count !== 1) {
|
||
throw new Error('资产库存已变化,请刷新后重试')
|
||
}
|
||
|
||
const updatedEquipment = await tx.equipment.findUnique({
|
||
where: { id: equipment.id },
|
||
include: equipmentInclude
|
||
})
|
||
|
||
return { record, updatedEquipment }
|
||
})
|
||
}
|
||
|
||
const findActiveBorrowRecord = async (
|
||
equipmentId: number,
|
||
borrowRecordId?: number,
|
||
personId?: number
|
||
) => {
|
||
if (borrowRecordId) {
|
||
return prisma.borrowRecord.findFirst({
|
||
where: {
|
||
id: borrowRecordId,
|
||
equipment_id: equipmentId,
|
||
status: '已借出'
|
||
}
|
||
})
|
||
}
|
||
|
||
if (personId) {
|
||
return prisma.borrowRecord.findFirst({
|
||
where: {
|
||
equipment_id: equipmentId,
|
||
person_id: personId,
|
||
status: '已借出'
|
||
},
|
||
orderBy: { borrow_time: 'desc' }
|
||
})
|
||
}
|
||
|
||
const activeRecords = await prisma.borrowRecord.findMany({
|
||
where: {
|
||
equipment_id: equipmentId,
|
||
status: '已借出'
|
||
},
|
||
orderBy: { borrow_time: 'desc' },
|
||
take: 2
|
||
})
|
||
|
||
if (activeRecords.length > 1) {
|
||
throw new Error('该资产存在多条未归还记录,请明确选择归还使用者')
|
||
}
|
||
|
||
return activeRecords[0] || null
|
||
}
|
||
|
||
const getChildrenDiff = async (equipmentId: number, borrowRecord: any) => {
|
||
if (!borrowRecord?.children_snapshot) {
|
||
return null
|
||
}
|
||
|
||
const borrowedChildren = JSON.parse(borrowRecord.children_snapshot) as any[]
|
||
const currentChildren = await prisma.equipment.findMany({
|
||
where: { parent_id: equipmentId },
|
||
select: {
|
||
id: true,
|
||
equipment_code: true,
|
||
equipment_name: true,
|
||
equipment_model: true,
|
||
equipment_type: true,
|
||
unit_price: true
|
||
}
|
||
})
|
||
|
||
const borrowedIds = new Set(borrowedChildren.map((child) => child.id))
|
||
const currentIds = new Set(currentChildren.map((child) => child.id))
|
||
const removed = borrowedChildren.filter((child) => !currentIds.has(child.id))
|
||
const added = currentChildren.filter((child) => !borrowedIds.has(child.id))
|
||
|
||
if (removed.length === 0 && added.length === 0) {
|
||
return null
|
||
}
|
||
|
||
return { removed, added }
|
||
}
|
||
|
||
const returnEquipmentInTransaction = async (
|
||
equipment: any,
|
||
borrowRecord: any,
|
||
returnCondition: string,
|
||
notes?: string
|
||
) => {
|
||
return prisma.$transaction(async (tx) => {
|
||
const returnTime = new Date()
|
||
const updatedBorrowRecord = await tx.borrowRecord.updateMany({
|
||
where: {
|
||
id: borrowRecord.id,
|
||
status: '已借出'
|
||
},
|
||
data: {
|
||
return_time: returnTime,
|
||
status: '已归还',
|
||
return_condition: returnCondition,
|
||
notes
|
||
}
|
||
})
|
||
|
||
if (updatedBorrowRecord.count !== 1) {
|
||
throw new Error('该借用记录已归还,请刷新后重试')
|
||
}
|
||
|
||
const equipmentUpdate = await tx.equipment.updateMany({
|
||
where: {
|
||
id: equipment.id,
|
||
remaining_quantity: { lt: equipment.total_quantity }
|
||
},
|
||
data: {
|
||
remaining_quantity: { increment: 1 },
|
||
borrowed_value: { decrement: Number(equipment.unit_price) },
|
||
available_value: { increment: Number(equipment.unit_price) },
|
||
status: '可用'
|
||
}
|
||
})
|
||
|
||
if (equipmentUpdate.count !== 1) {
|
||
throw new Error('资产库存已达到上限,请检查归还记录')
|
||
}
|
||
|
||
return {
|
||
id: borrowRecord.id,
|
||
person_id: borrowRecord.person_id,
|
||
return_time: returnTime,
|
||
status: '已归还'
|
||
}
|
||
})
|
||
}
|
||
|
||
const mapBorrowRecord = (record: any) => ({
|
||
id: record.id,
|
||
equipment_id: record.equipment_id,
|
||
equipment_code: record.equipment_code,
|
||
equipment_name: record.equipment?.equipment_name,
|
||
storage_location_id: record.equipment?.storage_location_id ?? null,
|
||
storageLocation: record.equipment?.storageLocation ?? null,
|
||
person: record.person
|
||
? {
|
||
id: record.person.id,
|
||
nickname: record.person.nickname,
|
||
real_name: record.person.real_name,
|
||
department: record.person.department,
|
||
phone: record.person.phone
|
||
}
|
||
: {
|
||
id: record.person_id,
|
||
nickname: record.person_nickname,
|
||
real_name: record.person_name
|
||
},
|
||
person_id: record.person_id,
|
||
person_name: record.person_name,
|
||
person_nickname: record.person_nickname,
|
||
person_identifier: record.person_identifier,
|
||
borrow_time: record.borrow_time,
|
||
expected_return_time: record.expected_return_time,
|
||
is_long_term: record.is_long_term,
|
||
return_time: record.return_time,
|
||
status: record.status,
|
||
return_condition: record.return_condition,
|
||
notes: record.notes,
|
||
children_snapshot: record.children_snapshot
|
||
})
|
||
|
||
// 借用资产
|
||
export const borrowEquipment = async (req: Request, res: Response) => {
|
||
try {
|
||
const { equipment_id, equipment_code, person_id, expected_return_time, notes, is_long_term } =
|
||
req.body
|
||
|
||
const equipmentIdNum = parseNumber(equipment_id)
|
||
const equipment = await getEquipmentByIdentifier(equipmentIdNum, equipment_code)
|
||
|
||
if (!equipment) {
|
||
return errorResponse(res, '资产不存在', 404)
|
||
}
|
||
|
||
if (equipmentIdNum && equipment_code && equipment.equipment_code !== equipment_code) {
|
||
return errorResponse(res, '资产编号与ID不匹配', 422)
|
||
}
|
||
|
||
let person
|
||
try {
|
||
person = await ensurePersonAvailable(parseNumber(person_id))
|
||
} catch (error: any) {
|
||
return errorResponse(res, error.message || '使用者验证失败', 422)
|
||
}
|
||
|
||
try {
|
||
ensureEquipmentBorrowable(equipment)
|
||
} catch (error: any) {
|
||
return errorResponse(res, error.message)
|
||
}
|
||
|
||
const longTerm = Boolean(is_long_term)
|
||
const expectedReturn = longTerm ? null : parseDate(expected_return_time)
|
||
const combinedNotes = appendLongTermNotes(notes, longTerm)
|
||
const { children, snapshot } = await getChildrenSnapshot(equipment.id)
|
||
const { record: borrowRecord } = await borrowEquipmentInTransaction(
|
||
equipment,
|
||
person,
|
||
expectedReturn,
|
||
combinedNotes,
|
||
longTerm,
|
||
snapshot
|
||
)
|
||
|
||
successResponse(
|
||
res,
|
||
{
|
||
id: borrowRecord.id,
|
||
borrow_time: borrowRecord.borrow_time,
|
||
children_count: children.length
|
||
},
|
||
'借用成功'
|
||
)
|
||
} catch (error: any) {
|
||
console.error('[借用资产失败]', {
|
||
error: error?.message || error,
|
||
stack: error?.stack,
|
||
body: req.body,
|
||
user: res.locals.user
|
||
})
|
||
errorResponse(res, error.message || '借用资产失败')
|
||
}
|
||
}
|
||
|
||
// 扫码出库
|
||
export const scanBorrow = async (req: Request, res: Response) => {
|
||
try {
|
||
const { equipment_code, person_id, expected_return_time, notes, is_long_term } = req.body
|
||
|
||
const equipment = await getEquipmentByIdentifier(undefined, equipment_code)
|
||
if (!equipment) {
|
||
return errorResponse(res, '资产不存在', 404)
|
||
}
|
||
|
||
let person
|
||
try {
|
||
person = await ensurePersonAvailable(parseNumber(person_id))
|
||
} catch (error: any) {
|
||
return errorResponse(res, error.message || '使用者验证失败', 422)
|
||
}
|
||
|
||
try {
|
||
ensureEquipmentBorrowable(equipment)
|
||
} catch (error: any) {
|
||
return errorResponse(res, error.message)
|
||
}
|
||
|
||
const longTerm = Boolean(is_long_term)
|
||
const expectedReturn = longTerm ? null : parseDate(expected_return_time)
|
||
const combinedNotes = appendLongTermNotes(notes, longTerm)
|
||
const { children, snapshot } = await getChildrenSnapshot(equipment.id)
|
||
const { record: borrowRecord, updatedEquipment } = await borrowEquipmentInTransaction(
|
||
equipment,
|
||
person,
|
||
expectedReturn,
|
||
combinedNotes,
|
||
longTerm,
|
||
snapshot
|
||
)
|
||
|
||
successResponse(
|
||
res,
|
||
{
|
||
id: borrowRecord.id,
|
||
equipment_code: equipment.equipment_code,
|
||
equipment_name: equipment.equipment_name,
|
||
borrow_time: borrowRecord.borrow_time,
|
||
status: '已借出',
|
||
remaining_quantity: updatedEquipment?.remaining_quantity ?? 0,
|
||
equipment_status: updatedEquipment?.status ?? '已借出',
|
||
storage_location_id: equipment.storage_location_id,
|
||
storageLocation: equipment.storageLocation,
|
||
children_count: children.length
|
||
},
|
||
'出库成功'
|
||
)
|
||
} catch (error: any) {
|
||
console.error('[扫码出库失败]', {
|
||
error: error?.message || error,
|
||
stack: error?.stack,
|
||
body: req.body,
|
||
user: res.locals.user
|
||
})
|
||
errorResponse(res, error.message || '出库失败')
|
||
}
|
||
}
|
||
|
||
// 批量扫码出库
|
||
export const scanBorrowBatch = async (req: Request, res: Response) => {
|
||
try {
|
||
const { equipment_codes, person_id, expected_return_time, notes, is_long_term } = req.body as {
|
||
equipment_codes: string[]
|
||
person_id: number
|
||
expected_return_time?: string
|
||
notes?: string
|
||
is_long_term?: boolean
|
||
}
|
||
|
||
if (!Array.isArray(equipment_codes) || equipment_codes.length === 0) {
|
||
return errorResponse(res, '资产编码列表不能为空', 422)
|
||
}
|
||
|
||
let person
|
||
try {
|
||
person = await ensurePersonAvailable(parseNumber(person_id))
|
||
} catch (error: any) {
|
||
return errorResponse(res, error.message || '使用者验证失败', 422)
|
||
}
|
||
|
||
const longTerm = Boolean(is_long_term)
|
||
const expectedReturn = longTerm ? null : parseDate(expected_return_time)
|
||
const combinedNotes = appendLongTermNotes(notes, longTerm)
|
||
const results: any[] = []
|
||
let successCount = 0
|
||
let failedCount = 0
|
||
|
||
for (const code of equipment_codes) {
|
||
try {
|
||
const equipment = await getEquipmentByIdentifier(undefined, code)
|
||
if (!equipment) {
|
||
results.push({ equipment_code: code, status: 'failed', message: '资产不存在' })
|
||
failedCount++
|
||
continue
|
||
}
|
||
|
||
try {
|
||
ensureEquipmentBorrowable(equipment)
|
||
} catch (err: any) {
|
||
results.push({ equipment_code: code, status: 'failed', message: err.message })
|
||
failedCount++
|
||
continue
|
||
}
|
||
|
||
const { snapshot } = await getChildrenSnapshot(equipment.id)
|
||
await borrowEquipmentInTransaction(
|
||
equipment,
|
||
person,
|
||
expectedReturn,
|
||
combinedNotes,
|
||
longTerm,
|
||
snapshot
|
||
)
|
||
|
||
results.push({ equipment_code: code, status: 'success', message: '出库成功' })
|
||
successCount++
|
||
} catch (error: any) {
|
||
results.push({
|
||
equipment_code: code,
|
||
status: 'failed',
|
||
message: error.message || '出库失败'
|
||
})
|
||
failedCount++
|
||
}
|
||
}
|
||
|
||
successResponse(
|
||
res,
|
||
{
|
||
success_count: successCount,
|
||
failed_count: failedCount,
|
||
results
|
||
},
|
||
'批量出库完成'
|
||
)
|
||
} catch (error: any) {
|
||
console.error('[批量出库失败]', {
|
||
error: error?.message || error,
|
||
stack: error?.stack,
|
||
body: req.body,
|
||
user: res.locals.user
|
||
})
|
||
errorResponse(res, error.message || '批量出库失败')
|
||
}
|
||
}
|
||
|
||
// 归还资产
|
||
export const returnEquipment = async (req: Request, res: Response) => {
|
||
try {
|
||
const {
|
||
equipment_id,
|
||
equipment_code,
|
||
borrow_record_id,
|
||
person_id,
|
||
return_condition = '正常',
|
||
notes,
|
||
confirm_children_diff
|
||
} = req.body as Record<string, any>
|
||
|
||
const equipmentIdNum = parseNumber(equipment_id)
|
||
const equipment = await getEquipmentByIdentifier(equipmentIdNum, equipment_code)
|
||
|
||
if (!equipment) {
|
||
return errorResponse(res, '资产不存在', 404)
|
||
}
|
||
|
||
let borrowRecord
|
||
try {
|
||
borrowRecord = await findActiveBorrowRecord(
|
||
equipment.id,
|
||
parseNumber(borrow_record_id),
|
||
parseNumber(person_id)
|
||
)
|
||
} catch (error: any) {
|
||
return errorResponse(res, error.message || '未找到对应的借用记录', 422)
|
||
}
|
||
|
||
if (!borrowRecord) {
|
||
return errorResponse(res, '未找到对应的借用记录')
|
||
}
|
||
|
||
const childrenDiff = await getChildrenDiff(equipment.id, borrowRecord)
|
||
if (childrenDiff && !confirm_children_diff) {
|
||
return successResponse(res, {
|
||
need_confirm: true,
|
||
children_diff: childrenDiff,
|
||
message: '配件与借出时不一致,请确认后继续'
|
||
}, '配件差异提醒')
|
||
}
|
||
|
||
const finalNotes = childrenDiff
|
||
? [notes, `配件变更:移除${childrenDiff.removed.length}个,新增${childrenDiff.added.length}个`]
|
||
.filter(Boolean)
|
||
.join(';')
|
||
: notes
|
||
|
||
await returnEquipmentInTransaction(equipment, borrowRecord, return_condition, finalNotes)
|
||
|
||
successResponse(
|
||
res,
|
||
{
|
||
id: borrowRecord.id,
|
||
return_time: new Date(),
|
||
children_diff: childrenDiff
|
||
},
|
||
'归还成功'
|
||
)
|
||
} catch (error: any) {
|
||
console.error('[归还资产失败]', {
|
||
error: error?.message || error,
|
||
stack: error?.stack,
|
||
body: req.body,
|
||
user: res.locals.user
|
||
})
|
||
errorResponse(res, error.message || '归还资产失败')
|
||
}
|
||
}
|
||
|
||
// 扫码入库
|
||
export const scanReturn = async (req: Request, res: Response) => {
|
||
try {
|
||
const {
|
||
equipment_code,
|
||
return_condition = '正常',
|
||
notes,
|
||
person_id,
|
||
borrow_record_id,
|
||
confirm_children_diff
|
||
} = req.body as Record<string, any>
|
||
|
||
const equipment = await getEquipmentByIdentifier(undefined, equipment_code)
|
||
|
||
if (!equipment) {
|
||
return errorResponse(res, '资产不存在', 404)
|
||
}
|
||
|
||
let borrowRecord = null
|
||
try {
|
||
borrowRecord = await findActiveBorrowRecord(
|
||
equipment.id,
|
||
parseNumber(borrow_record_id),
|
||
parseNumber(person_id)
|
||
)
|
||
} catch (error: any) {
|
||
return errorResponse(res, error.message || '未找到对应的借用记录,请选择正确的使用者', 422)
|
||
}
|
||
|
||
if (!borrowRecord) {
|
||
return errorResponse(res, '未找到对应的借用记录,请选择正确的使用者', 404)
|
||
}
|
||
|
||
const childrenDiff = await getChildrenDiff(equipment.id, borrowRecord)
|
||
if (childrenDiff && !confirm_children_diff) {
|
||
return successResponse(res, {
|
||
need_confirm: true,
|
||
children_diff: childrenDiff,
|
||
message: '配件与借出时不一致,请确认后继续'
|
||
}, '配件差异提醒')
|
||
}
|
||
|
||
const finalNotes = childrenDiff
|
||
? [notes, `配件变更:移除${childrenDiff.removed.length}个,新增${childrenDiff.added.length}个`]
|
||
.filter(Boolean)
|
||
.join(';')
|
||
: notes
|
||
|
||
const updatedRecord = await returnEquipmentInTransaction(
|
||
equipment,
|
||
borrowRecord,
|
||
return_condition,
|
||
finalNotes
|
||
)
|
||
|
||
successResponse(
|
||
res,
|
||
{
|
||
id: updatedRecord.id,
|
||
equipment_code: equipment.equipment_code,
|
||
equipment_name: equipment.equipment_name,
|
||
return_time: updatedRecord.return_time,
|
||
status: '已归还',
|
||
person_id: updatedRecord.person_id
|
||
},
|
||
'入库成功'
|
||
)
|
||
} catch (error: any) {
|
||
console.error('[扫码入库失败]', {
|
||
error: error?.message || error,
|
||
stack: error?.stack,
|
||
body: req.body,
|
||
user: res.locals.user
|
||
})
|
||
errorResponse(res, error.message || '入库失败')
|
||
}
|
||
}
|
||
|
||
// 批量扫码入库
|
||
export const scanReturnBatch = async (req: Request, res: Response) => {
|
||
try {
|
||
const {
|
||
equipment_codes,
|
||
return_condition = '正常',
|
||
notes
|
||
} = req.body as { equipment_codes: string[]; return_condition?: string; notes?: string }
|
||
|
||
if (!Array.isArray(equipment_codes) || equipment_codes.length === 0) {
|
||
return errorResponse(res, '资产编码列表不能为空', 422)
|
||
}
|
||
|
||
const results: any[] = []
|
||
let successCount = 0
|
||
let failedCount = 0
|
||
|
||
for (const code of equipment_codes) {
|
||
try {
|
||
const equipment = await getEquipmentByIdentifier(undefined, code)
|
||
|
||
if (!equipment) {
|
||
results.push({ equipment_code: code, status: 'failed', message: '资产不存在' })
|
||
failedCount++
|
||
continue
|
||
}
|
||
|
||
const activeBorrowRecords = await prisma.borrowRecord.findMany({
|
||
where: {
|
||
equipment_id: equipment.id,
|
||
status: '已借出'
|
||
},
|
||
orderBy: { borrow_time: 'desc' },
|
||
take: 2
|
||
})
|
||
const borrowRecord = activeBorrowRecords[0]
|
||
|
||
if (!borrowRecord) {
|
||
results.push({ equipment_code: code, status: 'failed', message: '未找到对应的借用记录' })
|
||
failedCount++
|
||
continue
|
||
}
|
||
|
||
if (activeBorrowRecords.length > 1) {
|
||
results.push({ equipment_code: code, status: 'failed', message: '存在多条未归还记录,请使用单个扫码归还' })
|
||
failedCount++
|
||
continue
|
||
}
|
||
|
||
const childrenDiff = await getChildrenDiff(equipment.id, borrowRecord)
|
||
if (childrenDiff) {
|
||
results.push({ equipment_code: code, status: 'failed', message: '配件与借出时不一致,请使用单个扫码归还确认' })
|
||
failedCount++
|
||
continue
|
||
}
|
||
|
||
await returnEquipmentInTransaction(equipment, borrowRecord, return_condition, notes)
|
||
|
||
results.push({ equipment_code: code, status: 'success', message: '入库成功' })
|
||
successCount++
|
||
} catch (error: any) {
|
||
results.push({
|
||
equipment_code: code,
|
||
status: 'failed',
|
||
message: error.message || '入库失败'
|
||
})
|
||
failedCount++
|
||
}
|
||
}
|
||
|
||
successResponse(
|
||
res,
|
||
{
|
||
success_count: successCount,
|
||
failed_count: failedCount,
|
||
results
|
||
},
|
||
'批量入库完成'
|
||
)
|
||
} catch (error: any) {
|
||
console.error('[批量入库失败]', {
|
||
error: error?.message || error,
|
||
stack: error?.stack,
|
||
body: req.body,
|
||
user: res.locals.user
|
||
})
|
||
errorResponse(res, error.message || '批量入库失败')
|
||
}
|
||
}
|
||
|
||
// 根据资产编码查询借用记录
|
||
export const getBorrowRecordByCode = async (req: Request, res: Response) => {
|
||
try {
|
||
const { equipment_code } = req.params
|
||
|
||
const equipment = await getEquipmentByIdentifier(undefined, equipment_code)
|
||
|
||
if (!equipment) {
|
||
return errorResponse(res, '资产不存在', 404)
|
||
}
|
||
|
||
const borrowRecords = await prisma.borrowRecord.findMany({
|
||
where: {
|
||
equipment_id: equipment.id,
|
||
status: '已借出'
|
||
},
|
||
orderBy: { borrow_time: 'desc' },
|
||
include: {
|
||
person: true,
|
||
equipment: {
|
||
select: {
|
||
equipment_name: true,
|
||
storage_location_id: true,
|
||
storageLocation: {
|
||
select: {
|
||
id: true,
|
||
name: true,
|
||
code: true,
|
||
status: true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
})
|
||
|
||
if (borrowRecords.length === 0) {
|
||
return errorResponse(res, '未找到对应的借用记录', 404)
|
||
}
|
||
|
||
successResponse(
|
||
res,
|
||
{
|
||
equipment_code: equipment.equipment_code,
|
||
equipment_name: equipment.equipment_name,
|
||
unit_price: Number(equipment.unit_price),
|
||
equipment_value: Number(equipment.unit_price),
|
||
storage_location_id: equipment.storage_location_id,
|
||
storageLocation: equipment.storageLocation,
|
||
borrow_records: borrowRecords.map(mapBorrowRecord),
|
||
can_return: true,
|
||
message: '资产已借出,可以选择对应使用者归还'
|
||
},
|
||
'查询成功'
|
||
)
|
||
} catch (error: any) {
|
||
errorResponse(res, error.message || '查询借用记录失败')
|
||
}
|
||
}
|
||
|
||
// 获取借用记录列表
|
||
export const getBorrowRecordList = async (req: Request, res: Response) => {
|
||
try {
|
||
const { page = 1, pageSize = 10, status, person_name, person_id } = req.query
|
||
|
||
const filters: any[] = []
|
||
|
||
if (status) {
|
||
filters.push({ status })
|
||
}
|
||
|
||
const personIdNum = parseNumber(person_id)
|
||
if (personIdNum) {
|
||
filters.push({ person_id: personIdNum })
|
||
}
|
||
|
||
if (person_name) {
|
||
const kw = person_name as string
|
||
filters.push({
|
||
OR: [
|
||
{ person_name: { contains: kw } },
|
||
{ person_nickname: { contains: kw } },
|
||
{ person_identifier: { contains: kw } }
|
||
]
|
||
})
|
||
}
|
||
|
||
const where = filters.length ? { AND: filters } : undefined
|
||
const skip = (Number(page) - 1) * Number(pageSize)
|
||
|
||
const [list, total] = await Promise.all([
|
||
prisma.borrowRecord.findMany({
|
||
where,
|
||
skip,
|
||
take: Number(pageSize),
|
||
orderBy: { borrow_time: 'desc' },
|
||
include: {
|
||
person: true,
|
||
equipment: {
|
||
select: {
|
||
equipment_name: true,
|
||
storage_location_id: true,
|
||
storageLocation: {
|
||
select: {
|
||
id: true,
|
||
name: true,
|
||
code: true,
|
||
status: true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}),
|
||
prisma.borrowRecord.count({ where })
|
||
])
|
||
|
||
successResponse(
|
||
res,
|
||
{
|
||
list: list.map(mapBorrowRecord),
|
||
total,
|
||
page: Number(page),
|
||
pageSize: Number(pageSize)
|
||
},
|
||
'获取成功'
|
||
)
|
||
} catch (error: any) {
|
||
errorResponse(res, error.message || '获取借用记录列表失败')
|
||
}
|
||
}
|