Skip to content

Search Form Items

<nv-search-form></nv-search-form> 내부 슬롯에서 사용하는 검색용 폼 아이템입니다.

이 컴포넌트들은 nv-input-wrap 을 껍데기로 사용합니다. 상세 폼과 같은 그리드 시스템(column-size × merge-cell)을 쓰고, <el-form-item> 속성도 그대로 상속받습니다. 자세한 속성 목록은 공식문서를 참고하세요.

각 필드는 상위 nv-search-form 이 내려준 검색 레지스트리에 스스로 등록합니다. 그래서 필드마다 필터 객체를 넘길 필요가 없고, 화면에서 사라진 필드는 조건 태그에서도 자동으로 빠집니다.

공통 Props

이름타입기본값설명
nv-fieldModelFieldundefined모델 필드 정의. 조건 키(key)와 라벨(label)을 함께 제공한다
nv-keystring''조건 키. nv-field 를 주면 그쪽 key 가 쓰인다
nv-labelstring / nullnull라벨로 표시될 문자열. 생략하면 nv-field.label
nv-init-valuestring / null / anynull초기값 (검색어 또는 초기 선택값 등)
no-labelbooleanfalsetrue면 라벨 표시 안 함 (검색 바처럼 좁은 곳)
merge-cellnumber1grid의 column 병합 — #inline 에서도 동작한다
columnbooleanfalse위젯을 세로로 쌓는다
nv-and-orstring'and'앞 조건과의 결합자 (and, or)
nv-operstring'eq'연산자 (eq, lf, gte 등)
nv-filterSearchRegistryundefined화면이 직접 만든 레지스트리를 쓸 때만 지정. 보통 생략한다

nv-search-field

  • 검색 필드의 진입점입니다. nv-field.type 으로 위젯을 자동 선택하므로, 화면은 "어떤 필드인지"만 적으면 됩니다.
  • CMS 의 모든 검색 화면이 이 컴포넌트를 씁니다. 아래의 개별 nv-search-* 는 이 컴포넌트가 위임하는 구현체입니다.
nv-field.type선택되는 위젯
Booleannv-search-toggle
Instant / LocalDateTime / LocalDate / Datenv-search-period
그 외 + nv-lv-mapper 지정nv-search-select
그 외nv-search-text

타입만으로 정할 수 없는 것은 widget 으로 지정합니다.

widget쓰는 경우
code같은 Boolean/코드 목록이라도 라디오로 보여야 할 때
checkbox같은 코드 목록이라도 다중 선택이어야 할 때
text / select / period / toggle자동 선택 결과를 덮어쓸 때
custom기본 슬롯을 쓸 때 (슬롯을 주면 자동으로 선택됩니다)
html
<nv-search-field :nv-field="nv.fields.board.NAME"/>                          <!-- String  → text -->
<nv-search-field :nv-field="nv.fields.board.ENABLED"/>                       <!-- Boolean → toggle -->
<nv-search-field :nv-field="nv.fields.board.CREATED_DT"/>                    <!-- Instant → period -->
<nv-search-field :nv-field="nv.fields.board.STATUS" :nv-lv-mapper="codes.status"/>  <!-- → select -->
<nv-search-field widget="code" :nv-field="nv.fields.board.ENABLED" :nv-lv-mapper="codes.boolean"/>  <!-- 토글 대신 라디오 -->

커스텀 위젯 (기본 슬롯)

  • 전용 nv-search-* 컴포넌트를 새로 만들지 않고도 아무 컴포넌트나 검색 필드로 쓸 수 있습니다.
  • 기본 슬롯을 주면 nv-search-fieldnv-search-custom 으로 위임합니다. 등록·해제·그리드·라벨·조건 태그는 껍데기가 처리하고, 슬롯은 조건 노드(model)만 받아 v-model 로 물리면 됩니다.
이름타입기본값설명
nv-format(node) => string | nulln => n.val조건 태그에 표시할 값
nv-has-value(node) => booleanval 이 비어있지 않은지조건 태그 노출 여부
nv-init-node() => any{ao, op, val}조건 노드의 초기 구조

값 하나짜리 위젯

el-rate 처럼 검색 컴포넌트가 아닌 것도 그대로 씁니다. 값을 넣으면 아래에 조건 태그가 뜹니다.

html
<nv-search-field :nv-field="nv.fields.review.RATE"
                 :nv-init-value="0"
                 :nv-has-value="hasRate"
                 :nv-format="fmtRate"
                 v-slot="{ model }">
  <el-rate v-model="model.val"/>
</nv-search-field>
typescript
const hasRate = (node) => node.val > 0;
const fmtRate = (node) => '★'.repeat(node.val ?? 0);

TIP

콜백은 조건 노드 전체를 받습니다(node.val 이 아니라 node). nv-init-node 로 노드 모양을 바꿀 수 있기 때문입니다.

노드 구조를 바꾸는 위젯 (범위 조건)

nv-init-node 로 노드 모양을 바꾸면 위젯 하나가 조건 여러 개를 만들 수 있습니다. {from, to}ops 를 넣으면 reduceQ 가 같은 경로에 조건 두 개(gte/lte)를 생성합니다.

html
<nv-search-field :nv-field="nv.fields.order.AMOUNT"
                 :nv-init-node="amountRange"
                 :nv-has-value="hasAmount"
                 :nv-format="fmtAmount"
                 v-slot="{ model }">
  <el-input-number v-model="model.from.value" :min="0" :step="1000" controls-position="right"/>
  <span class="q-mx-xs">~</span>
  <el-input-number v-model="model.to.value" :min="0" :step="1000" controls-position="right"/>
</nv-search-field>
typescript
const amountRange = () => ({
  ops: ['gte', 'lte'],                       // 없으면 기간(d_gt/d_lt)으로 해석된다
  from: { enabled: true, value: null },
  to: { enabled: true, value: null },
});
const hasAmount = (node) => node.from.value != null || node.to.value != null;
const fmtAmount = (node) => `${node.from.value ?? ''} ~ ${node.to.value ?? ''}`;

전송되는 조건 트리:

json
{ "ao": "and", "conds": [
  { "field": "ord.amount", "op": "gte", "val": 10000 },
  { "field": "ord.amount", "op": "lte", "val": 50000 }
]}

WARNING

nv-field.key 는 백엔드 {X}SearchSchema선언된 경로여야 하고, 쓰는 연산자(gte/lte 등)도 허용돼 있어야 합니다. 선언에 없으면 조건이 조용히 드롭됩니다(fail-closed). 상세는 저장소의 docs/backend/search-query-spec.md 참고

nv-search-dynamic

  • 이 컴포넌트는 <el-select> 컴포넌트의 속성들을 그대로 상속받아 활용할 수 있습니다. 자세한 속성 목록은 공식문서를 참고하세요.
html
<nv-search-dynamic nv-key="keyword" :nv-lv-mapper="codes.keyword" />
typescript
const codes = ref(
    filterTool.toMapper({
        keyword: [
            { label: '전체', value: 'acnt.sample1,acnt.sample2' },
            { label: '샘플1', value: 'acnt.sample1' },
            { label: '샘플2', value: 'acnt.sample2' },
        ],
    })
);

nv-search-text

  • 이 컴포넌트는 <el-input> 컴포넌트의 속성들을 그대로 상속받아 활용할 수 있습니다. 자세한 속성 목록은 공식문서를 참고하세요.
html
<nv-search-text :nv-field="nv.fields.user.SAMPLE"/>
typescript
const alias = 'acnt';

const SAMPLE = {
    key: `${alias}.sample`,
    property: 'sample',
    type: 'sample',
    label: '샘플',
    desc: '샘플',
    defaultVal: null,
};

const nv = {
    fields: {
        user: {
            SAMPLE: SAMPLE,
        },
    },
};

nv-search-select

  • 이 컴포넌트는 <el-select> 컴포넌트의 속성들을 그대로 상속받아 활용할 수 있습니다. 자세한 속성 목록은 공식문서를 참고하세요.
html
<nv-search-select :nv-field="SAMPLE" :nv-lv-mapper="codes.sample"/>
typescript
const alias = 'acnt';

const SAMPLE = {
    key: `${alias}.sample`,
    property: 'sample',
    type: 'sample',
    label: '샘플',
    desc: '샘플',
    defaultVal: null,
};

const nv = {
    fields: {
        user: {
            SAMPLE: SAMPLE,
        },
    },
};

const codes = ref(
    filterTool.toMapper({
        sample: [
            { label: '전체', value: null },
            { label: '샘플1', value: 'a' },
            { label: '샘플2', value: 'b' },
            { label: '샘플3', value: 'c' },
        ],
    })
);

nv-search-code (Radio)

  • 이 컴포넌트는 <el-radio> 컴포넌트의 속성들을 그대로 상속받아 활용할 수 있습니다. 자세한 속성 목록은 공식문서를 참고하세요.
html
<nv-search-code :nv-field="nv.fields.user.SAMPLE" :nv-lv-mapper="codes.boolean"/>
typescript
const alias = 'acnt';

const SAMPLE = {
    key: `${alias}.sample`,
    property: 'sample',
    type: 'sample',
    label: '샘플',
    desc: '샘플',
    defaultVal: null,
};

const nv = {
    fields: {
        user: {
            SAMPLE: SAMPLE,
        },
    },
};

const codes = ref(
    filterTool.toMapper({
        boolean: [
            { label: 'A', value: 'A' },
            { label: 'B', value: 'B' },
            { label: 'C', value: 'C' },
        ],
    })
);

nv-search-period (Date Range Picker)

  • 이 컴포넌트는 <el-date-picker> 컴포넌트의 속성들을 그대로 상속받아 활용할 수 있습니다. 자세한 속성 목록은 공식문서를 참고하세요.

