Merge branch 'dev' of http://47.92.113.182:3000/cq_anquan/safety-eval-service-frontend into dev
commit
2d08e2e9e5
|
|
@ -15,7 +15,7 @@ module.exports = {
|
||||||
API_HOST: "http://192.168.0.134",
|
API_HOST: "http://192.168.0.134",
|
||||||
//API_HOST: "http://192.168.0.150", //太浅
|
//API_HOST: "http://192.168.0.150", //太浅
|
||||||
// API_HOST: "http://192.168.0.152",
|
// API_HOST: "http://192.168.0.152",
|
||||||
//API_HOST: "http://192.168.0.103", //huwei
|
// API_HOST: "http://192.168.0.103", //huwei
|
||||||
},
|
},
|
||||||
production: {
|
production: {
|
||||||
// 应用后端分支名称,部署上线需要
|
// 应用后端分支名称,部署上线需要
|
||||||
|
|
|
||||||
|
|
@ -224,10 +224,10 @@ function PersonnelInfoPage(props) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "能力",
|
title: "能力",
|
||||||
width: 80,
|
width: 260,
|
||||||
dataIndex: "abilityNames",
|
dataIndex: "abilityNames",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
render: (text) => "暂无",
|
render: (text) => text || '暂无',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "操作",
|
title: "操作",
|
||||||
|
|
@ -394,6 +394,7 @@ function StaffFormModal({
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadBasicDisciplineMajors = async () => {
|
const loadBasicDisciplineMajors = async () => {
|
||||||
|
|
||||||
await queryBasicDisciplineMajor({ pageSize: 999 });
|
await queryBasicDisciplineMajor({ pageSize: 999 });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -449,6 +450,7 @@ function StaffFormModal({
|
||||||
}
|
}
|
||||||
|
|
||||||
form.setFieldsValue(setFields);
|
form.setFieldsValue(setFields);
|
||||||
|
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
if (!cancelled) setDetailLoading(false);
|
if (!cancelled) setDetailLoading(false);
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ import {
|
||||||
DatePicker,
|
DatePicker,
|
||||||
Space,
|
Space,
|
||||||
ConfigProvider,
|
ConfigProvider,
|
||||||
|
Tag,
|
||||||
|
Tooltip,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import {
|
import {
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
|
|
@ -101,6 +103,30 @@ const getFileExt = (name = "") => {
|
||||||
return parts.length > 1 ? parts.pop().toUpperCase() : "PDF";
|
return parts.length > 1 ? parts.pop().toUpperCase() : "PDF";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 解析 JSON 文件列表,渲染为可下载链接列表 */
|
||||||
|
const renderFileLinks = (jsonStr) => {
|
||||||
|
if (!jsonStr) return "-";
|
||||||
|
try {
|
||||||
|
const files = JSON.parse(jsonStr);
|
||||||
|
if (!Array.isArray(files) || files.length === 0) return "-";
|
||||||
|
return files.map((f, i) => (
|
||||||
|
<div key={i} className="erl-file-cell" style={{ marginBottom: 4 }}>
|
||||||
|
<i>{getFileExt(f.name || f.url)}</i>
|
||||||
|
<a
|
||||||
|
href={f.url}
|
||||||
|
download={f.name}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
{f.name || "未命名文件"}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
} catch {
|
||||||
|
return jsonStr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getOptionLabel = (options, value) =>
|
const getOptionLabel = (options, value) =>
|
||||||
options.find((item) => item.value === value)?.label || value || "-";
|
options.find((item) => item.value === value)?.label || value || "-";
|
||||||
|
|
||||||
|
|
@ -131,6 +157,8 @@ const EvalReportLibrary = (props) => {
|
||||||
const [rectifyVisible, setRectifyVisible] = useState(false);
|
const [rectifyVisible, setRectifyVisible] = useState(false);
|
||||||
const [rectifyRecord, setRectifyRecord] = useState(null);
|
const [rectifyRecord, setRectifyRecord] = useState(null);
|
||||||
const [uploadedFile, setUploadedFile] = useState(null);
|
const [uploadedFile, setUploadedFile] = useState(null);
|
||||||
|
const [contractFiles, setContractFiles] = useState([]);
|
||||||
|
const [processDocFiles, setProcessDocFiles] = useState([]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
evalReportPageLoading,
|
evalReportPageLoading,
|
||||||
|
|
@ -188,6 +216,8 @@ const EvalReportLibrary = (props) => {
|
||||||
|
|
||||||
const handleOpenAdd = () => {
|
const handleOpenAdd = () => {
|
||||||
setUploadedFile(null);
|
setUploadedFile(null);
|
||||||
|
setContractFiles([]);
|
||||||
|
setProcessDocFiles([]);
|
||||||
uploadForm.resetFields();
|
uploadForm.resetFields();
|
||||||
uploadForm.setFieldsValue({
|
uploadForm.setFieldsValue({
|
||||||
reportYear: dayjs().year(),
|
reportYear: dayjs().year(),
|
||||||
|
|
@ -225,6 +255,40 @@ const EvalReportLibrary = (props) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 合同文件上传
|
||||||
|
const handleContractUploadChange = (info) => {
|
||||||
|
if (info.file.status === "error") {
|
||||||
|
message.error(`${info.file.name} 上传失败`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const doneFiles = info.fileList
|
||||||
|
.filter((f) => f.status === "done" && f.response?.data)
|
||||||
|
.map((f) => ({
|
||||||
|
uid: f.uid,
|
||||||
|
url: f.response.data.url || f.response.data.fileUrl || "",
|
||||||
|
name: f.response.data.name || f.response.data.fileName || f.name,
|
||||||
|
}))
|
||||||
|
.filter((f) => f.url);
|
||||||
|
setContractFiles(doneFiles);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 其他过程文档上传
|
||||||
|
const handleProcessDocUploadChange = (info) => {
|
||||||
|
if (info.file.status === "error") {
|
||||||
|
message.error(`${info.file.name} 上传失败`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const doneFiles = info.fileList
|
||||||
|
.filter((f) => f.status === "done" && f.response?.data)
|
||||||
|
.map((f) => ({
|
||||||
|
uid: f.uid,
|
||||||
|
url: f.response.data.url || f.response.data.fileUrl || "",
|
||||||
|
name: f.response.data.name || f.response.data.fileName || f.name,
|
||||||
|
}))
|
||||||
|
.filter((f) => f.url);
|
||||||
|
setProcessDocFiles(doneFiles);
|
||||||
|
};
|
||||||
|
|
||||||
const handleAddOk = async () => {
|
const handleAddOk = async () => {
|
||||||
const values = await uploadForm.validateFields().catch(() => null);
|
const values = await uploadForm.validateFields().catch(() => null);
|
||||||
if (!values) return;
|
if (!values) return;
|
||||||
|
|
@ -252,6 +316,8 @@ const EvalReportLibrary = (props) => {
|
||||||
SECRET_LEVEL_OPTIONS,
|
SECRET_LEVEL_OPTIONS,
|
||||||
values.secretLevelCode,
|
values.secretLevelCode,
|
||||||
),
|
),
|
||||||
|
contractFileUrls: contractFiles.length > 0 ? JSON.stringify(contractFiles) : undefined,
|
||||||
|
processDocUrls: processDocFiles.length > 0 ? JSON.stringify(processDocFiles) : undefined,
|
||||||
remarks: values.remarks,
|
remarks: values.remarks,
|
||||||
submitToRegulator: values.submitToRegulator === 1,
|
submitToRegulator: values.submitToRegulator === 1,
|
||||||
};
|
};
|
||||||
|
|
@ -838,6 +904,50 @@ const EvalReportLibrary = (props) => {
|
||||||
<Select options={SECRET_LEVEL_OPTIONS} />
|
<Select options={SECRET_LEVEL_OPTIONS} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Form.Item label="合同上传">
|
||||||
|
<Upload
|
||||||
|
name="file"
|
||||||
|
action={UPLOAD_ACTION}
|
||||||
|
headers={{ token: sessionStorage.getItem("token") || "" }}
|
||||||
|
onChange={handleContractUploadChange}
|
||||||
|
accept=".pdf,.doc,.docx,.jpg,.jpeg,.png,.zip,.rar"
|
||||||
|
maxCount={20}
|
||||||
|
beforeUpload={(file) => {
|
||||||
|
const isLt100M = file.size / 1024 / 1024 <= 100;
|
||||||
|
if (!isLt100M) {
|
||||||
|
message.error("单个文件不超过 100MB");
|
||||||
|
return Upload.LIST_IGNORE;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button icon={<UploadOutlined />}>选择合同文件</Button>
|
||||||
|
</Upload>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Form.Item label="其他过程文档">
|
||||||
|
<Upload
|
||||||
|
name="file"
|
||||||
|
action={UPLOAD_ACTION}
|
||||||
|
headers={{ token: sessionStorage.getItem("token") || "" }}
|
||||||
|
onChange={handleProcessDocUploadChange}
|
||||||
|
accept=".pdf,.doc,.docx,.jpg,.jpeg,.png,.zip,.rar"
|
||||||
|
maxCount={20}
|
||||||
|
beforeUpload={(file) => {
|
||||||
|
const isLt100M = file.size / 1024 / 1024 <= 100;
|
||||||
|
if (!isLt100M) {
|
||||||
|
message.error("单个文件不超过 100MB");
|
||||||
|
return Upload.LIST_IGNORE;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button icon={<UploadOutlined />}>选择过程文档</Button>
|
||||||
|
</Upload>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<Form.Item name="remarks" label="备注">
|
<Form.Item name="remarks" label="备注">
|
||||||
<TextArea
|
<TextArea
|
||||||
|
|
@ -921,6 +1031,12 @@ const EvalReportLibrary = (props) => {
|
||||||
<span>{detailData.fileName || "-"}</span>
|
<span>{detailData.fileName || "-"}</span>
|
||||||
</div>
|
</div>
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="合同文件" span={2}>
|
||||||
|
{renderFileLinks(detailData.contractFileUrls)}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="过程文档" span={2}>
|
||||||
|
{renderFileLinks(detailData.processDocUrls)}
|
||||||
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label="备注" span={2}>
|
<Descriptions.Item label="备注" span={2}>
|
||||||
{detailData.remarks || "-"}
|
{detailData.remarks || "-"}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
|
|
|
||||||
|
|
@ -210,6 +210,17 @@ const getFileExtLabel = (name = "") => {
|
||||||
return ext && ext !== name ? ext.toUpperCase() : "PDF";
|
return ext && ext !== name ? ext.toUpperCase() : "PDF";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 解析存储的 JSON 文件列表字符串,返回数组 */
|
||||||
|
const parseFileList = (jsonStr) => {
|
||||||
|
if (!jsonStr) return [];
|
||||||
|
try {
|
||||||
|
const arr = JSON.parse(jsonStr);
|
||||||
|
return Array.isArray(arr) ? arr : [];
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const EvalReportDatabase = (props) => {
|
const EvalReportDatabase = (props) => {
|
||||||
const [searchForm] = Form.useForm();
|
const [searchForm] = Form.useForm();
|
||||||
const [exportForm] = Form.useForm();
|
const [exportForm] = Form.useForm();
|
||||||
|
|
@ -310,6 +321,19 @@ const EvalReportDatabase = (props) => {
|
||||||
getData(pagination);
|
getData(pagination);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 下载指定 URL 的文件 */
|
||||||
|
const handleFileDownload = (fileUrl, fileName) => {
|
||||||
|
if (!fileUrl) {
|
||||||
|
message.warning("文件地址不存在");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const hide = message.loading("正在下载...", 0);
|
||||||
|
downloadFileByUrl(fileUrl, fileName)
|
||||||
|
.then(() => message.success("下载已开始"))
|
||||||
|
.catch(() => message.error("下载失败,请稍后重试"))
|
||||||
|
.finally(() => hide());
|
||||||
|
};
|
||||||
|
|
||||||
const handleViewDetail = async (record) => {
|
const handleViewDetail = async (record) => {
|
||||||
setDetailData(null);
|
setDetailData(null);
|
||||||
setDetailVisible(true);
|
setDetailVisible(true);
|
||||||
|
|
@ -822,13 +846,59 @@ const EvalReportDatabase = (props) => {
|
||||||
headers={["文件名称", "文件类型", "版本"]}
|
headers={["文件名称", "文件类型", "版本"]}
|
||||||
rows={[
|
rows={[
|
||||||
[
|
[
|
||||||
detailData.fileName || detailData.reportName || "正式安全评价报告.pdf",
|
<span
|
||||||
|
style={{ color: "#1677ff", cursor: "pointer" }}
|
||||||
|
onClick={() =>
|
||||||
|
handleFileDownload(
|
||||||
|
detailData.fileUrl,
|
||||||
|
detailData.fileName || detailData.reportName || "正式安全评价报告.pdf"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{detailData.fileName || detailData.reportName || "正式安全评价报告.pdf"}
|
||||||
|
</span>,
|
||||||
getFileExtLabel(detailData.fileName),
|
getFileExtLabel(detailData.fileName),
|
||||||
"V1.0",
|
"V1.0",
|
||||||
],
|
],
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</ModalSection>
|
</ModalSection>
|
||||||
|
<ModalSection
|
||||||
|
title="合同文件"
|
||||||
|
desc="查看上传的合同文件。"
|
||||||
|
>
|
||||||
|
<ProtoTable
|
||||||
|
headers={["文件名称", "文件类型"]}
|
||||||
|
rows={parseFileList(detailData.contractFileUrls).map((f) => [
|
||||||
|
<span
|
||||||
|
key={f.url}
|
||||||
|
style={{ color: "#1677ff", cursor: "pointer" }}
|
||||||
|
onClick={() => handleFileDownload(f.url, f.name || "未命名文件")}
|
||||||
|
>
|
||||||
|
{f.name || "未命名文件"}
|
||||||
|
</span>,
|
||||||
|
getFileExtLabel(f.name || f.url),
|
||||||
|
])}
|
||||||
|
/>
|
||||||
|
</ModalSection>
|
||||||
|
<ModalSection
|
||||||
|
title="其他过程文档"
|
||||||
|
desc="查看上传的过程文档。"
|
||||||
|
>
|
||||||
|
<ProtoTable
|
||||||
|
headers={["文件名称", "文件类型"]}
|
||||||
|
rows={parseFileList(detailData.processDocUrls).map((f) => [
|
||||||
|
<span
|
||||||
|
key={f.url}
|
||||||
|
style={{ color: "#1677ff", cursor: "pointer" }}
|
||||||
|
onClick={() => handleFileDownload(f.url, f.name || "未命名文件")}
|
||||||
|
>
|
||||||
|
{f.name || "未命名文件"}
|
||||||
|
</span>,
|
||||||
|
getFileExtLabel(f.name || f.url),
|
||||||
|
])}
|
||||||
|
/>
|
||||||
|
</ModalSection>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div className="redb-loading">
|
<div className="redb-loading">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue