qcast-100 물건현황 ..
This commit is contained in:
parent
b02ad92fca
commit
847c4cc371
15
src/app/[locale]/management/stuff/detail/page.jsx
Normal file
15
src/app/[locale]/management/stuff/detail/page.jsx
Normal file
@ -0,0 +1,15 @@
|
||||
import React from 'react'
|
||||
import Hero from '@/components/Hero'
|
||||
import StuffDetail from '@/components/management/StuffDetail'
|
||||
export default function ManagementStuffDetailPage() {
|
||||
return (
|
||||
<>
|
||||
<div className="pt-48 flex justify-left">
|
||||
<h1 className="text-4xl archivo-black-regular">물건정보</h1>
|
||||
</div>
|
||||
<div className="m2">
|
||||
<StuffDetail />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -1,14 +1,19 @@
|
||||
import Hero from '@/components/Hero'
|
||||
import StuffSearchCondition from '@/components/management/StuffSearchCondition'
|
||||
import Stuff from '@/components/management/Stuff'
|
||||
import { initCheck } from '@/util/session-util'
|
||||
|
||||
import Hero from '@/components/Hero'
|
||||
export default async function ManagementStuffPage() {
|
||||
await initCheck()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Hero title="물건관리" />
|
||||
<div className="container flex flex-wrap items-center justify-between mx-auto p-4 m-4 border">
|
||||
<Hero title="물건현황" />
|
||||
<div>
|
||||
<div className="m2">
|
||||
<StuffSearchCondition />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col justify-center my-8 pt-20">
|
||||
<Stuff />
|
||||
</div>
|
||||
</>
|
||||
|
||||
@ -14,6 +14,7 @@ export default function RangeDatePicker(props) {
|
||||
setDateRange(update)
|
||||
}}
|
||||
isClearable={true}
|
||||
// showMonthYearPicker={true}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,7 +1,372 @@
|
||||
'use client'
|
||||
|
||||
import React, { useEffect, useState, useRef } from 'react'
|
||||
import { useRouter, usePathname } from 'next/navigation'
|
||||
import { Button } from '@nextui-org/react'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { QToast } from '@/hooks/useToast'
|
||||
import StuffQGrid from './StuffQGrid'
|
||||
import { useI18n } from '@/locales/client'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { stuffSearchState } from '@/store/stuffAtom'
|
||||
import { queryStringFormatter } from '@/util/common-utils'
|
||||
import dayjs from 'dayjs'
|
||||
import isLeapYear from 'dayjs/plugin/isLeapYear' // 윤년 판단 플러그인
|
||||
dayjs.extend(isLeapYear)
|
||||
|
||||
export default function Stuff() {
|
||||
const stuffSearchParams = useRecoilValue(stuffSearchState)
|
||||
|
||||
const { get, del } = useAxios()
|
||||
const gridRef = useRef()
|
||||
const lang = useI18n()
|
||||
|
||||
const [gridCount, setGridCount] = useState(0)
|
||||
const [selectedRowData, setSelectedRowData] = useState([])
|
||||
const [selectedRowDataCount, setSelectedRowDataCount] = useState(0)
|
||||
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
|
||||
//그리드 내부 복사버튼
|
||||
const copyNo = async (value) => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(value)
|
||||
QToast({
|
||||
message: `${value}물건번호가 복사되었습니다`,
|
||||
type: 'info',
|
||||
})
|
||||
} catch (error) {
|
||||
QToast({
|
||||
message: `클립보드 복사에 실패하였습니다`,
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const [gridProps, setGridProps] = useState({
|
||||
gridData: [],
|
||||
isPageable: false,
|
||||
// sets 10 rows per page (default is 100)
|
||||
paginationPageSize: 100,
|
||||
// allows the user to select the page size from a predefined list of page sizes
|
||||
paginationPageSizeSelector: [100, 200, 300, 400],
|
||||
gridColumns: [
|
||||
{
|
||||
field: 'lastEditDatetime',
|
||||
headerName: lang('stuff.gridHeader.lastEditDatetime'),
|
||||
headerCheckboxSelection: true,
|
||||
headerCheckboxSelectionCurrentPageOnly: true, //페이징시 현재 페이지만 체크되도록
|
||||
checkboxSelection: true,
|
||||
showDisabledCheckboxes: true,
|
||||
// headerClass: 'centered', //_test.scss에 추가 테스트
|
||||
// .centered {
|
||||
// .ag-header-cell-label {
|
||||
// justify-content: center !important;
|
||||
// }
|
||||
// }
|
||||
cellStyle: { textAlign: 'center' },
|
||||
//suppressMovable: true, //헤더 못움직이게
|
||||
// width : 100
|
||||
// minWidth : 100
|
||||
// maxWidth : 100
|
||||
valueFormatter: function (params) {
|
||||
if (params.value) {
|
||||
return dayjs(params?.value).format('YYYY.MM.DD HH:mm:ss')
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'objectNo',
|
||||
headerName: lang('stuff.gridHeader.objectNo'),
|
||||
// headerClass: 'centered', //_test.scss에 추가 테스트
|
||||
cellRenderer: function (params) {
|
||||
if (params.data.objectNo) {
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
size="sm"
|
||||
// isDisabled={params.data.successful ? false : true}
|
||||
color="default"
|
||||
onPress={() => {
|
||||
copyNo(params.value)
|
||||
}}
|
||||
>
|
||||
복사
|
||||
</Button>
|
||||
<span>{params.value}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
cellRendererParams: {
|
||||
onPress: copyNo,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'planTotCnt',
|
||||
headerName: lang('stuff.gridHeader.planTotCnt'),
|
||||
cellStyle: { textAlign: 'right' },
|
||||
},
|
||||
{ field: 'objectName', headerName: lang('stuff.gridHeader.objectName'), cellStyle: { textAlign: 'left' } },
|
||||
{
|
||||
field: 'saleStoreId',
|
||||
headerName: lang('stuff.gridHeader.saleStoreId'),
|
||||
cellStyle: { textAlign: 'left' },
|
||||
},
|
||||
{ field: 'saleStoreName', headerName: lang('stuff.gridHeader.saleStoreName'), cellStyle: { textAlign: 'left' } },
|
||||
{ field: 'address', headerName: lang('stuff.gridHeader.address'), cellStyle: { textAlign: 'left' } },
|
||||
{ field: 'dispCompanyName', headerName: lang('stuff.gridHeader.dispCompanyName'), cellStyle: { textAlign: 'left' } },
|
||||
{ field: 'receiveUser', headerName: lang('stuff.gridHeader.receiveUser'), cellStyle: { textAlign: 'left' } },
|
||||
{
|
||||
field: 'specDate',
|
||||
headerName: lang('stuff.gridHeader.specDate'),
|
||||
valueFormatter: function (params) {
|
||||
if (params.value) {
|
||||
return dayjs(params?.value).format('YYYY.MM.DD')
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
},
|
||||
cellStyle: { textAlign: 'center' },
|
||||
},
|
||||
{
|
||||
field: 'createDatetime',
|
||||
headerName: lang('stuff.gridHeader.createDatetime'),
|
||||
valueFormatter: function (params) {
|
||||
if (params.value) {
|
||||
return dayjs(params?.value).format('YYYY.MM.DD')
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
},
|
||||
cellStyle: { textAlign: 'center' },
|
||||
},
|
||||
],
|
||||
gridCount: 0,
|
||||
})
|
||||
|
||||
//그리드 더블클릭
|
||||
const getCellDoubleClicked = (event) => {
|
||||
if (event.column.colId === 'objectNo') {
|
||||
return
|
||||
} else {
|
||||
console.log(' 상세이동::::::::', event.data)
|
||||
if (event.data.objectNo) {
|
||||
router.push(`${pathname}/detail?objectNo=${event.data.objectNo.toString()}`)
|
||||
} else {
|
||||
QToast({
|
||||
message: '물건정보가 없습니다',
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//그리드 체크박스 선택시
|
||||
const getSelectedRowdata = (data) => {
|
||||
// console.log('data:::', data)
|
||||
// let delData = data.map((row) => {
|
||||
// return row.objectNo
|
||||
// })
|
||||
// console.log('delData::', delData)
|
||||
setSelectedRowData(data)
|
||||
setSelectedRowDataCount(data.length)
|
||||
}
|
||||
|
||||
//물건삭제
|
||||
const fnDeleteRowData = (data) => {
|
||||
console.log('물건삭제:::::::::::')
|
||||
if (data.length === 0) {
|
||||
QToast({
|
||||
message: '삭제할 데이터를 선택하세요',
|
||||
type: 'error',
|
||||
})
|
||||
return false
|
||||
}
|
||||
let errCount = 0
|
||||
data.forEach((cell) => {
|
||||
if (!cell.objectNo) {
|
||||
// if (errCount === 0) {
|
||||
// QToast({
|
||||
// message: `물건정보가 있는 행만 삭제 됩니다`,
|
||||
// type: 'error',
|
||||
// })
|
||||
// }
|
||||
errCount++
|
||||
}
|
||||
})
|
||||
|
||||
async function fetchDelete(data) {
|
||||
console.log('물건삭제API호출!!!!!!!!!', data)
|
||||
//행추가말고 api데이터만 보냄
|
||||
// let newData = data.filter((item) => item.company != null)
|
||||
// console.log('삭제에 전송되는 데이타::', newData)
|
||||
// await del({ url: '', data:newData })
|
||||
await get({ url: 'https://www.ag-grid.com/example-assets/space-mission-data.json' })
|
||||
// try {
|
||||
// const res = await del({url:'', data:newData})
|
||||
|
||||
// if(!res || res.length === 0) {
|
||||
|
||||
// } else {
|
||||
fetchData()
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('Data Delete error:', error);
|
||||
// }
|
||||
}
|
||||
|
||||
// 삭제API 완료 후 fetchData Api호출
|
||||
async function fetchData() {
|
||||
console.log('물건삭제후 조회API호출!!!!!!!!!!!!!', stuffSearchParams)
|
||||
const data = await get({ url: 'https://www.ag-grid.com/example-assets/space-mission-data.json' })
|
||||
setGridProps({ ...gridProps, gridData: data, count: data.length })
|
||||
setGridCount(data.length)
|
||||
//data.length = 10
|
||||
//setGridProps({ ...gridProps, gridData: data, count: data.length-1})
|
||||
//setGridCount(data.length - 1 )
|
||||
}
|
||||
|
||||
if (errCount === 0) {
|
||||
// console.log('errCount::::::::', errCount)
|
||||
fetchDelete(data)
|
||||
// fetchData()
|
||||
} else {
|
||||
QToast({
|
||||
message: `물건정보가 있는 행만 선택해주세요`,
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//행추가
|
||||
let newCount = 0
|
||||
const addRowItems = () => {
|
||||
// console.log('girdRef::::::', gridRef.current.api)
|
||||
const newItems = [
|
||||
{
|
||||
mission: newCount + 1,
|
||||
successful: true,
|
||||
},
|
||||
]
|
||||
gridRef.current.api.applyTransaction({
|
||||
add: newItems,
|
||||
addIndex: newCount,
|
||||
})
|
||||
newCount++
|
||||
}
|
||||
|
||||
//행삭제
|
||||
const removeRowItems = () => {
|
||||
// console.log('selectedRowData::', selectedRowData)
|
||||
let errCount = 0
|
||||
selectedRowData.forEach((cell) => {
|
||||
if (!cell.company) {
|
||||
let newSelectedRowData = selectedRowData.filter((item) => item.company == null)
|
||||
gridRef.current.api.applyTransaction({ remove: newSelectedRowData })
|
||||
} else {
|
||||
if (errCount === 0) {
|
||||
QToast({
|
||||
message: `행추가로 추가 한 행만 삭제됩니다.`,
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
errCount++
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 진입시 그리드 데이터 조회
|
||||
useEffect(() => {
|
||||
if (stuffSearchParams?.code === 'S') {
|
||||
const params = {
|
||||
schObjectNo: '',
|
||||
schSaleStoreId: '',
|
||||
schAddress: '',
|
||||
schObjectName: '',
|
||||
schSaleStoreName: '',
|
||||
schSpecDateYn: '',
|
||||
schReceiveUser: '',
|
||||
schDispCompanyName: '',
|
||||
schDateType: 'U',
|
||||
schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'),
|
||||
schToDt: dayjs(new Date()).format('YYYY-MM-DD'),
|
||||
}
|
||||
|
||||
async function fetchData() {
|
||||
console.log('화면진입:::::::::::::', params)
|
||||
const apiUrl = `/api/object/v1.0/object?saleStoreId=201TES01&${queryStringFormatter(params)}`
|
||||
// console.log('apiUrl::', apiUrl)
|
||||
|
||||
await get({
|
||||
url: apiUrl,
|
||||
}).then((res) => {
|
||||
if (res.length > 0) {
|
||||
console.log('API결과:::::::', res)
|
||||
setGridProps({ ...gridProps, gridData: res, count: res.length })
|
||||
setGridCount(res.length)
|
||||
}
|
||||
})
|
||||
}
|
||||
fetchData()
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (stuffSearchParams?.code === 'E') {
|
||||
console.log('조회 눌럿을때 ::::::::::::::', stuffSearchParams)
|
||||
async function fetchData() {
|
||||
const apiUrl = `/api/object/v1.0/object?saleStoreId=201TES01&${queryStringFormatter(stuffSearchParams)}`
|
||||
await get({ url: apiUrl }).then((res) => {
|
||||
console.log('API결과:::::::', res)
|
||||
setGridProps({ ...gridProps, gridData: res, count: res.length })
|
||||
setGridCount(res.length)
|
||||
})
|
||||
}
|
||||
fetchData()
|
||||
}
|
||||
}, [stuffSearchParams])
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Management Stuff</h1>
|
||||
<div className="text-2xl">
|
||||
물건목록
|
||||
<span>
|
||||
전체 : {gridCount} // 선택 : {selectedRowDataCount}
|
||||
</span>
|
||||
<div align="right">
|
||||
{/* <Button
|
||||
color="primary"
|
||||
onPress={() => {
|
||||
fnDeleteRowData(selectedRowData)
|
||||
}}
|
||||
>
|
||||
물건삭제
|
||||
</Button> */}
|
||||
{/* <Button
|
||||
color="primary"
|
||||
onPress={() => {
|
||||
addRowItems()
|
||||
}}
|
||||
>
|
||||
행추가
|
||||
</Button>
|
||||
<Button
|
||||
color="primary"
|
||||
onPress={() => {
|
||||
removeRowItems()
|
||||
}}
|
||||
>
|
||||
행삭제
|
||||
</Button> */}
|
||||
</div>
|
||||
<div style={{ width: '100%', height: '100%' }}>
|
||||
<StuffQGrid {...gridProps} getSelectedRowdata={getSelectedRowdata} getCellDoubleClicked={getCellDoubleClicked} gridRef={gridRef} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
388
src/components/management/StuffDetail.jsx
Normal file
388
src/components/management/StuffDetail.jsx
Normal file
@ -0,0 +1,388 @@
|
||||
'use client'
|
||||
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { useRouter, useSearchParams } from 'next/navigation'
|
||||
import { Input, RadioGroup, Radio, Button, Autocomplete, AutocompleteItem, Select, SelectItem, Checkbox, Textarea } from '@nextui-org/react'
|
||||
import Link from 'next/link'
|
||||
import { get } from '@/lib/Axios'
|
||||
import { queryStringFormatter } from '@/util/common-utils'
|
||||
import dayjs from 'dayjs'
|
||||
export default function StuffDetail() {
|
||||
const router = useRouter()
|
||||
const searchParams = useSearchParams()
|
||||
const [receiveUser, setReceiveUser] = useState('') //담당자
|
||||
const [name2, setName2] = useState('') //물건명
|
||||
const [name3, setName3] = useState('') //물건명후리가나
|
||||
const [zipCode, setZipCode] = useState('') //우편번호
|
||||
const [name5, setName5] = useState('') //수직적설량
|
||||
const [gubun, setGubun] = useState('NEW') //신축 기축
|
||||
const [sel, setSel] = useState('') //경칭선택
|
||||
const [sel2, setSel2] = useState('') //발전량시뮬레이션지역
|
||||
const [sel3, setSel3] = useState('') //기준풍속
|
||||
const [sel4, setSel4] = useState('') //설치높이
|
||||
|
||||
const [errors, setErrors] = useState({})
|
||||
const [isFormValid, setIsFormValid] = useState(false) //임시저장, 진짜저장 버튼 컨트롤
|
||||
const [testSelOption, setTestSelOption] = useState([]) // 테스트용
|
||||
const [autoSelectValue, setAutoSelectValue] = useState('') //판매점명 자동완성
|
||||
const [buttonValid, setButtonValid] = useState(true) //주소검색 활성화 컨트롤
|
||||
const [isSelected, setIsSelected] = useState(false) //한랭지대첵 체크박스
|
||||
const [isSelected2, setIsSelected2] = useState(false) //염해지역용아이템사용 체크박스
|
||||
const [gubun2, setGubun2] = useState('1') //면조도구분 라디오
|
||||
const [gubun3, setGubun3] = useState('A') //계약조건 라디오
|
||||
const [memo, setMemo] = useState('') //메모
|
||||
const objectNo = searchParams.get('objectNo') //url에서 물건번호 꺼내서 바로 set
|
||||
|
||||
const [address1, setAddress1] = useState('') //우편API리턴 도도부현명
|
||||
const [address2, setAddress2] = useState('') //우편API리턴 시구정촌명
|
||||
const [address3, setAddress3] = useState('') //우편API리턴 마을 지역명
|
||||
const [prefcode, setPrefCode] = useState(1) //우편API prefcode
|
||||
|
||||
const [editMode, setEditMode] = useState('NEW')
|
||||
const [detailData, setDetailData] = useState({})
|
||||
|
||||
useEffect(() => {
|
||||
// console.log('상세화면진입:::::::::', searchParams.get('objectNo'))
|
||||
// console.log('물건번호::::', objectNo)
|
||||
|
||||
if (objectNo) {
|
||||
console.log('상세::')
|
||||
setEditMode('EDIT')
|
||||
//http://localhost:8080/api/object/v1.0/object/R201TES01240906007/1
|
||||
//일단 플랜번호 무조건 1로
|
||||
//API 호출
|
||||
get({ url: `/api/object/v1.0/object/${objectNo}/1` }).then((res) => {
|
||||
if (res != null) {
|
||||
// console.log('res:::::::', res)
|
||||
setDetailData(res)
|
||||
//setTestSelOption(res)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
console.log('신규:::')
|
||||
}
|
||||
}, [objectNo])
|
||||
|
||||
useEffect(() => {
|
||||
validateForm()
|
||||
}, [receiveUser, name2, name3, gubun, sel, autoSelectValue, zipCode, sel2, sel3, name5, sel4])
|
||||
|
||||
// 우편번호 숫자만 체크
|
||||
const textTypeHandler = (e) => {
|
||||
//\D 숫자가 아닌것(특수문자포함)과 매치, [^0-9]와 동일
|
||||
if (!e.target.value.match(/\D/g)) {
|
||||
setZipCode(e.target.value)
|
||||
}
|
||||
}
|
||||
|
||||
// 수직적설량 숫자만
|
||||
const textTypeHandler2 = (e) => {
|
||||
if (!e.target.value.match(/[^0-9]/g)) {
|
||||
setName5(e.target.value)
|
||||
}
|
||||
}
|
||||
const validateForm = () => {
|
||||
let errors = {}
|
||||
|
||||
if (!receiveUser || receiveUser.trim().length === 0) {
|
||||
errors.receiveUser = '담당자 is required.'
|
||||
}
|
||||
|
||||
if (!name2 || name2.trim().length === 0) {
|
||||
errors.name2 = '물건명 is required.'
|
||||
}
|
||||
|
||||
if (!name3 || name3.trim().length === 0) {
|
||||
errors.name3 = '물건명후리가나 is required.'
|
||||
}
|
||||
|
||||
if (!sel) {
|
||||
errors.sel = '경칭선택 is required'
|
||||
}
|
||||
|
||||
if (!sel2) {
|
||||
errors.sel2 = '발전량시뮬레이션지역 is required'
|
||||
}
|
||||
|
||||
if (!sel3) {
|
||||
errors.sel3 = '기준풍속 is required'
|
||||
}
|
||||
|
||||
if (!sel4) {
|
||||
errors.sel4 = '설치높이 is required'
|
||||
}
|
||||
|
||||
if (!autoSelectValue) {
|
||||
errors.autoSelectValue = '판매점ID자동완성 is required'
|
||||
}
|
||||
|
||||
if (!zipCode || zipCode.length != 7) {
|
||||
errors.zipCode = '우편번호 is required.'
|
||||
setButtonValid(true)
|
||||
} else {
|
||||
setButtonValid(false)
|
||||
}
|
||||
|
||||
if (!name5) {
|
||||
errors.name5 = '수직적설량 is required.'
|
||||
}
|
||||
|
||||
// console.log('errors::', errors)
|
||||
setErrors(errors)
|
||||
setIsFormValid(Object.keys(errors).length === 0)
|
||||
}
|
||||
|
||||
// 우편번호 API
|
||||
const onSearchPostNumber = () => {
|
||||
if (!zipCode) {
|
||||
return alert('우편번호 입력해')
|
||||
}
|
||||
const params = {
|
||||
zipcode: zipCode,
|
||||
}
|
||||
|
||||
get({ url: `https://zipcloud.ibsnet.co.jp/api/search?${queryStringFormatter(params)}` }).then((res) => {
|
||||
console.log('우편API RES::::::::', res)
|
||||
if (res.status === 200) {
|
||||
if (res.results.length > 0) {
|
||||
setAddress1(res.results[0].address1)
|
||||
setAddress2(res.results[0].address2)
|
||||
setAddress3(res.results[0].address3)
|
||||
setPrefCode(res.results[0].prefcode)
|
||||
} else {
|
||||
alert('등록된 우편번호에서 주소를 찾을 수 없습니다. 다시 입력해주세요.')
|
||||
}
|
||||
} else {
|
||||
alert(res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const onTempSave = () => {
|
||||
console.log('임시저장::', isFormValid)
|
||||
}
|
||||
|
||||
const onSave = () => {
|
||||
console.log('진짜저장isFormValid:::', isFormValid)
|
||||
}
|
||||
|
||||
const moveList = () => {
|
||||
router.push('/management/stuff')
|
||||
}
|
||||
|
||||
const changeAddress2 = (e) => {
|
||||
console.log('e:::::::', e.target.value)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{(editMode === 'NEW' && <div>신규:::::::::::</div>) || <div>상세:::::::::::</div>}
|
||||
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
|
||||
<div>
|
||||
<span>물건번호</span>
|
||||
<span>{objectNo}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>사양확정일</span>
|
||||
<span>{detailData?.specDate ? dayjs(detailData.specDate).format('YYYY.MM.DD') : null}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>갱신일시</span>
|
||||
<span>
|
||||
{detailData?.lastEditDatetime
|
||||
? dayjs(detailData.lastEditDatetime).format('YYYY.MM.DD HH:mm:ss')
|
||||
: detailData?.createDatetime
|
||||
? dayjs(detailData.createDatetime).format('YYYY.MM.DD HH:mm:ss')
|
||||
: null}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>등록일</span>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div>(*필수 입력항목)</div>
|
||||
<div>
|
||||
<span>담당자*</span>
|
||||
<input type="text" placeholder="Kim Ji Young" defaultValue={detailData?.receiveUser} onChange={(e) => setReceiveUser(e.target.value)} />
|
||||
</div>
|
||||
<div>
|
||||
<span>물건구분/물건명 *</span>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_gubun"
|
||||
id="radio_new"
|
||||
value={'NEW'}
|
||||
checked={gubun === 'NEW' ? true : false}
|
||||
onChange={(e) => {
|
||||
setGubun(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_new">신축</label>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_gubun"
|
||||
id="radio_old"
|
||||
value={'OLD'}
|
||||
checked={gubun === 'OLD' ? true : false}
|
||||
onChange={(e) => {
|
||||
setGubun(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_old">기축</label>
|
||||
<div>
|
||||
<input type="text" placeholder="물건명" value={name2} onChange={(e) => setName2(e.target.value)} />
|
||||
</div>
|
||||
<div className="flex w-full max-w-xs flex-col gap-2">
|
||||
<Select label="경칭선택" className="max-w-xs" onChange={(e) => setSel(e.target.value)}>
|
||||
<SelectItem key="1">111</SelectItem>
|
||||
<SelectItem key="2">222</SelectItem>
|
||||
<SelectItem key="3">333</SelectItem>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<span>물건명 후리가나</span>
|
||||
<input type="text" placeholder="물건명 후리가나" value={name3} onChange={(e) => setName3(e.target.value)} />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span>판매점명 /ID *</span>
|
||||
<div className="flex w-full max-w-xs flex-col gap-2">
|
||||
<Autocomplete
|
||||
className="max-w-xs"
|
||||
defaultItems={testSelOption}
|
||||
label="판매점ID자동완성으로 바꾸기"
|
||||
selectedKey={autoSelectValue}
|
||||
onSelectionChange={setAutoSelectValue}
|
||||
>
|
||||
{(option) => <AutocompleteItem key={option.id}>{option.name}</AutocompleteItem>}
|
||||
</Autocomplete>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span>우편번호*</span>
|
||||
<input type="text" placeholder="숫자7자리 입력여부 체크" value={zipCode} maxLength="7" onChange={textTypeHandler} />
|
||||
<Button onClick={onSearchPostNumber} isDisabled={buttonValid}>
|
||||
주소검색
|
||||
</Button>
|
||||
*우편번호 7자리를 입력한 후, 주소검색 버튼을 클릭해 주십시오
|
||||
</div>
|
||||
<div>
|
||||
<span>도도부현 / 주소*</span>
|
||||
{/* <input type="text" placeholder="주소검색 결과 select로 변경하기 공통코드 api리턴값 selected" disabled /> */}
|
||||
<input type="text" placeholder="주소검색 결과 주소 셋팅 칸" value={address2 + address3} onChange={changeAddress2} />
|
||||
</div>
|
||||
<div>
|
||||
<span>발전량시뮬레이션지역*</span>
|
||||
<Select label="발전량시뮬레이션지역" className="max-w-xs" onChange={(e) => setSel2(e.target.value)}>
|
||||
<SelectItem key="1">111</SelectItem>
|
||||
<SelectItem key="2">222</SelectItem>
|
||||
<SelectItem key="3">333</SelectItem>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<span>기준풍속*</span>
|
||||
<Select label="기준풍속" className="max-w-xs" onChange={(e) => setSel3(e.target.value)}>
|
||||
<SelectItem key="1">111</SelectItem>
|
||||
<SelectItem key="2">222</SelectItem>
|
||||
<SelectItem key="3">333</SelectItem>
|
||||
</Select>
|
||||
m/s이하
|
||||
</div>
|
||||
<div>
|
||||
<span>수직적설량*</span>
|
||||
<input type="text" placeholder="수직적설량" value={name5} maxLength="3" onChange={textTypeHandler2} /> cm
|
||||
<Checkbox isSelected={isSelected} onValueChange={setIsSelected}>
|
||||
한랭지대책시행
|
||||
</Checkbox>
|
||||
</div>
|
||||
<div>
|
||||
<span>면조도구분*</span>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_gubun2"
|
||||
id="radio_1"
|
||||
value={'1'}
|
||||
checked={gubun2 === '1' ? true : false}
|
||||
onChange={(e) => {
|
||||
setGubun2(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_1">III·IV</label>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_gubun2"
|
||||
id="radio_2"
|
||||
value={'2'}
|
||||
checked={gubun2 === '2' ? true : false}
|
||||
onChange={(e) => {
|
||||
setGubun2(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_2">II</label>
|
||||
<Checkbox isSelected={isSelected2} onValueChange={setIsSelected2}>
|
||||
염해지역용아이템사용
|
||||
</Checkbox>
|
||||
</div>
|
||||
<div>
|
||||
<span>설치높이*</span>
|
||||
<Select label="설치높이" className="max-w-xs" onChange={(e) => setSel4(e.target.value)}>
|
||||
<SelectItem key="1">111</SelectItem>
|
||||
<SelectItem key="2">222</SelectItem>
|
||||
<SelectItem key="3">333</SelectItem>
|
||||
</Select>
|
||||
m
|
||||
</div>
|
||||
<div>
|
||||
<span>계약조건</span>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_gubun3"
|
||||
id="radio_a"
|
||||
value={'A'}
|
||||
checked={gubun3 === 'A' ? true : false}
|
||||
onChange={(e) => {
|
||||
setGubun3(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_a">잉여</label>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_gubun3"
|
||||
id="radio_b"
|
||||
value={'B'}
|
||||
checked={gubun3 === 'B' ? true : false}
|
||||
onChange={(e) => {
|
||||
setGubun3(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_2">전량</label>
|
||||
</div>
|
||||
<div>
|
||||
<span>메모</span>
|
||||
<Textarea
|
||||
value={memo}
|
||||
onValueChange={setMemo}
|
||||
disableAutosize
|
||||
classNames={{
|
||||
base: 'max-w-xs',
|
||||
input: 'resize-y min-h-[40px]',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{!isFormValid ? (
|
||||
<>
|
||||
<Button onClick={onTempSave}>임시저장</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button onClick={onSave}>진짜저장</Button>
|
||||
</>
|
||||
)}
|
||||
<Link href="/management/stuff">
|
||||
<button type="button">물건목록</button>
|
||||
</Link>
|
||||
{/* <Button onPress={moveList}>물건목록2</Button> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
116
src/components/management/StuffQGrid.jsx
Normal file
116
src/components/management/StuffQGrid.jsx
Normal file
@ -0,0 +1,116 @@
|
||||
import React from 'react'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { AgGridReact } from 'ag-grid-react'
|
||||
|
||||
import 'ag-grid-community/styles/ag-grid.css'
|
||||
import 'ag-grid-community/styles/ag-theme-quartz.css'
|
||||
|
||||
export default function StuffQGrid(props) {
|
||||
const { gridData, gridColumns, isPageable = true, count, gridRef } = props
|
||||
/**
|
||||
* 행 데이터를 설정할 때 useState을 사용하여 렌더링 전반에 걸쳐 일관된 배열 참조를 유지하는 것이 좋습니다
|
||||
*/
|
||||
const [rowData, setRowData] = useState(null)
|
||||
|
||||
/**
|
||||
* Column Definitions를 설정할 때는 useMemo 또는 useState를 사용하여 렌더 간에 일관된 참조를 유지하십시오.
|
||||
* 응용 프로그램이 Column Definitions를 동적으로 변경하는 경우에도 렌더링 간에 일관된 참조를 유지하려면 useMemo 또는 useState를 사용하십시오.
|
||||
*/
|
||||
const [colDefs, setColDefs] = useState(
|
||||
gridColumns ?? [
|
||||
{ field: 'mission', filter: true },
|
||||
{ field: 'company' },
|
||||
{ field: 'location' },
|
||||
{ field: 'date' },
|
||||
{ field: 'price', valueFormatter: (params) => `₩ ${params.value.toLocaleString()}` },
|
||||
{ field: 'successful' },
|
||||
{ field: 'rocket' },
|
||||
],
|
||||
)
|
||||
|
||||
/**
|
||||
* defaultColDef 속성을 제공할 때 이 인라인 또는 구성 요소의 단순 개체로 정의하지 마십시오. 이렇게 하면 모든 렌더링에서 새 인스턴스가 생성됩니다.
|
||||
* 대신 or useState 를 사용하여 useMemo 렌더 간에 일관된 참조가 유지되도록 합니다.
|
||||
*/
|
||||
const defaultColDef = useMemo(() => {
|
||||
return {
|
||||
filter: false,
|
||||
flex: 1,
|
||||
sortable: false,
|
||||
suppressMovable: true,
|
||||
resizable: false,
|
||||
suppressSizeToFit: false,
|
||||
headerClass: 'centered', //_test.scss에 추가 테스트
|
||||
}
|
||||
}, [])
|
||||
|
||||
/**
|
||||
* 단순 유형(string, boolean 및 number)의 속성은 렌더링 간에 값으로 비교되므로 후크를 사용할 필요가 없습니다.
|
||||
*/
|
||||
const rowBuffer = 100
|
||||
|
||||
/**
|
||||
* 모든 렌더링에서 그리드 상태를 재설정하지 않도록 useCallback을 사용하는 것이 좋습니다.
|
||||
* api데이타 해당 컬럼에 따라 로우 체크박스 체크 가능여부 등 컨트롤
|
||||
*/
|
||||
const isRowSelectable = useCallback(
|
||||
(params) => {
|
||||
return !!params.data
|
||||
},
|
||||
[count],
|
||||
)
|
||||
|
||||
// 체크박스 체크시
|
||||
const onSelectionChanged = useCallback((event) => {
|
||||
props.getSelectedRowdata(event.api.getSelectedRows())
|
||||
}, [])
|
||||
|
||||
//더블클릭
|
||||
const onCellDoubleClicked = useCallback((event) => {
|
||||
// if (event.column.colId === 'company') {
|
||||
// return
|
||||
// } else {
|
||||
props.getCellDoubleClicked(event)
|
||||
// }
|
||||
}, [])
|
||||
|
||||
//컨텐츠에 따라 컬럼넓이 자동조절
|
||||
const autoSizeStrategy = useMemo(() => {
|
||||
return {
|
||||
type: 'fitCellContents',
|
||||
}
|
||||
}, [])
|
||||
|
||||
const onGridReady = useCallback((event) => {
|
||||
// 헤더 사이즈 조정 컬럼에 width값으로 계산
|
||||
event.api.sizeColumnsToFit()
|
||||
}, [])
|
||||
|
||||
// Fetch data & update rowData state
|
||||
useEffect(() => {
|
||||
gridData ? setRowData(gridData) : ''
|
||||
}, [gridData])
|
||||
|
||||
return (
|
||||
<div className="ag-theme-quartz" style={{ height: 500 }}>
|
||||
<AgGridReact
|
||||
ref={gridRef}
|
||||
onGridReady={onGridReady}
|
||||
rowBuffer={rowBuffer}
|
||||
rowData={rowData}
|
||||
columnDefs={colDefs}
|
||||
defaultColDef={defaultColDef}
|
||||
isRowSelectable={isRowSelectable}
|
||||
rowSelection={'multiple'}
|
||||
suppressRowClickSelection={true}
|
||||
onSelectionChanged={onSelectionChanged}
|
||||
onCellDoubleClicked={onCellDoubleClicked}
|
||||
pagination={isPageable}
|
||||
//paginationPageSize={paginationPageSize}
|
||||
//paginationPageSizeSelector={paginationPageSizeSelector}
|
||||
autoSizeStrategy={autoSizeStrategy}
|
||||
overlayNoRowsTemplate={'<span className="ag-overlay-loading-center">물건 목록이 없습니다.</span>'}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
264
src/components/management/StuffSearchCondition.jsx
Normal file
264
src/components/management/StuffSearchCondition.jsx
Normal file
@ -0,0 +1,264 @@
|
||||
'use client'
|
||||
|
||||
import React, { useEffect } from 'react'
|
||||
import { useState } from 'react'
|
||||
import { Input, RadioGroup, Radio, Button } from '@nextui-org/react'
|
||||
import RangeDatePicker from '@/components/common/datepicker/RangeDatePicker'
|
||||
import { useRecoilState, useResetRecoilState } from 'recoil'
|
||||
import { stuffSearchState } from '@/store/stuffAtom'
|
||||
import dayjs from 'dayjs'
|
||||
import isLeapYear from 'dayjs/plugin/isLeapYear' // 윤년 판단 플러그인
|
||||
dayjs.extend(isLeapYear)
|
||||
import Link from 'next/link'
|
||||
export default function StuffSearchCondition() {
|
||||
//달력 props 관련 날짜 셋팅
|
||||
const [dateRange, setDateRange] = useState([dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), dayjs(new Date()).format('YYYY-MM-DD')])
|
||||
const [startRangeDate, endRangeDate] = dateRange
|
||||
|
||||
const rangeDatePickerProps = {
|
||||
startRangeDate, //시작일
|
||||
endRangeDate, //종료일
|
||||
setDateRange,
|
||||
}
|
||||
|
||||
//여기서 선택한 검색조건들을 recoil로 관리
|
||||
const resetStuffRecoil = useResetRecoilState(stuffSearchState)
|
||||
const [stuffSearch, setStuffSearch] = useRecoilState(stuffSearchState)
|
||||
const [objectNo, setObjectNo] = useState('') //물건번호
|
||||
const [saleStoreId, setSaleStoreId] = useState('') //판매대리점ID
|
||||
const [address, setAddress] = useState('') //물건주소
|
||||
const [objectName, setobjectName] = useState('') //물건명
|
||||
const [saleStoreName, setSaleStoreName] = useState('') //판매대리점명
|
||||
const [specDateYn, setSpecDateYn] = useState('') //사양 확인('', 'Y', 'N')
|
||||
const [receiveUser, setReceiveUser] = useState('') //담당자
|
||||
const [dispCompanyName, setDispCompanyName] = useState('') //견적처
|
||||
const [dateType, setDateType] = useState('U') //갱신일(U)/등록일(R)
|
||||
|
||||
// 조회
|
||||
const onSubmit = () => {
|
||||
let diff = dayjs(endRangeDate).diff(startRangeDate, 'day')
|
||||
if (diff > 366) {
|
||||
return alert('최대1년 조회 가능합니다.')
|
||||
}
|
||||
setStuffSearch({
|
||||
schObjectNo: stuffSearch?.schObjectNo ? stuffSearch.schObjectNo : objectNo,
|
||||
schSaleStoreId: stuffSearch?.schSaleStoreId ? stuffSearch.schSaleStoreId : saleStoreId,
|
||||
schAddress: stuffSearch?.schAddress ? stuffSearch.schAddress : address,
|
||||
schObjectName: stuffSearch?.schObjectName ? stuffSearch.schObjectName : objectName,
|
||||
schSaleStoreName: stuffSearch?.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName,
|
||||
schSpecDateYn: stuffSearch?.schSpecDateYn ? stuffSearch.schSpecDateYn : specDateYn,
|
||||
schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser,
|
||||
schDispCompanyName: stuffSearch?.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName,
|
||||
schDateType: stuffSearch?.schDateType ? stuffSearch.schDateType : dateType,
|
||||
schFromDt: dayjs(startRangeDate).format('YYYY-MM-DD'),
|
||||
schToDt: dayjs(endRangeDate).format('YYYY-MM-DD'),
|
||||
code: 'E',
|
||||
})
|
||||
}
|
||||
|
||||
//초기화
|
||||
const resetRecoil = () => {
|
||||
setObjectNo('')
|
||||
setSaleStoreId('')
|
||||
setAddress('')
|
||||
setobjectName('')
|
||||
setSaleStoreName('')
|
||||
setSpecDateYn('')
|
||||
setReceiveUser('')
|
||||
setDispCompanyName('')
|
||||
setDateType('U')
|
||||
setDateRange([dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), dayjs(new Date()).format('YYYY-MM-DD')])
|
||||
resetStuffRecoil()
|
||||
}
|
||||
|
||||
//x로 날짜 비웠을때 기본값으로 셋팅
|
||||
useEffect(() => {
|
||||
if (!startRangeDate && !endRangeDate) {
|
||||
setDateRange([dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), dayjs(new Date()).format('YYYY-MM-DD')])
|
||||
}
|
||||
}, [startRangeDate, endRangeDate])
|
||||
|
||||
useEffect(() => {
|
||||
setDateRange([
|
||||
stuffSearch?.schFromDt ? stuffSearch.schFromDt : dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'),
|
||||
stuffSearch?.schToDt ? stuffSearch.schToDt : dayjs(new Date()).format('YYYY-MM-DD'),
|
||||
])
|
||||
}, [stuffSearch])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div align="right">
|
||||
<Link href="/management/stuff/detail">
|
||||
<button type="button">물건신규등록</button>
|
||||
</Link>
|
||||
<Button size="sm" onClick={onSubmit}>
|
||||
조회
|
||||
</Button>
|
||||
<Button size="sm" onClick={resetRecoil}>
|
||||
초기화
|
||||
</Button>
|
||||
</div>
|
||||
<div className="w-full flex flex-col gap-4">
|
||||
{Array(4)
|
||||
.fill()
|
||||
.map((_, i) => {
|
||||
if (i === 0) {
|
||||
return (
|
||||
<div key={i} className="flex w-full flex-wrap md:flex-nowrap mb-6 md:mb-0 gap-4">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="물건번호 입력"
|
||||
value={stuffSearch?.code === 'E' ? stuffSearch.schObjectNo : objectNo}
|
||||
onChange={(e) => {
|
||||
setObjectNo(e.target.value)
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', schObjectNo: e.target.value })
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="판매대리점ID 입력"
|
||||
value={stuffSearch?.schSaleStoreId ? stuffSearch.schSaleStoreId : saleStoreId}
|
||||
onChange={(e) => {
|
||||
setSaleStoreId(e.target.value)
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', schSaleStoreId: e.target.value })
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="물건주소 입력"
|
||||
value={stuffSearch?.address ? stuffSearch.address : address}
|
||||
onChange={(e) => {
|
||||
setAddress(e.target.value)
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', address: e.target.value })
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
} else if (i === 1) {
|
||||
return (
|
||||
<div key={i} className="flex w-full flex-wrap md:flex-nowrap mb-6 md:mb-0 gap-4">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="물건명 입력"
|
||||
value={stuffSearch?.schObjectName ? stuffSearch.schObjectName : objectName}
|
||||
onChange={(e) => {
|
||||
setobjectName(e.target.value)
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', schObjectName: e.target.value })
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="물건명 입력"
|
||||
value={stuffSearch?.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName}
|
||||
onChange={(e) => {
|
||||
setSaleStoreName(e.target.value)
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', schSaleStoreName: e.target.value })
|
||||
}}
|
||||
/>
|
||||
<div>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_sayang"
|
||||
id="radio_all"
|
||||
checked={stuffSearch?.schSpecDateYn === '' ? true : false}
|
||||
value={''}
|
||||
onChange={(e) => {
|
||||
setSpecDateYn(e.target.value)
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', schSpecDateYn: e.target.value })
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_all">ALL</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_sayang"
|
||||
id="radio_y"
|
||||
checked={stuffSearch?.schSpecDateYn === 'Y' ? true : false}
|
||||
value={'Y'}
|
||||
onChange={(e) => {
|
||||
setSpecDateYn(e.target.value)
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', schSpecDateYn: e.target.value })
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_y">사양 확인</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio"
|
||||
id="radio_n"
|
||||
checked={stuffSearch?.schSpecDateYn === 'N' ? true : false}
|
||||
value={'N'}
|
||||
onChange={(e) => {
|
||||
setSpecDateYn(e.target.value)
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', schSpecDateYn: e.target.value })
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_n">사양 미확인</label>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
} else if (i === 2) {
|
||||
return (
|
||||
<div key={i} className="flex w-full flex-wrap md:flex-nowrap mb-6 md:mb-0 gap-4">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="담당자 입력"
|
||||
value={stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser}
|
||||
onChange={(e) => {
|
||||
setReceiveUser(e.target.value)
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', schReceiveUser: e.target.value })
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="견적처 입력"
|
||||
value={stuffSearch?.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName}
|
||||
onChange={(e) => {
|
||||
setDispCompanyName(e.target.value)
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', schDispCompanyName: e.target.value })
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<div key={i} className="flex w-full flex-wrap md:flex-nowrap mb-6 md:mb-0 gap-4">
|
||||
<div>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_ptype"
|
||||
id="radio_u"
|
||||
checked={stuffSearch?.schDateType === 'U' ? true : false}
|
||||
value={'U'}
|
||||
onChange={(e) => {
|
||||
setDateType(e.target.value)
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', schDateType: e.target.value })
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_u">갱신일</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio_ptype"
|
||||
id="radio_r"
|
||||
checked={stuffSearch?.schDateType === 'R' ? true : false}
|
||||
value={'R'}
|
||||
onChange={(e) => {
|
||||
setDateType(e.target.value)
|
||||
setStuffSearch({ ...stuffSearch, code: 'S', schDateType: e.target.value })
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="radio_r">등록일</label>
|
||||
</div>
|
||||
<RangeDatePicker {...rangeDatePickerProps} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -4,4 +4,15 @@ export default {
|
||||
hello: 'こんにちは',
|
||||
welcome: 'こんにちは {name}!',
|
||||
locale: '現在のロケールは {locale} です。',
|
||||
'stuff.gridHeader.lastEditDatetime': '갱신일시',
|
||||
'stuff.gridHeader.objectNo': '물건번호',
|
||||
'stuff.gridHeader.planTotCnt': '플랜 수',
|
||||
'stuff.gridHeader.objectName': '물건명',
|
||||
'stuff.gridHeader.saleStoreId': '대리점ID',
|
||||
'stuff.gridHeader.saleStoreName': '대리점명',
|
||||
'stuff.gridHeader.address': '물건주소',
|
||||
'stuff.gridHeader.dispCompanyName': '견적처',
|
||||
'stuff.gridHeader.receiveUser': '담당자',
|
||||
'stuff.gridHeader.specDate': '사양확인',
|
||||
'stuff.gridHeader.createDatetime': '등록일',
|
||||
}
|
||||
|
||||
@ -4,4 +4,15 @@ export default {
|
||||
hello: '안녕',
|
||||
welcome: '안녕 {name}!',
|
||||
locale: '현재 로케일은 {locale}입니다.',
|
||||
'stuff.gridHeader.lastEditDatetime': '갱신일시',
|
||||
'stuff.gridHeader.objectNo': '물건번호',
|
||||
'stuff.gridHeader.planTotCnt': '플랜 수',
|
||||
'stuff.gridHeader.objectName': '물건명',
|
||||
'stuff.gridHeader.saleStoreId': '대리점ID',
|
||||
'stuff.gridHeader.saleStoreName': '대리점명',
|
||||
'stuff.gridHeader.address': '물건주소',
|
||||
'stuff.gridHeader.dispCompanyName': '견적처',
|
||||
'stuff.gridHeader.receiveUser': '담당자',
|
||||
'stuff.gridHeader.specDate': '사양확인',
|
||||
'stuff.gridHeader.createDatetime': '등록일',
|
||||
}
|
||||
|
||||
22
src/store/stuffAtom.js
Normal file
22
src/store/stuffAtom.js
Normal file
@ -0,0 +1,22 @@
|
||||
import { atom } from 'recoil'
|
||||
import dayjs from 'dayjs'
|
||||
import isLeapYear from 'dayjs/plugin/isLeapYear' // 윤년 판단 플러그인
|
||||
dayjs.extend(isLeapYear)
|
||||
export const stuffSearchState = atom({
|
||||
key: 'stuffSearchState',
|
||||
default: {
|
||||
schObjectNo: '', //물건번호
|
||||
schSaleStoreId: '', //판매대리점ID
|
||||
schAddress: '', //물건주소
|
||||
schObjectName: '', //물건명
|
||||
schSaleStoreName: '', //판매대리점명
|
||||
schSpecDateYn: '', //사양타입 ('', 'Y', 'N')
|
||||
schReceiveUser: '', //담당자
|
||||
schDispCompanyName: '', //견적처
|
||||
schDateType: 'U', //갱신일(U)/등록일(R)
|
||||
schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), //시작일
|
||||
schToDt: dayjs(new Date()).format('YYYY-MM-DD'), //종료일
|
||||
code: 'S',
|
||||
},
|
||||
dangerouslyAllowMutability: true,
|
||||
})
|
||||
@ -41,7 +41,7 @@
|
||||
.grid-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid black; /* 그리드 외각선 */
|
||||
border: 1px solid black; /* 그리드 외각선 */
|
||||
text-align: center; /* 그리드 내 가운데 정렬 */
|
||||
}
|
||||
|
||||
@ -79,3 +79,9 @@
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.centered {
|
||||
.ag-header-cell-label {
|
||||
justify-content: center !important;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user