fix(ms): 材料导入模板重建 + IIS子目录路径修复 + 隐藏分类数据列
- 按用户参考模板重建 imft.xlsx,保持表头/行结构一致 - fetch路径加 /iapip-ms/ 前缀适配 IIS 子目录部署 - 动态写入的分类数据列设为 hidden,用户下载时不可见 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T71oHHhfhLAWAL9EuoFuYh
This commit is contained in:
parent
8ee0784f20
commit
b26546d459
Binary file not shown.
|
|
@ -191,8 +191,7 @@ const ImportMaterialsModal: React.FC<{
|
|||
onClick={async () => {
|
||||
setDownloading(true)
|
||||
try {
|
||||
const file = await fetch('/fts/imft.xlsx')
|
||||
// const file = await fetch('/iapip-ms/fts/imft.xlsx')
|
||||
const file = await fetch('/iapip-ms/fts/imft.xlsx')
|
||||
const wb = new ExcelJS.Workbook()
|
||||
await wb.xlsx.load(await file.arrayBuffer())
|
||||
const ws = wb.getWorksheet(1)
|
||||
|
|
@ -200,9 +199,11 @@ const ImportMaterialsModal: React.FC<{
|
|||
const categories = await api.config.getMtrlCatList()
|
||||
categories.forEach((fc, i) => {
|
||||
ws.getCell(1 + i, 43).value = fc.first_category
|
||||
ws.getColumn(43).hidden = true
|
||||
ws.getColumn(44 + i).values = fc.second_categories.map(
|
||||
(sc) => sc.second_category
|
||||
)
|
||||
ws.getColumn(44 + i).hidden = true
|
||||
})
|
||||
}
|
||||
await downloadXLSX(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,270 @@
|
|||
import { ExcelValidator } from '@/common/excel-validator'
|
||||
import { AnyObj, FROM_TYPE } from '@/common/types'
|
||||
import { downloadXLSX, toNum } from '@/common/utils'
|
||||
import api from '@/services/api'
|
||||
import { ModalForm } from '@ant-design/pro-components'
|
||||
import { Alert, Button, Divider, Tag, Upload, message, theme } from 'antd'
|
||||
import { RcFile } from 'antd/es/upload'
|
||||
import * as ExcelJS from 'exceljs'
|
||||
import React, { useState } from 'react'
|
||||
import ImportFile from '../apply-request-modal/import-file'
|
||||
|
||||
const ImportTemplatesModal: React.FC<{
|
||||
title: string
|
||||
trigger: JSX.Element
|
||||
}> = ({ title, trigger }) => {
|
||||
const { token } = theme.useToken()
|
||||
const [open, setOpen] = useState(false)
|
||||
const [downloading, setDownloading] = useState(false)
|
||||
const [uploading, setUploading] = useState(false)
|
||||
const [errMsg, setErrMsg] = useState<string>()
|
||||
const [parsedResult, setParseResult] = useState<AnyObj[]>()
|
||||
const [uploadFile, setUploadFile] = useState<RcFile>()
|
||||
const beforeUpload = async (file: RcFile) => {
|
||||
setUploading(true)
|
||||
const msgKey = 'UPLOADING_TEMPLATES'
|
||||
try {
|
||||
message.open({
|
||||
key: msgKey,
|
||||
type: 'loading',
|
||||
content: '正在解析'
|
||||
})
|
||||
const wb = new ExcelJS.Workbook()
|
||||
await wb.xlsx.load(await file.arrayBuffer())
|
||||
const ws = wb.getWorksheet(1)
|
||||
if (ws) {
|
||||
const templates: AnyObj[] = []
|
||||
ws.getRows(6, 10)?.forEach((row, idx) => {
|
||||
const id = row.getCell(1).value?.toString()
|
||||
const name = row.getCell(2).value?.toString()
|
||||
const category = row.getCell(3).value?.toString()
|
||||
const province = row.getCell(4).value?.toString()
|
||||
const city = row.getCell(5).value?.toString()
|
||||
const constr_area = toNum(row.getCell(6).value?.toString())
|
||||
if (id && name && category && province && city && constr_area) {
|
||||
templates.push({
|
||||
id,
|
||||
idx: 6 + idx,
|
||||
name,
|
||||
category,
|
||||
province,
|
||||
city,
|
||||
constr_area,
|
||||
display: 1,
|
||||
from: FROM_TYPE.IMPORT,
|
||||
spaces: [] as AnyObj
|
||||
})
|
||||
}
|
||||
})
|
||||
ws.getRows(20, 500)?.forEach((row, idx) => {
|
||||
const temp_id = row.getCell(2).value?.toString()
|
||||
const name = row.getCell(5).value?.toString()
|
||||
const category = row.getCell(6).value?.toString()
|
||||
const area = toNum(row.getCell(7).value?.toString())
|
||||
const volume = toNum(row.getCell(8).value?.toString())
|
||||
const env_temp = toNum(row.getCell(9).value?.toString())
|
||||
const env_hum = toNum(row.getCell(10).value?.toString())
|
||||
const env_vent_rate = toNum(row.getCell(11).value?.toString())
|
||||
const apc_lmt_std_id = row.getCell(12).value?.toString()
|
||||
if (temp_id && name && category && area && volume && apc_lmt_std_id) {
|
||||
templates.find((temp) => {
|
||||
if (temp.id === temp_id) {
|
||||
temp.spaces.push({
|
||||
idx: 20 + idx,
|
||||
name,
|
||||
category,
|
||||
layout: 0,
|
||||
area,
|
||||
volume,
|
||||
env_temp,
|
||||
env_hum,
|
||||
env_vent_rate,
|
||||
apc_lmt_std_id
|
||||
})
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
})
|
||||
const excelValidator = new ExcelValidator()
|
||||
if (await excelValidator.importTemplates(templates)) {
|
||||
message.open({
|
||||
key: msgKey,
|
||||
type: 'success',
|
||||
content: '上传成功',
|
||||
duration: 2
|
||||
})
|
||||
setErrMsg(undefined)
|
||||
setParseResult(templates)
|
||||
setUploadFile(file)
|
||||
setUploading(false)
|
||||
return file
|
||||
}
|
||||
setErrMsg(excelValidator.errorMessage)
|
||||
}
|
||||
} catch (err) {}
|
||||
message.destroy(msgKey)
|
||||
setUploading(false)
|
||||
return false
|
||||
}
|
||||
return (
|
||||
<ModalForm
|
||||
open={open}
|
||||
title={title}
|
||||
width={690}
|
||||
modalProps={{
|
||||
maskClosable: false,
|
||||
destroyOnClose: true,
|
||||
styles: {
|
||||
content: {
|
||||
paddingTop: 20,
|
||||
paddingBottom: 16
|
||||
}
|
||||
},
|
||||
onCancel: () => setOpen(false)
|
||||
}}
|
||||
onOpenChange={(v) => {
|
||||
if (!v) {
|
||||
setParseResult(undefined)
|
||||
setUploadFile(undefined)
|
||||
}
|
||||
}}
|
||||
submitter={{
|
||||
render: () => (
|
||||
<div className="w-full flex pt-1 justify-center space-x-4">
|
||||
{!parsedResult ? (
|
||||
<>
|
||||
<Button
|
||||
style={{ width: 120 }}
|
||||
loading={downloading}
|
||||
onClick={async () => {
|
||||
setDownloading(true)
|
||||
try {
|
||||
const file = await fetch('/iapip-ms/fts/itft.xlsx')
|
||||
const wb = new ExcelJS.Workbook()
|
||||
await wb.xlsx.load(await file.arrayBuffer())
|
||||
const ws = wb.getWorksheet(1)
|
||||
if (ws) {
|
||||
const categories = await api.config.getProjSpaceCatList()
|
||||
categories.forEach((pc, i) => {
|
||||
ws.getCell(1 + i, 19).value = pc.project_category
|
||||
ws.getColumn(20 + i).values = pc.space_categories.map(
|
||||
(sc) => sc.space_category
|
||||
)
|
||||
})
|
||||
const cities = await api.config.getCityInfoList()
|
||||
cities.forEach((p, i) => {
|
||||
ws.getCell(1 + i, 56).value = p.province
|
||||
ws.getColumn(57 + i).values = p.cities.map((c) => c.city)
|
||||
})
|
||||
}
|
||||
await downloadXLSX(
|
||||
await wb.xlsx.writeBuffer(),
|
||||
'批量导入模板(文件模板).xlsx'
|
||||
)
|
||||
} catch (err) {}
|
||||
setDownloading(false)
|
||||
}}
|
||||
>
|
||||
{downloading ? '正在下载' : '下载文件模板'}
|
||||
</Button>
|
||||
<Upload accept=".xlsx" showUploadList={false} beforeUpload={beforeUpload}>
|
||||
<Button type="primary" style={{ width: 120 }} disabled={uploading}>
|
||||
上传文件解析
|
||||
</Button>
|
||||
</Upload>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Upload accept=".xlsx" showUploadList={false} beforeUpload={beforeUpload}>
|
||||
<Button style={{ width: 120 }} disabled={uploading}>
|
||||
重新上传
|
||||
</Button>
|
||||
</Upload>
|
||||
<ImportFile
|
||||
title="导入公共模板申请"
|
||||
trigger={
|
||||
<Button type="primary" style={{ width: 120 }}>
|
||||
确认导入
|
||||
</Button>
|
||||
}
|
||||
onFinish={async (data) => {
|
||||
if (uploadFile) {
|
||||
if (parsedResult.length) {
|
||||
try {
|
||||
await api.audit.importTemplates({
|
||||
file: uploadFile,
|
||||
data: parsedResult,
|
||||
qty: parsedResult.length,
|
||||
desc: data.desc
|
||||
})
|
||||
message.success('申请成功')
|
||||
setOpen(false)
|
||||
return true
|
||||
} catch (err) {}
|
||||
} else {
|
||||
message.error('至少包含一条解析数据')
|
||||
}
|
||||
} else {
|
||||
message.error('找不到上传文件,请重新上传')
|
||||
}
|
||||
return false
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
trigger={React.cloneElement(trigger, { onClick: () => setOpen(true) })}
|
||||
>
|
||||
<Divider style={{ marginTop: 16, marginBottom: 12 }} />
|
||||
{errMsg ? <Alert message={errMsg} type="error" showIcon style={{ marginBottom: 12 }} /> : ''}
|
||||
<div className="px-6 pt-3 pb-6 space-y-2">
|
||||
<label>导入说明</label>
|
||||
<div style={{ color: token.colorTextSecondary }}>
|
||||
1. 请下载文件模板, 并根据要求填写后上传文件进行解析
|
||||
</div>
|
||||
<div style={{ color: token.colorTextSecondary }}>
|
||||
2. 解析成功后, 确认解析数量是否一致, 点击确认即可导入
|
||||
</div>
|
||||
</div>
|
||||
{parsedResult ? (
|
||||
<>
|
||||
<Divider style={{ margin: 0 }} />
|
||||
<div className="p-6 space-y-2">
|
||||
<div>
|
||||
<label className="mr-4">导入文件:</label>
|
||||
<Button
|
||||
type="link"
|
||||
style={{ padding: 0 }}
|
||||
onClick={async () => {
|
||||
if (uploadFile) {
|
||||
await downloadXLSX(await uploadFile.arrayBuffer(), uploadFile.name)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{uploadFile?.name ?? '下载'}
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<label className="mr-4">解析结果:</label>
|
||||
解析成功, 请确认解析数量一致后点击确认导入
|
||||
</div>
|
||||
<div>
|
||||
<label className="mr-4">解析数据:</label>共
|
||||
<Tag style={{ marginInline: 5 }}>{parsedResult.length}</Tag>
|
||||
条数据
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
<Divider style={{ margin: 0 }} />
|
||||
</ModalForm>
|
||||
)
|
||||
}
|
||||
|
||||
export default ImportTemplatesModal
|
||||
Loading…
Reference in New Issue