在做 react 项目的时候,项目需求中有一个展示家族成员 case 管理的画面,左侧以列表的形式展示成员以及成员相关的case 列表,左侧则是与列表case 时间相对应的图表展示
实现方式如下:
import { useState, useEffect, useRef } from 'react'
import { Link } from 'react-router-dom'
import { generateClient } from 'aws-amplify/api';
import { Dropdown, Modal, Spin, Form, Input, Row, Col, DatePicker, Select, Button, Popover } from 'antd'
import { LoadingOutlined, ExclamationCircleFilled,CloseOutlined } from '@ant-design/icons'
import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat';
// 样式
import styles from './index.module.scss'
// aws 接口
import { listNeedyPeople, getIssues } from '../../../../../graphql/queries'
// icon
import { supportDate, menuIcon, downIcon, progressIcon, stopIcon, overIcon, discribetionIcon, rightIcon, dragIcon, deleteIcon, shareBlueIcon, moreIcon,select } from '../../../../../icons'dayjs.extend(customParseFormat);const { TextArea } = Input
const { confirm } = Modal
const client = generateClient()
const { RangePicker } = DatePickerconst consultantAndInstitutions = [{ label: '塚原 優芽/A市福祉課', value: '1/1' },{ label: '安藤晃/A地区地域包括支援センター', value: '2/2' },{ label: '佐川栄子 /A病院', value: '3/3' },{ label: '岩平 幹夫/生活困窮者自立相談支援センター', value: '4/4' },{ label: '小松原佳枝/基幹相談支援センター', value: '5/5' },{ label: '宇野 夏美/ハローワーク', value: '6/6' },{ label: '栗田 政信/みどりクリニック', value: '7/7' },{ label: '清水祥子/スクールカウンセラー', value: '8/8' },{ label: '橘義人/多機関協働事業', value: '9/9' },
]const repetition = [{ label: 'なし', value: '1' }
]const CaseManagement = (props) => {var encodedParams = sessionStorage.getItem('encodedParams');var decodedParams = decodeURIComponent(encodedParams);var paramsObj = JSON.parse(decodedParams)const tableRef = useRef(null)const { authority, caseManagementList, onFold, onShowIssues, onChangeStatus, onOpenSelectStatus, onEditTask, onShowFlag, onRefresh } = propsconst weekDay = ['日', '月', '火', '水', '木', '金', '土']const [open, setOpen] = useState(false)const [spinning, setSpinning] = useState(false)const [familyMembers, setFamilyMembers] = useState([])const [currentSelectFamilyMember, setCurrentSelectFamilyMember] = useState("")const [currentPageStatus, setCurrentPageStatus] = useState('create')const [isTaskCreate, setIsTaskCreate] = useState(true)const [currentUpdateTask, setCurrentUpdateTask] = useState('')const [taskForm, setTaskForm] = useState({taskContent: "",taskStartDate: "",taskEndDate: "", consultantAndInstitutions: "",repetition: "",alertNotification: "",status: "1",})const [openActivity, setOpenActivity] = useState(false)const [isActivityCreate, setIsActivityCreate] = useState(true)const [currentUpdateActivity, setCurrentUpdateActivity] = useState('')const [activityForm, setActivityForm] = useState({activityContent: "",activityStartDate: "",activityEndDate: "", consultantAndInstitutions: "",repetition: "",alertNotification: "",status: "1",})const handleTaskCreate = () => {setIsTaskCreate(true)setOpen(true)}const handleTaskUpdate = () => {setCurrentPageStatus('update')setIsTaskCreate(false)onEditTask()}const handleSubmitTask = async () => {try {if(!currentSelectFamilyMember) returnsetSpinning(true)// 在此处调用新增/修改 case 接口setOpen(false)setSpinning(false)setTaskForm({taskContent: "",taskStartDate: "",taskEndDate: "",consultantAndInstitutions: "",repetition: "",alertNotification: "",status: "1",})setCurrentSelectFamilyMember("")setIsTaskCreate(true)} catch(err) {setSpinning(false)console.error(err)}}const handleActivityCreate = () => {setIsActivityCreate(true)setOpenActivity(true)}const handleActivityUpdate = (caseIndex, activityIndex, activity) => {const activityform = {activityContent: activity.activityContent,activityStartDate: activity.activityStartDate,activityEndDate: activity.activityEndDate, consultantAndInstitutions: activity.consultantAndInstitutions,repetition: activity.repetition,alertNotification: activity.alertNotification,status: activity.status,}setActivityForm(activityform)setCurrentSelectFamilyMember(caseManagementList[caseIndex].value)setCurrentUpdateActivity(activity.id)setIsActivityCreate(false)setOpenActivity(true)}const handleSubmitActivity = async () => {try {if(!currentSelectFamilyMember) returnsetSpinning(true)// 创建小蓝旗活动setOpenActivity(false)setSpinning(false)setActivityForm({activityContent: "",activityStartDate: "",activityEndDate: "", consultantAndInstitutions: "",repetition: "",alertNotification: "",status: "1",})setCurrentSelectFamilyMember("")} catch(err) {console.error(err)}}const handleCancel = () => {setOpen(false)setTaskForm({taskContent: "",taskStartDate: "",taskEndDate: "",consultantAndInstitutions: "",repetition: "",alertNotification: "",status: "1",})setCurrentSelectFamilyMember("")setOpenActivity(false)setActivityForm({activityContent: "",activityStartDate: "",activityEndDate: "", consultantAndInstitutions: "",repetition: "",alertNotification: "",status: "1",})}const handleFold = (item, index) => {onFold(index)}const handleGoBack = () => {setCurrentPageStatus('create')setIsTaskCreate(true)}// 课题const [issues, setIssues] = useState({})const handleShowIssues = async (item, index) => {try {onShowIssues(index)if(!item.issuesInfoId) return setIssues({})const res = await client.graphql({ query: getIssues, variables: { id: item.issuesInfoId } });if(res.data.getIssues) {setIssues(res.data.getIssues)}} catch(err) {console.error(err)}}const handleEditTask = (i, index, task) => {const taskform = {taskContent: task.taskContent,taskStartDate: task.taskStartDate,taskEndDate: task.taskEndDate, consultantAndInstitutions: task.consultantAndInstitutions,repetition: task.repetition,alertNotification: task.alertNotification,status: task.status,}setTaskForm(taskform)setCurrentSelectFamilyMember(caseManagementList[i].value)setCurrentUpdateTask(task.id)setIsTaskCreate(false)setOpen(true)}const handleDeleteTask = async (task) => {try {confirm({title: '削除してよろしいですか?',okText: '確認',icon: <ExclamationCircleFilled />,content: null,async onOk() {// 调用删除 case 接口},onCancel() {console.log('Cancel');},});} catch(err) {console.error(err)}}const fetchlistNeedyPeople = async () => {try {const ListNeedyPeople = await client.graphql({ query: listNeedyPeople, variables: { filter: { familygroupID: { eq: paramsObj.id } }, limit: 1000 } });if (ListNeedyPeople.data.listNeedyPeople) {const data = ListNeedyPeople.data.listNeedyPeople.itemsconst familyMember = data.filter(item => item.fullName !== null).map(item => ({label: item.fullName, value: item.id}))setFamilyMembers(familyMember)}} catch (err) {console.error(err)}}useEffect(() => {fetchlistNeedyPeople()}, [])const items = [{label: <div style={{display: 'flex', alignItems: 'center', width: 214, height: 41, fontSize: 16}} onClick={handleTaskCreate}>タスクの追加</div>,key: '0',},{type: 'divider',},{label: <div style={{display: 'flex', alignItems: 'center', width: 214, height: 41, fontSize: 16}} onClick={handleTaskUpdate}>タスクの編集</div>,key: '1',},{type: 'divider',},{label: <div style={{display: 'flex', alignItems: 'center', width: 214, height: 41, fontSize: 16}} onClick={handleActivityCreate}>イベントの追加</div>,key: '2',},]const status = [{ value: '1', label: '順調' },{ value: '2', label: '遅滞' },{ value: '3', label: '完了' },]const handleOpenChange = (i, index, newOpen) => {onOpenSelectStatus(i, index, newOpen)}const handleChangeStatus = async (i, index, statu, task) => {try {onChangeStatus(i, index, statu)// 调用修改 case 接口修改状态} catch(err) {console.error(err)}}const handleMouseEnter = (activity) => {onShowFlag(activity)}// ---const currentYear = new Date().getFullYear()const currentMonth = new Date().getMonth() + 1const currentDate = new Date().getDate()const currentMonthDateCount = new Date(currentYear, currentMonth, 0).getDate()const currentMonthDateArr = []for(let i = 1; i <= currentMonthDateCount; i++) {currentMonthDateArr.push({date: i, week: weekDay[new Date(`${currentYear}-${currentMonth}-${i}`).getDay()]})}const prevMonth = currentMonth - 1 === 0 ? 12 : currentMonth - 1const prevMonthInYear = prevMonth > currentMonth ? currentYear - 1 : currentYearconst prevMonthDateCount = new Date(prevMonthInYear, prevMonth, 0).getDate()const prevMonthDateArr = []for(let i = 1; i <= prevMonthDateCount; i++) {prevMonthDateArr.push({date: i, week: weekDay[new Date(`${prevMonthInYear}-${prevMonth}-${i}`).getDay()]})}const nextMonth = currentMonth + 1 === 13 ? 1 : currentMonth + 1const nextMonthInYear = nextMonth < currentMonth ? currentYear + 1 : currentYearconst nextMonthDateCount = new Date(nextMonthInYear, nextMonth, 0).getDate()const nextMonthDateArr = []for(let i = 1; i <= nextMonthDateCount; i++) {nextMonthDateArr.push({date: i, week: weekDay[new Date(`${nextMonthInYear}-${nextMonth}-${i}`).getDay()]})}const [taskPreviewTimePeriod, setTaskPreviewTimePeriod] = useState({startTime: `${prevMonthInYear}年${prevMonth > 9 ? prevMonth : '0' + prevMonth}月`,endTime: `${nextMonthInYear}年${nextMonth > 9 ? nextMonth : '0' + nextMonth}月`})const [times, setTimes] = useState([{year: prevMonthInYear,month: prevMonth > 9 ? prevMonth : '0' + prevMonth,date: prevMonthDateArr},{year: currentYear,month: currentMonth > 9 ? currentMonth : '0' + currentMonth,date: currentMonthDateArr},{year: nextMonthInYear,month: nextMonth > 9 ? nextMonth : '0' + nextMonth,date: nextMonthDateArr},])useEffect(() => {let pattern = /(\d{4})年(\d{2})月/; let replacement = "$1/$2"; const timePeriodMonthCount = new Date(+new Date(taskPreviewTimePeriod.endTime.replace(pattern, replacement)) - (+new Date(taskPreviewTimePeriod.startTime.replace(pattern, replacement)))).getMonth() + 1const timePeriod = []let year = Number(taskPreviewTimePeriod.startTime.replace(pattern, replacement).split('/')[0])let month = Number(taskPreviewTimePeriod.startTime.replace(pattern, replacement).split('/')[1])for(let i = 0; i < timePeriodMonthCount; i++) {const date = []const monthDateCount = new Date(year, month, 0).getDate()for(let j = 1; j <= monthDateCount; j++) {date.push({date: j, week: weekDay[new Date(`${year}-${month}-${j}`).getDay()]})}timePeriod.push({year: year,month: month > 9 ? month : '0' + month,date: date})if(month + 1 > 12) {year += 1month = 1} else {month += 1}}setTimes(timePeriod)setTimeout(() => {const index = timePeriod.findIndex(item => item.month === (new Date().getMonth() > 9 ? new Date().getMonth() : '0' + new Date().getMonth()))const count = timePeriod.reduce((count, item, i) => {if(index >= i) {count += item.date.length}return count}, 0)tableRef.current.scrollLeft = count * 40 + (new Date(+new Date() - (+new Date(`${new Date().getFullYear()}/${new Date().getMonth() + 1}/01`))).getDate() - 1) * 40 - tableRef.current.offsetWidth / 2 + 40}, 100)}, [taskPreviewTimePeriod])return (<div className={styles.root}>{currentPageStatus === 'create' &&<div className="header"><header><h2>進捗管理</h2><span className="tag">相談受付</span></header><RangePickerallowClear={false}picker="month"size="large"suffixIcon={<img src={supportDate} alt="supportDate" />}format="YYYY年MM月"value={[dayjs(taskPreviewTimePeriod.startTime, 'YYYY年MM月'), dayjs(taskPreviewTimePeriod.endTime, 'YYYY年MM月')]}onChange={(dates, dateStings) => { setTaskPreviewTimePeriod({startTime: dateStings[0], endTime: dateStings[1]}) }}/></div>}<div className="container">{/* 左侧列表区域html */}<div className="case_list">{currentPageStatus === 'create'{/* 创建 case */}? <><div className="case_list_title"><Dropdownmenu={{items,}}trigger={['click']}><img className="icon" src={menuIcon} alt="" /></Dropdown><h3>タスク一覧</h3></div><div className="case_list_container">{caseManagementList.map((item, index) => ((item.caseManagementList && item.caseManagementList.length > 0) &&<div key={item.value} className="case_list_content"><div className="case_title"><Link className="family_member_name">{`${item.label}さん`}</Link><img className="icon" style={{transform: `rotate(${item.isFold ? '0deg' : '180deg'})`, transition: 'all .2s'}} src={downIcon} alt="" onClick={() => handleFold(item, index)} /></div><div className="case_content" style={{height: item.isFold ? 0 : item.caseManagementList.length * 54, overflow: 'hidden', transition: 'all .2s'}}>{item.caseManagementList.map((task, index) => (<div key={index} className="case_item" style={{backgroundColor: index % 2 !== 0 ? '#F2F2F2' : '#FFFFFF'}}><div className="case_item_title"><h4>{task.taskContent}</h4><span>{task.taskStartDate} - {task.taskEndDate}</span></div><div className="status">{task.status === '1' && <div className="tag tag_progress"><img src={progressIcon} alt="" /> <span>順調</span></div>}{task.status === '2' && <div className="tag tag_stop"><img src={stopIcon} alt="" /> <span>遅滞</span></div>}{task.status === '3' && <div className="tag tag_over"><img src={overIcon} alt="" /> <span>完了</span></div>}</div><div className="consultantAndInstitutions">{consultantAndInstitutions.find(e => e.value === task.consultantAndInstitutions)? <><span>{consultantAndInstitutions.find(e => e.value === task.consultantAndInstitutions).label.split('/')[1]}</span> <span>{consultantAndInstitutions.find(e => e.value === task.consultantAndInstitutions).label.split('/')[0]}</span></>: null}</div><Button type="primary" style={{fontSize: 14, borderWidth: 2, width: 76, height: 32}} ghost shape="round">フォロー</Button></div>))}</div></div>))}</div></>{/* 更新 case */}: <><header className="editstatus_header"><h2>タスクの編集</h2><Button type="primary" style={{fontSize: 14, width: 130, height: 31, marginLeft: 20}} ghost onClick={handleGoBack}>進捗管理に戻る</Button></header><div className="case_list_container_edit">{caseManagementList.map((item, i) => ((item.caseManagementList && item.caseManagementList.length > 0) &&<div key={item.value} className="case_list_content"><div className="case_title" style={{backgroundColor: !item.isShowIssues ? '#EDEDED' : '#E5EBFF'}}><Link className="family_member_name">{`${item.label}さん`}</Link><div className="title_right"><img className="icon" src={discribetionIcon} alt="" /><span>参考情報を見る</span><img className="icon" style={{transform: `rotate(${!item.isShowIssues ? '0deg' : '180deg'})`, transition: 'all .2s'}} src={rightIcon} alt="" onClick={() => handleShowIssues(item, i)} /></div>{item.isShowIssues && <div className="issue_content_container"><div className="issue_content"><div className="title"><h3>本人の主訴・状況</h3><img src={shareBlueIcon} alt="" /></div><div style={{fontSize: 14, fontWeight: 400, whiteSpace: 'pre-line'}} dangerouslySetInnerHTML={{ __html: issues.chiefComplaintSituation ? issues.chiefComplaintSituation : "-" }}></div></div><div className="issue_content"><div className="title"><h3>課題と背景要因</h3><img src={shareBlueIcon} alt="" /></div><div style={{fontSize: 14, fontWeight: 400, whiteSpace: 'pre-line'}} dangerouslySetInnerHTML={{ __html: issues.issuesAndBackgroundFactors ? issues.issuesAndBackgroundFactors : "-" }}></div></div><div className="issue_content"><div className="title"><h3>課題のまとめと支援方針</h3><img src={shareBlueIcon} alt="" /></div><div style={{fontSize: 14, fontWeight: 400, whiteSpace: 'pre-line'}} dangerouslySetInnerHTML={{ __html: issues.consultationPolicy ? issues.consultationPolicy : "-" }}></div></div></div>}</div><div className="case_content">{item.caseManagementList.map((task, index) => (<div key={index} className="case_item" onClick={() => handleEditTask(i, index, task)}><img className="drag" src={dragIcon} alt="" /><div className="case_item_title"><h4>{task.taskContent}</h4><span>{task.taskStartDate} - {task.taskEndDate}</span></div><Popoverplacement="bottom"trigger="click"open={task.open}onOpenChange={(newOpen) => handleOpenChange(i, index, newOpen)}content={<>{status.map(statu => <div key={statu.value} style={{width: 60, height: 32, paddingTop: 6, fontSize: 14, fontWeight: 500, textAlign: 'center', cursor: 'pointer'}} onClick={(e) => {e.stopPropagation(); e.preventDefault(); handleChangeStatus(i, index, statu, task)}}>{statu.label}</div>)}</>}><div className="status" onClick={(e) => {e.stopPropagation(); e.preventDefault();}}><img src={downIcon} alt="" /><span>{status.find(s => s.value === task.status) ? status.find(s => s.value === task.status).label : ""}</span></div></Popover><div className="consultantAndInstitutions">{consultantAndInstitutions.find(e => e.value === task.consultantAndInstitutions)? <><span>{consultantAndInstitutions.find(e => e.value === task.consultantAndInstitutions).label.split('/')[1]}</span> <span>{consultantAndInstitutions.find(e => e.value === task.consultantAndInstitutions).label.split('/')[0]}</span></>: null}</div><img className="delete" src={deleteIcon} alt="" onClick={(e) => {e.stopPropagation(); e.preventDefault(); handleDeleteTask(task)}} /></div>))}</div></div>))}</div><div style={{padding: '16px 4px 0 0'}}><Button type="primary" loading={spinning} size="large" style={{height: 50}} block onClick={handleTaskCreate}>+タスクの新規作成</Button></div></>}</div>{/* 右边图表区域html */}<div className="table" ref={tableRef}><div className="thead"><div className="thead_date">{times.map((time, index) => (<div key={index} className="time"><div className="month">{time.year}年{time.month}月</div><div className="dates">{time.date.map(date => (<divkey={`${time.month}-${date.date}`}className={['日', '土'].includes(date.week) ? 'date date_saturday_sunday' : 'date'}style={{color: date.week === '日' ? "#D30000" : "#000000"}}><span>{date.date}</span><span>{date.week}</span></div>))}</div></div>))}</div></div><div className="tbody" style={{width: 40 * (times.reduce((count, item) => { count += item.date.length; return count }, 0))}}>{times.map((time, index) => (<div key={index} className="time">{time.date.map(date => (<divkey={`${time.month}-${date.date}`}className={['日', '土'].includes(date.week) ? 'date date_saturday_sunday' : 'date'}>{currentPageStatus === 'create' && caseManagementList.map((item, j) => ((item.caseManagementList && item.caseManagementList.length > 0) &&<div key={item.value} className="case_list_content"><div className="case_title">{item.activityList.map((activity, i) => {return `${time.year}/${time.month}/${date.date > 9 ? date.date : '0' + date.date}` === activity.activityStartDate? (<div key={i} className="case_item_active"><div className="activity"><div className="flagstaff"></div><pclassName="flag"style={{minWidth: activity.isShow ? activity.activityContent.length * 18 : 38, transition: 'all .2s'}}onMouseEnter={() => handleMouseEnter(activity)}onMouseLeave={() => handleMouseEnter(null)}onClick={() => handleActivityUpdate(j, i, activity)}>{activity.isShow && activity.activityContent}</p></div></div>): null})}</div><div className="case_content" style={{height: item.isFold ? 0 : item.caseManagementList.length * 54, display: item.isFold ? 'none' : 'block', transition: 'all .2s'}}>{item.caseManagementList.map((task, index) => {return `${time.year}/${time.month}/${date.date > 9 ? date.date : '0' + date.date}` === task.taskStartDate? (<div key={index} className="case_item_active">{task.status === '1' &&<div className="task task_progress" style={{width: 40 * (new Date(+new Date(task.taskEndDate) - (+new Date(task.taskStartDate))).getDate()) - 10}}><div title={task.taskContent}>{task.taskContent}</div><img src={moreIcon} alt="" /></div>}{(task.status === '2' || task.status === '3') &&<div className="task task_over" style={{width: 40 * (new Date(+new Date(task.taskEndDate) - (+new Date(task.taskStartDate))).getDate()) - 10}}><div title={task.taskContent}>{task.taskContent}</div><img src={moreIcon} alt="" /></div>}</div>): <div key={index} className="case_item"></div>})}</div></div>))}{`${currentYear}-${currentMonth > 9 ? currentMonth : '0' + currentMonth}-${currentDate}` === `${time.year}-${time.month}-${date.date}` &&<div style={{position: 'absolute', top: 0, left: 19, width: 2, height: '100%', backgroundColor: '#FC0000'}}></div>}</div>))}</div>))}</div></div></div><Modaltitle={isTaskCreate ? "タスク作成" : "タスク編集"}width="655px"mask={false}keyboard={false}maskClosable={false}closeIcon={<CloseOutlined style={{fontSize:25}} />}open={open}style={{top: 'calc(100vh - 846px)',left: 114,margin: 0}}onCancel={() => { handleCancel() }}footer={<div style={{padding: '0 20px 20px'}}><Button type="primary" loading={spinning} size="large" style={{height: 50}} block onClick={handleSubmitTask}>{isTaskCreate ? 'タスクを追加する' : 'タスクを編集する'}</Button></div>}><Spin spinning={spinning} indicator={<LoadingOutlined style={{ fontSize: 48, marginTop: 80 }} spin />}><Formname="編集する"labelCol={{span: 10,}}style={{padding: '20px 20px 0'}}size="large"layout="vertical"autoComplete="off"><Row><Col span={24}><Form.Itemlabel="タスク内容"><TextArearows={3}autoSize={{minRows: 2,maxRows: 4,}}value={taskForm.taskContent}placeholder="タスク内容を入力してください"onChange={(e) => { setTaskForm({...taskForm, taskContent: e.target.value}) }}/></Form.Item></Col><Col span={12} style={{paddingRight: 10}}><Form.Itemlabel="開始日"><DatePickerformat="YYYY/MM/DD"disabledDate={(current) => taskForm.taskStartDate === "" ? false : dayjs(taskForm.taskEndDate, "YYYY/MM/DD") < current}style={{width: '100%', height: 50}}suffixIcon={<img src={supportDate} alt="supportDate" />}value={taskForm.taskStartDate === "" ? "" : dayjs(taskForm.taskStartDate, "YYYY/MM/DD")}onChange={(date, dateString) => {setTaskForm({...taskForm, taskStartDate: dateString})}}/></Form.Item></Col><Col span={12} style={{paddingLeft: 10}}><Form.Itemlabel="終了日"><DatePickerformat="YYYY/MM/DD"disabledDate={(current) => taskForm.taskStartDate === "" ? false : dayjs(taskForm.taskStartDate, "YYYY/MM/DD") > current}style={{width: '100%', height: 50}}suffixIcon={<img src={supportDate} alt="supportDate" />}value={taskForm.taskEndDate === "" ? "" : dayjs(taskForm.taskEndDate, "YYYY/MM/DD")}onChange={(date, dateString) => {setTaskForm({...taskForm, taskEndDate: dateString})}}/></Form.Item></Col><Col span={24}><Form.Itemlabel="担当者/機関"><Selectstyle={{width: 400,height: 50}}suffixIcon={<img src={select} alt="select" />}value={taskForm.consultantAndInstitutions}onChange={(val) => {setTaskForm({...taskForm, consultantAndInstitutions: val})}}options={consultantAndInstitutions}/></Form.Item></Col><Col span={24}><Form.Itemlabel="対象者"><Selectstyle={{width: 400,height: 50}}suffixIcon={<img src={select} alt="select" />}disabled={!isTaskCreate}value={currentSelectFamilyMember}onChange={(val) => {setCurrentSelectFamilyMember(val)}}options={familyMembers}/></Form.Item></Col><Col span={24}><Form.Itemlabel="繰り返し"><Selectstyle={{width: 400,height: 50}}suffixIcon={<img src={select} alt="select" />}value={taskForm.repetition}onChange={(val) => {setTaskForm({...taskForm, repetition: val})}}options={repetition}/></Form.Item></Col><Col span={24}><Form.Itemlabel="アラート通知"><Selectstyle={{width: 400,height: 50}}suffixIcon={<img src={select} alt="select" />}value={taskForm.alertNotification}onChange={(val) => {setTaskForm({...taskForm, alertNotification: val})}}options={[]}/></Form.Item></Col></Row></Form></Spin></Modal><Modaltitle={isActivityCreate ? "イベント作成" : "イベント編集"}width="800px"mask={false}keyboard={false}maskClosable={false}closeIcon={<CloseOutlined style={{fontSize:25}} />}open={openActivity}style={{top: 'calc(100vh - 846px)',left: 'calc(100vw - 820px)',margin: 0}}onCancel={() => { handleCancel() }}footer={<div style={{padding: '0 20px 20px'}}><Button type="primary" loading={spinning} size="large" style={{height: 50}} block onClick={handleSubmitActivity}>{isActivityCreate ? 'イベントを追加する' : 'イベントを編集する'}</Button></div>}><Spin spinning={spinning} indicator={<LoadingOutlined style={{ fontSize: 48, marginTop: 80 }} spin />}><Formname="編集する"labelCol={{span: 10,}}style={{padding: '20px 20px 0'}}size="large"layout="vertical"autoComplete="off"><Row><Col span={24}><Form.Itemlabel="イベント内容"><TextArearows={3}autoSize={{minRows: 2,maxRows: 4,}}value={activityForm.activityContent}placeholder="タスク内容を入力してください"onChange={(e) => { setActivityForm({...activityForm, activityContent: e.target.value}) }}/></Form.Item></Col><Col span={12} style={{paddingRight: 10}}><Form.Itemlabel="開始日"><DatePickerformat="YYYY/MM/DD"disabledDate={(current) => activityForm.activityStartDate === "" ? false : dayjs(activityForm.activityEndDate, "YYYY/MM/DD") < current}style={{width: '100%', height: 50}}suffixIcon={<img src={supportDate} alt="supportDate" />}value={activityForm.activityStartDate === "" ? "" : dayjs(activityForm.activityStartDate, "YYYY/MM/DD")}onChange={(date, dateString) => {setActivityForm({...activityForm, activityStartDate: dateString})}}/></Form.Item></Col><Col span={12} style={{paddingLeft: 10}}><Form.Itemlabel="終了日"><DatePickerformat="YYYY/MM/DD"suffixIcon={<img src={supportDate} alt="supportDate" />}disabledDate={(current) => activityForm.activityStartDate === "" ? false : dayjs(activityForm.activityStartDate, "YYYY/MM/DD") > current}style={{width: '100%', height: 50}}value={activityForm.activityEndDate === "" ? "" : dayjs(activityForm.activityEndDate, "YYYY/MM/DD")}onChange={(date, dateString) => {setActivityForm({...activityForm, activityEndDate: dateString})}}/></Form.Item></Col><Col span={24}><Form.Itemlabel="担当者/機関"><Selectstyle={{width: 400,height: 50}}suffixIcon={<img src={select} alt="select" />}value={activityForm.consultantAndInstitutions}onChange={(val) => {setActivityForm({...activityForm, consultantAndInstitutions: val})}}options={consultantAndInstitutions}/></Form.Item></Col><Col span={24}><Form.Itemlabel="対象者"><Selectstyle={{width: 400,height: 50}}suffixIcon={<img src={select} alt="select" />}disabled={!isActivityCreate}value={currentSelectFamilyMember}onChange={(val) => {setCurrentSelectFamilyMember(val)}}options={familyMembers}/></Form.Item></Col><Col span={24}><Form.Itemlabel="繰り返し"><Selectstyle={{width: 400,height: 50}}suffixIcon={<img src={select} alt="select" />}value={activityForm.repetition}onChange={(val) => {setActivityForm({...activityForm, repetition: val})}}options={repetition}/></Form.Item></Col><Col span={24}><Form.Itemlabel="アラート通知"><Selectstyle={{width: 400,height: 50}}suffixIcon={<img src={select} alt="select" />}value={activityForm.alertNotification}onChange={(val) => {setActivityForm({...activityForm, alertNotification: val})}}options={[]}/></Form.Item></Col></Row></Form></Spin></Modal></div>)
}export default CaseManagement
样式:
.root {:global{display: flex;flex-direction: column;height: calc(100vh - 189px);overflow: auto;background: #fff;padding: 0 0 0 10px;.header {display: flex;align-items: center;width: 100%;header {display: flex;align-items: center;width: 655px;margin-top: 10px;margin-bottom: 20px;h2 {font-size: 24px;}.tag {height: 31px;padding: 0 10px;border: 2px solid #00bb4b;border-radius: 16px;background-color: #dcecd2;color: #00bb4b;font-size: 16px;margin-left: 30px;}}}.container {flex: 1;display: flex;width: 100%;.case_list {display: flex;flex-direction: column;width: 655px;border-right: 1px solid #ECECEC;.editstatus_header {display: flex;align-items: center;width: 100%;margin-top: 10px;margin-bottom: 20px;h2 {font-size: 24px;}}&_title {display: flex;align-items: center;width: 100%;height: 81px;padding: 0 20px;background-color: #ededed;border-bottom: 1px solid #D9D9D9;.icon {width: 32px;height: 32px;margin-right: 10px;&:hover {cursor: pointer;}}h3 {font-size: 16px;}}&_container {width: 100%;.case_list_content {width: 100%;min-height: 40px;overflow: hidden;.case_title {display: flex;align-items: center;justify-content: space-between;width: 100%;height: 48px;padding: 0 10px;background-color: #E5EBFF;.family_member_name {font-size: 16px;text-decoration: underline;}.icon {width: 16px;height: 16px;&:hover {cursor: pointer;background-color: rgba(0, 0, 0, .02);}}}.case_content {.case_item {display: flex;align-items: center;width: 100%;height: 54px;padding: 0 12px;.case_item_title {flex: 1;display: flex;flex-direction: column;height: 100%;h4 {font-size: 16px;font-weight: 700;margin-top: 6px;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 1;overflow: hidden;text-overflow: ellipsis;}span {font-size: 12px;font-weight: 700;color: #747474;}}.status {display: flex;width: 70px;text-align: center;img {width: 8px;}.tag {display: flex;align-items: center;height: 26px;line-height: 26px;padding: 0 8px;border-radius: 16px;font-size: 12px;}.tag_progress {border: 2px solid #00bb4b;background-color: #dcecd2;color: #00bb4b;}.tag_stop {border: 2px solid #D30000;background-color: #FF11041A;color: #D30000;}.tag_over {border: 2px solid #81CCF2;background-color: #C9D4FD63;color: #81CCF2;}}.consultantAndInstitutions {flex: 1.2;color: #747474;font-size: 12px;font-weight: 700;}}}}}&_container_edit {flex: 1;width: 100%;padding-right: 4px;.case_list_content {width: 100%;min-height: 40px;.case_title {display: flex;align-items: center;justify-content: space-between;width: 100%;height: 48px;padding: 0 0 0 10px;margin-top: 12px;background-color: #EDEDED;position: relative;.family_member_name {font-size: 16px;text-decoration: underline;}.issue_content_container {position: absolute;top: 0;left: 650px;width: calc(100vw - 812px);background-color: #E5EBFF;padding: 0 20px 22px;z-index: 999;.issue_content {width: 100%;border-radius: 20px;border: 1px solid #D8D8D8;background-color: #FFFFFF;padding: 16px 16px 24px 24px;margin-top: 22px;.title {display: flex;justify-content: space-between;align-items: center;h3 {font-size: 16px;font-weight: 700;}img {width: 43px;}}}}.title_right {display: flex;align-items: center;span {font-size: 12px;margin-top: 2px;}.icon {width: 32px;height: 32px;&:hover {cursor: pointer;background-color: rgba(0, 0, 0, .02);}}}}.case_content {.case_item {display: flex;align-items: center;width: 100%;height: 54px;padding: 0 4px;border: 1px solid #E9E9E9;margin-top: 4px;transition: .2s all;&:hover {cursor: pointer;background-color: #f3f3f3;}.drag {width: 32px;height: 32px;margin-right: 8px;&:hover {cursor: pointer;}}.case_item_title {flex: 1;display: flex;flex-direction: column;height: 100%;h4 {font-size: 16px;font-weight: 700;margin-top: 6px;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 1;overflow: hidden;text-overflow: ellipsis;}span {font-size: 12px;font-weight: 700;color: #747474;}}.status {display: flex;align-items: center;width: 86px;height: 36px;border: 2px solid #909090;border-radius: 18px;overflow: hidden;margin: 0 10px;&:hover {cursor: pointer;}.ant-select-selector {width: 60px;border: 0;padding: 0;}img {width: 20px;margin: 0 10px;}span {margin-top: 2px;font-size: 12px;font-weight: 500;}}.consultantAndInstitutions {flex: 1.3;color: #747474;font-size: 12px;font-weight: 700;}.delete {&:hover {cursor: pointer;}}}}}}}.table {flex: 1;display: flex;flex-direction: column;overflow-x: auto;.thead {display: flex;width: 100%;height: 81px;&_date {display: flex;.time {width: 100%;height: 100%;}.month {width: 100%;height: 30px;line-height: 30px;padding: 0 10px;border: 1px solid #ECECEC;border-left: 0;}.dates {display: flex;align-items: center;.date {display: flex;flex-direction: column;align-items: center;position: relative;min-width: 40px;height: 51px;font-size: 16px;font-weight: 700;border: 1px solid #ECECEC;border-top: 0;border-left: 0;padding-top: 4px;span:nth-child(1) {font-size: 16px;font-weight: 700;}span:nth-child(2) {font-size: 11px;font-weight: 500;}}.date_saturday_sunday {background-color: #F5F5F5;}}}}.tbody {flex: 1;display: flex;position: relative;overflow-x: auto;.time {display: flex;.date {position: relative;min-width: 40px;border-right: 1px solid #ECECEC;.case_list_content {min-height: 40px;.case_title {height: 48px;.case_item_active {height: 100%;position: relative;.activity {display: flex;position: absolute;top: 0;left: 0;z-index: 999;.flag {min-width: 38px;height: 28px;line-height: 28px;color: #fff;font-size: 16px;font-weight: 700;background-color: #486EF8;overflow: hidden;&:hover {cursor: pointer;}}.flagstaff {min-width: 4px;height: 48px;background-color: #486EF8;}}}}.case_content {.case_item_active {height: 54px;position: relative;.task {display: flex;align-items: center;justify-content: space-between;position: absolute;top: 8px;left: 4px;height: 38px;border-radius: 3px;padding: 0 10px;overflow: hidden;z-index: 99;div {flex: 1;font-size: 16px;font-weight: 700;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 1;overflow: hidden;text-overflow: ellipsis;}img {width: 37px;&:hover {cursor: pointer;}}}.task_progress {color: #000000;border: 1px solid #486EF8;background-color: #486EF866;}.task_over {color: #747474;border: 1px solid #414141;background-color: #00000040;div {text-decoration: line-through;}}}.case_item {height: 54px;}}}}.date_saturday_sunday {background-color: #F5F5F5;}}}}}.menu_item {width: 214px;height: 41px;line-height: 41px;font-size: 16px;}}
}