97 CSS module, scoped

source: categories/study/vue-experiance/vue-experiance_9-97.md

97 CSS module, scoped


<template>
    <div
            ref="noticePopup"
            :class="[$style.map_overlay, isClassName]"
            :style="{ position: 'fixed', zIndex: 100, top, left }"
    >
        <overlay-scroll :style="{ maxHeight: '221px' }">
            <li v-for="(item, index) in noticeDetailData.data" :key="index">
                <h1 :class="$style.title">
                    <span :class="$style.txt">알림 {{ index + 1 }}</span>
                </h1>
                <dl :class="$style.info_list">
                    <div :class="$style.info_area">
                        <dt :class="$style.info_title">센서타입</dt>
                        <dd :class="$style.info_cont">{{ item.sensorTypeName }}</dd>
                    </div>
                    <div :class="$style.info_area">
                        <dt :class="$style.info_title">센서명</dt>
                        <dd :class="$style.info_cont">{{ item.sensorName }}</dd>
                    </div>
                    <div :class="$style.info_area">
                        <dt :class="$style.info_title">
                            {{ noticeType === 'sensor' ? '품목구분' : '알림구분' }}
                        </dt>
                        <dd :class="$style.info_cont">{{ item.noticeDivisionName }}</dd>
                    </div>
                    <div :class="$style.info_area">
                        <dt :class="$style.info_title">임계치</dt>
                        <dd :class="$style.info_cont">{{ item.limitValueName }}</dd>
                    </div>
                    <div :class="$style.info_area">
                        <dt :class="$style.info_title">측정값</dt>
                        <dd :class="$style.info_cont">{{ item.measureValueName }}</dd>
                    </div>
                    <div :class="$style.info_area">
                        <dt :class="$style.info_title">발생일시</dt>
                        <dd :class="$style.info_cont">{{ item.measureTime }}</dd>
                    </div>
                    <div :class="$style.info_area">
                        <dt :class="$style.info_title">알림내용</dt>
                        <dd :class="$style.info_cont">{{ item.content }}</dd>
                    </div>
                    <div :class="$style.info_area">
                        <dt :class="$style.info_title">발생위치</dt>
                        <dd :class="$style.info_cont">{{ item.noticeAddr }}</dd>
                    </div>
                </dl>
            </li>
        </overlay-scroll>
        <div :class="$style.btn_area">
            <button
                    type="button"
                    :class="$style.btn"
                    @click="closeTransitNoticePopup"
            >
                닫기
            </button>
            <button
                    type="button"
                    :class="[$style.btn, $style.black]"
                    @click="clickDetail"
            >
                상세보기
            </button>
        </div>
    </div>
</template>

<script>
    import OverlayScroll from '@/components/renew/reuse/OverlayScroll';
    import { EventBus } from '@/plugins/eventBus';
    export default {
        name: 'NoticePopup',
        components: {
            OverlayScroll,
        },
        props: {
            noticeDetailData: {
                type: Object,
                required: true,
            },
            noticeType: {
                type: String,
            },
            target: {
                type: HTMLButtonElement,
                required: true,
            },
            className: {
                type: String,
                default: '',
            },
        },
        data() {
            return {
                start: null,
                progress: null,
                top: 0,
                left: 0,
            };
        },
        computed: {
            isClassName() {
                console.log(this.className.split(' ').join(' '));
                return this.className.split(' ').join(' ');
            },
        },
        mounted() {
            requestAnimationFrame(this.positionUpdate);
        },
        methods: {
            closeTransitNoticePopup() {
                this.$emit('click:closeNoticePopup');
            },
            clickDetail() {
                EventBus.$emit(
                        'clickNoticeDetail',
                        'notification-history',
                        this.noticeDetailData,
                );
                this.$emit('click:closeNoticePopup');
            },
            positionUpdate() {
                if (!this.target || !this.$refs.noticePopup) {
                    return;
                }
                const targetParentRect =
                        this.target.parentElement.getBoundingClientRect();
                const targetRect = this.target.getBoundingClientRect();
                this.top = targetRect.top + targetRect.height + 'px';
                this.left =
                        targetParentRect.left +
                        targetParentRect.width -
                        this.$refs.noticePopup.getBoundingClientRect().width -
                        10 +
                        'px';
                requestAnimationFrame(this.positionUpdate);
            },
        },
    };
</script>

<style module lang="scss">
    .map_overlay {
        box-sizing: border-box;
        width: 280px;
        border-radius: 8px;
        background-color: #fff;
        box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.2);
        text-align: left;

    .title {
        padding: 16px 16px 0;
        font-size: 0;

    .txt {
        color: #222;
        font-weight: normal;
        font-size: 14px;
        line-height: 21px;
        vertical-align: middle;
    }
    }

    .info_list {
        margin-top: 10px;
        padding: 0 16px;
    }

    .info_area {
        display: flex;

    .info_title {
        flex: 0 0 88px;
        color: #a1a1a1;
        font-size: 12px;
        line-height: 22px;
    }

    .info_cont {
        flex: 1 1 auto;
        margin-left: 8px;
        color: #555;
        font-size: 12px;
        line-height: 22px;
    }
    }

    .btn_area {
        box-sizing: border-box;
        padding: 16px 0;
        font-size: 0;
        text-align: center;

    .btn {
        padding: 3px 10px;
        border: 1px solid #e1e1e1;
        color: #262626;
        font-size: 12px;
        line-height: 18px;

    &.black {
         border-color: #555;
         background-color: #555;
         color: #fff;
     }

    &:not(:first-child) {
         margin-left: 4px;
     }
    }
    }
    }
</style>


<template>
    <div v-if="noPlan" class="no_result_area">
        <div class="no_result">
            <div>
                <p class="txt">운행중인 운송정보가 없습니다.</p>
                <btn-anchor
                        :type="'button'"
                        :class-name="'bg_yellow'"
                        @btnAnchorClick="openCreateTransitPlanPopup"
                >
                    운송계획 등록하기
                </btn-anchor>
            </div>
        </div>
    </div>
    <div v-else>
        <div class="header">
            <span class="title">운송정보</span>
            <div v-if="btnVisible" class="btn_area">
                <btn-anchor
                        v-if="boardPlanTestMode"
                        :class-name="'bg_white'"
                        :type="'button'"
                        :is-disabled="notAvailableModifyStatus"
                        @btnAnchorClick="boardPlanTestModeNextStep"
                >
                    운송전/운송출발
                </btn-anchor>
                <btn-anchor
                        v-if="!notAvailableCancel"
                        :class-name="'bg_white'"
                        :type="'button'"
                        :is-disabled="notAvailableCancel"
                        @btnAnchorClick="openCancelTransitPlanPopup"
                >
                    운송취소
                </btn-anchor>
                <btn-anchor
                        v-if="!notAvailableModify"
                        :class-name="'bg_white'"
                        :type="'button'"
                        :is-disabled="notAvailableModify"
                        @btnAnchorClick="openModifyTransitPlanPopup"
                >
                    수정
                </btn-anchor>
            </div>
        </div>
        <dl class="plan_info_list">
            <div class="plan_info_item">
                <dt class="tit">운송계획 등록자</dt>
                <dd class="cont">{{ boardPlanInfo.regMemberName }}</dd>
            </div>
            <div class="plan_info_item">
                <dt class="tit">운송계획 등록일시</dt>
                <dd class="cont">{{ boardPlanInfo.regDt }}</dd>
            </div>
            <div class="plan_info_item">
                <dt class="tit">출발 예정 일시</dt>
                <dd class="cont">{{ boardPlanInfo.startDt }}</dd>
            </div>
            <div class="plan_info_item">
                <dt class="tit">운송내용</dt>
                <dd class="cont">{{ boardPlanInfo.transitContent }}</dd>
            </div>
        </dl>
        <table-section>
            <template #header>
                <span class="title">운송지</span>
            </template>
            <template #table>
                <overlay-scroll>
                    <table class="table table_normal table_row_type">
                        <caption>
                            <span class="screen_out">운송지 테이블</span>
                        </caption>
                        <colgroup>
                            <col style="width: 60px" />
                            <col style="width: 224px" />
                            <col style="width: 64px" />
                            <col style="width: 112px" />
                            <col style="width: 64px" />
                            <col style="width: 96px" />
                            <col style="width: 68px" />
                        </colgroup>
                        <thead>
                        <tr>
                            <th scope="col">구분</th>
                            <th scope="col">주소</th>
                            <th scope="col">수령인</th>
                            <th scope="col">수령인 연락처</th>
                            <th scope="col">상태</th>
                            <th scope="col">출발/도착시간</th>
                            <th scope="col">이상알림</th>
                        </tr>
                        </thead>
                        <tbody>
                        <tr
                                v-if="
									!boardPlanInfo.locationList ||
									!boardPlanInfo.locationList.length
								"
                        >
                            <td colspan="7">운송계획 운송지 정보가 없습니다.</td>
                        </tr>
                        <tr
                                v-for="(item, index) in boardPlanInfo.locationList"
                                v-else
                                :key="index"
                                :class="{ is_error: item.countWarns }"
                        >
                            <td>
                                <c-tooltip>
                                    <div class="text-overflow-ellipsis">
                                        {{ getLocationTypeName(index) }}
                                    </div>
                                </c-tooltip>
                            </td>
                            <td>
                                <c-tooltip>
                                    <div class="text-overflow-ellipsis">
                                        {{ getAddr(item) }}
                                    </div>
                                </c-tooltip>
                            </td>
                            <td>
                                <c-tooltip>
                                    <div class="text-overflow-ellipsis">
                                        {{ item.name | checkEmptyData }}
                                    </div>
                                </c-tooltip>
                            </td>
                            <td>
                                <c-tooltip>
                                    <div class="text-overflow-ellipsis">
                                        {{ item.contactNo | convertPhoneNumber | checkEmptyData }}
                                    </div>
                                </c-tooltip>
                            </td>
                            <td v-if="availableLocationStatusChange(item)">
                                <btn-anchor
                                        v-if="!vehicleInfo.params.isCancelPlan"
                                        :type="'button'"
                                        :class-name="'bg_black small'"
                                        @btnAnchorClick="changeLocationStatus(item)"
                                >도착</btn-anchor
                                >
                                <p v-else>-</p>
                            </td>
                            <td v-else>
                                <c-tooltip>
                                    <div class="text-overflow-ellipsis">
                                        {{ getStatusName(item) }}
                                    </div>
                                </c-tooltip>
                            </td>
                            <td>
                                <c-tooltip>
                                    <div class="text-overflow-ellipsis">
                                        {{ item.time | dateTimeFormatDash2 | checkEmptyData }}
                                    </div>
                                </c-tooltip>
                            </td>
                            <td>
                                <template v-if="item.countWarns">
                                    <btn-anchor
                                            :type="'button'"
                                            :class-name="'link is_error'"
                                            @btnAnchorClick="clickNoticePopup2($event, item)"
                                    >{{ item.countWarns }}</btn-anchor
                                    >
                                </template>
                                <template v-else>
                                    <c-tooltip>
                                        <div class="text-overflow-ellipsis">
                                            {{ item.countWarns }}
                                        </div>
                                    </c-tooltip>
                                </template>
                            </td>
                        </tr>
                        </tbody>
                    </table>
                </overlay-scroll>
            </template>
        </table-section>
        <table-section>
            <template #header>
                <span class="title">품목정보</span>
            </template>
            <template #table>
                <table class="table table_normal table_row_type">
                    <caption>
                        <span class="screen_out">품목정보 테이블</span>
                    </caption>
                    <colgroup>
                        <col style="width: 60px" />
                        <col style="width: 220px" />
                        <col style="width: 88px" />
                        <col style="width: 64px" />
                        <col style="width: 96px" />
                        <col style="width: 160px" />
                    </colgroup>
                    <thead>
                    <tr>
                        <th scope="col">번호</th>
                        <th scope="col">물품명</th>
                        <th scope="col">수량</th>
                        <th scope="col">단위</th>
                        <th scope="col">운송지</th>
                        <th scope="col">비고</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr
                            v-if="!boardPlanInfo.goodsList || !boardPlanInfo.goodsList.length"
                    >
                        <td colspan="6">운송계획 품목 정보가 없습니다.</td>
                    </tr>
                    <tr
                            v-for="(item, index) in boardPlanInfo.goodsList"
                            v-else
                            :key="index"
                    >
                        <td>
                            <c-tooltip>
                                <div class="text-overflow-ellipsis">
                                    {{ index + 1 }}
                                </div>
                            </c-tooltip>
                        </td>
                        <td>
                            <c-tooltip>
                                <div class="text-overflow-ellipsis">
                                    {{ item.name }}
                                </div>
                            </c-tooltip>
                        </td>
                        <td>
                            <c-tooltip>
                                <div class="text-overflow-ellipsis">
                                    {{ item.qty }}
                                </div>
                            </c-tooltip>
                        </td>
                        <td>
                            <c-tooltip>
                                <div class="text-overflow-ellipsis">
                                    {{ item.unit }}
                                </div>
                            </c-tooltip>
                        </td>
                        <td>
                            <c-tooltip>
                                <div class="text-overflow-ellipsis">
                                    {{ item.locationTypeName }}
                                </div>
                            </c-tooltip>
                        </td>
                        <td>
                            <c-tooltip>
                                <div class="text-overflow-ellipsis">
                                    {{ item.remark | checkEmptyData }}
                                </div>
                            </c-tooltip>
                        </td>
                    </tr>
                    </tbody>
                </table>
            </template>
        </table-section>
        <!-- [S] 이상알림 팝업 -->
        <div>
            <notice-popup
                    v-if="noticeDetailData.activeNoticePopup"
                    :target="noticePopupTarget"
                    :notice-detail-data="noticeDetailData"
                    :class-name="$style.custom"
                    @click:closeNoticePopup="closeTransitNoticePopup"
            />
        </div>
        <!-- // [E] 이상알림 팝업 -->
    </div>
