mirror of
https://git.hmsn.ink/kospo/svcm/oa.git
synced 2026-03-20 07:13:44 +09:00
469 lines
14 KiB
Vue
469 lines
14 KiB
Vue
<script setup lang="ts">
|
|
import {getDetailPrcs, updatePrcsNo, putSurveyPrcsNo} from '/src/service/priceApi'
|
|
import { type Person } from '/@src/utils/types'
|
|
import {formatDatefromString} from "/@src/utils/common/comfunc.ts";
|
|
|
|
|
|
const notyf = useNotyf()
|
|
const loading = ref(false)
|
|
const router = useRouter()
|
|
|
|
const props = defineProps<{
|
|
prcsNo: iPrcs
|
|
}>()
|
|
|
|
|
|
onBeforeMount(async ()=>{
|
|
let result;
|
|
if(history.state.key === undefined) {
|
|
result = await getDetailPrcs(props.prcsNo)
|
|
} else {
|
|
result = await getDetailPrcs(history.state.key)
|
|
}
|
|
getDetailList(result)
|
|
})
|
|
|
|
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: '', // 키값
|
|
stCdFalg: false, // 버튼 컴포넌트화
|
|
svyYn: false,
|
|
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){
|
|
console.log("arg",arg)//svy_yn
|
|
if(!props.prcsNo){
|
|
params.stCdFalg = true
|
|
}
|
|
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 = formatDatefromString(arg.regSdat)
|
|
generalParams.regEdat = formatDatefromString(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
|
|
params.prcsAtts = arg.prcsAtts
|
|
params.svyYn = arg.svyYn
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
const onChangeFinal = async () => {
|
|
let res = null
|
|
try {
|
|
loading.value = true
|
|
res = await putSurveyPrcsNo(params.prcsNo)
|
|
if (res.request.status === 200) {
|
|
notyf.primary('가격조사 완료 되었습니다.')
|
|
router.push({path: '/app/contractManagement'})
|
|
}
|
|
} catch (e) {
|
|
console.log('error')
|
|
notyf.error(e.message)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const onPrcsFileDownload = async (prcsNo: string, fileOrd: number, logiFnm: string) => {
|
|
const link = document.createElement('a')
|
|
link.href = `https://svcm.hmsn.ink/api/prcs/${prcsNo}/${fileOrd}` //todo
|
|
link.setAttribute('download', logiFnm)
|
|
link.setAttribute('target', '_blank')
|
|
document.body.appendChild(link)
|
|
link.click()
|
|
}
|
|
</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 is-7">
|
|
<input
|
|
:readonly=true
|
|
v-model="params.cateSelect"
|
|
class="input custom-text-filter"
|
|
placeholder="제목"
|
|
disabled
|
|
>
|
|
</span>
|
|
</td>
|
|
<td>제목</td>
|
|
<td colspan="6">
|
|
<div class="column is-fullhd">
|
|
<VField class="pr-2">
|
|
<VControl>
|
|
<input
|
|
:readonly=true
|
|
v-model="generalParams.title"
|
|
class="input custom-text-filter"
|
|
placeholder="제목"
|
|
disabled
|
|
>
|
|
</VControl>
|
|
</VField>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>내용</td>
|
|
<td colspan="10">
|
|
<div class="column is-fullhd">
|
|
<VField class="pr-2">
|
|
<VControl>
|
|
<textarea
|
|
:readonly=true
|
|
v-model="generalParams.content"
|
|
class="input custom-text-filter"
|
|
placeholder="내용"
|
|
disabled
|
|
/>
|
|
</VControl>
|
|
</VField>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>규격입력</td>
|
|
<td colspan="2">
|
|
<span class="column is-7">
|
|
<VButton
|
|
color='success'
|
|
icon="fas"
|
|
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"
|
|
>
|
|
<template #body-cell="{ row, column, index, value }">
|
|
<!-- 예: 특정 컬럼이면 input, 아니면 그냥 값 출력 -->
|
|
<div>
|
|
<input
|
|
:readonly=true
|
|
v-if="column.editable"
|
|
v-model="row[column.key]"
|
|
class="input custom-text-filter"
|
|
disabled
|
|
/>
|
|
<span v-else-if="column.key=='num'">{{index+1}}</span>
|
|
<span v-else>{{ value }}</span>
|
|
</div>
|
|
</template>
|
|
</ComVFlexTable>
|
|
</template>
|
|
<template #cancel>
|
|
</template>
|
|
</VModal>
|
|
</span>
|
|
</td>
|
|
<td>등록기간</td>
|
|
<td colspan="6">
|
|
<div class="columns">
|
|
<div class="column is-4">
|
|
<input
|
|
:readonly=true
|
|
v-model="generalParams.regSdat"
|
|
class="input custom-text-filter"
|
|
disabled
|
|
>
|
|
</div>
|
|
<div style="transform: translateY(15px)">~</div>
|
|
<div class="column is-4">
|
|
<input
|
|
:readonly=true
|
|
v-model="generalParams.regEdat"
|
|
class="input custom-text-filter"
|
|
disabled
|
|
>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>첨부파일</td>
|
|
<td colspan="9">
|
|
<div class="column is-12">
|
|
<VField>
|
|
<VLabel>첨부파일</VLabel>
|
|
<VControl>
|
|
<div
|
|
v-for="f in params.prcsAtts"
|
|
:key="f.logiFnm"
|
|
class="content estimate-file-wrapper"
|
|
>
|
|
<div class="estimate-file-name">
|
|
{{ f.logiFnm }}{{" ("}}{{Math.ceil(f.size / 1024)}}kb{{")"}}
|
|
</div>
|
|
<div class="estimate-file-size">
|
|
|
|
</div>
|
|
<div>
|
|
<i class="fa fa-download estimate-file-download" @click="onPrcsFileDownload(f.prcsNo, f.fileOrd, f.logiFnm)" />
|
|
</div>
|
|
</div>
|
|
</VControl>
|
|
</VField>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>견적서확인</td>
|
|
<td colspan="9">
|
|
<slot name="status"
|
|
v-if="!params.svyYn"
|
|
>
|
|
<div style="display: flex; justify-content: flex-end; gap: 8px;">
|
|
<VButton
|
|
color="primary"
|
|
icon="fas fa-circle"
|
|
elevated
|
|
@click="onChangeFinal"
|
|
>
|
|
가격조사 완료
|
|
</VButton>
|
|
</div>
|
|
</slot>
|
|
<div class="mt-2">
|
|
<ComVFlexTable
|
|
:key="params.prcsBizs.length"
|
|
:data="params.prcsBizs"
|
|
:columns="params.prcsBizsColumn"
|
|
:compact="true"
|
|
:separators="true"
|
|
>
|
|
<template #body-cell="{ column, index, value }">
|
|
<div>
|
|
<span v-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"
|
|
:compact="true">
|
|
<template #body-cell="{ row, column, index, value }">
|
|
<!-- 예: 특정 컬럼이면 input, 아니면 그냥 값 출력 -->
|
|
<div>
|
|
<span v-if="column.key=='attendNm' && !value">{{'재중'}}</span>
|
|
<span v-else>{{value}}</span>
|
|
</div>
|
|
</template>
|
|
</ComVFlexTable>
|
|
</div>
|
|
<slot name="button" v-if="params.stCdFalg">
|
|
<div style="display: flex; justify-content: flex-end; gap: 8px; margin-top: 10px;">
|
|
<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>
|
|
</slot>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
/*css 추가 start*/
|
|
.flex-table {
|
|
.flex-table-header {
|
|
padding: 0.1rem !important;
|
|
min-height: 40px;
|
|
border-top-left-radius: .75rem;
|
|
border-top-right-radius: .75rem;
|
|
}
|
|
|
|
.flex-table-cell {
|
|
.w-100 {
|
|
width: 100%;
|
|
}
|
|
}
|
|
.flex-table-item {
|
|
padding: 0.1rem !important;
|
|
min-height: 40px;
|
|
|
|
.column {
|
|
min-height: 40px;
|
|
padding: 0.1rem !important;
|
|
}
|
|
|
|
&:last-child {
|
|
border-bottom-left-radius: .75rem;
|
|
border-bottom-right-radius: .75rem;
|
|
}
|
|
}
|
|
}
|
|
|
|
.table-container {
|
|
overflow:hidden;
|
|
.control {
|
|
width: 100%;
|
|
}
|
|
td {
|
|
padding: 10px 10px !important;
|
|
.columns {
|
|
margin-left: 10px !important;
|
|
padding-top: 10px;
|
|
}
|
|
.column {
|
|
padding: 0 !important;
|
|
}
|
|
}
|
|
}
|
|
|
|
.text-center {
|
|
text-align:center;
|
|
}
|
|
.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> |