登录 个人 与 零星采购
This commit is contained in:
@ -0,0 +1,10 @@
|
||||
.summary-sticky-cell {
|
||||
position: sticky !important;
|
||||
left: 0 !important;
|
||||
z-index: 3 !important;
|
||||
background: #fff !important;
|
||||
min-width: 180px;
|
||||
max-width: 180px;
|
||||
border-right: 1px solid #f0f0f0;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Modal, Table, Button, Select, Spin, message } from 'antd';
|
||||
import { reviewInfo, update } from '../services';
|
||||
import { reviewInfo, groupByList, update } from '../services';
|
||||
import { connect } from 'umi';
|
||||
import './GroupLeaderModal.less'
|
||||
interface GroupLeaderModalProps {
|
||||
visible: boolean;
|
||||
view: boolean;
|
||||
@ -11,7 +12,6 @@ interface GroupLeaderModalProps {
|
||||
dispatch: any;
|
||||
}
|
||||
|
||||
// 只读备注弹窗
|
||||
const RemarkViewModal: React.FC<{
|
||||
visible: boolean;
|
||||
onCancel: () => void;
|
||||
@ -52,12 +52,11 @@ const GroupLeaderModal: React.FC<GroupLeaderModalProps> = ({
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [suppliers, setSuppliers] = useState<any[]>([]);
|
||||
const [items, setItems] = useState<any[]>([]);
|
||||
// groupSummaryResult: { [supplierId]: 0|1 }
|
||||
const [supplierReviewerMap, setSupplierReviewerMap] = useState<Record<string, string[]>>({});
|
||||
const [groupSummaryResult, setGroupSummaryResult] = useState<{ [k: string]: '0' | '1' | undefined }>({});
|
||||
// 查看备注弹窗
|
||||
const [remarkModal, setRemarkModal] = useState({ open: false, remark: '', file: undefined as any });
|
||||
|
||||
// 拉取数据
|
||||
// 适配新结构
|
||||
useEffect(() => {
|
||||
if (visible && record?.id) {
|
||||
setLoading(true);
|
||||
@ -65,17 +64,38 @@ const GroupLeaderModal: React.FC<GroupLeaderModalProps> = ({
|
||||
.then((res: any) => {
|
||||
const supplierList = res?.data || [];
|
||||
setSuppliers(supplierList);
|
||||
// 所有项,取第一家公司
|
||||
const allItems = (supplierList[0]?.coscoAccessItemList || []);
|
||||
// 非summary项
|
||||
setItems(allItems.filter((item: any) => item.itemType !== 'summary'));
|
||||
// summary 行初始化
|
||||
|
||||
// ============ 1. 收集所有评审项(itemType==='item') ===========
|
||||
const allItemsSet = new Set<string>();
|
||||
const allItemsArr: any[] = [];
|
||||
supplierList.forEach((sup: any) => {
|
||||
(sup.coscoAccessUserItemList || []).forEach((u: any) => {
|
||||
if (u.itemType === 'item' && !allItemsSet.has(u.itemName)) {
|
||||
allItemsSet.add(u.itemName);
|
||||
allItemsArr.push({ id: u.itemId, itemName: u.itemName });
|
||||
}
|
||||
});
|
||||
});
|
||||
setItems(allItemsArr);
|
||||
|
||||
// ============ 2. 组员收集 =============
|
||||
const tempReviewerMap: Record<string, string[]> = {};
|
||||
supplierList.forEach((sup: any) => {
|
||||
const reviewerSet = new Set<string>();
|
||||
(sup.coscoAccessUserItemList || []).forEach((u: any) => {
|
||||
if (u.itemType === 'item' && u.reviewBy) {
|
||||
reviewerSet.add(u.reviewBy);
|
||||
}
|
||||
});
|
||||
tempReviewerMap[sup.supplierId] = Array.from(reviewerSet);
|
||||
});
|
||||
setSupplierReviewerMap(tempReviewerMap);
|
||||
|
||||
// ============= 3. 汇总行初始化 ============
|
||||
const summaryMap: { [k: string]: '0' | '1' | undefined } = {};
|
||||
supplierList.forEach((sup: any) => {
|
||||
// summary 行
|
||||
const summaryItem = (sup.coscoAccessItemList || []).find((i: any) => i.itemType === 'summary');
|
||||
// summaryMap[sup.supplierId] = summaryItem?.reviewResult;coscoAccessUserItemList
|
||||
summaryMap[sup.supplierId] = summaryItem.coscoAccessUserItemList[0]?.reviewResult;
|
||||
const summary = (sup.coscoAccessUserItemList || []).find((u: any) => u.itemType === 'summary');
|
||||
summaryMap[sup.supplierId] = summary?.reviewResult;
|
||||
});
|
||||
setGroupSummaryResult(summaryMap);
|
||||
})
|
||||
@ -83,6 +103,7 @@ const GroupLeaderModal: React.FC<GroupLeaderModalProps> = ({
|
||||
} else if (!visible) {
|
||||
setSuppliers([]);
|
||||
setItems([]);
|
||||
setSupplierReviewerMap({});
|
||||
setGroupSummaryResult({});
|
||||
}
|
||||
}, [visible, record]);
|
||||
@ -97,29 +118,22 @@ const GroupLeaderModal: React.FC<GroupLeaderModalProps> = ({
|
||||
|
||||
// 提交
|
||||
const handleSubmit = () => {
|
||||
// 只收集 summary 行参数
|
||||
let summaryParams: any[] = [];
|
||||
summaryParams = suppliers.map((sup: any) => {
|
||||
// 找到summary项
|
||||
const summaryItem = (sup.coscoAccessItemList || []).find((i: any) => i.itemType === 'summary');
|
||||
let summaryParams: any[] = suppliers.map((sup: any) => {
|
||||
const summaryItem = (sup.coscoAccessUserItemList || []).find((i: any) => i.itemType === 'summary');
|
||||
if (!summaryItem) return null;
|
||||
return {
|
||||
id: summaryItem.coscoAccessUserItemList[0].id,
|
||||
id: summaryItem.id,
|
||||
reviewResult: groupSummaryResult[sup.supplierId],
|
||||
remark: '', // 可拓展
|
||||
remark: '',
|
||||
coscoAccessTtemAttachments: undefined,
|
||||
accessWorkId: record?.id
|
||||
}
|
||||
}).filter(Boolean);
|
||||
let accessWorkId = ''
|
||||
if(record?.id) {
|
||||
accessWorkId = record?.id
|
||||
}
|
||||
|
||||
let accessWorkId = record?.id || '';
|
||||
for (let index = 0; index < summaryParams.length; index++) {
|
||||
if(summaryParams[index].reviewResult === null) {
|
||||
message.warning('有未评审项');
|
||||
return
|
||||
if(summaryParams[index].reviewResult === null || summaryParams[index].reviewResult === undefined) {
|
||||
message.warning('有未评审项');
|
||||
return
|
||||
}
|
||||
}
|
||||
update({ coscoAccessUserItemList: summaryParams, accessWorkId }).then((res: any) => {
|
||||
@ -140,27 +154,15 @@ const GroupLeaderModal: React.FC<GroupLeaderModalProps> = ({
|
||||
fixed: 'left',
|
||||
},
|
||||
...suppliers.map(sup => {
|
||||
// 当前公司所有人员(所有非summary项,取 coscoAccessUserItemList 多个)
|
||||
const reviewerSet = new Set<string>();
|
||||
(sup.coscoAccessItemList || []).forEach((item: any) => {
|
||||
if (item.itemType !== 'summary' && Array.isArray(item.coscoAccessUserItemList)) {
|
||||
item.coscoAccessUserItemList.forEach((u: any) => {
|
||||
reviewerSet.add(u.reviewBy);
|
||||
});
|
||||
}
|
||||
});
|
||||
const reviewers = Array.from(reviewerSet);
|
||||
const reviewers = supplierReviewerMap[sup.supplierId] || [];
|
||||
return {
|
||||
title: (
|
||||
<div>
|
||||
{/* <div style={{ fontWeight: 600 }}>{sup.supplierName}</div> */}
|
||||
<a
|
||||
onClick={() => {
|
||||
dispatch({
|
||||
type: 'globalModal/show',
|
||||
payload: {
|
||||
id: sup.supplierId,
|
||||
},
|
||||
payload: { id: sup.supplierId },
|
||||
});
|
||||
}}
|
||||
>
|
||||
@ -175,10 +177,10 @@ const GroupLeaderModal: React.FC<GroupLeaderModalProps> = ({
|
||||
width: 100,
|
||||
align: 'center',
|
||||
render: (_: any, row: any) => {
|
||||
// 在sup.coscoAccessItemList里找该itemName下该人员
|
||||
const item = (sup.coscoAccessItemList || []).find((it: any) => it.itemName === row.itemName && it.itemType !== 'summary');
|
||||
if (!item) return null;
|
||||
const userItem = (item.coscoAccessUserItemList || []).find((u: any) => u.reviewBy === reviewBy);
|
||||
// itemName+reviewBy精确查找
|
||||
const userItem = (sup.coscoAccessUserItemList || []).find(
|
||||
(u: any) => u.itemType === 'item' && u.itemName === row.itemName && u.reviewBy === reviewBy
|
||||
);
|
||||
if (!userItem) return null;
|
||||
return (
|
||||
<div>
|
||||
@ -207,18 +209,9 @@ const GroupLeaderModal: React.FC<GroupLeaderModalProps> = ({
|
||||
itemName: item.itemName
|
||||
};
|
||||
suppliers.forEach(sup => {
|
||||
// 每个人员一格
|
||||
const reviewerSet = new Set<string>();
|
||||
(sup.coscoAccessItemList || []).forEach((it: any) => {
|
||||
if (it.itemType !== 'summary' && Array.isArray(it.coscoAccessUserItemList)) {
|
||||
it.coscoAccessUserItemList.forEach((u: any) => {
|
||||
reviewerSet.add(u.reviewBy);
|
||||
});
|
||||
}
|
||||
});
|
||||
const reviewers = Array.from(reviewerSet);
|
||||
const reviewers = supplierReviewerMap[sup.supplierId] || [];
|
||||
reviewers.forEach((reviewBy: string) => {
|
||||
row[`${sup.supplierId}_${reviewBy}`] = null; // 具体显示用render
|
||||
row[`${sup.supplierId}_${reviewBy}`] = null;
|
||||
});
|
||||
});
|
||||
return row;
|
||||
@ -227,25 +220,22 @@ const GroupLeaderModal: React.FC<GroupLeaderModalProps> = ({
|
||||
// summary 行
|
||||
const summaryRow = (
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={-1}>结果汇总</Table.Summary.Cell>
|
||||
<Table.Summary.Cell
|
||||
index={-1}
|
||||
className="summary-sticky-cell"
|
||||
>
|
||||
结果汇总
|
||||
</Table.Summary.Cell>
|
||||
{suppliers.map((sup, index) => {
|
||||
// 统计reviewer个数
|
||||
const reviewerSet = new Set<string>();
|
||||
(sup.coscoAccessItemList || []).forEach((item: any) => {
|
||||
if (item.itemType !== 'summary' && Array.isArray(item.coscoAccessUserItemList)) {
|
||||
item.coscoAccessUserItemList.forEach((u: any) => {
|
||||
reviewerSet.add(u.reviewBy);
|
||||
});
|
||||
}
|
||||
});
|
||||
const colSpan = reviewerSet.size || 1;
|
||||
const reviewers = supplierReviewerMap[sup.supplierId] || [];
|
||||
const colSpan = reviewers.length || 1;
|
||||
return (
|
||||
<Table.Summary.Cell index={index} key={sup.supplierId} colSpan={colSpan} align="center">
|
||||
{view && (
|
||||
<span style={{color: groupSummaryResult[sup.supplierId] === '0'? '#52c41a': '#f5222d' }}> {groupSummaryResult[sup.supplierId] === '0'? '合格': '不合格'}</span>
|
||||
)}
|
||||
{ !view && (
|
||||
<Select
|
||||
<Select
|
||||
style={{ width: 120 }}
|
||||
value={groupSummaryResult[sup.supplierId]}
|
||||
placeholder="请选择"
|
||||
|
@ -1,9 +1,10 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Modal, Table, Button, Radio, Input, Upload, message, Spin } from 'antd';
|
||||
import { reviewInfo, uploadFile, update } from '../services';
|
||||
import { reviewInfo, groupByList, uploadFile, update } from '../services';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { connect } from 'umi';
|
||||
//主体参数接口
|
||||
|
||||
// 参数类型
|
||||
interface ResultModalProps {
|
||||
visible: boolean;
|
||||
view: boolean;
|
||||
@ -15,7 +16,6 @@ interface ResultModalProps {
|
||||
interface RowData {
|
||||
key: string;
|
||||
itemName: string;
|
||||
// 其他如有
|
||||
}
|
||||
type CellValue = {
|
||||
reviewResult?: '0' | '1';
|
||||
@ -53,8 +53,6 @@ const RemarkViewModal: React.FC<{
|
||||
</Modal>
|
||||
);
|
||||
|
||||
|
||||
//主体
|
||||
const ResultModal: React.FC<ResultModalProps> = ({
|
||||
visible,
|
||||
view,
|
||||
@ -63,15 +61,12 @@ const ResultModal: React.FC<ResultModalProps> = ({
|
||||
onSubmit,
|
||||
dispatch,
|
||||
}) => {
|
||||
// type: 'teamMembers' | 'groupLeader'
|
||||
// 供应商、评审项、单元格数据
|
||||
const [suppliers, setSuppliers] = useState<any[]>([]);
|
||||
const [items, setItems] = useState<any[]>([]);
|
||||
const [userItemMatrix, setUserItemMatrix] = useState<any[][]>([]);
|
||||
// userItemId为唯一key
|
||||
const [cellData, setCellData] = useState<{ [userItemId: string]: CellValue }>({});
|
||||
const [loading, setLoading] = useState(false);
|
||||
// 查看备注弹窗
|
||||
// 查看备注弹窗
|
||||
const [remarkModal, setRemarkModal] = useState({ open: false, remark: '', file: undefined as any });
|
||||
// 备注弹窗
|
||||
const [remarksModalVisible, setRemarksModalVisible] = useState(false);
|
||||
@ -83,30 +78,33 @@ const ResultModal: React.FC<ResultModalProps> = ({
|
||||
useEffect(() => {
|
||||
if (visible && record?.id) {
|
||||
setLoading(true);
|
||||
reviewInfo({ id: record.id })
|
||||
.then((res: any) => {
|
||||
const supplierList = res?.data || [];
|
||||
|
||||
// 拉取所有评审项(groupByList)和所有供应商评审数据(reviewInfo)
|
||||
Promise.all([
|
||||
groupByList({ accessWorkId: record.id }),
|
||||
reviewInfo({ id: record.id }),
|
||||
])
|
||||
.then(([groupRes, reviewRes]: any) => {
|
||||
// 1. 评审项
|
||||
const itemList = (groupRes?.data || []).filter((it: any) => it.itemType !== 'summary');
|
||||
setItems(itemList);
|
||||
|
||||
// 2. 供应商(reviewInfo),每个供应商有coscoAccessUserItemList(平铺)
|
||||
const supplierList = reviewRes?.data || [];
|
||||
setSuppliers(supplierList);
|
||||
|
||||
// 用第一家供应商取所有“非summary”的评审项
|
||||
const baseItems = (supplierList[0]?.coscoAccessItemList || []).filter(
|
||||
(item: any) => item.itemType !== 'summary'
|
||||
);
|
||||
setItems(baseItems);
|
||||
|
||||
// 构建userItem二维矩阵:[row][col]=userItem/null
|
||||
// userItemMatrix[row][col]为对应格的userItem
|
||||
// 3. 构建表格的 userItemMatrix(每行item,每列供应商,单元格为对应userItem/null)
|
||||
const matrix: any[][] = [];
|
||||
const newCellData: { [userItemId: string]: CellValue } = {};
|
||||
baseItems.forEach((item: any, rowIdx: number) => {
|
||||
|
||||
itemList.forEach((item: any, rowIdx: number) => {
|
||||
matrix[rowIdx] = [];
|
||||
supplierList.forEach((sup: any, colIdx: number) => {
|
||||
const cur = (sup.coscoAccessItemList || []).find((it: any) => it.itemName === item.itemName && it.itemType !== 'summary');
|
||||
const userItem =
|
||||
cur?.coscoAccessUserItemList?.length > 0
|
||||
? cur.coscoAccessUserItemList[0]
|
||||
: null;
|
||||
matrix[rowIdx][colIdx] = userItem;
|
||||
// 在当前供应商的 coscoAccessUserItemList 里找itemName完全一致的userItem
|
||||
const userItem = (sup.coscoAccessUserItemList || []).find(
|
||||
(ui: any) => ui.itemName === item.itemName && ui.itemType !== 'summary'
|
||||
);
|
||||
matrix[rowIdx][colIdx] = userItem || null;
|
||||
|
||||
// 初始化cellData
|
||||
if (userItem) {
|
||||
@ -224,7 +222,7 @@ const ResultModal: React.FC<ResultModalProps> = ({
|
||||
}
|
||||
|
||||
for (let index = 0; index < result.length; index++) {
|
||||
if(result[index].reviewResult === null) {
|
||||
if(result[index].reviewResult === null || result[index].reviewResult === undefined) {
|
||||
message.warning('有未评审项');
|
||||
return
|
||||
}
|
||||
@ -273,17 +271,14 @@ const ResultModal: React.FC<ResultModalProps> = ({
|
||||
const v = cellData[userItem.id] || {};
|
||||
return (
|
||||
<>
|
||||
|
||||
{view && (
|
||||
<>
|
||||
<span style={{color: v.reviewResult === '0'? '#52c41a': '#f5222d' }}> {v.reviewResult === '0'? '合格': '不合格'}</span>
|
||||
<Button type="link" size="small" onClick={() =>
|
||||
setRemarkModal({ open: true, remark: v.remark || '', file: v.file })
|
||||
}>查看备注</Button>
|
||||
</>
|
||||
setRemarkModal({ open: true, remark: v.remark || '', file: v.file })
|
||||
}>查看备注</Button>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
{ !view && (
|
||||
<div>
|
||||
<Radio.Group
|
||||
@ -312,7 +307,6 @@ const ResultModal: React.FC<ResultModalProps> = ({
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -327,66 +321,66 @@ const ResultModal: React.FC<ResultModalProps> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
title="评审结果"
|
||||
visible={visible}
|
||||
onCancel={onCancel}
|
||||
footer={[
|
||||
<Button key="cancel" onClick={onCancel}>
|
||||
{view ? '关闭' : '取消'}
|
||||
</Button>,
|
||||
!view && (
|
||||
<Button key="submit" type="primary" onClick={handleSubmit}>
|
||||
提交评审结果
|
||||
</Button>
|
||||
)
|
||||
]}
|
||||
width={1000}
|
||||
bodyStyle={{ maxHeight: '60vh', overflowY: 'auto' }}
|
||||
centered
|
||||
destroyOnClose
|
||||
>
|
||||
<Spin spinning={loading}>
|
||||
<Table
|
||||
dataSource={tableData}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
bordered
|
||||
scroll={{ x: 300 * suppliers.length + 200 }}
|
||||
/>
|
||||
</Spin>
|
||||
<Modal
|
||||
title="备注/上传附件"
|
||||
visible={remarksModalVisible}
|
||||
onCancel={() => setRemarksModalVisible(false)}
|
||||
title="评审结果"
|
||||
visible={visible}
|
||||
onCancel={onCancel}
|
||||
footer={[
|
||||
<Button key="cancel" onClick={() => setRemarksModalVisible(false)}>
|
||||
取消
|
||||
<Button key="cancel" onClick={onCancel}>
|
||||
{view ? '关闭' : '取消'}
|
||||
</Button>,
|
||||
<Button key="submit" type="primary" onClick={handleSubmitRemarks}>
|
||||
提交
|
||||
</Button>
|
||||
!view && (
|
||||
<Button key="submit" type="primary" onClick={handleSubmit}>
|
||||
提交评审结果
|
||||
</Button>
|
||||
)
|
||||
]}
|
||||
width={1000}
|
||||
bodyStyle={{ maxHeight: '60vh', overflowY: 'auto' }}
|
||||
centered
|
||||
destroyOnClose
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
placeholder="请输入备注"
|
||||
value={remarks}
|
||||
onChange={e => setRemarks(e.target.value)}
|
||||
/>
|
||||
<Upload {...uploadProps}>
|
||||
<Button style={{ marginTop: 12 }}>点击上传</Button>
|
||||
</Upload>
|
||||
<Spin spinning={loading}>
|
||||
<Table
|
||||
dataSource={tableData}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
bordered
|
||||
scroll={{ x: 300 * suppliers.length + 200 }}
|
||||
/>
|
||||
</Spin>
|
||||
<Modal
|
||||
title="备注/上传附件"
|
||||
visible={remarksModalVisible}
|
||||
onCancel={() => setRemarksModalVisible(false)}
|
||||
footer={[
|
||||
<Button key="cancel" onClick={() => setRemarksModalVisible(false)}>
|
||||
取消
|
||||
</Button>,
|
||||
<Button key="submit" type="primary" onClick={handleSubmitRemarks}>
|
||||
提交
|
||||
</Button>
|
||||
]}
|
||||
destroyOnClose
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
placeholder="请输入备注"
|
||||
value={remarks}
|
||||
onChange={e => setRemarks(e.target.value)}
|
||||
/>
|
||||
<Upload {...uploadProps}>
|
||||
<Button style={{ marginTop: 12 }}>点击上传</Button>
|
||||
</Upload>
|
||||
</Modal>
|
||||
</Modal>
|
||||
</Modal>
|
||||
<RemarkViewModal
|
||||
visible={remarkModal.open}
|
||||
onCancel={() => setRemarkModal({ open: false, remark: '', file: undefined })}
|
||||
remark={remarkModal.remark}
|
||||
file={remarkModal.file}
|
||||
/>
|
||||
</>
|
||||
<RemarkViewModal
|
||||
visible={remarkModal.open}
|
||||
onCancel={() => setRemarkModal({ open: false, remark: '', file: undefined })}
|
||||
remark={remarkModal.remark}
|
||||
file={remarkModal.file}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -17,6 +17,13 @@ export const getPage = (data: getPageData) => request.post('/coscoAccessWork/get
|
||||
userId?: string;
|
||||
}
|
||||
export const reviewInfo = (params: reviewInfoData) => request.get(`/coscoAccessWork/reviewInfo`, { params });
|
||||
/**
|
||||
* 评审项
|
||||
*/
|
||||
interface groupByListoData {
|
||||
accessWorkId: string;
|
||||
}
|
||||
export const groupByList = (params: groupByListoData) => request.get(`/coscoAccessItem/groupByList`, { params });
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
|
Reference in New Issue
Block a user