</template>

<script>
    import { mapActions, mapGetters } from 'vuex';
    import TableSection from '@/components/renew/reuse/TableSection';
    import BtnAnchor from '@/components/renew/reuse/BtnAnchor';
    import { EventBus } from '@/plugins/eventBus';
    import request from '@/api/index';
    import OverlayScroll from '@/components/renew/reuse/OverlayScroll';
    import CTooltip from '@/components/renew/reuse/CTooltip';
    import NoticePopup from '@/components/renew/reuse/NoticePopup';

    export default {
        name: 'PartStatusTransitPopupDetailVehicleInfo',
        components: {
            OverlayScroll,
            TableSection,
            BtnAnchor,
            CTooltip,
            NoticePopup,
        },
        props: {
            vehicleInfo: {
                type: Object,
                required: true,
            },
        },
        data() {
            return {
                boardPlanInfo: {},
                noPlan: false,
                boardPlanTestMode: false,
                isBtnVisible: true,
                noticeDetailData: {
                    partSeq: '',
                    vehicleSeq: '',
                    seq: '',
                    startDt: '',
                    activeNoticePopup: false,
                    data: [],
                },
                noticePopupTarget: null,
            };
        },
        computed: {
            ...mapGetters('transit', ['boardPlan']),
            getLocationTypeName() {
                return index => {
                    const maxLength = this.boardPlanInfo.locationList.length - 1;
                    switch (index) {
                        case 0:
                            return '출발지';
                        case maxLength:
                            return '도착지';
                        default:
                            return '경유지';
                    }
                };
            },
            getAddr() {
                return item => `(${item.zipcode}) ${item.addr}`;
            },
            // 현재 계획 수정가능 여부
            notAvailableModify() {
                return !['WAIT', 'BEFORE'].includes(this.boardPlanInfo.status);
            },
            // 계획 임의 상태 변경여부
            notAvailableModifyStatus() {
                return !['WAIT', 'BEFORE'].includes(this.boardPlanInfo.status);
            },
            // 도착상태 변경 가능여부
            availableLocationStatusChange() {
                return item => {
                    // 최초 출발지 경유지로 출발은 '모바일'에서만 수행
                    if (['BEFORE', 'WAIT'].includes(this.vehicleInfo.status)) {
                        return false;
                    }
                    // 출발지가 아니고 출발 전, 출발 상태일 경우 도착 상태 변경 가능
                    return (
                            item.locationType !== 'START' &&
                            ['PLS00', 'PLS01'].includes(item.status)
                    );
                };
            },
            notAvailableCancel() {
                return this.vehicleInfo.status === 'DONE';
            },
            //팝업 우측 상단 액션 버튼 노출 여부
            btnVisible() {
                const result = this.vehicleInfo.isBtnVisible === undefined;
                // eslint-disable-next-line vue/no-side-effects-in-computed-properties
                return (this.isBtnVisible = result);
            },
            // 상태이름 출력
            getStatusName() {
                return item => (item.status === 'PLS03' ? '-' : item.statusName);
            },
        },
        watch: {
            boardPlan(val) {
                this.boardPlanInfo = { ...val };
            },
        },
        created() {
            this.noPlan = !this.vehicleInfo.params.planSeq;
            if (!this.noPlan) {
                // 운송계획 정보 조회
                this.getBoardPlan(this.vehicleInfo);
            }
        },
        methods: {
            ...mapActions('transit', ['getBoardPlan']),
            // 운송취소 팝업 열기
            openCancelTransitPlanPopup() {
                const { vehicleSeq, params } = this.vehicleInfo;
                const { partSeq, startDt, planSeq } = params;
                EventBus.$emit('open:canceltransitplan', {
                    before: 'PartStatusTransitPopupDetailVehicleInfo',
                    origin: this.vehicleInfo,
                    vehicleSeq,
                    params: {
                        partSeq,
                        startDt,
                        seq: planSeq,
                    },
                });
            },
            // 운송계획 수정 열기 (현재 운송계획 수정)
            openModifyTransitPlanPopup() {
                const params = {
                    vehicleSeq: this.vehicleInfo.vehicleSeq,
                    seq: this.vehicleInfo.params.planSeq,
                    ...this.vehicleInfo.params,
                };
                EventBus.$emit('open:modifytransitplan', params, true);
                EventBus.$emit('close:transitpopupdetail');
            },
            // 운송계획 등록 팝업 열기
            openCreateTransitPlanPopup() {
                EventBus.$emit('open:createtransitplan', {
                    vehicleSeq: this.vehicleInfo.vehicleSeq,
                });
                EventBus.$emit('close:transitpopupdetail');
            },
            // 운송계획 다음 상태로 변경 (운송전 / 운송중)
            async boardPlanTestModeNextStep() {
                const vehicleSeq = this.vehicleInfo.vehicleSeq;
                const { partSeq, startDt, planSeq } = this.vehicleInfo.params;
                const status = this.boardPlanInfo.status;
                if (status === 'WAIT') {
                    const testUrl = `/transit/board/plan/reserve/${vehicleSeq}`;
                    // 운송전 상태로
                    await request.put(testUrl, {
                        partSeq,
                        startDt,
                        seq: planSeq,
                    });
                    this.$toasted.show('[TEST MODE] 차량이 운송전 상태로 변경되었습니다.');
                }
                if (status === 'BEFORE') {
                    const testUrl = `/transit/board/plan/status/${vehicleSeq}`;
                    // 운송중 상태로
                    await request.put(testUrl, {
                        partSeq,
                        startDt,
                        planSeq,
                        seq: 1,
                    });
                    this.$toasted.show('[TEST MODE] 차량이 운송중 상태로 변경되었습니다.');
                }
                EventBus.$emit('refresh:kanbancontents');
                EventBus.$emit('close:transitpopupdetail');
            },
            clickNoticePopup3(e, item) {
                EventBus.$emit('click:noticePopup', e, item);
            },
            // 위치정보 수정 (도착상태 변경)
            changeLocationStatus(item) {
                EventBus.$emit('open:changelocationstatus', item);
            },
            //이상알림 레이어팝업
            clickNoticePopup2({ target }, item) {
                // 차량 이상정보 갱신
                this.noticePopupTarget = target;
                this.noticeDetailData.activeNoticePopup = false;

                this.noticeDetailData.data = item.warnList;
                this.noticeDetailData.partSeq = item.partSeq;
                this.noticeDetailData.vehicleSeq = item.vehicleSeq;
                this.noticeDetailData.startDt = item.startDt;
                this.noticeDetailData.planSeq = item.planSeq;

                this.noticeDetailData.activeNoticePopup = true;
            },
            closeTransitNoticePopup() {
                this.noticeDetailData.activeNoticePopup = false;
            },
        },
    };
</script>

<style module lang="scss">
    //.custom {
    //	background-color: #000;
    //
    //	[class^='NoticePopup_txt'] {
          //		color: #fff;
          //	}
    //}
</style>