mirror of
https://git.hmsn.ink/kospo/svcm/oa.git
synced 2026-03-20 11:53:38 +09:00
first
This commit is contained in:
435
src/pages/app/ContractInsert.vue
Normal file
435
src/pages/app/ContractInsert.vue
Normal file
@@ -0,0 +1,435 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
const registerFormOpen = ref(false)
|
||||
const params = reactive({
|
||||
cateCd: '',
|
||||
contNo: '',
|
||||
title: '',
|
||||
compNm: '',
|
||||
signDt: '',
|
||||
contAmt: '',
|
||||
contStatCd: '',
|
||||
contStat: '',
|
||||
regsabun: '',
|
||||
regNm: '',
|
||||
regDt: '',
|
||||
reason: '',
|
||||
page: 1,
|
||||
row: 10,
|
||||
flexColumn: [],
|
||||
modalColumn: [],
|
||||
})
|
||||
|
||||
params.modalColumn = [
|
||||
{ key: 'cateNm', label: '분야' },
|
||||
{ key: 'title', label: '제목' },
|
||||
{ key: 'regNm', label: '담당자' },
|
||||
{ key: 'stNm', label: '등록상태' },
|
||||
{ key: 'title', label: '비고' },
|
||||
{ key: 'regNm', label: '선택' },
|
||||
]
|
||||
const selectedCode = ref()
|
||||
|
||||
const data = reactive({
|
||||
contractData: [],
|
||||
priceSearchData: [],
|
||||
})
|
||||
|
||||
const isLoading = ref(false)
|
||||
watch(registerFormOpen, async (isOpen) => {
|
||||
if (isOpen) {
|
||||
isLoading.value = true
|
||||
// error.value = null
|
||||
try {
|
||||
const priceSearchDataRespone = await axios.get('/api/cont/prcs')
|
||||
console.log(priceSearchDataRespone.data)
|
||||
data.priceSearchData = Array.isArray(priceSearchDataRespone.data) ? priceSearchDataRespone.data : []
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
data.priceData = []
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
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(/-$/, '')
|
||||
}
|
||||
|
||||
function getDateDiff(start, end) {
|
||||
if (!start || !end) return null
|
||||
const startDate = new Date(start)
|
||||
const endDate = new Date(end)
|
||||
const diff = Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24))
|
||||
return diff >= 0 ? diff + 1 : null
|
||||
}
|
||||
|
||||
const contractPeriod = computed(() => {
|
||||
const start = params.regSdt
|
||||
const end = params.regEdt
|
||||
const startStr = formatDate(start)
|
||||
const endStr = formatDate(end)
|
||||
const diff = getDateDiff(start, end)
|
||||
if (startStr && endStr && diff) {
|
||||
return `${startStr} ~ ${endStr} (${diff}일)`
|
||||
}
|
||||
else if (startStr && endStr) {
|
||||
return `${startStr} ~ ${endStr}`
|
||||
}
|
||||
else if (startStr) {
|
||||
return `${startStr} ~`
|
||||
}
|
||||
else if (endStr) {
|
||||
return `~ ${endStr}`
|
||||
}
|
||||
else {
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
</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: 20%;">
|
||||
<col style="width: 20%;">
|
||||
<col style="width: 10%;">
|
||||
<col style="width: 10%;">
|
||||
<col style="width: 20%;">
|
||||
<col style="width: 10%;">
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>분야</td>
|
||||
<td>
|
||||
<span class="colum">
|
||||
<VField class="pr-2">
|
||||
<VCodeSelect
|
||||
v-model="selectedCode"
|
||||
cd_grp="5/"
|
||||
/></VField>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<VButton
|
||||
color="primary"
|
||||
@click="registerFormOpen = true"
|
||||
>
|
||||
가격조사 가져오기
|
||||
</VButton>
|
||||
<VModal
|
||||
is="form"
|
||||
:open="registerFormOpen"
|
||||
title="계약관리 등록"
|
||||
size="contract-big"
|
||||
actions="right"
|
||||
@submit.prevent="registerFormOpen = false"
|
||||
@close="registerFormOpen = false"
|
||||
>
|
||||
<template #content>
|
||||
<div class="modal-form">
|
||||
<ComVFlexTable
|
||||
:data="data.priceSearchData"
|
||||
:columns="params.modalColumn"
|
||||
:compact="true"
|
||||
:separators="true"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #action>
|
||||
<VButton
|
||||
type="submit"
|
||||
color="primary"
|
||||
raised
|
||||
>
|
||||
Save Changes
|
||||
</VButton>
|
||||
</template>
|
||||
</VModal>
|
||||
</td>
|
||||
<td>
|
||||
<VField class="is-flex">
|
||||
<VControl raw subcontrol>
|
||||
<VCheckbox
|
||||
label="가격조사여부"
|
||||
color="info"
|
||||
/>
|
||||
</VControl>
|
||||
</VField>
|
||||
</td>
|
||||
<td colspan="3">
|
||||
<div class="column is-fullhd">
|
||||
<VField>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.reason"
|
||||
class="input custom-text-filter"
|
||||
placeholder="가격조사 안했을 시 예외 사유 입력(필수)"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>계약명</td>
|
||||
<td colspan="6">
|
||||
<VField>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.title"
|
||||
class="input custom-text-filter"
|
||||
placeholder="계약명"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>계약상대자</td>
|
||||
<td>
|
||||
<VField>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.regNm"
|
||||
class="input custom-text-filter"
|
||||
placeholder="사업자번호"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</td>
|
||||
<td>
|
||||
<VField>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.compNm"
|
||||
class="input custom-text-filter"
|
||||
placeholder="업체명"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</td>
|
||||
<td>
|
||||
<VButton color="warning">
|
||||
부정당 확인
|
||||
</VButton>
|
||||
</td>
|
||||
<td>
|
||||
<VButton color="success">
|
||||
정상
|
||||
</VButton>
|
||||
</td>
|
||||
<td>
|
||||
<VButton color="warning">
|
||||
분할계약 확인
|
||||
</VButton>
|
||||
</td>
|
||||
<td>
|
||||
<VButton color="success">
|
||||
정상
|
||||
</VButton>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>계약체결일</td>
|
||||
<td>
|
||||
<VField>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.signDt"
|
||||
class="input custom-text-filter"
|
||||
placeholder="계약체결일"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</td>
|
||||
<td>
|
||||
<VButton
|
||||
color="primary"
|
||||
>
|
||||
계 약 금 액
|
||||
</VButton>
|
||||
<VModal
|
||||
actions="center"
|
||||
title="계약금액"
|
||||
>
|
||||
<template #content>
|
||||
<VPlaceholderSection
|
||||
title="Go Premium"
|
||||
subtitle="Unlock more features and business tools by going premium"
|
||||
/>
|
||||
</template>
|
||||
<template #action>
|
||||
<VButton color="primary" raised>
|
||||
등록
|
||||
</VButton>
|
||||
</template>
|
||||
</VModal>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<VField>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.contAmt"
|
||||
class="input custom-text-filter"
|
||||
placeholder="금액"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</td>
|
||||
<td colspan="1">
|
||||
<span class="colum">
|
||||
<VField>
|
||||
<VSelect>
|
||||
<VOption value="">
|
||||
수의계약 사유
|
||||
</VOption>
|
||||
</VSelect>
|
||||
</VField>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<VButton>근거</VButton>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>계약기간</td>
|
||||
<td colspan="1">
|
||||
<div>
|
||||
<div>
|
||||
<VDatePicker
|
||||
v-model="params.regSdt"
|
||||
color="green"
|
||||
trim-weeks
|
||||
>
|
||||
<template #default="{ inputValue, inputEvents }">
|
||||
<VField>
|
||||
<VControl icon="lucide:calendar">
|
||||
<input
|
||||
class="input v-input"
|
||||
type="text"
|
||||
:value="inputValue"
|
||||
placeholder="시작일"
|
||||
v-on="inputEvents"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</template>
|
||||
</VDatePicker>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td colspan="1">
|
||||
<div class="pr-2">
|
||||
<div>
|
||||
<VDatePicker
|
||||
v-model="params.regEdt"
|
||||
color="green"
|
||||
trim-weeks
|
||||
>
|
||||
<template #default="{ inputValue, inputEvents }">
|
||||
<VField>
|
||||
<VControl icon="lucide:calendar">
|
||||
<input
|
||||
class="input v-input"
|
||||
type="text"
|
||||
:value="inputValue"
|
||||
placeholder="종료일"
|
||||
v-on="inputEvents"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</template>
|
||||
</VDatePicker>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td colspan="5">
|
||||
계약기간 : {{ contractPeriod }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>첨부파일</td>
|
||||
<td colspan="1">
|
||||
<VButton color="info">
|
||||
등록
|
||||
</VButton>
|
||||
</td>
|
||||
<td colspan="5" />
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="bottom-button">
|
||||
<VButton
|
||||
to="/app/DocumentManagement"
|
||||
>
|
||||
전 표 (임시)
|
||||
</VButton>
|
||||
<VButton>저 장</VButton>
|
||||
<VButton>취 소</VButton>
|
||||
</div>
|
||||
</div>
|
||||
</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);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
tr:nth-child(3) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
tr td button{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
tr:nth-child(5) > td:nth-child(4) {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-button {
|
||||
text-align: center;
|
||||
button {
|
||||
background-color: cornflowerblue;
|
||||
margin: 10px;
|
||||
font-weight: bold;
|
||||
border-color: var(--primary);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
button:nth-child(2) {
|
||||
background-color: #AB9A6c;
|
||||
}
|
||||
button:nth-child(3) {
|
||||
background-color: silver;
|
||||
}
|
||||
.field {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
</style>
|
||||
389
src/pages/app/DocumentManagement.vue
Normal file
389
src/pages/app/DocumentManagement.vue
Normal file
@@ -0,0 +1,389 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
const affiliationCode = ref()
|
||||
const taxCode = ref('')
|
||||
const currencyCode = ref('KRW')
|
||||
const taxInvoiceCode = ref()
|
||||
const accountSubjectCode = ref()
|
||||
const params = reactive({
|
||||
cateCd: '',
|
||||
contNo: '',
|
||||
title: '',
|
||||
compNm: '',
|
||||
signDt: '',
|
||||
contAmt: 0,
|
||||
contStatCd: '',
|
||||
contStat: '',
|
||||
regsabun: '',
|
||||
regNm: '',
|
||||
regDt: '',
|
||||
reason: '',
|
||||
page: 1,
|
||||
row: 10,
|
||||
flexColumn: [],
|
||||
modalColumn: [],
|
||||
})
|
||||
const selected = ref('cost')
|
||||
const formattedNumber = ref(0)
|
||||
|
||||
function onInput(event) {
|
||||
let onlyNumber = event.target.value.replace(/[^0-9]/g, '')
|
||||
formattedNumber.value = onlyNumber ? Number(onlyNumber).toLocaleString() : ''
|
||||
}
|
||||
|
||||
</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">
|
||||
<VField>
|
||||
<VCodeSelect
|
||||
v-model="affiliationCode"
|
||||
cd_grp=11 >
|
||||
</VCodeSelect>
|
||||
</VField>
|
||||
</td>
|
||||
<td colspan="7" />
|
||||
</tr>
|
||||
<tr>
|
||||
<td>계약명</td>
|
||||
<td colspan="9">
|
||||
<VField>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.title"
|
||||
class="input custom-text-filter"
|
||||
placeholder="계약명"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>계약상대자</td>
|
||||
<td colspan="2">
|
||||
<VField>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.regNm"
|
||||
class="input custom-text-filter"
|
||||
placeholder="사업자번호"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<VField>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.title"
|
||||
class="input custom-text-filter"
|
||||
placeholder="업체명"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</td>
|
||||
<td>
|
||||
<VButton color="danger">
|
||||
구매처 확인
|
||||
</VButton>
|
||||
</td>
|
||||
<td>
|
||||
<VButton color="success">
|
||||
정상
|
||||
</VButton>
|
||||
</td>
|
||||
<td colspan="2" />
|
||||
</tr>
|
||||
<tr>
|
||||
<td>공급가액</td>
|
||||
<td colspan="2">
|
||||
<VField>
|
||||
<VControl>
|
||||
<input
|
||||
:value="formattedNumber"
|
||||
placeholder="금액"
|
||||
@input="onInput"
|
||||
class="input custom-text-filter"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</td>
|
||||
<td style="color: black">(부가세 별도)</td>
|
||||
<td style="background-color: var(--primary); text-align: center">
|
||||
<span>세금코드</span>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<VField>
|
||||
<VCodeSelect v-model="taxCode" cd_grp="12">
|
||||
<template #code="{ item }">
|
||||
{{ item.cd }}
|
||||
</template>
|
||||
</VCodeSelect>
|
||||
</VField>
|
||||
</td>
|
||||
<td style="background-color: var(--primary); text-align: center">통화</td>
|
||||
<td colspan="2">
|
||||
<VField>
|
||||
<VCodeSelect v-model="currencyCode" cd_grp="13">
|
||||
<template #code="{ item }">
|
||||
{{ item.cd }}
|
||||
</template>
|
||||
</VCodeSelect>
|
||||
</VField>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>증빙일</td>
|
||||
<td colspan="2">
|
||||
<div>
|
||||
<VDatePicker
|
||||
v-model="params.regSdt"
|
||||
color="green"
|
||||
trim-weeks
|
||||
>
|
||||
<template #default="{ inputValue, inputEvents }">
|
||||
<VField>
|
||||
<VControl icon="lucide:calendar">
|
||||
<input
|
||||
class="input v-input"
|
||||
type="text"
|
||||
:value="inputValue"
|
||||
placeholder="증빙일"
|
||||
v-on="inputEvents"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</template>
|
||||
</VDatePicker>
|
||||
</div>
|
||||
</td>
|
||||
<td />
|
||||
<td style="background-color: var(--primary); text-align: center">
|
||||
<span>전기일</span>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<div>
|
||||
<VDatePicker
|
||||
v-model="params.regSdt2"
|
||||
color="green"
|
||||
trim-weeks
|
||||
>
|
||||
<template #default="{ inputValue, inputEvents }">
|
||||
<VField>
|
||||
<VControl icon="lucide:calendar">
|
||||
<input
|
||||
class="input v-input"
|
||||
type="text"
|
||||
:value="inputValue"
|
||||
placeholder="전기일"
|
||||
v-on="inputEvents"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</template>
|
||||
</VDatePicker>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>계좌관리</td>
|
||||
<td>
|
||||
<VField>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.title"
|
||||
class="input custom-text-filter"
|
||||
placeholder="계약번호"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<VField>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.title"
|
||||
class="input custom-text-filter"
|
||||
placeholder="계좌번호"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</td>
|
||||
<td>
|
||||
<VButton color="info">
|
||||
계좌조회
|
||||
</VButton>
|
||||
</td>
|
||||
<td >
|
||||
<VButton color="warning">
|
||||
계좌확인중
|
||||
</VButton>
|
||||
</td>
|
||||
<td>
|
||||
<VButton color="success">
|
||||
정상
|
||||
</VButton>
|
||||
</td>
|
||||
<td style="background-color: var(--primary); text-align: center">
|
||||
<span>세금계산서</span>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<VField>
|
||||
<VCodeSelect
|
||||
v-model="taxInvoiceCode"
|
||||
cd_grp=12 >
|
||||
</VCodeSelect>
|
||||
</VField>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>예산관리</td>
|
||||
<td>
|
||||
<VButton
|
||||
color="primary"
|
||||
@click="centeredActionsOpen = true"
|
||||
>
|
||||
G/L계정
|
||||
</VButton>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<VField>
|
||||
<VCodeSelect
|
||||
v-model="accountSubjectCode"
|
||||
cd_grp=12 >
|
||||
</VCodeSelect>
|
||||
</VField>
|
||||
</td>
|
||||
<td>
|
||||
<VButton
|
||||
color="info"
|
||||
@click="selected = 'cost'"
|
||||
:class="{ 'disabled-button': selected === 'wbs' }"
|
||||
>
|
||||
코스트센터
|
||||
</VButton>
|
||||
</td>
|
||||
<td>
|
||||
<VButton
|
||||
color="info"
|
||||
@click="selected = 'wbs'"
|
||||
:class="{ 'disabled-button': selected === 'cost' }"
|
||||
>
|
||||
WBS
|
||||
</VButton>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<VField>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.title"
|
||||
class="input custom-text-filter"
|
||||
placeholder="코드"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>첨부파일</td>
|
||||
<td colspan="1">
|
||||
<VButton color="info">
|
||||
등록
|
||||
</VButton>
|
||||
</td>
|
||||
<td colspan="5">
|
||||
<div>('준공보고서' 또는 '검수보고서' 등)</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="bottom-button">
|
||||
<VButton>전 표 생 성</VButton>
|
||||
<VButton>취 소</VButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.table tbody td {
|
||||
color: var(--smoke-white);
|
||||
|
||||
}
|
||||
|
||||
.datatable-table {
|
||||
td{
|
||||
font-family: var(--font),serif;
|
||||
vertical-align: middle;
|
||||
padding: 4px 20px;
|
||||
border-bottom: 1px solid var(--fade-grey);
|
||||
}
|
||||
|
||||
td:nth-child(1) {
|
||||
background-color: var(--primary);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
tr:nth-child(3) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
tr td button{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.bottom-button {
|
||||
text-align: center;
|
||||
button {
|
||||
background-color: cornflowerblue;
|
||||
margin: 10px;
|
||||
font-weight: bold;
|
||||
border-color: var(--primary);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
button:nth-child(2) {
|
||||
background-color: #AB9A6c;
|
||||
}
|
||||
button:nth-child(3) {
|
||||
background-color: silver;
|
||||
}
|
||||
|
||||
.field {
|
||||
margin: 0px 0px;
|
||||
}
|
||||
|
||||
.button.v-button {
|
||||
padding: 0px 0px;
|
||||
}
|
||||
|
||||
.disabled-button {
|
||||
//opacity: 0.5;
|
||||
background-color: #ccc;
|
||||
cursor: not-allowed;
|
||||
//transition: all 0.2s;
|
||||
}
|
||||
|
||||
</style>
|
||||
521
src/pages/app/PriceInsert.vue
Normal file
521
src/pages/app/PriceInsert.vue
Normal 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>
|
||||
187
src/pages/app/approval.vue
Normal file
187
src/pages/app/approval.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<script setup lang="ts">
|
||||
import { getPriceList } from '/@src/service/price'
|
||||
|
||||
onBeforeMount(async () => {
|
||||
await getPriceListData()
|
||||
})
|
||||
|
||||
const selectedCode = ref()
|
||||
const paymentCode = ref()
|
||||
|
||||
|
||||
const emits = defineEmits(['on-tr-click'])
|
||||
const masks = ref({
|
||||
modelValue: 'YYYY-MM-DD',
|
||||
})
|
||||
|
||||
const params = reactive({
|
||||
priceData: [],
|
||||
felxColumn: [
|
||||
{ key: 'cateNm', label: '분야' },
|
||||
{ key: 'title', label: '제목' },
|
||||
{ key: 'regNm', label: '담당자' },
|
||||
{ key: 'regSdat', label: '최초등록일' },
|
||||
{ key: 'stNm', label: '등록 상태' },
|
||||
{ key: 'title', label: '비고' }
|
||||
],
|
||||
prcsParams: []
|
||||
})
|
||||
|
||||
async function getPriceListData(){
|
||||
params.prcsParams = {
|
||||
params:{
|
||||
regSdt: '1970-01-01',
|
||||
regEdt: '2070-01-01',
|
||||
page: '1',
|
||||
row: '3'
|
||||
}
|
||||
}
|
||||
const result = await getPriceList(params.prcsParams)
|
||||
params.priceData = result.content
|
||||
}
|
||||
|
||||
const searchPrice = () => {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-content is-navbar-lg">
|
||||
<div>
|
||||
<div class="datatable-toolbar">
|
||||
<div class="column is-2">
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
분야
|
||||
</VLabel>
|
||||
<VCodeSelect
|
||||
cd_grp=5
|
||||
v-model="selectedCode"/>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-2">
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
결제상태
|
||||
</VLabel>
|
||||
<VCodeSelect
|
||||
cd_grp=2
|
||||
v-model="paymentCode"/>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-2">
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
담당자
|
||||
</VLabel>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.title"
|
||||
class="input custom-text-filter"
|
||||
placeholder="담당자"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-5">
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
등록기간
|
||||
</VLabel>
|
||||
<VControl>
|
||||
<div class="columns">
|
||||
<div class="column is-6">
|
||||
<VDatePicker
|
||||
v-model.string="params.regSdt"
|
||||
color="green"
|
||||
:masks="masks"
|
||||
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-6">
|
||||
<VDatePicker
|
||||
v-model.string="params.regEdt"
|
||||
color="green"
|
||||
:masks="masks"
|
||||
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>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-1">
|
||||
<div style="padding-top:20px;float:right;">
|
||||
<VButtons>
|
||||
<VButton
|
||||
color="primary"
|
||||
elevated
|
||||
icon="fas fa-search"
|
||||
@click.stop="searchPrice"
|
||||
>
|
||||
검색
|
||||
</VButton>
|
||||
</VButtons>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="datatable-wrapper">
|
||||
<ComVFlexTable
|
||||
:data="params.priceData"
|
||||
:columns="params.felxColumn"
|
||||
:separators="true"
|
||||
:clickable="true"
|
||||
:compact="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<VButtons class="v-buttons-right-align">
|
||||
<VButton
|
||||
color="primary"
|
||||
icon="fas fa-plus"
|
||||
elevated
|
||||
to="/app/PriceInsert"
|
||||
>
|
||||
등록
|
||||
</VButton>
|
||||
</VButtons>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.v-buttons-right-align {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 1rem; // 필요 시 간격 추가
|
||||
}
|
||||
|
||||
</style>
|
||||
255
src/pages/app/contractManagement.vue
Normal file
255
src/pages/app/contractManagement.vue
Normal file
@@ -0,0 +1,255 @@
|
||||
<script setup lang="ts">
|
||||
import axios from 'axios'
|
||||
import {useRouter} from "vue-router";
|
||||
|
||||
export type MinimalTheme = 'darker' | 'light'
|
||||
|
||||
const emits = defineEmits(['on-search', 'on-tr-click'])
|
||||
const selUser = ref()
|
||||
const masks = ref({
|
||||
modelValue: 'YYYY-MM-DD',
|
||||
})
|
||||
|
||||
const selectedCode = ref()
|
||||
|
||||
watch(selUser, (value) => {
|
||||
console.log(value)
|
||||
})
|
||||
|
||||
const data = reactive({
|
||||
contractData: [],
|
||||
priceData: [],
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const contractResponse = await axios.get('/api/cont/prcs')
|
||||
data.contractData = Array.isArray(contractResponse.data) ? contractResponse.data : []
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
data.contractData = []
|
||||
}
|
||||
})
|
||||
|
||||
const registerFormOpen = ref(false)
|
||||
const isLoading = ref(false)
|
||||
|
||||
watch(registerFormOpen, async (isOpen) => {
|
||||
if (isOpen) {
|
||||
isLoading.value = true
|
||||
// error.value = null
|
||||
try {
|
||||
const priceResponse = await axios.get('/api/prcs/page?regSdt=1970-01-01®Edt=2070-01-01&page=1&row=10')
|
||||
console.log(priceResponse.data.content)
|
||||
data.priceData = Array.isArray(priceResponse.data.content) ? priceResponse.data.content : []
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error)
|
||||
data.priceData = []
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
function handleRowClick(row) {
|
||||
router.push({
|
||||
name: 'DocumentManagement',
|
||||
params: { id: row.contractDetailedData },
|
||||
})
|
||||
}
|
||||
const params = reactive({
|
||||
priceData: [],
|
||||
flexColumn: [
|
||||
{ key: 'cateNm', label: '분야' },
|
||||
{ key: 'title', label: '제목' },
|
||||
{ key: 'regNm', label: '담당자' },
|
||||
{ key: 'regSdat', label: '최초등록일' },
|
||||
{ key: 'stNm', label: '등록 상태' },
|
||||
{ key: 'title', label: '비고' },
|
||||
],
|
||||
prcsParams: [],
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-content is-navbar-lg">
|
||||
<div>
|
||||
<div class="datatable-toolbar">
|
||||
<div class="column is-2">
|
||||
<!-- <VUserList v-model="selUser"/>-->
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
분야
|
||||
</VLabel>
|
||||
<VCodeSelect
|
||||
cd_grp=5
|
||||
v-model="selectedCode"/>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-2">
|
||||
<!-- <VUserList v-model="selUser"/>-->
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
계약번호
|
||||
</VLabel>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.title"
|
||||
class="input custom-text-filter"
|
||||
placeholder="계약번호"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-2">
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
담당자
|
||||
</VLabel>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.title"
|
||||
class="input custom-text-filter"
|
||||
placeholder="담당자명"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-5">
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
계약일
|
||||
</VLabel>
|
||||
<VControl>
|
||||
<div class="columns">
|
||||
<div class="column is-6">
|
||||
<VDatePicker
|
||||
v-model="params.regSdt"
|
||||
color="green"
|
||||
:masks="masks"
|
||||
trim-weeks
|
||||
>
|
||||
<template #default="{ inputValue, inputEvents }">
|
||||
<VField>
|
||||
<VControl icon="lucide:calendar">
|
||||
<input
|
||||
class="input v-input"
|
||||
type="text"
|
||||
:value="inputValue"
|
||||
placeholder="시작일"
|
||||
v-on="inputEvents"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</template>
|
||||
</VDatePicker>
|
||||
</div>
|
||||
<div style="transform: translateY(15px)">
|
||||
~
|
||||
</div>
|
||||
<div class="column is-6">
|
||||
<VDatePicker
|
||||
v-model="params.regEdt"
|
||||
color="green"
|
||||
:masks="masks"
|
||||
trim-weeks
|
||||
>
|
||||
<template #default="{ inputValue, inputEvents }">
|
||||
<VField>
|
||||
<VControl icon="lucide:calendar">
|
||||
<input
|
||||
class="input v-input"
|
||||
type="text"
|
||||
:value="inputValue"
|
||||
placeholder="종료일"
|
||||
v-on="inputEvents"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</template>
|
||||
</VDatePicker>
|
||||
</div>
|
||||
</div>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-1" style="position:relative;">
|
||||
<div style="padding-top:20px;float:right;">
|
||||
<VButtons>
|
||||
<VButton
|
||||
color="primary"
|
||||
elevated
|
||||
icon="fas fa-search"
|
||||
@click.stop="emits('on-search', params)"
|
||||
>
|
||||
검색
|
||||
</VButton>
|
||||
</VButtons>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="datatable-wrapper">
|
||||
<ComVFlexTable
|
||||
:data="data.contractData"
|
||||
:columns="params.flexColumn"
|
||||
:separators="true"
|
||||
:clickable="true"
|
||||
:rounded="true"
|
||||
:compact="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<VButtons>
|
||||
<VButton
|
||||
color="primary"
|
||||
icon="fas fa-plus"
|
||||
elevated
|
||||
to="/app/ContractInsert"
|
||||
style="margin-top: 20px"
|
||||
>
|
||||
등록
|
||||
</VButton>
|
||||
</VButtons>
|
||||
|
||||
<!-- 모달창 시작-->
|
||||
<VModal
|
||||
is="form"
|
||||
:open="registerFormOpen"
|
||||
title="계약관리 등록"
|
||||
size="contract-big"
|
||||
actions="right"
|
||||
@submit.prevent="registerFormOpen = false"
|
||||
@close="registerFormOpen = false"
|
||||
>
|
||||
<template #content>
|
||||
<div class="modal-form">
|
||||
<ComVFlexTable
|
||||
:data="data.priceData"
|
||||
:columns="{ cateNm: '분야',
|
||||
title: '제목',
|
||||
content: '담당자',
|
||||
stNm: '등록상태',
|
||||
stCd: '비고',
|
||||
regSabun: '선택',
|
||||
}"
|
||||
:compact="true"
|
||||
:separators="true"
|
||||
@row-click="handleRowClick"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #action>
|
||||
<VButton
|
||||
type="submit"
|
||||
color="primary"
|
||||
raised
|
||||
>
|
||||
Save Changes
|
||||
</VButton>
|
||||
</template>
|
||||
</VModal>
|
||||
</div>>
|
||||
</template>
|
||||
5
src/pages/app/index.vue
Normal file
5
src/pages/app/index.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- Your content here -->
|
||||
</div>
|
||||
</template>
|
||||
481
src/pages/app/paymentManagement.vue
Normal file
481
src/pages/app/paymentManagement.vue
Normal file
@@ -0,0 +1,481 @@
|
||||
<script setup lang="ts">
|
||||
// import { getIntegratedApproval } from '/src/service/integratedApprovalApi'
|
||||
import { getIntegratedApproval, updateIntegratedApproval } from '/src/service/integratedPayment'
|
||||
import type { VFlexTableWrapperSortFunction, VFlexTableWrapperFilterFunction } from '/src/components/app-vuero/ComVFlexTableWrapper.vue'
|
||||
import { users } from '/src/data/layouts/card-grid-v1'
|
||||
|
||||
onBeforeMount(async () => {
|
||||
await getIntegratedPaymentList()
|
||||
})
|
||||
const isModalOpen = ref(false)
|
||||
const selectedRow = ref<any>(null)
|
||||
|
||||
const masks = ref({
|
||||
modelValue: 'YYYY-MM-DD',
|
||||
})
|
||||
|
||||
const params = reactive({
|
||||
title: '',
|
||||
priceData: [],
|
||||
flexColumn: [
|
||||
{ key: 'apprNo', label: '결재번호', cellClass: 'paymentColumn1' },
|
||||
{ key: 'title', label: '제목', cellClass: 'paymentColumn2' },
|
||||
{ key: 'name', label: '작성자', cellClass: 'paymentColumn3' },
|
||||
{
|
||||
key: 'regDt',
|
||||
label: '등록일',
|
||||
cellClass: 'paymentColumn4',
|
||||
format: formatRegDt,
|
||||
},
|
||||
{ key: 'process', label: '구분', cellClass: 'paymentColumn5' },
|
||||
],
|
||||
flexWrapperColumn: {
|
||||
apprNo: { label: '결재번호', cellClass: 'paymentColumn1', searchable: true, sortable: true },
|
||||
title: { label: '제목', cellClass: 'paymentColumn2', searchable: true, sortable: true },
|
||||
name: { label: '작성자', cellClass: 'paymentColumn3', searchable: true, sortable: true },
|
||||
regDt: { label: '등록일', cellClass: 'paymentColumn4', searchable: true, sortable: true },
|
||||
process: { label: '구분', cellClass: 'paymentColumn5', searchable: true, sortable: true },
|
||||
},
|
||||
paymentParams: [],
|
||||
})
|
||||
|
||||
function formatRegDt(value) {
|
||||
return value ? value.substring(0, 16) : ''
|
||||
}
|
||||
|
||||
async function getIntegratedPaymentList() {
|
||||
const paymentParams = {
|
||||
title: '',
|
||||
page: '1',
|
||||
row: '10',
|
||||
sabun: '17131303',
|
||||
}
|
||||
const result = await getIntegratedApproval(paymentParams)
|
||||
params.paymentParams = result.content.map(item => ({
|
||||
...item,
|
||||
process: gubunMap[item.gubun] || '',
|
||||
}))
|
||||
}
|
||||
|
||||
async function updateIntegratedPaymentList() {
|
||||
const paymentUpdateParams = {
|
||||
apprNo: selectedRow.value.apprNo,
|
||||
apprOrd: selectedRow.value.apprOrd,
|
||||
apprStatCd: '0200', // 결재 상태변경 (결재승인 0200 결재회수 0300 결재반려 0400)
|
||||
reason: '',
|
||||
sabun: selectedRow.value.sabun,
|
||||
}
|
||||
const result = await updateIntegratedApproval(paymentUpdateParams)
|
||||
console.log(result)
|
||||
alert('결재승인완료')
|
||||
window.location.reload(true)
|
||||
}
|
||||
|
||||
const gubunMap = {
|
||||
SAP: '전표생성',
|
||||
SVCM: '가격조사',
|
||||
}
|
||||
|
||||
const searchApproval = async () => {
|
||||
const paymentParams = {
|
||||
params: {
|
||||
title: params.title,
|
||||
page: '1',
|
||||
row: '10',
|
||||
},
|
||||
}
|
||||
const result = await getIntegratedApproval(paymentParams)
|
||||
params.paymentParams = result.content
|
||||
console.log(params.paymentParams)
|
||||
}
|
||||
|
||||
type User = (typeof users)[0]
|
||||
|
||||
// duplicate user data to grow the array
|
||||
const data: User[] = []
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
data.push(...users)
|
||||
}
|
||||
|
||||
// this is a sample for custom sort function
|
||||
const locationSorter: VFlexTableWrapperSortFunction<User> = ({ order, a, b }) => {
|
||||
if (order === 'asc') {
|
||||
return a.location.localeCompare(b.location)
|
||||
}
|
||||
else if (order === 'desc') {
|
||||
return b.location.localeCompare(a.location)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// this is a sample for custom filter function
|
||||
const userFilter: VFlexTableWrapperFilterFunction<User> = ({ searchTerm, row }) => {
|
||||
if (!searchTerm) {
|
||||
return true
|
||||
}
|
||||
|
||||
// search either in the name or the bio
|
||||
return (
|
||||
row.name.toLocaleLowerCase().includes(searchTerm.toLocaleLowerCase())
|
||||
|| row.bio.toLocaleLowerCase().includes(searchTerm.toLocaleLowerCase())
|
||||
)
|
||||
}
|
||||
|
||||
// 로우 클릭 핸들러
|
||||
const onRowClick = (row: any) => {
|
||||
selectedRow.value = row
|
||||
isModalOpen.value = true
|
||||
console.log(selectedRow)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-content is-navbar-lg">
|
||||
<div>
|
||||
<div class="datatable-toolbar">
|
||||
<div class="column is-2">
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
결재제목
|
||||
</VLabel>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="params.title"
|
||||
class="input custom-text-filter"
|
||||
placeholder="결재제목"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-5">
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
등록기간
|
||||
</VLabel>
|
||||
<VControl>
|
||||
<div class="columns">
|
||||
<div class="column is-6">
|
||||
<VDatePicker
|
||||
v-model.string="params.regSdt"
|
||||
color="green"
|
||||
:masks="masks"
|
||||
trim-weeks
|
||||
>
|
||||
<template #default="{ inputValue, inputEvents }">
|
||||
<VField>
|
||||
<VControl icon="lucide:calendar">
|
||||
<input
|
||||
class="input v-input"
|
||||
type="text"
|
||||
:value="inputValue"
|
||||
placeholder="시작일"
|
||||
v-on="inputEvents"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</template>
|
||||
</VDatePicker>
|
||||
</div>
|
||||
<div style="transform: translateY(15px)">
|
||||
~
|
||||
</div>
|
||||
<div class="column is-6">
|
||||
<VDatePicker
|
||||
v-model.string="params.regEdt"
|
||||
color="green"
|
||||
:masks="masks"
|
||||
trim-weeks
|
||||
>
|
||||
<template #default="{ inputValue, inputEvents }">
|
||||
<VField>
|
||||
<VControl icon="lucide:calendar">
|
||||
<input
|
||||
class="input v-input"
|
||||
type="text"
|
||||
:value="inputValue"
|
||||
placeholder="종료일"
|
||||
v-on="inputEvents"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</template>
|
||||
</VDatePicker>
|
||||
</div>
|
||||
</div>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-1">
|
||||
<div style="padding-top:20px;float:right;">
|
||||
<VButtons>
|
||||
<VButton
|
||||
color="primary"
|
||||
elevated
|
||||
icon="fas fa-search"
|
||||
@click.stop="searchApproval"
|
||||
>
|
||||
검색
|
||||
</VButton>
|
||||
</VButtons>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="datatable-wrapper">
|
||||
<ComVFlexTable
|
||||
:data="params.paymentParams"
|
||||
:columns="params.flexColumn"
|
||||
:separators="true"
|
||||
:clickable="true"
|
||||
:compact="true"
|
||||
:use-payment-header="true"
|
||||
@row-click="onRowClick"
|
||||
>
|
||||
<template #payment-header>
|
||||
<div class="flex-table-header">
|
||||
<span class="flex-table-item paymentColumn1">결재번호</span>
|
||||
<span class="flex-table-item paymentColumn2">제목</span>
|
||||
<span class="flex-table-item paymentColumn3">작성자</span>
|
||||
<span class="flex-table-item paymentColumn4">등록일</span>
|
||||
<span class="flex-table-item paymentColumn5">구분</span>
|
||||
</div>
|
||||
</template>
|
||||
</ComVFlexTable>
|
||||
|
||||
<!-- 모달 컴포넌트 추가 -->
|
||||
<VModal
|
||||
is="form"
|
||||
v-model:open="isModalOpen"
|
||||
title="결재창"
|
||||
size="big"
|
||||
actions="center"
|
||||
@submit.prevent="isModalOpen = false"
|
||||
@close="isModalOpen = false"
|
||||
>
|
||||
<template #content>
|
||||
<div class="modal-form">
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-4">
|
||||
<div class="field">
|
||||
<label>결재번호</label>
|
||||
<div class="control">
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
placeholder="결재번호"
|
||||
:value="selectedRow?.apprNo"
|
||||
readonly
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-4">
|
||||
<div class="field">
|
||||
<label>제목</label>
|
||||
<div class="control">
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
placeholder="제목"
|
||||
:value="selectedRow?.title"
|
||||
readonly
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-4">
|
||||
<div class="field">
|
||||
<label>작성자</label>
|
||||
<div class="control">
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
placeholder="작성자"
|
||||
:value="selectedRow?.name"
|
||||
readonly
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-4">
|
||||
<div class="field">
|
||||
<label>구분</label>
|
||||
<div class="control">
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
placeholder="구분"
|
||||
:value="selectedRow?.process"
|
||||
readonly
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-4">
|
||||
<div class="field">
|
||||
<label>결재상태</label>
|
||||
<div class="control">
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
placeholder="결재상태"
|
||||
:value="selectedRow?.apprStat"
|
||||
readonly
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-4">
|
||||
<div class="field">
|
||||
<label>등록일</label>
|
||||
<div class="control">
|
||||
<input
|
||||
type="text"
|
||||
class="input"
|
||||
placeholder="등록일"
|
||||
:value="selectedRow?.regDt"
|
||||
readonly
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #action>
|
||||
<VButton type="submit" color="info" raised>반려</VButton>
|
||||
<VButton type="submit" color="primary" raised @click="updateIntegratedPaymentList">승인</VButton>
|
||||
</template>
|
||||
</VModal>
|
||||
<!-- <VFlexTableWrapper :columns="params.flexWrapperColumn" :data="params.paymentParams">-->
|
||||
<!--<!–-->
|
||||
<!-- Here we retrieve the internal wrapperState.-->
|
||||
<!-- Note that we can not destructure it-->
|
||||
<!-- –>-->
|
||||
<!-- <template #default="wrapperState">-->
|
||||
<!-- <pre>data: {{ data }}</pre>-->
|
||||
<!-- <!– We can place any content inside the default slot–>-->
|
||||
<!-- <VFlexTableToolbar>-->
|
||||
<!-- <template #left>-->
|
||||
<!-- <!– We can bind wrapperState.searchInput to any input –>-->
|
||||
<!-- <VField>-->
|
||||
<!-- <VControl icon="lucide:search">-->
|
||||
<!-- <input-->
|
||||
<!-- v-model="wrapperState.searchInput"-->
|
||||
<!-- type="text"-->
|
||||
<!-- class="input is-rounded"-->
|
||||
<!-- placeholder="Filter..."-->
|
||||
<!-- >-->
|
||||
<!-- </VControl>-->
|
||||
<!-- </VField>-->
|
||||
<!-- </template>-->
|
||||
|
||||
<!-- <template #right>-->
|
||||
<!-- <!– We can also bind wrapperState.limit –>-->
|
||||
<!-- <VField>-->
|
||||
<!-- <VControl>-->
|
||||
<!-- <div class="select is-rounded">-->
|
||||
<!-- <select v-model="wrapperState.limit">-->
|
||||
<!-- <option :value="1">-->
|
||||
<!-- 1 results per page-->
|
||||
<!-- </option>-->
|
||||
<!-- <option :value="10">-->
|
||||
<!-- 10 results per page-->
|
||||
<!-- </option>-->
|
||||
<!-- <option :value="15">-->
|
||||
<!-- 15 results per page-->
|
||||
<!-- </option>-->
|
||||
<!-- <option :value="25">-->
|
||||
<!-- 25 results per page-->
|
||||
<!-- </option>-->
|
||||
<!-- <option :value="50">-->
|
||||
<!-- 50 results per page-->
|
||||
<!-- </option>-->
|
||||
<!-- </select>-->
|
||||
<!-- </div>-->
|
||||
<!-- </VControl>-->
|
||||
<!-- </VField>-->
|
||||
<!-- </template>-->
|
||||
<!-- </VFlexTableToolbar>-->
|
||||
|
||||
<!-- <!–-->
|
||||
<!-- The VFlexTable "data" and "columns" props-->
|
||||
<!-- will be inherited from parent VFlexTableWrapper-->
|
||||
<!-- –>-->
|
||||
<!-- <VFlexTable rounded>-->
|
||||
<!-- <!– Custom "name" cell content –>-->
|
||||
<!-- <template #body-cell="{ row, column }">-->
|
||||
<!-- <template v-if="column.key === 'name'">-->
|
||||
<!-- <VAvatar-->
|
||||
<!-- size="medium"-->
|
||||
<!-- :picture="row.medias.avatar"-->
|
||||
<!-- :badge="row.medias.badge"-->
|
||||
<!-- :initials="row.initials"-->
|
||||
<!-- />-->
|
||||
<!-- <div>-->
|
||||
<!-- <span class="dark-text" :title="row.name">-->
|
||||
<!-- {{ row?.shortname }}-->
|
||||
<!-- </span>-->
|
||||
<!-- <VTextEllipsis-->
|
||||
<!-- width="280px"-->
|
||||
<!-- class="light-text"-->
|
||||
<!-- :title="row.bio"-->
|
||||
<!-- >-->
|
||||
<!-- <small>{{ row?.bio }}</small>-->
|
||||
<!-- </VTextEllipsis>-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
<!-- </template>-->
|
||||
<!-- </VFlexTable>-->
|
||||
|
||||
<!-- <!– Table Pagination with wrapperState.page binded–>-->
|
||||
<!-- <VFlexPagination-->
|
||||
<!-- v-model:current-page="wrapperState.page"-->
|
||||
<!-- class="mt-6"-->
|
||||
<!-- :item-per-page="wrapperState.limit"-->
|
||||
<!-- :total-items="wrapperState.total"-->
|
||||
<!-- :max-links-displayed="5"-->
|
||||
<!-- no-router-->
|
||||
<!-- />-->
|
||||
<!-- </template>-->
|
||||
<!-- </VFlexTableWrapper>-->
|
||||
</div>
|
||||
</div>
|
||||
<!-- <VButtons class="v-buttons-right-align">-->
|
||||
<!-- <VButton-->
|
||||
<!-- color="primary"-->
|
||||
<!-- icon="fas fa-plus"-->
|
||||
<!-- elevated-->
|
||||
<!-- to="/app/PriceInsert"-->
|
||||
<!-- >-->
|
||||
<!-- 등록-->
|
||||
<!-- </VButton>-->
|
||||
<!-- </VButtons>-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
input[readonly] {
|
||||
background-color: #f5f5f5; /* 살짝 회색 배경 */
|
||||
color: #888; /* 글자색 연하게 */
|
||||
cursor: not-allowed; /* 마우스 커서 변경 */
|
||||
border-color: #e0e0e0; /* 테두리 연하게 */
|
||||
}
|
||||
|
||||
.v-buttons-right-align {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 1rem; // 필요 시 간격 추가
|
||||
}
|
||||
|
||||
.flex-table .flex-table-item {
|
||||
background-color: var(--primary);
|
||||
border: 0px;
|
||||
}
|
||||
.flex-table .flex-table-header {
|
||||
padding: 0px;
|
||||
}
|
||||
.flex-table.is-table-clickable .flex-table-item:hover, .flex-table.is-table-clickable .flex-table-item:focus-within a:hover {
|
||||
background-color: var(--primary)!important;
|
||||
}
|
||||
</style>
|
||||
413
src/pages/app/priceDetail.vue
Normal file
413
src/pages/app/priceDetail.vue
Normal file
@@ -0,0 +1,413 @@
|
||||
<script setup lang="ts">
|
||||
import {getDetailPrcs, updatePrcsNo} from '/src/service/priceApi'
|
||||
import { type Person } from '/@src/utils/types'
|
||||
|
||||
const notyf = useNotyf()
|
||||
const loading = ref(false)
|
||||
const router = useRouter()
|
||||
|
||||
onBeforeMount(async ()=>{
|
||||
const result = await getDetailPrcs(history.state.key)
|
||||
getDetailList(result)
|
||||
})
|
||||
|
||||
const showTable = ref(false)
|
||||
const detailActionsOpen = ref(false)
|
||||
const apprLine = defineModel<Person[]>()
|
||||
|
||||
const generalParams = reactive({
|
||||
title: "",
|
||||
content: "",
|
||||
regSdat: "",
|
||||
regEdat: "",
|
||||
prvYn: true,
|
||||
prvRsn : "",
|
||||
prvPwd : "",
|
||||
aiYn: true,
|
||||
})
|
||||
const params = reactive({
|
||||
cateSelect: '',
|
||||
prcsNo: '', // 키값
|
||||
stCd:'',//결재상태 코드{ 등록중:0100[회수버튼],
|
||||
// 회수: 0300, 반려: 0400, 등록 완료: 0200 }
|
||||
prcsAttsColumn:[ //첨부파일 입력
|
||||
{ key: 'logiFnm', label: '구분'},
|
||||
{ key: 'data', label: '데이터'}
|
||||
],
|
||||
prcsAtts: [], //첨부파일 데이터
|
||||
felxColumn: [
|
||||
{ key: 'gubunNm', label: '구분'},
|
||||
{ key: 'deptNm', label: '부서' },
|
||||
{ key: 'sabun', label: '사번' },
|
||||
{ key: 'name', label: '이름' },
|
||||
{ key: 'attendNm', label: '비고' },
|
||||
{ key: 'apprStat', label: '결재상태'},
|
||||
{ key: 'date', label: '승인일자'},
|
||||
],
|
||||
priceData:[],
|
||||
prcsBizsColumn: [ //견적사 입력
|
||||
{ key: 'num', label: '구분', width: '10%' },
|
||||
{ key: 'email', label: '이메일', editable: true, width: '50px' },
|
||||
{ key: 'bizNo', label: '사업자번호', editable: true, width: '50px'},
|
||||
],
|
||||
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 },
|
||||
],
|
||||
dtlSpecs: [], //상세 규격 입력 데이터
|
||||
})
|
||||
|
||||
function getDetailList(arg){
|
||||
params.prcsNo = arg.prcsNo
|
||||
params.stCd = arg.stCd
|
||||
params.cateSelect = arg.cateNm
|
||||
generalParams.title = arg.title
|
||||
generalParams.content = arg.content
|
||||
params.prcsBizs = arg.prcsBizs.map(req => ({
|
||||
bizNo: req.bizNo,
|
||||
email: req.email,
|
||||
}))
|
||||
params.dtlSpecs = arg.dtlSpecs
|
||||
generalParams.regSdat = formatDate(arg.regSdat)
|
||||
generalParams.regEdat = formatDate(arg.regEdat)
|
||||
apprLine.value = arg.apprMst.apprReqs.map(req => ({
|
||||
gubunNm: req.gubunNm,
|
||||
deptCd: req.deptCd,
|
||||
deptNm: req.deptNm,
|
||||
sabun: req.sabun,
|
||||
name: req.name,
|
||||
apprNo: req.apprNo,
|
||||
apprOrd: req.apprOrd,
|
||||
apprStat: req.apprStat,
|
||||
attendNm: req.attendNm
|
||||
})) //비고 데이터 없음, 승인일자 없음 todo
|
||||
}
|
||||
|
||||
const updateState = async () => {
|
||||
let res = null
|
||||
try {
|
||||
loading.value = true
|
||||
const paramsPrice = {
|
||||
prcsNo : params.prcsNo
|
||||
}
|
||||
res = await updatePrcsNo(paramsPrice.prcsNo)
|
||||
notyf.dismissAll()
|
||||
if (res.request.status === 200) {
|
||||
notyf.primary('회수 되었습니다.')
|
||||
router.push({path: '/app/priceManagement'})
|
||||
}
|
||||
} catch (e) {
|
||||
notyf.error(e.message)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
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(/-$/,'')
|
||||
}
|
||||
|
||||
</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%;">
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>분야</td>
|
||||
<td colspan="2">
|
||||
<span class="column is-7">
|
||||
<input
|
||||
:readonly=true
|
||||
v-model="params.cateSelect"
|
||||
class="input custom-text-filter"
|
||||
placeholder="제목"
|
||||
>
|
||||
</span>
|
||||
</td>
|
||||
<td>제목</td>
|
||||
<td colspan="3">
|
||||
<div class="column is-fullhd">
|
||||
<VField class="pr-2">
|
||||
<VControl>
|
||||
<input
|
||||
:readonly=true
|
||||
v-model="generalParams.title"
|
||||
class="input custom-text-filter"
|
||||
placeholder="제목"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>내용</td>
|
||||
<td colspan="6">
|
||||
<div class="column is-fullhd">
|
||||
<VField class="pr-2">
|
||||
<VControl>
|
||||
<textarea
|
||||
:readonly=true
|
||||
v-model="generalParams.content"
|
||||
class="input custom-text-filter"
|
||||
placeholder="내용"
|
||||
/>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>규격입력</td>
|
||||
<td colspan="2">
|
||||
<VButton
|
||||
:color="params.btnChangeFlag? 'success':'primary'"
|
||||
icon="fas fa-plus"
|
||||
elevated
|
||||
@click="detailActionsOpen = true"
|
||||
>
|
||||
<span> 상세 규격 입력</span>
|
||||
</VButton>
|
||||
<VModal
|
||||
:open="detailActionsOpen"
|
||||
actions="center"
|
||||
title="상세 규격 입력"
|
||||
size="contract-big"
|
||||
cancelLabel="닫기"
|
||||
@close="detailActionsOpen = false"
|
||||
>
|
||||
<template #content>
|
||||
<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
|
||||
:readonly=true
|
||||
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>{{ value }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</ComVFlexTable>
|
||||
</template>
|
||||
<template #cancel>
|
||||
</template>
|
||||
</VModal>
|
||||
</td>
|
||||
<td>등록기간</td>
|
||||
<td colspan="5">
|
||||
<div class="columns">
|
||||
<div class="column is-5">
|
||||
<!-- <VDatePicker-->
|
||||
<!-- v-model="generalParams.regSdat"-->
|
||||
<!-- color="green"-->
|
||||
<!-- disabled-->
|
||||
<!-- trim-weeks-->
|
||||
<!-- style="pointer-events: none;"-->
|
||||
<!-- >-->
|
||||
<!-- <template #default="{ inputValue, inputEvents }">-->
|
||||
<!-- <VField>-->
|
||||
<!-- <VControl icon="lucide:calendar">-->
|
||||
<!-- <input-->
|
||||
<!-- :readonly=true-->
|
||||
<!-- class="input v-input"-->
|
||||
<!-- type="text"-->
|
||||
<!-- :value="inputValue"-->
|
||||
<!-- v-on="inputEvents"-->
|
||||
<!-- placeholder="시작일"-->
|
||||
<!-- >-->
|
||||
<!-- </VControl>-->
|
||||
<!-- </VField>-->
|
||||
<!-- </template>-->
|
||||
<!-- </VDatePicker>-->
|
||||
<input
|
||||
:readonly=true
|
||||
v-model="generalParams.regSdat"
|
||||
class="input custom-text-filter"
|
||||
placeholder="제목"
|
||||
>
|
||||
</div>
|
||||
<div style="transform: translateY(15px)">~</div>
|
||||
<div class="column is-5">
|
||||
<!-- <VDatePicker-->
|
||||
<!-- v-model="generalParams.regEdat"-->
|
||||
<!-- color="green"-->
|
||||
<!-- trim-weeks-->
|
||||
<!-- disabledDates=""-->
|
||||
<!-- >-->
|
||||
<!-- <template #default="{ inputValue, inputEvents }">-->
|
||||
<!-- <VField>-->
|
||||
<!-- <VControl icon="lucide:calendar">-->
|
||||
<!-- <input-->
|
||||
<!-- :readonly=true-->
|
||||
<!-- class="input v-input"-->
|
||||
<!-- type="text"-->
|
||||
<!-- :value="inputValue"-->
|
||||
<!-- v-on="inputEvents"-->
|
||||
<!-- placeholder="종료일"-->
|
||||
<!-- >-->
|
||||
<!-- </VControl>-->
|
||||
<!-- </VField>-->
|
||||
<!-- </template>-->
|
||||
<!-- </VDatePicker>-->
|
||||
<input
|
||||
:readonly=true
|
||||
v-model="generalParams.regEdat"
|
||||
class="input custom-text-filter"
|
||||
placeholder="제목"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>첨부파일</td>
|
||||
<td colspan="3">
|
||||
<VField class="file has-name is-right">
|
||||
<div class="file-label">
|
||||
<input
|
||||
class="file-input"
|
||||
type="file"
|
||||
name="resume">
|
||||
<span class="file-cta">
|
||||
<span class="file-icon">
|
||||
<i class="fas fa-cloud-upload-alt"/>
|
||||
</span>
|
||||
<span class="file-label">첨부파일</span>
|
||||
</span>
|
||||
<span class="file-name light-text">2022.xls</span>
|
||||
</div>
|
||||
</VField>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>견적요청</td>
|
||||
<td colspan="6">
|
||||
<VButton
|
||||
color="primary"
|
||||
icon="fas fa-plus"
|
||||
elevated
|
||||
@click="showTable = !showTable"
|
||||
>
|
||||
견적사 입력
|
||||
</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
|
||||
:readonly=true
|
||||
v-if="column.editable"
|
||||
v-model="row[column.key]"
|
||||
class="editable-input"
|
||||
/>
|
||||
<span v-else-if="column.key=='num'">{{index + 1}}</span>
|
||||
<!-- readonly 출력 -->
|
||||
<span v-else>{{ value }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</ComVFlexTable>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</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>{{value}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</ComVFlexTable>
|
||||
</div>
|
||||
<div>
|
||||
<VButton
|
||||
v-if="params.stCd === '0100'"
|
||||
color="warning"
|
||||
@click.stop="updateState"
|
||||
>
|
||||
회수
|
||||
</VButton>
|
||||
<VButton
|
||||
to="/app/priceManagement"
|
||||
v-if="params.stCd === '0100' | '0200' | '0300' | '0400'"
|
||||
color="info"
|
||||
>
|
||||
닫기
|
||||
</VButton>
|
||||
</div>
|
||||
</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>
|
||||
217
src/pages/app/priceManagement.vue
Normal file
217
src/pages/app/priceManagement.vue
Normal file
@@ -0,0 +1,217 @@
|
||||
<script setup lang="ts">
|
||||
import { getPriceList } from '/@src/service/priceApi'
|
||||
const router = useRouter()
|
||||
|
||||
onBeforeMount(async () => {
|
||||
await getPriceListData()
|
||||
const userSession = useUserSession()
|
||||
params.sessionUser = userSession.user.data
|
||||
|
||||
})
|
||||
|
||||
const masks = ref({
|
||||
modelValue: 'YYYY-MM-DD',
|
||||
})
|
||||
const searchParamsList = reactive({
|
||||
cateCd : '', //분야코드
|
||||
stCd : '', //등록상태
|
||||
regNm : '', //담당자
|
||||
regSdt: '',//등록시작일
|
||||
regEdt: '',//등록종료일
|
||||
page: 1,//페이지
|
||||
row: 3 //아이템갯수
|
||||
})
|
||||
const params = reactive({
|
||||
sessionUser:'',
|
||||
priceData: [],
|
||||
felxColumn: [
|
||||
{ key: 'cateNm', label: '분야' },
|
||||
{ key: 'title', label: '제목' },
|
||||
{ key: 'regNm', label: '담당자' },
|
||||
{ key: 'regDt', label: '등록일' },
|
||||
{ key: 'stNm', label: '등록 상태' },
|
||||
]
|
||||
})
|
||||
|
||||
async function getPriceListData(){
|
||||
const priceBase = {
|
||||
params:{
|
||||
regSdt: '1970-01-01',
|
||||
regEdt: '2070-01-01',
|
||||
page: '1',
|
||||
row: '20'
|
||||
}
|
||||
}
|
||||
const result = await getPriceList(priceBase)
|
||||
params.priceData = result.content
|
||||
}
|
||||
|
||||
const searchPrice = async () => {
|
||||
const searchParams = {
|
||||
params: {
|
||||
cateCd : searchParamsList.cateCd, //분야코드
|
||||
stCd : searchParamsList.stCd, //등록상태
|
||||
regNm : searchParamsList.regNm, //담당자
|
||||
regSdt: searchParamsList.regSdt,//등록시작일
|
||||
regEdt: searchParamsList.regEdt,//등록종료일
|
||||
page: 1,//페이지
|
||||
row: 3 //아이템갯수
|
||||
}
|
||||
}
|
||||
const result = await getPriceList(searchParams)
|
||||
params.priceData = result.content
|
||||
}
|
||||
|
||||
function getPriceDetail(){
|
||||
//stCd 결재상태 코드 [등록전:0000, 등록중:0100, ]
|
||||
if(params.sessionUser.sabun == arguments[0].regSabun && arguments[0].stCd == '0000'){
|
||||
router.push({ path: '/app/priceUpdate', state: { key: arguments[0].prcsNo }})
|
||||
}else{
|
||||
router.push({ path: '/app/priceDetail', state: { key: arguments[0].prcsNo }})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-content is-navbar-lg">
|
||||
<div>
|
||||
<div class="datatable-toolbar">
|
||||
<div class="column is-2">
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
분야
|
||||
</VLabel>
|
||||
<VCodeSelect
|
||||
cd_grp=5
|
||||
v-model="searchParamsList.cateCd"
|
||||
placeholder="전체"/>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-2">
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
등록상태
|
||||
</VLabel>
|
||||
<VCodeSelect
|
||||
cd_grp=1
|
||||
v-model="searchParamsList.stCd"
|
||||
placeholder="전체"/>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-2">
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
담당자
|
||||
</VLabel>
|
||||
<VControl>
|
||||
<input
|
||||
v-model="searchParamsList.regNm"
|
||||
class="input custom-text-filter"
|
||||
placeholder="담당자"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-5">
|
||||
<VField class="pr-2">
|
||||
<VLabel class="has-fullwidth">
|
||||
등록기간
|
||||
</VLabel>
|
||||
<VControl>
|
||||
<div class="columns">
|
||||
<div class="column is-6">
|
||||
<VDatePicker
|
||||
v-model.string="searchParamsList.regSdt"
|
||||
color="green"
|
||||
:masks="masks"
|
||||
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-6">
|
||||
<VDatePicker
|
||||
v-model.string="searchParamsList.regEdt"
|
||||
color="green"
|
||||
:masks="masks"
|
||||
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>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
<div class="column is-1">
|
||||
<div style="padding-top:20px;float:right;">
|
||||
<VButtons>
|
||||
<VButton
|
||||
color="primary"
|
||||
elevated
|
||||
icon="fas fa-search"
|
||||
@click.stop="searchPrice"
|
||||
>
|
||||
검색
|
||||
</VButton>
|
||||
</VButtons>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="datatable-wrapper">
|
||||
<ComVFlexTable
|
||||
:data="params.priceData"
|
||||
:columns="params.felxColumn"
|
||||
:separators="true"
|
||||
:clickable="true"
|
||||
:compact="true"
|
||||
@rowClick="getPriceDetail"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<VButtons class="v-buttons-right-align">
|
||||
<VButton
|
||||
color="primary"
|
||||
icon="fas fa-plus"
|
||||
elevated
|
||||
to="/app/PriceInsert"
|
||||
>
|
||||
등록
|
||||
</VButton>
|
||||
</VButtons>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.v-buttons-right-align {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 1rem; // 필요 시 간격 추가
|
||||
}
|
||||
|
||||
</style>
|
||||
509
src/pages/app/priceUpdate.vue
Normal file
509
src/pages/app/priceUpdate.vue
Normal file
@@ -0,0 +1,509 @@
|
||||
<script setup lang="ts">
|
||||
import {getDetailPrcs, updatePrice} from '/src/service/priceApi'
|
||||
import { type Person } from '/@src/utils/types'
|
||||
|
||||
const notyf = useNotyf()
|
||||
const loading = ref(false)
|
||||
const router = useRouter()
|
||||
|
||||
onBeforeMount(async ()=>{
|
||||
const result = await getDetailPrcs(history.state.key)
|
||||
getDetailList(result)
|
||||
})
|
||||
|
||||
const showTable = ref(false)
|
||||
const detailActionsOpen = ref(false)
|
||||
const apprLine = defineModel<Person[]>()
|
||||
|
||||
const generalParams = reactive({
|
||||
title: "",
|
||||
content: "",
|
||||
regSdat: "",
|
||||
regEdat: "",
|
||||
prvYn: true,
|
||||
prvRsn : "",
|
||||
prvPwd : "",
|
||||
aiYn: true,
|
||||
})
|
||||
const params = reactive({
|
||||
cateSelect: '',
|
||||
prcsNo: '',
|
||||
stCd: '', //상태코드 등록 전 : 0000
|
||||
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: 'apprStat', label: '결재상태'},
|
||||
{ key: 'date', 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: [], //상세 규격 입력 데이터
|
||||
detailData :[
|
||||
{ cateNm: '홍길동', age: 30, email: 'hong@example.com' },
|
||||
{ name: '김철수', age: 28, email: 'kim@example.com' },
|
||||
],
|
||||
btnChangeFlag: false
|
||||
})
|
||||
|
||||
function getDetailList(arg){
|
||||
params.prcsNo = arg.prcsNo
|
||||
params.stCd = arg.stCd
|
||||
params.cateSelect = arg.cateCd
|
||||
generalParams.title = arg.title
|
||||
generalParams.content = arg.content
|
||||
params.prcsBizs = arg.prcsBizs.map(req => ({
|
||||
bizNo: req.bizNo,
|
||||
email: req.email,
|
||||
}))
|
||||
params.dtlSpecs = arg.dtlSpecs
|
||||
generalParams.regSdat = arg.regSdat
|
||||
generalParams.regEdat = arg.regEdat
|
||||
apprLine.value = arg.apprMst.apprReqs.map(req => ({
|
||||
gubunCd: req.gubunCd,
|
||||
deptCd: req.deptCd,
|
||||
deptNm: req.deptNm,
|
||||
sabun: req.sabun,
|
||||
name: req.name,
|
||||
apprNo: req.apprNo,
|
||||
apprOrd: req.apprOrd,
|
||||
apprStat: req.apprStat,
|
||||
attendCd: req.attendCd
|
||||
})) //비고 데이터 없음, 승인일자 없음 todo
|
||||
}
|
||||
|
||||
const changeButton = () => {
|
||||
//todo 상세 규격 api 테우기
|
||||
params.btnChangeFlag = true
|
||||
close()
|
||||
}
|
||||
|
||||
const validation = () => {
|
||||
notyf.dismissAll() //todo
|
||||
if(generalParams.regSdat > generalParams.regEdat){
|
||||
notyf.error("등록 종료일은 등록 시작일보다 빠를 수 없습니다.")
|
||||
return
|
||||
}
|
||||
|
||||
if(apprLine.value.length < 2){
|
||||
notyf.error("결재선은 두 명이상 입력해주세요.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const updatePriceOne = async () => {
|
||||
let res = null
|
||||
try{
|
||||
loading.value = true
|
||||
validation()
|
||||
const paramsPrice ={
|
||||
prcsNo : params.prcsNo,
|
||||
cateCd : params.cateSelect,
|
||||
title: generalParams.title,
|
||||
content: generalParams.content,
|
||||
regSdat: formatDate(generalParams.regSdat),
|
||||
regEdat: formatDate(generalParams.regEdat),
|
||||
prvYn: false,
|
||||
prvRsn : "",
|
||||
prvPwd : "",
|
||||
aiYn: false,
|
||||
prcsBizs: params.prcsBizs.map(({ num, ...rest }) => rest), //견적사 입력 데이터
|
||||
dtlSpecs: [], //todo
|
||||
// params.dtlSpecs.map(({ num, ...rest }) => rest), //상세 규격 입력 데이터
|
||||
prcsAtts: params.prcsAtts, //첨부파일 데이터
|
||||
apprReqs: apprLine.value.map(({ deptNm, ...rest }) => rest), //결재선 데이터
|
||||
}
|
||||
res = await updatePrice(paramsPrice)
|
||||
notyf.dismissAll()
|
||||
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(/-$/,'')
|
||||
}
|
||||
|
||||
</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%;">
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>분야</td>
|
||||
<td colspan="2">
|
||||
<span class="column is-7">
|
||||
<VField class="pr-2">
|
||||
<VCodeSelect
|
||||
cd_grp=5
|
||||
v-model="params.cateSelect"/>
|
||||
</VField>
|
||||
</span>
|
||||
</td>
|
||||
<td>제목</td>
|
||||
<td colspan="3">
|
||||
<div class="column is-fullhd">
|
||||
<VField class="pr-2">
|
||||
<VControl>
|
||||
<input
|
||||
v-model="generalParams.title"
|
||||
class="input custom-text-filter"
|
||||
placeholder="제목"
|
||||
>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>내용</td>
|
||||
<td colspan="6">
|
||||
<div class="column is-fullhd">
|
||||
<VField class="pr-2">
|
||||
<VControl>
|
||||
<textarea
|
||||
v-model="generalParams.content"
|
||||
class="input custom-text-filter"
|
||||
placeholder="내용"
|
||||
/>
|
||||
</VControl>
|
||||
</VField>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>규격입력</td>
|
||||
<td colspan="2">
|
||||
<VButton
|
||||
:color="params.btnChangeFlag? 'success':'primary'"
|
||||
icon="fas fa-plus"
|
||||
elevated
|
||||
@click="detailActionsOpen = true"
|
||||
>
|
||||
<span v-if="params.btnChangeFlag == false"> 상세 규격 입력</span>
|
||||
<span v-else-if="params.btnChangeFlag"> 상세 규격 등록 완료</span>
|
||||
</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" @click="changeButton">
|
||||
등록
|
||||
</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
|
||||
disabledDates=""
|
||||
>
|
||||
<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="3">
|
||||
<VField class="file has-name is-right">
|
||||
<div class="file-label">
|
||||
<input
|
||||
class="file-input"
|
||||
type="file"
|
||||
name="resume">
|
||||
<span class="file-cta">
|
||||
<span class="file-icon">
|
||||
<i class="fas fa-cloud-upload-alt"/>
|
||||
</span>
|
||||
<span class="file-label">첨부파일</span>
|
||||
</span>
|
||||
<span class="file-name light-text">2022.xls</span>
|
||||
</div>
|
||||
</VField>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>견적요청</td>
|
||||
<td colspan="6">
|
||||
<VButton
|
||||
color="primary"
|
||||
icon="fas fa-plus"
|
||||
elevated
|
||||
@click="showTable = !showTable"
|
||||
>
|
||||
견적사 입력
|
||||
</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"
|
||||
/>
|
||||
<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>
|
||||
</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'" class="column">
|
||||
<VField class="pr-1">
|
||||
<VCodeSelect
|
||||
cd_grp=7
|
||||
v-model="row.gubunCd"/>
|
||||
</VField>
|
||||
</span>
|
||||
<span v-else-if="column.key=='attendCd'" class="column">
|
||||
<VField class="pr-1">
|
||||
<VCodeSelect
|
||||
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="updatePriceOne"
|
||||
raised>
|
||||
수정
|
||||
</VButton>
|
||||
<VButton
|
||||
to="/app/priceManagement"
|
||||
v-if="params.stCd === '0000'"
|
||||
color="info"
|
||||
>
|
||||
닫기
|
||||
</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>
|
||||
Reference in New Issue
Block a user