props

이름타입기본값설명
timebooleanfalse시간까지 포함할지 여부
formatstring'YYYY.MM.DD'날짜 포맷
nv-init-from-valuestring/ nullnull날짜 range 시작 값
nv-init-to-valuestring/ nullnull날짜 range 끝 값
html
<nv-search-period :nv-field="nv.fields.user.SAMPLE"/>
typescript
const alias = 'acnt';

const SAMPLE = {
    key: `${alias}.sample`,
    property: 'sample',
    type: 'sample',
    label: '샘플',
    desc: '샘플',
    defaultVal: null,
};

const nv = {
    fields: {
        user: {
            SAMPLE: SAMPLE,
        },
    },
};

nv-search-toggle

  • 이 컴포넌트는 <el-switch> 컴포넌트의 속성들을 그대로 상속받아 활용할 수 있습니다. 자세한 속성 목록은 공식문서를 참고하세요.
html
<nv-search-toggle :nv-field="nv.fields.user.SAMPLE" :nv-init-value="true"/>
typescript
const alias = 'acnt';

const SAMPLE = {
    key: `${alias}.sample`,
    property: 'sample',
    type: 'sample',
    label: '샘플',
    desc: '샘플',
    defaultVal: null,
};

const nv = {
    fields: {
        user: {
            SAMPLE: SAMPLE,
        },
    },
};

nv-search-checkbox

  • 이 컴포넌트는 <el-checkbox> 컴포넌트의 속성들을 그대로 상속받아 활용할 수 있습니다. 자세한 속성 목록은 공식문서를 참고하세요.
  • 연산자는 in 이 기본입니다. 여러 값을 고르면 field IN (…) 조건이 됩니다.
이름타입기본값설명
nv-init-valueany[] / anynull초기 선택값. 화면의 기본 범위를 지정할 때 씁니다
nv-except-valueany[]null선택할 수 없도록 잠글 값 목록
except-nullbooleanfalse"전체" 체크박스를 없앱니다
html
<nv-search-checkbox :nv-field="nv.fields.user.SAMPLE" :nv-lv-mapper="codes.check"/>
typescript
const alias = 'acnt';

const SAMPLE = {
    key: `${alias}.sample`,
    property: 'sample',
    type: 'sample',
    label: '샘플',
    desc: '샘플',
    defaultVal: null,
};

const nv = {
    fields: {
        user: {
            SAMPLE: SAMPLE,
        },
    },
};

const codes = ref(
    filterTool.toMapper({
        check: [
            { label: 'A', value: 'A' },
            { label: 'B', value: 'B' },
            { label: 'C', value: 'C' },
        ],
    })
);

merge-cell

  • merge-cell prop을 사용하여 폼 필드가 그리드 시스템에서 차지할 컬럼의 수를 동적으로 조절합니다. 이는 마치 HTML 테이블의 colspan 속성과 유사한 기능을 제공합니다.
  • 이를 통해 폼 내에서 특정 필드의 너비를 강조하거나 레이아웃을 시각적으로 조정하는 데 유용합니다. 예를 들어, 중요한 입력 필드를 더 넓게 표시하거나, 관련 없는 필드들을 묶어서 공간을 절약할 수 있습니다.
  • 상세 폼(nv-form-group × nv-input-wrap)과 같은 그리드 시스템입니다. 컨테이너가 열 수를 정하고 셀이 그중 몇 칸을 병합할지 정합니다.
영역열 수를 정하는 것비고
고급 검색 (#filters, 탭 슬롯)nv-search-formcolumn-size (기본 2)화면 폭에 따라 자동으로 줄어든다
검색 바 (#inline)필드 개수만큼 (각 inline-min-cell-width~inline-max-cell-width)남는 폭을 먹지 않는다 — 버튼이 필드 바로 뒤에 붙는다
상세 폼nv-form-groupcolumn-size (기본 2)

merge-cell 은 컨테이너의 실제 열 수를 넘지 않도록 자동으로 잘립니다.

column-size :

label="셀 병합 조절" merge-cell :
html
<div>
    <small>column-size : </small>
    <el-input-number v-model="num" :min="1" :max="5" class="q-mb-md" />
    <br/>
    <small>label="셀 병합 조절" merge-cell : </small>
    <el-input-number v-model="mergeCell" :min="1" :max="5" class="q-mb-md" />
</div>

<nv-search-form always-expanded :column-size="num" :query="queries.SAMPLE" v-if="loaded">
<template #filters>
    <nv-search-text :merge-cell="mergeCell" :nv-field="nvFields.SAMPLE8"/>
    <nv-search-text :nv-field="nvFields.SAMPLE"/>
    <nv-search-text :merge-cell="3" :nv-field="nvFields.SAMPLE3"/>
</template>
</nv-search-form>
typescript
const num = ref(3)
const mergeCell = ref(2)