index.tsx 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001
  1. "use client";
  2. import React, { useMemo, useState, useEffect } from "react";
  3. import { AgGridReact } from "ag-grid-react";
  4. import {
  5. ClientSideRowModelModule,
  6. ColDef,
  7. ColGroupDef,
  8. ModuleRegistry,
  9. ValidationModule,
  10. ICellRendererParams,
  11. CellClassParams,
  12. CellClickedEvent,
  13. SelectEditorModule,
  14. CellStyleModule
  15. } from "ag-grid-community";
  16. import "ag-grid-community/styles/ag-theme-alpine.css";
  17. import DateChangeDialog from "./DateChangeDialog";
  18. import Chat from "./ChatPartner";
  19. // 注册必要的模块
  20. ModuleRegistry.registerModules([
  21. ClientSideRowModelModule,
  22. SelectEditorModule,
  23. CellStyleModule,
  24. ...(process.env.NODE_ENV!== "production"? [ValidationModule] : [])
  25. ]);
  26. // 事由选项
  27. const reasonOptions = [
  28. "臨時変更",
  29. "計画変更",
  30. "休日調整",
  31. "その他"
  32. ];
  33. const affiliationName = "羽田ベース";
  34. // TODO type
  35. const historyData = [
  36. {
  37. type: '履歴',
  38. date: '2025/01/05 10:00',
  39. action: '指示書受領'
  40. }
  41. ];
  42. const weekTexts = ["火", "水", "木", "金", "土", "日", "月"];
  43. const GridExample = () => {
  44. const [orderInfo, setOrderInfo] = useState({
  45. deliveryPartner: {
  46. monthYear: "2025年7月",
  47. affiliationName: "羽田ベース"
  48. },
  49. monthlyInstruction: {
  50. versionOptions: ["ver-1", "ver-2", "ver-3", "ver-4", "ver-5"],
  51. selectedVersion: "ver-1"
  52. }
  53. });
  54. const [documentInfo, setDocumentInfo] = useState({
  55. corpCode: "3888888888",
  56. reportMonth: "2025年6月度",
  57. company: "ヤマト運輸株式会社",
  58. branch: "羽田CGB",
  59. corpPhone: "03-6756-7164",
  60. corpName: "(有)AAAA 御中",
  61. });
  62. const [paymentInfo, setPaymentInfo] = useState({
  63. paymentAmountText: "支払代金は現行の値下駄契約書明細の定めのとおり",
  64. paymentMethod: "全額現金口座振込",
  65. paymentDeadline: "毎月未納め、翌々月10日支払い(出発日基準)",
  66. consumptionTaxText: "法定税率による消費税額・地方消費税額は加算して決済します",
  67. transferFeeText: "請求金額より差し引いて振込いたします",
  68. });
  69. const containerStyle = useMemo(() => ({ width: "100%" }), []);
  70. const gridStyle = useMemo(() => ({ width: "100%" }), []);
  71. const [rowData, setRowData] = useState(initializeRowData());
  72. const [showDialog, setShowDialog] = useState(false);
  73. const [modifiedCells, setModifiedCells] = useState<Set<string>>(new Set());
  74. const [selectedCell, setSelectedCell] = useState<{rowIndex: number | null, colId: string, currentValue: string} | null>(null);
  75. const [cellReasons, setCellReasons] = useState<Record<string, string>>({});
  76. const [showChat, setShowChat] = useState(false); // 控制聊天侧边栏显示的状态
  77. // 初始化样式
  78. useEffect(() => {
  79. const style = document.createElement('style');
  80. style.textContent = `
  81. .ag-theme-alpine .header-center .ag-header-cell-label {
  82. justify-content: center !important;
  83. text-align: center !important;
  84. }
  85. .ag-theme-alpine .header-center.ag-header-group-cell {
  86. text-align: center !important;
  87. }
  88. .ag-theme-alpine .header-center.ag-header-group-cell .ag-header-group-cell-label {
  89. justify-content: center !important;
  90. display: flex !important;
  91. width: 100% !important;
  92. }
  93. // .order-info-container {
  94. // margin-bottom: 20px;
  95. // padding: 15px;
  96. // border: 1px solid #dcdcdc;
  97. // border-radius: 4px;
  98. // }
  99. .order-info-section {
  100. margin-bottom: 35px;
  101. }
  102. .order-info-section h3 {
  103. margin: 0 0 5px 0;
  104. font-size: 14px;
  105. font-weight: bold;
  106. }
  107. .order-info-row {
  108. margin: 10px 0 10px 20px;
  109. font-size: 14px;
  110. }
  111. .status-section {
  112. width: 100%;
  113. border-collapse: collapse;
  114. margin-top: 8px;
  115. margin-left: 10px;
  116. }
  117. .status-section th,
  118. .status-section td {
  119. padding: 5px 10px;
  120. text-align: left;
  121. font-size: 14px;
  122. }
  123. .status-section th {
  124. font-weight: normal;
  125. }
  126. .confirm-request-btn {
  127. margin-left:80%;
  128. padding: 7px 50px;
  129. background-color: #000;
  130. color: #fff;
  131. border: none;
  132. cursor: pointer;
  133. font-size: 14px;
  134. margin-top: 50px;
  135. white-space: nowrap;
  136. }
  137. .partner-select-container {
  138. display: flex;
  139. align-items: center;
  140. margin-left: 20px;
  141. }
  142. .partner-select-container label {
  143. margin-right: 10px;
  144. white-space: nowrap;
  145. font-size: 14px;
  146. font-weight: bold;
  147. }
  148. .partner-select-container select {
  149. padding: 5px 35px;
  150. font-size: 14px;
  151. margin-left: 20px;
  152. padding-left: 10px;
  153. }
  154. .message-btn {
  155. float: right;
  156. padding: 7px 50px;
  157. background-color: #000;
  158. color: #fff;
  159. border: none;
  160. cursor: pointer;
  161. position: relative;
  162. top: -17px;
  163. }
  164. .save-btn {
  165. margin-left: auto;
  166. padding: 7px 50px;
  167. background-color: #000;
  168. color: #fff;
  169. border: none;
  170. cursor: pointer;
  171. margin-top: 50px;
  172. white-space: nowrap;
  173. }
  174. .action-buttons-container {
  175. display: flex;
  176. justify-content: flex-end;
  177. gap: 10px;
  178. }
  179. .add-row-btn {
  180. background: transparent;
  181. border: none;
  182. color: #0070c0;
  183. cursor: pointer;
  184. margin-left: 5px;
  185. }
  186. .action-btn {
  187. background-color: #000;
  188. color: #fff;
  189. border: none;
  190. padding: 7px 20px;
  191. cursor: pointer;
  192. font-size: 14px;
  193. }
  194. .history-table-custom {
  195. width: 100%;
  196. border-collapse: collapse;
  197. }
  198. .type-td {
  199. padding: 5px 20px;
  200. }
  201. .date-td {
  202. padding: 5px 20px;
  203. }
  204. .action-td {
  205. padding: 5px 20px;
  206. }
  207. .history-title-custom {
  208. font-size: 14px;
  209. font-weight: bold;
  210. margin-bottom: 8px;
  211. display: block;
  212. }
  213. .ag-header-cell-resize {
  214. &:after {
  215. display: none;
  216. }
  217. }
  218. .ag-theme-alpine .ag-cell {
  219. border-right: 1px solid #dcdcdc;
  220. text-align: center;
  221. }
  222. .ag-theme-alpine .ag-header-cell {
  223. border-right: 1px solid #dcdcdc;
  224. }
  225. .line-group-header {
  226. border-right: 1px solid #dcdcdc;
  227. }
  228. .date-group-header {
  229. border-right: 1px solid #dcdcdc !important;
  230. }
  231. .tokyoBranchCol{
  232. display: none;
  233. }
  234. .monthly-instruction-text {
  235. margin-left: 140px;
  236. white-space: nowrap;
  237. }
  238. .chat-sidebar {
  239. position: fixed;
  240. top: 0;
  241. right: 0;
  242. width: 1060px;
  243. height: 100vh;
  244. background-color: #fff;
  245. box-shadow: -2px 0 10px rgba(0, 0, 0, 0.1);
  246. z-index: 1000;
  247. display: flex;
  248. flex-direction: column;
  249. padding: 20px;
  250. box-sizing: border-box;
  251. overflow: hidden;
  252. }
  253. .chat-messages-container {
  254. flex: 1;
  255. overflow-y: auto;
  256. margin-bottom: 16px;
  257. }
  258. .overlay {
  259. position: fixed;
  260. top: 0;
  261. left: 0;
  262. right: 0;
  263. bottom: 0;
  264. background-color: rgba(0, 0, 0, 0.5);
  265. z-index: 999;
  266. }
  267. .desktop-only {
  268. display: table-cell;
  269. }
  270. .mobile-only {
  271. display: none;
  272. }
  273. .desktop-button-only {
  274. display: table-cell;
  275. }
  276. .mobile-button-only {
  277. display: none;
  278. }
  279. @media (max-width: 1280px) {
  280. .title-main {
  281. margin-left: -10px;
  282. letter-spacing: 1px !important;
  283. }
  284. .message-text {
  285. color: #0070c0;
  286. text-decoration: underline;
  287. cursor: pointer;
  288. float: right;
  289. margin-top: 20px;
  290. }
  291. .desktop-only {
  292. display: none !important;
  293. visibility: hidden !important;
  294. height: 0 !important;
  295. padding: 0 !important;
  296. margin: 0 !important;
  297. }
  298. .mobile-only {
  299. display: table-cell;
  300. }
  301. .desktop-button-only {
  302. display: none;
  303. }
  304. .mobile-button-only {
  305. display: table-cell;
  306. }
  307. .mobile-button-only span {
  308. color: #0070c0;
  309. text-decoration: underline;
  310. cursor: pointer;
  311. white-space: nowrap;
  312. }
  313. .message-btn {
  314. padding: 4px 20px;
  315. top: 20px;
  316. margin-right: -25px;
  317. }
  318. .partner-select-container select {
  319. margin-left: 5px;
  320. padding: 3px 15px;
  321. }
  322. .order-info-section {
  323. margin-bottom: 80px;
  324. }
  325. .partner-select-container {
  326. display: flex;
  327. align-items: center;
  328. gap: 10px;
  329. margin-left: 20px;
  330. margin-top: 20px;
  331. flex-wrap: nowrap;
  332. width: calc(100% - 40px);
  333. }
  334. .action-buttons-container {
  335. display: block;
  336. margin-top: 20px;
  337. }
  338. .confirm-request-btn,
  339. .save-btn {
  340. padding: 5px 30px;
  341. margin-top: 20px;
  342. margin-left: -10px;
  343. display: block;
  344. width: 140px;
  345. }
  346. .monthly-instruction-text {
  347. margin-left: 10px;
  348. }
  349. .company-info-right {
  350. margin-top: 120px !important;
  351. margin-left: -70px !important;
  352. }
  353. .payment-table {
  354. width: 100% !important;
  355. }
  356. .payment-table tbody tr {
  357. display: block;
  358. margin-bottom: 10px;
  359. }
  360. .payment-table tbody td {
  361. display: block;
  362. width: 100% !important;
  363. box-sizing: border-box;
  364. padding: 5px 0 !important;
  365. }
  366. .mobile-text{
  367. font-weight: bold;
  368. margin-left:-15px;
  369. }
  370. .btn-group-mobile {
  371. display: block !important;
  372. text-align: center;
  373. padding-right: 0 !important;
  374. margin-top: 30px;
  375. }
  376. .btn-group-mobile .action-btn {
  377. display: block !important;
  378. margin: 0 auto 25px auto !important;
  379. width: 200px;
  380. padding: 8px 0 !important;
  381. }
  382. .request-info-section {
  383. border-bottom: 1px solid #000;
  384. padding-bottom: 10px;
  385. }
  386. }
  387. @media (max-width: 345px) {
  388. .partner-select-container select {
  389. margin-left: -15px ;
  390. }
  391. .order-info-month{
  392. margin-left:123px !important;
  393. }
  394. .order-info-affiliation{
  395. margin-left:80px !important;
  396. }
  397. }
  398. `;
  399. document.head.appendChild(style);
  400. return () => {
  401. document.head.removeChild(style);
  402. };
  403. }, []);
  404. // 生成1-31的日期列定义
  405. const generateDateColumns = () => {
  406. const columns: ColGroupDef[] = [];
  407. for (let i = 1; i <= 31; i++) {
  408. const weekIndex = (i - 1) % weekTexts.length;
  409. const colId = `date_${i}`;
  410. columns.push({
  411. headerName: i.toString(),
  412. headerClass: "header-center date-group-header",
  413. children: [
  414. {
  415. field: colId,
  416. headerName: weekTexts[weekIndex],
  417. headerClass: "header-center",
  418. flex: 1,
  419. minWidth: 55,
  420. cellRenderer: (params: ICellRendererParams) => {
  421. const cellValue = params.value || "";
  422. const rowIndex = params.node.rowIndex;
  423. const cellKey = `${rowIndex}-${colId}`;
  424. const reason = cellReasons[cellKey] || "";
  425. return (
  426. <div
  427. title={reason? `变更理由:${reason}` : ""}
  428. style={{
  429. minHeight: '100%',
  430. width: '100%',
  431. display: 'flex',
  432. alignItems: 'center',
  433. justifyContent: 'center'
  434. }}
  435. >
  436. {cellValue}
  437. </div>
  438. );
  439. },
  440. onCellClicked: (params: CellClickedEvent) => {
  441. setSelectedCell({
  442. rowIndex: params.node.rowIndex,
  443. colId: colId,
  444. currentValue: params.value as string
  445. });
  446. setShowDialog(true);
  447. },
  448. cellStyle: (params: CellClassParams) => {
  449. const rowIndex = params.node.rowIndex;
  450. const cellKey = `${rowIndex}-${colId}`;
  451. const isModified = modifiedCells.has(cellKey);
  452. if (isModified) {
  453. return { backgroundColor: '#3a8aca' };
  454. }
  455. return null;
  456. }
  457. }
  458. ]
  459. });
  460. }
  461. return columns;
  462. };
  463. // 初始化行数据
  464. function initializeRowData() {
  465. return [
  466. {
  467. "AM": "",
  468. "発": "032990",
  469. "着": "025990",
  470. "系統": "02",
  471. "線便名": "大賀10t①",
  472. "入庫場所": "羽田CGB",
  473. "入庫時間": "21:00",
  474. "使用車両(トン)": "13",
  475. "checkboxCol": "",
  476. ...Array.from({ length: 31 }, (_, i) => ({
  477. [`date_${i + 1}`]: (i + 1) % 3 === 0? "〇" : ""
  478. })).reduce((acc, curr) => ({...acc,...curr }), {})
  479. },
  480. {
  481. "AM": "",
  482. "発": "032990",
  483. "着": "027990",
  484. "系統": "23",
  485. "線便名": "大賀10t②",
  486. "入庫場所": "桜丘",
  487. "入庫時間": "19:00",
  488. "使用車両(トン)": "13",
  489. "checkboxCol": "",
  490. ...Array.from({ length: 31 }, (_, i) => ({
  491. [`date_${i + 1}`]: (i + 1) % 4 === 0? "〇" : ""
  492. })).reduce((acc, curr) => ({...acc,...curr }), {})
  493. },
  494. {
  495. "AM": "*",
  496. "発": "032990",
  497. "着": "027990",
  498. "系統": "G8",
  499. "線便名": "大賀10t③",
  500. "入庫場所": "目黒",
  501. "入庫時間": "18:00",
  502. "使用車両(トン)": "13",
  503. "checkboxCol": "",
  504. ...Array.from({ length: 31 }, (_, i) => ({
  505. [`date_${i + 1}`]: (i + 1) % 5 === 0? "〇" : ""
  506. })).reduce((acc, curr) => ({...acc,...curr }), {})
  507. },
  508. {
  509. "AM": "",
  510. "発": "032990",
  511. "着": "027990",
  512. "系統": "G9",
  513. "線便名": "西大阪交表",
  514. "入庫場所": "羽田CGB",
  515. "入庫時間": "21:00",
  516. "使用車両(トン)": "13",
  517. "checkboxCol": "",
  518. ...Array.from({ length: 31 }, (_, i) => ({
  519. [`date_${i + 1}`]: (i + 1) % 2 === 0? "〇" : ""
  520. })).reduce((acc, curr) => ({...acc,...curr }), {})
  521. },
  522. {
  523. "AM": "",
  524. "発": "061990",
  525. "着": "032990",
  526. "系統": "06",
  527. "線便名": "羽田CG交裏",
  528. "入庫場所": "西大阪B",
  529. "入庫時間": "19:00",
  530. "使用車両(トン)": "10",
  531. "checkboxCol": "",
  532. ...Array.from({ length: 31 }, (_, i) => ({
  533. [`date_${i + 1}`]: (i + 1) % 6 === 0? "〇" : ""
  534. })).reduce((acc, curr) => ({...acc,...curr }), {})
  535. },
  536. {
  537. "AM": "",
  538. "発": "032990",
  539. "着": "032990",
  540. "系統": "M8",
  541. "線便名": "大賀10t⑥",
  542. "入庫場所": "羽田CGB",
  543. "入庫時間": "21:00",
  544. "使用車両(トン)": "13",
  545. "checkboxCol": "",
  546. ...Array.from({ length: 31 }, (_, i) => ({
  547. [`date_${i + 1}`]: (i + 1) % 3 === 0? "〇" : ""
  548. })).reduce((acc, curr) => ({...acc,...curr }), {})
  549. },
  550. {
  551. "AM": "",
  552. "発": "032990",
  553. "着": "053990",
  554. "系統": "06",
  555. "線便名": "中部日祝",
  556. "入庫場所": "成城",
  557. "入庫時間": "19:00",
  558. "使用車両(トン)": "13",
  559. "checkboxCol": "",
  560. ...Array.from({ length: 31 }, (_, i) => ({
  561. [`date_${i + 1}`]: (i + 1) % 4 === 0? "〇" : ""
  562. })).reduce((acc, curr) => ({...acc,...curr }), {})
  563. },
  564. {
  565. "AM": "*",
  566. "発": "032990",
  567. "着": "027990",
  568. "系統": "G8",
  569. "線便名": "大賀10t③",
  570. "入庫場所": "目黒",
  571. "入庫時間": "18:00",
  572. "使用車両(トン)": "13",
  573. "checkboxCol": "",
  574. ...Array.from({ length: 31 }, (_, i) => ({
  575. [`date_${i + 1}`]: (i + 1) % 5 === 0? "〇" : ""
  576. })).reduce((acc, curr) => ({...acc,...curr }), {})
  577. },
  578. {
  579. "AM": "",
  580. "発": "032990",
  581. "着": "132990",
  582. "系統": "02",
  583. "線便名": "大賀7t",
  584. "入庫場所": "八幡山",
  585. "入庫時間": "19:00",
  586. "使用車両(トン)": "2",
  587. "checkboxCol": "",
  588. ...Array.from({ length: 31 }, (_, i) => ({
  589. [`date_${i + 1}`]: (i + 1) % 2 === 0? "〇" : ""
  590. })).reduce((acc, curr) => ({...acc,...curr }), {})
  591. },
  592. {
  593. "AM": "",
  594. "発": "061990",
  595. "着": "032990",
  596. "系統": "06",
  597. "線便名": "羽田CG交裏",
  598. "入庫場所": "西大阪B",
  599. "入庫時間": "19:00",
  600. "使用車両(トン)": "10",
  601. "checkboxCol": "",
  602. ...Array.from({ length: 31 }, (_, i) => ({
  603. [`date_${i + 1}`]: (i + 1) % 6 === 0? "〇" : ""
  604. })).reduce((acc, curr) => ({...acc,...curr }), {})
  605. },
  606. ];
  607. }
  608. // 构建列定义
  609. const columnDefs: (ColDef | ColGroupDef)[] = [
  610. {
  611. field: "checkboxCol",
  612. headerName: "",
  613. width: 50,
  614. cellRenderer: (params: ICellRendererParams) => {
  615. return <input type="checkbox" />;
  616. },
  617. headerClass: "header-center checkbox",
  618. },
  619. {
  620. field: "AM",
  621. headerClass: "header-center",
  622. width: 60,
  623. },
  624. {
  625. headerName: "線便",
  626. headerClass: "header-center line-group-header",
  627. children: [
  628. {
  629. field: "発",
  630. headerClass: "header-center",
  631. width: 85,
  632. },
  633. {
  634. field: "着",
  635. headerClass: "header-center",
  636. width: 85,
  637. },
  638. {
  639. field: "系統",
  640. headerClass: "header-center",
  641. width: 65,
  642. },
  643. {
  644. field: "線便名",
  645. headerClass: "header-center",
  646. width: 120,
  647. },
  648. ],
  649. },
  650. { field: "入庫場所", headerClass: "header-center", width: 110 },
  651. { field: "入庫時間", headerClass: "header-center", width: 90 },
  652. {
  653. field: "使用車両(トン)",
  654. headerClass: "header-center",
  655. width: 125,
  656. cellRenderer: (params: ICellRendererParams) => {
  657. return (
  658. <div style={{ textAlign: 'right'}}>
  659. {params.value || ''}
  660. </div>
  661. );
  662. }
  663. },
  664. ...generateDateColumns()
  665. ];
  666. // 处理对话框确认
  667. const handleDialogConfirm = (reason: string, changeValue: string) => {
  668. if (!selectedCell || selectedCell.rowIndex === null) return;
  669. const newRowData = [...rowData];
  670. const currentValue = selectedCell.currentValue;
  671. const newValue = currentValue === "〇"? "" : "〇";
  672. const targetRowIndex = selectedCell.rowIndex;
  673. const targetColId = selectedCell.colId;
  674. newRowData[targetRowIndex] = {
  675. ...newRowData[targetRowIndex],
  676. [targetColId]: newValue
  677. };
  678. setRowData(newRowData);
  679. const cellKey = `${targetRowIndex}-${targetColId}`;
  680. setModifiedCells(prev => {
  681. const newSet = new Set(prev);
  682. newSet.add(cellKey);
  683. return newSet;
  684. });
  685. setCellReasons(prev => ({
  686. ...prev,
  687. [cellKey]: reason
  688. }));
  689. setShowDialog(false);
  690. };
  691. // 处理对话框取消
  692. const handleDialogCancel = () => {
  693. setShowDialog(false);
  694. };
  695. // 处理消息按钮点击 - 切换聊天侧边栏显示状态
  696. const handleMessageClick = () => {
  697. setShowChat(true);
  698. };
  699. // 处理编辑按钮点击
  700. const handleEditClick = () => {
  701. alert('保存按钮被点击');
  702. };
  703. // 关闭聊天侧边栏
  704. const closeChatSidebar = () => {
  705. setShowChat(false);
  706. };
  707. return (
  708. <div style={containerStyle}>
  709. <div className="order-info-container">
  710. <div className="order-info-section">
  711. <div className="title-main" style={{ fontSize: '14px',letterSpacing:'5px' }}>受注詳細 指示書 ({affiliationName})</div>
  712. <button className="message-btn desktop-only" onClick={handleMessageClick}>
  713. メッセージ
  714. </button>
  715. <span
  716. className="message-text mobile-only"
  717. onClick={handleMessageClick}
  718. >
  719. メッセージ
  720. </span>
  721. </div>
  722. <div className="order-info-section">
  723. <h3>依頼情報 </h3>
  724. <div className="request-info-section"></div>
  725. <div className="order-info-row">
  726. 年月<span className="order-info-month" style={{ marginLeft: '130px' }}>{orderInfo.deliveryPartner.monthYear}</span>
  727. </div>
  728. <div className="order-info-row">
  729. 依頼ベース<span className="order-info-affiliation" style={{ marginLeft: '87px' }}>{orderInfo.deliveryPartner.affiliationName}</span>
  730. </div>
  731. </div>
  732. <div className="order-info-section">
  733. <h3>月間運行指示書</h3>
  734. <div className="request-info-section"></div>
  735. <div className="partner-select-container">
  736. <label>version選択</label>
  737. <select
  738. value={orderInfo.monthlyInstruction.selectedVersion}
  739. onChange={(e) => {
  740. setOrderInfo(prev => ({
  741. ...prev,
  742. monthlyInstruction: {
  743. ...prev.monthlyInstruction,
  744. selectedVersion: e.target.value
  745. }
  746. }));
  747. }}
  748. >
  749. {orderInfo.monthlyInstruction.versionOptions.map(version => (
  750. <option key={version} value={version}>{version}</option>
  751. ))}
  752. </select>
  753. <div className="mobile-button-only">
  754. <span>ダウンロード</span>
  755. </div>
  756. </div>
  757. <div className="action-buttons-container">
  758. <button className="confirm-request-btn">確認依頼</button>
  759. <button className="save-btn" onClick={handleEditClick}>保存</button>
  760. </div>
  761. <div style={{
  762. marginLeft: '20px',
  763. marginTop: '40px',
  764. display: 'flex',
  765. alignItems: 'flex-start',
  766. width: '100%',
  767. boxSizing: 'border-box'
  768. }}>
  769. <div style={{ display: 'flex', flexDirection: 'column' }}>
  770. <span style={{ marginRight: '10px' }}>{documentInfo.corpCode}</span>
  771. <span style={{ marginTop: '15px',whiteSpace: 'nowrap' }}>{documentInfo.corpName}</span>
  772. </div>
  773. <span className="monthly-instruction-text">月間運行指示書</span>
  774. <div style={{ marginLeft: 'auto', fontSize: '14px' }}>
  775. <div className="company-info-right" style={{ marginLeft: 'auto', fontSize: '14px' }}>
  776. <p>【{documentInfo.reportMonth}】</p>
  777. <p>署名・捺印の上、送達願います。</p>
  778. <p>(御社名+社員・納品担当者印)</p>
  779. <p>{documentInfo.company} {documentInfo.branch}</p>
  780. <p>TEL {documentInfo.corpPhone}</p>
  781. <p>FAX 03-6756-7376/7378</p>
  782. </div>
  783. </div>
  784. </div>
  785. </div>
  786. </div>
  787. <div style={gridStyle} className="ag-theme-alpine">
  788. <AgGridReact
  789. rowData={rowData}
  790. columnDefs={columnDefs}
  791. domLayout="autoHeight"
  792. />
  793. </div>
  794. <div style={{ marginTop: '40px', marginLeft: '20px', fontSize: '14px' }}>
  795. <table className="payment-table" style={{ width: '100%', borderCollapse: 'collapse' }}>
  796. <tbody>
  797. <tr>
  798. <td className="mobile-text" style={{ width: '150px', padding: '5px 0' }}>支払代金</td>
  799. <td style={{ padding: '5px 0' }}>{paymentInfo.paymentAmountText}</td>
  800. <td className="desktop-only" style={{ width: '200px', padding: '5px 0'}}>
  801. <span style={{
  802. display: 'inline-block',
  803. marginLeft:'-800px',
  804. }}>
  805. 受付の署名又は捺印の上返信下さい
  806. </span>
  807. </td>
  808. </tr>
  809. <tr>
  810. <td className="mobile-text">支払方法</td>
  811. <td>{paymentInfo.paymentMethod}</td>
  812. <td className="desktop-only" rowSpan={3} style={{
  813. verticalAlign: 'top',
  814. paddingTop: '40px',
  815. paddingLeft: '0',
  816. position:'relative'
  817. }}>
  818. <div style={{
  819. position:'relative',
  820. marginLeft: '-590px',
  821. display: 'inline-block'
  822. }}>
  823. <div style={{
  824. border: '1px solid #000',
  825. width: '60px',
  826. height: '60px',
  827. display: 'flex',
  828. justifyContent: 'center',
  829. alignItems: 'center',
  830. }}
  831. >
  832. 受付印
  833. </div>
  834. <div
  835. style={{
  836. position: 'absolute',
  837. bottom: 0,
  838. left: '-200px',
  839. width: '200px',
  840. height: '1px',
  841. backgroundColor: '#000',
  842. }}
  843. />
  844. </div>
  845. </td>
  846. </tr>
  847. <tr>
  848. <td className="mobile-text">支払期限</td>
  849. <td>{paymentInfo.paymentDeadline}</td>
  850. </tr>
  851. <tr>
  852. <td className="mobile-text">消費税</td>
  853. <td>{paymentInfo.consumptionTaxText}</td>
  854. </tr>
  855. <tr>
  856. <td className="mobile-text">振込手数料</td>
  857. <td>{paymentInfo.transferFeeText}</td>
  858. </tr>
  859. <tr>
  860. <td className="mobile-only" style={{ width: '200px', padding: '5px 0'}}>
  861. <span style={{
  862. display: 'inline-block',
  863. }}>
  864. 受付の署名又は捺印の上返信下さい
  865. </span>
  866. </td>
  867. <td className="mobile-only" rowSpan={3} style={{
  868. verticalAlign: 'top',
  869. paddingTop: '40px',
  870. paddingLeft: '0',
  871. position:'relative'
  872. }}>
  873. <div style={{
  874. position:'relative',
  875. marginLeft: '85%',
  876. display: 'inline-block'
  877. }}>
  878. <div style={{
  879. border: '1px solid #000',
  880. width: '60px',
  881. height: '60px',
  882. display: 'flex',
  883. justifyContent: 'center',
  884. alignItems: 'center',
  885. }}
  886. >
  887. 受付印
  888. </div>
  889. <div
  890. style={{
  891. position: 'absolute',
  892. bottom: 0,
  893. left: '-200px',
  894. width: '200px',
  895. height: '1px',
  896. backgroundColor: '#000',
  897. }}
  898. />
  899. </div>
  900. </td>
  901. </tr>
  902. </tbody>
  903. </table>
  904. </div>
  905. <div className="btn-group-mobile" style={{ display: 'flex', justifyContent: 'space-between', marginTop: '30px', paddingRight: '700px' }}>
  906. <div>
  907. <button className="action-btn">すべて承諾</button>
  908. <button className="action-btn" style={{ marginLeft: '10px' }}>チェックした指示を承諾</button>
  909. </div>
  910. <div className="desktop-button-only">
  911. <button className="action-btn">ダウンロード</button>
  912. </div>
  913. </div>
  914. <div style={{ marginTop: '80px' }}>
  915. <span className="history-title-custom">履歴管理</span>
  916. <table className="history-table-custom">
  917. <tbody>
  918. {historyData.map((item, index) => (
  919. <tr key={index}>
  920. <td className="type-td">{item.type}</td>
  921. <td className="date-td">{item.date}</td>
  922. <td className="action-td">{item.action}</td>
  923. </tr>
  924. ))}
  925. </tbody>
  926. </table>
  927. </div>
  928. {/* 使用封装的对话框组件 */}
  929. <DateChangeDialog
  930. show={showDialog}
  931. onClose={handleDialogCancel}
  932. onConfirm={handleDialogConfirm}
  933. reasonOptions={reasonOptions}
  934. />
  935. {/* 聊天侧边栏 */}
  936. {showChat && (
  937. <>
  938. {/* 半透明背景遮罩 */}
  939. <div className="overlay" onClick={closeChatSidebar}></div>
  940. {/* 聊天侧边栏容器 */}
  941. <div className="chat-sidebar">
  942. <Chat onClose={closeChatSidebar} />
  943. </div>
  944. </>
  945. )}
  946. </div>
  947. );
  948. };
  949. export default GridExample;