This commit is contained in:
2025-05-24 01:49:48 +09:00
commit 62abbcf4eb
2376 changed files with 325522 additions and 0 deletions

View File

@@ -0,0 +1,521 @@
<script setup lang="ts">
import { savePrice } from '/src/service/priceApi'
import { Person } from '/@src/utils/types'
const notyf = useNotyf()
const showTable = ref(false)
const detailActionsOpen = ref(false)
const apprLine = defineModel<Person[]>()
const today = new Date()
const loading = ref(false)
//포커스 설정 변수 정리
const cateSelectRef = ref()
const titleRef = ref()
const contentRef = ref()
const prcsBizsRef = ref()
const generalParams = reactive({
title: "",
content: "",
regSdat: "",
regEdat: "",
prvYn: true,
prvRsn : "",
prvPwd : "",
aiYn: true,
})
const params = reactive({
cateSelect: '',
prcsAttsColumn:[ //첨부파일 입력
{ key: 'logiFnm', label: '구분'},
{ key: 'data', label: '데이터'}
],
prcsAtts: [], //첨부파일 데이터
felxColumn: [
{ key: 'gubunCd', label: '구분'},
{ key: 'deptNm', label: '부서' },
{ key: 'sabun', label: '사번' },
{ key: 'name', label: '이름' },
{ key: 'attendCd', label: '비고' },
{ key: 'actions', label: '동작'}
],
priceData:[],
prcsBizsColumn: [ //견적사 입력
{ key: 'num', label: '구분', width: '10%' },
{ key: 'email', label: '이메일', editable: true, width: '50px' },
{ key: 'bizNo', label: '사업자번호', editable: true, width: '50px'},
{ key: 'actions', label: '동작', width: '100px'}
],
prcsBizs: [], //견적사 입력 데이터
dtlSpecsColumn: [
{ key: 'num', label: '번호', editable: false },
{ key: 'itemNm', label: '품명', editable: true },
{ key: 'spec', label: '규격', editable: true },
{ key: 'unit', label: '단위', editable: true },
{ key: 'qty', label: '수량', editable: true },
{ key: '', label: '단가(VAT별도)', editable: false },
{ key: '', label: '금액(VAT별도)', editable: false },
{ key: '', label: '삭제', editable: false },
],
dtlSpecs: [], //상세 규격 입력 데이터
})
const validation = () => {
if(!params.cateSelect){
notyf.error("필수값 입니다.")
cateSelectRef.value.focus() //todo 선택박스 필수값 체크하기
console.log(params.cateSelect)
return false
}
if(!generalParams.title){
notyf.error("필수값 입니다.")
titleRef.value.focus()
return false
}
if(!generalParams.content){
notyf.error("필수값 입니다.")
contentRef.value.focus()
return false
}
if(params.prcsBizs==[]){
notyf.error("견적요청을 입력해주세요")
prcsBizsRef.value.focus()
return false
}
if(apprLine.value.length < 2){
notyf.error("결재선은 두 명이상 입력해주세요.")
return false
}
return true
}
const savePriceOne = async () => {
let res = null
try{
loading.value = true
// if (!validation()) {
// return;
// }
const paramsPrice ={
cateCd : params.cateSelect,
title: generalParams.title,
content: generalParams.content,
regSdat: formatDate(generalParams.regSdat),
regEdat: formatDate(generalParams.regEdat),
prvYn: true,
prvRsn : "",
prvPwd : "",
aiYn: true,
prcsBizs: params.prcsBizs.map(({ num, ...rest }) => rest), //견적사 입력 데이터
dtlSpecs: params.dtlSpecs.map(({ num, ...rest }) => rest), //상세 규격 입력 데이터
prcsAtts: params.prcsAtts, //첨부파일 데이터
apprReqs: apprLine.value.map(({ deptNm, ...rest }) => rest), //결재선 데이터
}
res = await savePrice(paramsPrice)
if(res.request.status == '200'){
notyf.primary('수정 되었습니다.')
router.push({path: '/app/priceManagement'})
}
}catch(e){
notyf.error(e.message)
}finally {
loading.value = false
}
}
const addNewEstimateRow = () => {
const newRow = {}
params.prcsBizsColumn.forEach(col => {
if (col.key && col.key !== 'actions') {
newRow[col.key] = ''
}
})
params.prcsBizs.push(newRow)
}
const onDelete = (index: number) => {
if(params.prcsBizs.length-1 !== params.prcsBizsColumn.length
|| (params.prcsBizsColumn.length == 4 && params.prcsBizs.length-1 == params.prcsBizsColumn.length))
{
params.prcsBizs.splice(index, 1)
}
}
const addNewDetailRow = () => {
const newRow = {}
params.dtlSpecsColumn.forEach(col => {
if (col.key) {
newRow[col.key] = ''
}
})
params.dtlSpecs.push(newRow)
console.log(params.dtlSpecs.length)
}
const onDetailDelete = (index: number) => {
if(params.dtlSpecs.length-1 !== params.dtlSpecsColumn.length
|| (params.dtlSpecsColumn.length == 8 && params.dtlSpecs.length-1 == params.dtlSpecsColumn.length))
{
params.dtlSpecs.splice(index, 1)
}
}
function formatDate(dateStr) {
if (!dateStr) return ''
const date = new Date(dateStr)
return date.toLocaleDateString('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
}).replace(/\./g, '-').replace(/\s/g, '').replace(/-$/,'')
}
const onPayDelete = (index: number) => {
if(params.dtlSpecs.length-1 !== params.dtlSpecsColumn.length
|| (params.dtlSpecsColumn.length == 8 && params.dtlSpecs.length-1 == params.dtlSpecsColumn.length))
{
params.dtlSpecs.splice(index, 1)
}
}
const fileInput = ref<HTMLInputElement | null>(null)
const fileName = ref('')
function openFileDialog() {
fileInput.value?.click()
}
function onFileChange(event: Event) {
const target = event.target as HTMLInputElement
if (target.files && target.files.length > 0) {
fileName.value = target.files[0].name
// 여기서 파일 업로드 로직을 추가할 수 있습니다.
// 예: emit('file-selected', target.files[0])
}
}
</script>
<template>
<div class="page-content is-navbar-lg">
<div class="datatable-wrapper">
<div class="table-container">
<table class="table datatable-table is-fullwidth">
<colgroup>
<col style="width: 10%;">
<col style="width: 10%;">
<col style="width: 10%;">
<col style="width: 10%;">
<col style="width: 10%;">
<col style="width: 10%;">
<col style="width: 10%;">
<col style="width: 10%;">
<col style="width: 10%;">
<col style="width: 10%;">
</colgroup>
<tbody>
<tr>
<td>분야</td>
<td colspan="2">
<span class="column">
<VField class="pr-2">
<VCodeSelect
cd_grp=5
v-model="params.cateSelect"
ref="cateSelectRef"/>
</VField>
</span>
</td>
<td>제목</td>
<td colspan="6">
<div class="column is-fullhd">
<VField class="pr-2">
<VControl>
<input
v-model="generalParams.title"
class="input custom-text-filter"
placeholder="제목"
ref="titleRef"
>
</VControl>
</VField>
</div>
</td>
</tr>
<tr>
<td>내용</td>
<td colspan="9">
<div class="column is-fullhd">
<VField class="pr-2">
<VControl>
<textarea
v-model="generalParams.content"
class="input custom-text-filter"
placeholder="내용"
ref="contentRef"
/>
</VControl>
</VField>
</div>
</td>
</tr>
<tr>
<td>견적요청</td>
<td colspan="9">
<VButton
color="primary"
icon="fas fa-plus"
elevated
@click="showTable = !showTable"
style="width: 19%;"
>
견적사 입력
</VButton>
<div v-if="showTable" class="mt-2">
<ComVFlexTable
:key="params.prcsBizs.length"
:data="params.prcsBizs"
:columns="params.prcsBizsColumn"
:compact="true"
:separators="true"
:clickable="true"
>
<template #body-cell="{ row, column, index, value }">
<div>
<!-- 다른 editable 컬럼은 input -->
<input
v-if="column.editable"
v-model="row[column.key]"
class="editable-input"
ref="prcsBizsRef"
/>
<span v-else-if="column.key=='num'">{{index + 1}}</span>
<!-- readonly 출력 -->
<span v-else class="lnil lnil-close"
@click="onDelete(index)">{{ value }}</span>
</div>
</template>
</ComVFlexTable>
<div class="mt-2">
<VButton
color="primary"
icon="fas fa-plus"
@click="addNewEstimateRow"
>
추가
</VButton>
</div>
</div>
</td>
</tr>
<tr>
<td>규격입력</td>
<td colspan="2">
<VButton
color="primary"
icon="fas fa-plus"
elevated
@click="detailActionsOpen = true"
style="width: 100%;"
>
상세 규격 입력
</VButton>
<VModal
:open="detailActionsOpen"
actions="center"
title="상세 규격 입력"
size="contract-big"
@close="detailActionsOpen = false"
>
<template #content>
<VButton color="success">일괄업로드</VButton>
<ComVFlexTable
:key="params.dtlSpecs.length"
:data="params.dtlSpecs"
:columns="params.dtlSpecsColumn"
:separators="true"
:clickable="true"
>
<template #body-cell="{ row, column, index, value }">
<!-- : 특정 컬럼이면 input, 아니면 그냥 출력 -->
<div>
<input
v-if="column.editable"
v-model="row[column.key]"
class="editable-input"
/>
<span v-else-if="column.key=='num'">{{index+1}}</span>
<span v-else class="lnil lnil-close"
@click="onDetailDelete(index)">{{ value }}</span>
</div>
</template>
</ComVFlexTable>
<div class="mt-2">
<VButton
color="primary"
icon="fas fa-plus"
@click="addNewDetailRow"
>
추가
</VButton>
</div>
</template>
<template #action>
<VButton color="primary">
등록
</VButton>
</template>
</VModal>
</td>
<td>등록기간</td>
<td colspan="5">
<div class="columns">
<div class="column is-5">
<VDatePicker
v-model="generalParams.regSdat"
color="green"
trim-weeks
>
<template #default="{ inputValue, inputEvents }">
<VField>
<VControl icon="lucide:calendar">
<input
class="input v-input"
type="text"
:value="inputValue"
v-on="inputEvents"
placeholder="시작일"
>
</VControl>
</VField>
</template>
</VDatePicker>
</div>
<div style="transform: translateY(15px)">~</div>
<div class="column is-5">
<VDatePicker
v-model="generalParams.regEdat"
color="green"
trim-weeks
:minDate="today"
>
<template #default="{ inputValue, inputEvents }">
<VField>
<VControl icon="lucide:calendar">
<input
class="input v-input"
type="text"
:value="inputValue"
v-on="inputEvents"
placeholder="종료일"
>
</VControl>
</VField>
</template>
</VDatePicker>
</div>
</div>
</td>
</tr>
<tr>
<td>첨부파일</td>
<td colspan="10">
<VField class="file has-name is-left">
<VButton @click="openFileDialog">
파일 첨부
</VButton>
<input
ref="fileInput"
type="file"
style="display: none"
@change="onFileChange"
/>
<span v-if="fileName" class="file-name">{{ fileName }}</span>
</VField>
</td>
</tr>
</tbody>
</table>
</div>
<div class="column is-12">
<VUser v-model="apprLine"/>
</div>
<div class="column is-12">
<VField class="pr-2">
<VLabel class="has-fullwidth">
결재선
</VLabel>
</VField>
<ComVFlexTable
:data="apprLine"
:columns="params.felxColumn"
:separators="true"
:clickable="true"
:compact="true">
<template #body-cell="{ row, column, index, value }">
<!-- : 특정 컬럼이면 input, 아니면 그냥 출력 -->
<div>
<!-- <span v-if="column.key=='gubunCd' && index == 0" class="column">-->
<!-- {{row.gubunNm}}-->
<!-- </span>-->
<span v-if="column.key=='gubunCd'" class="column">
<VField class="pr-1">
<VCodeSelect
cd_grp=7
v-model="row.gubunCd"
/>
<!-- :disabled="index === 0"-->
</VField>
</span>
<span v-else-if="column.key=='attendCd' && index != 0" class="column">
<VField class="pr-1">
<VCodeSelect
placeholder="재중"
cd_grp=6
v-model="row.attendCd"/>
</VField>
</span>
<span v-else
@click="onDetailDelete(index)">{{value}}</span>
</div>
</template>
</ComVFlexTable>
</div>
<VButton
color="primary"
@click.stop="savePriceOne"
raised>
등록
</VButton>
</div>
</div>
</template>
<style scoped lang="scss">
.table tbody td {
color: var(--smoke-white);
}
.datatable-table {
padding: 12px 12px;
td:nth-child(1) {
background-color: var(--primary);
}
td:nth-child(3) {
background-color: var(--primary);
}
}
</style>