feat
parent
92ddaa1272
commit
201055a49b
|
|
@ -123,4 +123,14 @@ export const evalContractSave = declareRequest(
|
||||||
export const evalRiskAnalysisPeopleSave = declareRequest(
|
export const evalRiskAnalysisPeopleSave = declareRequest(
|
||||||
"riskAnalysisSaveLoading",
|
"riskAnalysisSaveLoading",
|
||||||
"Post > @/safetyEval/institution/eval-risk-analysis/participant/save",
|
"Post > @/safetyEval/institution/eval-risk-analysis/participant/save",
|
||||||
|
);
|
||||||
|
|
||||||
|
export const evalProjectMemberPage = declareRequest(
|
||||||
|
"memberLoading",
|
||||||
|
"Get > /safetyEval/institution/eval-project-member/page",
|
||||||
|
);
|
||||||
|
|
||||||
|
export const evalProjectMemberSave = declareRequest(
|
||||||
|
"memberSaveLoading",
|
||||||
|
"Post > @/safetyEval/institution/eval-project-member/save",
|
||||||
);
|
);
|
||||||
|
|
@ -101,6 +101,9 @@ const EvalProjectCreate = (props) => {
|
||||||
participants: selectedParticipants.map((item) => ({
|
participants: selectedParticipants.map((item) => ({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
name: item.userName,
|
name: item.userName,
|
||||||
|
deptName: item.deptName,
|
||||||
|
posName: item.postName,
|
||||||
|
capacity: '龟派气功波',
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
if (isView) {
|
if (isView) {
|
||||||
|
|
|
||||||
|
|
@ -1,100 +1,287 @@
|
||||||
import React from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Tag, Button, Card, Row, Col, Table, Statistic, Flex } from "antd";
|
import {
|
||||||
|
Tag, Button, Card, Row, Col, Table, Statistic, Flex, Modal, Radio, Checkbox, message, Spin,
|
||||||
|
} from "antd";
|
||||||
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
|
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
||||||
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
||||||
|
|
||||||
const TeamContent = () => (
|
const { router } = tools;
|
||||||
<div>
|
|
||||||
<div className="pf-permission">
|
|
||||||
<Tag color="blue" className="pf-tag">评价部经理 / 机构主账号</Tag>
|
|
||||||
<span className="pf-desc">
|
|
||||||
添加人员时可同时选择多个项目角色和多名人员;普通角色可配置多人。"项目负责人(项目组组长)"和"过程控制负责人"每个项目只能配置1人,选择任一唯一角色时,本次只能选择1名人员。
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
const ROLE_DEFINITIONS = [
|
||||||
<Row gutter={16} style={{ marginBottom: 16 }}>
|
{ value: "MARKETING_BUSINESS_REP", name: "市场部业务员", unique: false, summary: "获取项目基础信息,形成风险分析记录;风险通过后签订合同并下达任务通知单。" },
|
||||||
<Col span={6}>
|
{ value: "TECHNICAL_LEAD", name: "技术负责人", unique: false, summary: "评估人员专业匹配与技术可行性,审核检查表并开展评价报告技术审核。" },
|
||||||
<Card size="small">
|
{ value: "PROCESS_CONTROL_LEAD", name: "过程控制负责人", unique: true, summary: "核查利益冲突、资质范围和人员配置,负责受控管理、程序合规审核及归档前校验。" },
|
||||||
<Statistic title="已配置人员" value={5} suffix="人" />
|
{ value: "FINANCE_STAFF", name: "财务人员", unique: false, summary: "核算人工、费用、税金和利润等全成本,评估项目经济性及合同金额合理性。" },
|
||||||
|
{ value: "EVALUATION_AGENCY_HEAD", name: "评价机构负责人", unique: false, summary: "综合多方意见决定是否承接项目,并在全部审核通过后终审签发评价报告。" },
|
||||||
</Card>
|
{ value: "EVALUATION_DEPT_MANAGER", name: "评价部经理", unique: false, summary: "签发项目组任命文件,审核组长资格、行业经验及成员专业配置。" },
|
||||||
</Col>
|
{ value: "PROJECT_LEAD", name: "项目负责人(项目组组长)", unique: true, summary: "制定实施计划并组织启动、初勘、检查表、现场勘查、整改复查及报告编制。" },
|
||||||
<Col span={6}>
|
{ value: "PROJECT_TEAM_MEMBERS", name: "项目组各专业组员", unique: false, summary: "按专业分工开展资料收集、检查表编制、现场检查、危险辨识和评价报告专业内容编写。" },
|
||||||
<Card size="small">
|
{ value: "INTERNAL_AUDITOR", name: "内审人", unique: false, summary: "审核报告初稿及修改结果,重点核查依据、危险辨识、单元划分、评价方法和结论。" },
|
||||||
<Statistic title="已覆盖角色" value="5 / 11" />
|
{ value: "REPORT_COMPILER", name: "报告编制人", unique: false, summary: "整合各专业内容形成报告初稿,根据各级审核意见修改并整理全过程档案。" },
|
||||||
|
{ value: "ARCHIVES_ADMIN", name: "档案管理员", unique: false, summary: "办理档案交接、编号、分类、装订和入库,并按规定开展报告信息公开。" },
|
||||||
</Card>
|
];
|
||||||
</Col>
|
|
||||||
<Col span={6}>
|
|
||||||
<Card size="small">
|
|
||||||
<Statistic title="项目负责人" value="已配置" valueStyle={{ color: "#52c41a" }} />
|
|
||||||
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
<Col span={6}>
|
|
||||||
<Card size="small">
|
|
||||||
<Statistic title="过程控制负责人" value="待配置" valueStyle={{ color: "#faad14" }} />
|
|
||||||
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
<Flex justify="flex-end" align="center" style={{ marginBottom: 12 }}>
|
const TeamContent = (props) => {
|
||||||
|
const { safetyEvalBusiness, evalProjectMemberPage, evalProjectMemberSave } = props;
|
||||||
<Button type="primary" size="small">+ 添加人员与角色</Button>
|
const { evalProjectDetailData, memberLoading, memberSaveLoading } = safetyEvalBusiness || {};
|
||||||
</Flex>
|
const participants = evalProjectDetailData?.participants || [];
|
||||||
|
const projectId = router.query?.id;
|
||||||
|
|
||||||
<Table
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
dataSource={[
|
const [selectedRole, setSelectedRole] = useState(null);
|
||||||
{ id: 1, name: "张建国", dept: "评价一部", role: "项目负责人", qualification: "一级评价师/化工", check: "通过", duty: "制定实施计划并组织启动、初勘、检查表、现场勘查、整改复查及报告编制" },
|
const [selectedPersons, setSelectedPersons] = useState([]);
|
||||||
{ id: 2, name: "李明华", dept: "评价一部", role: "报告编制人", qualification: "二级评价师/安全", check: "通过", duty: "整合各专业内容形成报告初稿" },
|
const [teamMembers, setTeamMembers] = useState([]);
|
||||||
]}
|
|
||||||
columns={[
|
|
||||||
{ title: "姓名", dataIndex: "name" },
|
|
||||||
{ title: "部门/岗位", dataIndex: "dept" },
|
|
||||||
{ title: "项目角色", dataIndex: "role" },
|
|
||||||
{ title: "资质与专业", dataIndex: "qualification" },
|
|
||||||
{ title: "配置校验", dataIndex: "check" },
|
|
||||||
{ title: "主要职责", dataIndex: "duty", ellipsis: true },
|
|
||||||
{ title: "操作", width: 100, render: () => <Button type="link" danger size="small">移除</Button> },
|
|
||||||
]}
|
|
||||||
rowKey="id"
|
|
||||||
pagination={false}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<details style={{ marginTop: 12, cursor: "pointer" }}>
|
const fetchData = async () => {
|
||||||
<summary style={{ color: "#1677ff", fontSize: 13, padding: "8px 0" }}>查看11类项目角色职责说明</summary>
|
if (!projectId) return;
|
||||||
<div style={{ display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 8, padding: "8px 0" }}>
|
const res = await evalProjectMemberPage({ projectId });
|
||||||
{[
|
if (res?.success !== false && res?.data) {
|
||||||
{ name: "市场部业务员", unique: false, summary: "获取项目基础信息,形成风险分析记录;风险通过后签订合同并下达任务通知单。" },
|
setTeamMembers(
|
||||||
{ name: "技术负责人", unique: false, summary: "评估人员专业匹配与技术可行性,审核检查表并开展评价报告技术审核。" },
|
res.data.map((item) => ({
|
||||||
{ name: "过程控制负责人", unique: true, summary: "核查利益冲突、资质范围和人员配置,负责受控管理、程序合规审核及归档前校验。" },
|
...item,
|
||||||
{ name: "财务人员", unique: false, summary: "核算人工、费用、税金和利润等全成本,评估项目经济性及合同金额合理性。" },
|
roles: (item.role || []).map((r) => ({
|
||||||
{ name: "评价机构负责人", unique: false, summary: "综合多方意见决定是否承接项目,并在全部审核通过后终审签发评价报告。" },
|
role: r,
|
||||||
{ name: "评价部经理", unique: false, summary: "签发项目组任命文件,审核组长资格、行业经验及成员专业配置。" },
|
duty: item.responsibility || ROLE_DEFINITIONS.find((d) => d.value === r)?.summary || "",
|
||||||
{ name: "项目负责人(项目组组长)", unique: true, summary: "制定实施计划并组织启动、初勘、检查表、现场勘查、整改复查及报告编制。" },
|
})),
|
||||||
{ name: "项目组各专业组员", unique: false, summary: "按专业分工开展资料收集、检查表编制、现场检查、危险辨识和评价报告专业内容编写。" },
|
})),
|
||||||
{ name: "内审人", unique: false, summary: "审核报告初稿及修改结果,重点核查依据、危险辨识、单元划分、评价方法和结论。" },
|
);
|
||||||
{ name: "报告编制人", unique: false, summary: "整合各专业内容形成报告初稿,根据各级审核意见修改并整理全过程档案。" },
|
}
|
||||||
{ name: "档案管理员", unique: false, summary: "办理档案交接、编号、分类、装订和入库,并按规定开展报告信息公开。" },
|
};
|
||||||
].map((role) => (
|
|
||||||
<div key={role.name} style={{ border: "1px solid #e8e8e8", borderRadius: 6, padding: "8px 10px", background: "#f8fafc" }}>
|
useEffect(() => {
|
||||||
<strong style={{ fontSize: 13 }}>
|
if (evalProjectDetailData?.id) fetchData();
|
||||||
{role.name}
|
}, [projectId, evalProjectDetailData?.id]);
|
||||||
{role.unique && <Tag color="blue" style={{ marginLeft: 6, fontSize: 11 }}>单人唯一</Tag>}
|
|
||||||
</strong>
|
const isUniqueRole = selectedRole && ROLE_DEFINITIONS.find((r) => r.value === selectedRole)?.unique;
|
||||||
<p style={{ fontSize: 12, color: "#666", margin: "4px 0 0", lineHeight: 1.55 }}>{role.summary}</p>
|
|
||||||
</div>
|
const handlePersonChange = (checkedValues) => {
|
||||||
|
if (isUniqueRole && checkedValues.length > 1) {
|
||||||
|
setSelectedPersons([checkedValues[checkedValues.length - 1]]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSelectedPersons(checkedValues);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOpenModal = () => {
|
||||||
|
setSelectedRole(null);
|
||||||
|
setSelectedPersons([]);
|
||||||
|
setModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleConfirm = () => {
|
||||||
|
if (!selectedRole) { message.warning("请选择1个项目角色"); return; }
|
||||||
|
if (selectedPersons.length === 0) { message.warning("请至少选择1名人员"); return; }
|
||||||
|
const role = ROLE_DEFINITIONS.find((r) => r.value === selectedRole);
|
||||||
|
if (role?.unique && selectedPersons.length > 1) { message.warning("该角色为单人唯一角色,只能选择1名人员"); return; }
|
||||||
|
|
||||||
|
const newEntries = selectedPersons.map((personId) => {
|
||||||
|
const p = participants.find((item) => item.id === personId);
|
||||||
|
const existing = teamMembers.find((m) => m.personnelId === personId);
|
||||||
|
return {
|
||||||
|
personnelId: p.id,
|
||||||
|
personnelName: p.name,
|
||||||
|
deptName: p.deptName,
|
||||||
|
capacity: p.capacity,
|
||||||
|
...(existing?.id ? { id: existing.id } : {}),
|
||||||
|
roles: [{ role: selectedRole, duty: role?.summary || "" }],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setTeamMembers((prev) => {
|
||||||
|
const merged = [...prev];
|
||||||
|
newEntries.forEach((entry) => {
|
||||||
|
const existing = merged.find((m) => m.personnelId === entry.personnelId);
|
||||||
|
if (existing) {
|
||||||
|
if (!existing.roles.find((r) => r.role === entry.roles[0].role)) {
|
||||||
|
existing.roles.push(entry.roles[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
merged.push(entry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return merged;
|
||||||
|
});
|
||||||
|
setModalOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemovePerson = (personnelId) => {
|
||||||
|
setTeamMembers((prev) => prev.filter((m) => m.personnelId !== personnelId));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = async () => {
|
||||||
|
const payload = teamMembers.map((m) => ({
|
||||||
|
id: m.id,
|
||||||
|
projectId,
|
||||||
|
personnelId: m.personnelId,
|
||||||
|
personnelName: m.personnelName,
|
||||||
|
deptName: m.deptName,
|
||||||
|
capacity: m.capacity,
|
||||||
|
role: m.roles.map((r) => r.role),
|
||||||
|
responsibility: m.roles[0]?.duty,
|
||||||
|
}));
|
||||||
|
const res = await evalProjectMemberSave(payload);
|
||||||
|
if (res?.success !== false) {
|
||||||
|
message.success("保存成功");
|
||||||
|
fetchData();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const allRoles = teamMembers.flatMap((m) => m.roles.map((r) => r.role));
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ title: "姓名", dataIndex: "personnelName", width: 120, ellipsis: true },
|
||||||
|
{ title: "部门/岗位", dataIndex: "deptName", width: 200, ellipsis: true },
|
||||||
|
{
|
||||||
|
title: "项目角色", dataIndex: "roles", width: 350,
|
||||||
|
render: (roles) => (
|
||||||
|
<div style={{ display: "flex", flexWrap: "wrap", gap: 4 }}>
|
||||||
|
{roles.map((r) => (
|
||||||
|
<Tag key={r.role} color="blue">
|
||||||
|
{ROLE_DEFINITIONS.find((d) => d.value === r.role)?.name || r.role}
|
||||||
|
</Tag>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</details>
|
),
|
||||||
|
},
|
||||||
|
{ title: "资质与专业", dataIndex: "capacity", width: 200, ellipsis: true },
|
||||||
|
{
|
||||||
|
title: "主要职责", dataIndex: "roles", ellipsis: true,
|
||||||
|
render: (roles) => roles.map((r) => r.duty).join(";"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作", width: 80, fixed: "right",
|
||||||
|
render: (_, record) => (
|
||||||
|
<Button type="link" danger size="small" onClick={() => handleRemovePerson(record.personnelId)}>移除</Button>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
<Flex justify="flex-end" gap={8} style={{ marginTop: 16 }}>
|
return (
|
||||||
<Button>暂存</Button>
|
<Spin spinning={memberLoading}>
|
||||||
<Button>生成项目组任命文件</Button>
|
<div>
|
||||||
<Button type="primary">确认项目组</Button>
|
<div className="pf-permission">
|
||||||
</Flex>
|
<Tag color="blue" className="pf-tag">评价部经理 / 机构主账号</Tag>
|
||||||
|
<span className="pf-desc">
|
||||||
</div>
|
添加人员时可同时选择多个项目角色和多名人员;普通角色可配置多人。"项目负责人(项目组组长)"和"过程控制负责人"每个项目只能配置1人,选择任一唯一角色时,本次只能选择1名人员。
|
||||||
);
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
export default TeamContent;
|
<Row gutter={16} className="pf-stats-row">
|
||||||
|
<Col span={6}>
|
||||||
|
<Card size="small">
|
||||||
|
<Statistic title="已配置人员" value={teamMembers.length} suffix="人" />
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
<Col span={6}>
|
||||||
|
<Card size="small">
|
||||||
|
<Statistic title="已覆盖角色" value={new Set(allRoles).size + " / 11"} />
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
<Col span={6}>
|
||||||
|
<Card size="small">
|
||||||
|
<Statistic title="项目负责人" value={allRoles.includes("PROJECT_LEAD") ? "已配置" : "待配置"}
|
||||||
|
valueStyle={{ color: allRoles.includes("PROJECT_LEAD") ? "#52c41a" : "#faad14" }} />
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
<Col span={6}>
|
||||||
|
<Card size="small">
|
||||||
|
<Statistic title="过程控制负责人" value={allRoles.includes("PROCESS_CONTROL_LEAD") ? "已配置" : "待配置"}
|
||||||
|
valueStyle={{ color: allRoles.includes("PROCESS_CONTROL_LEAD") ? "#52c41a" : "#faad14" }} />
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
<Flex justify="flex-end" className="pf-add-bar">
|
||||||
|
<Button type="primary" size="small" onClick={handleOpenModal}>+ 添加人员与角色</Button>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Table dataSource={teamMembers} columns={columns} rowKey="personnelId" pagination={false} scroll={{ x: 1600, y: 320 }} />
|
||||||
|
|
||||||
|
<details className="pf-role-guide">
|
||||||
|
<summary className="pf-role-guide-title">查看11类项目角色职责说明</summary>
|
||||||
|
<div className="pf-role-guide-grid">
|
||||||
|
{ROLE_DEFINITIONS.map((role) => (
|
||||||
|
<div key={role.value} className="pf-role-card">
|
||||||
|
<strong className="pf-role-card-title">
|
||||||
|
{role.name}
|
||||||
|
{role.unique && <Tag color="blue" className="pf-unique-tag">单人唯一</Tag>}
|
||||||
|
</strong>
|
||||||
|
<p className="pf-role-card-desc">{role.summary}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<Flex justify="flex-end" gap={8} className="pf-bottom-actions">
|
||||||
|
<Button onClick={handleSave} loading={memberSaveLoading}>暂存</Button>
|
||||||
|
<Button>生成项目组任命文件</Button>
|
||||||
|
<Button type="primary">确认项目组</Button>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Modal title="添加项目人员与角色" open={modalOpen} onCancel={() => setModalOpen(false)} width={700}
|
||||||
|
footer={
|
||||||
|
<Flex justify="flex-end" gap={8}>
|
||||||
|
<Button onClick={() => setModalOpen(false)}>取消</Button>
|
||||||
|
<Button type="primary" onClick={handleConfirm}>确认添加</Button>
|
||||||
|
</Flex>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="pf-modal-hint">
|
||||||
|
{selectedRole && ROLE_DEFINITIONS.find((r) => r.value === selectedRole)?.unique
|
||||||
|
? `已选择唯一角色,人员数量限制为1人。当前已选 ${selectedPersons.length} 人。`
|
||||||
|
: `已选择 ${selectedRole ? 1 : 0} 个角色、${selectedPersons.length} 名人员。`}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="pf-modal-section">
|
||||||
|
<h4 className="pf-modal-section-title">1. 选择项目角色</h4>
|
||||||
|
<Radio.Group value={selectedRole}
|
||||||
|
onChange={(e) => { setSelectedRole(e.target.value); setSelectedPersons([]); }}
|
||||||
|
className="pf-w-full"
|
||||||
|
>
|
||||||
|
<div className="pf-choice-grid">
|
||||||
|
{ROLE_DEFINITIONS.map((role) => (
|
||||||
|
<label key={role.value}
|
||||||
|
className={`pf-choice-card ${selectedRole === role.value ? "pf-choice-card-active" : ""}`}
|
||||||
|
>
|
||||||
|
<Radio value={role.value} className="pf-hidden-control" />
|
||||||
|
<strong className="pf-choice-card-name">
|
||||||
|
{role.name}
|
||||||
|
{role.unique && <Tag color="blue" className="pf-unique-tag">单人唯一</Tag>}
|
||||||
|
</strong>
|
||||||
|
<span className="pf-choice-card-sub">{role.summary}</span>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Radio.Group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h4 className="pf-modal-section-title">2. 选择人员(可多选)</h4>
|
||||||
|
{participants.length === 0 ? (
|
||||||
|
<div className="pf-empty">暂无可用人员数据</div>
|
||||||
|
) : (
|
||||||
|
<Checkbox.Group value={selectedPersons} onChange={handlePersonChange} className="pf-w-full">
|
||||||
|
<div className="pf-choice-grid-full">
|
||||||
|
{participants.map((person) => (
|
||||||
|
<label key={person.id}
|
||||||
|
className={`pf-choice-card ${selectedPersons.includes(person.id) ? "pf-choice-card-active" : ""}`}
|
||||||
|
>
|
||||||
|
<Checkbox value={person.id} className="pf-hidden-control" />
|
||||||
|
<strong className="pf-choice-card-name">{person.name} · {person.deptName}</strong>
|
||||||
|
<span className="pf-choice-card-sub">
|
||||||
|
{person.posName}{person.capacity ? ` · ${person.capacity}` : ""}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Checkbox.Group>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Connect([NS_SAFETY_EVAL_BUSINESS], true)(TeamContent);
|
||||||
|
|
@ -107,4 +107,129 @@
|
||||||
&-w-full {
|
&-w-full {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 项目组 - 统计行
|
||||||
|
&-stats-row {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 项目组 - 添加按钮行
|
||||||
|
&-add-bar {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 项目组 - 角色职责说明折叠区
|
||||||
|
&-role-guide {
|
||||||
|
margin-top: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-role-guide-title {
|
||||||
|
color: #1677ff;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-role-guide-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-role-card {
|
||||||
|
border: 1px solid #e8e8e8;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
background: #f8fafc;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-role-card-title {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-role-card-desc {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
margin: 4px 0 0;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 项目组 - 底部操作行
|
||||||
|
&-bottom-actions {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 弹窗 - 提示文字
|
||||||
|
&-modal-hint {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 弹窗 - 区块
|
||||||
|
&-modal-section {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-modal-section-title {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 弹窗 - 选择卡片网格
|
||||||
|
&-choice-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-choice-grid-full {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 弹窗 - 选择卡片
|
||||||
|
&-choice-card {
|
||||||
|
border: 1px solid #e8e8e8;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
background: #f8fafc;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-choice-card-active {
|
||||||
|
background: #e6f4ff;
|
||||||
|
border-color: #1677ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-choice-card-name {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-choice-card-sub {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
display: block;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 弹窗 - 空状态
|
||||||
|
&-empty {
|
||||||
|
color: #999;
|
||||||
|
padding: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 弹窗 - 唯一标签
|
||||||
|
&-unique-tag {
|
||||||
|
margin-left: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐藏 radio / checkbox 原生控件
|
||||||
|
&-hidden-control {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue