123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- <template>
- <v-form ref="form" v-model="valid" class="login-form" @submit.prevent>
- <div>
- <v-row dense no-gutters class="justify-space-between">
- <template v-for="(item, index) in props.items.options">
- <slot :name="item.prevSlot"></slot>
- <v-col :key="item.key" v-if="!item.hide" :cols="item.col || '12'" class="position">
- <template v-if="item.slotTitle">
- <div :class="item.class" :style="item.slotTitleStyle">{{ item.slotTitle }}</div>
- </template>
- <div class="d-flex" :class="item.flexStyle || 'flex-row'">
- <v-text-field
- v-if="['text', 'password', 'number'].includes(item.type)"
- :type="item.type"
- v-model="item.value"
- :rules="item.rules"
- :disabled="item.disabled"
- :density="item.dense || 'compact'"
- :color="item.color"
- :label="item.label"
- :placeholder="item.placeholder || item.label"
- variant="outlined"
- :width="item.width"
- :autofocus="item.autofocus"
- :class="item.class"
- :suffix="item.suffix"
- :append-inner-icon="item.appendIcon"
- :clearable="item.clearable"
- :readonly="item.readonly"
- :prepend-inner-icon="item.prependInnerIcon"
- hide-spin-buttons
- @wheel="$event => handleWheel($event, item)"
- @keyup.enter="item.keyupEnterNative && item.keyupEnterNative(index)"
- @click="item.click && item.click(index)"
- @click:append-inner="item.clickAppendInner"
- @change="handleChange(item)"
- />
- <v-autocomplete
- v-if="item.type === 'autocomplete'"
- :rules="item.rules"
- v-model="item.value"
- :attach="!item.noAttach"
- :loading="item.loading"
- :label="item.label"
- :placeholder="item.placeholder || item.label"
- :items="item.items"
- :item-text="item.itemText || 'label'"
- :item-value="item.itemValue || 'value'"
- variant="outlined"
- :density="item.dense || 'compact'"
- :disabled="item.disabled"
- :multiple="item.multiple"
- :clearable="item.clearable"
- :search="item.searchInput"
- :hide-no-data="item.hideNoData"
- :no-data-text="item.noDataText || 'No data available'"
- :hide-selected="item.hideSelected"
- @change="handleChange(item)"
- >
- <template v-if="item.slotAppendItem" v-slot:append-item>
- <slot :name="item.slotAppendItem" :item="item"></slot>
- </template>
- <template v-if="item.prependItem" #prepend-item>
- <slot :name="item.prependItem" :item="item"></slot>
- </template>
- </v-autocomplete>
- <!-- autocomplete2 多选纸片样式 -->
- <v-autocomplete
- v-if="item.type === 'autocomplete2'"
- v-model="item.value"
- :rules="item.rules"
- :attach="!item.noAttach"
- :loading="item.loading"
- :label="item.label"
- :placeholder="item.placeholder || item.label"
- :items="item.canCreate ? [inputUpdateValue, ...item.items].filter(Boolean) : item.items"
- :item-text="item.itemText || 'label'"
- :item-value="item.itemValue || 'value'"
- variant="outlined"
- :density="item.dense || 'compact'"
- :multiple="item.multiple"
- :clearable="item.clearable"
- :search-input="item.searchInput"
- :hide-no-data="item.hideNoData"
- :hide-selected="item.hideSelected"
- :readonly="item.readonly"
- @change="handleChange(item)"
- @update:search-input="$event => item.canCreate ? inputUpdateValue = $event : inputUpdateAutocomplete($event)"
- :hide-details="!item.showDetails"
- deletable-chips
- cache-items
- small-chips
- ></v-autocomplete>
- <v-combobox
- v-if="item.type === 'combobox'"
- :rules="item.rules"
- v-model="item.value"
- :attach="true"
- :label="item.label"
- :placeholder="item.placeholder || item.label"
- :items="item.items"
- :item-text="item.itemText || 'label'"
- :item-value="item.itemValue || 'value'"
- variant="outlined"
- :density="item.dense || 'compact'"
- :clearable="item.clearable"
- :disabled="item.disabled"
- @change="handleChange(item)"
- >
- <template v-if="item.hasIcon" v-slot:selection="data">
- <v-icon color="blue darken-2">{{ data.item.label }}</v-icon>
- </template>
- <!-- <template v-if="item.hasIcon" v-slot:item="data">
- <v-list-item-avatar>
- <v-icon>{{ data.item.label }}</v-icon>
- </v-list-item-avatar>
- <v-list-item-content>
- {{ data.item.label }}
- </v-list-item-content>
- </template> -->
- </v-combobox>
- <v-textarea
- v-if="item.type === 'textarea'"
- :rules="item.rules"
- v-model="item.value"
- :label="item.label"
- :placeholder="item.placeholder || item.label"
- :no-resize="!item.resize"
- variant="outlined"
- :density="item.dense || 'compact'"
- :rows="item.rows || 3"
- :disabled="item.disabled"
- @change="handleChange(item)"
- ></v-textarea>
- <v-radio-group
- v-if="item.type === 'ifRadio'"
- v-model="item.value"
- :disabled="item.disabled"
- mandatory
- row
- @change="handleChange(item)"
- >
- <template v-slot:label>
- <div :style="`width: ${item.width || 120}px;`">{{ item.label }}</div>
- </template>
- <v-radio
- v-for="radio in item.items"
- :key="`${item.key}_radio_${radio.label}`"
- :readonly="radio.readonly"
- :label="radio.label"
- :value="radio.value"
- class="mr-8"
- ></v-radio>
- </v-radio-group>
- <template v-if="item.type === 'checkbox'">
- <div style="width: 120px;" class="mt-4 label text-left">{{ item.label }}</div>
- <div :style="item.style">
- <v-checkbox
- v-model="item.value"
- v-for="k in item.items"
- :key="k.key"
- :label="k.label"
- :color="item.color"
- :value="k.value"
- :readonly="k.readonly"
- hide-details
- :multiple="true"
- class="mr-3"
- ></v-checkbox>
- </div>
- </template>
- <v-file-input
- v-if="item.type === 'upload'"
- :prepend-icon="item.prependIcon || ''"
- :append-icon="item.appendIcon"
- :append-outer-icon="item.appendOuterIcon"
- :show-size="item.showSize"
- variant="outlined"
- :density="item.dense || 'compact'"
- v-model="item.value"
- :placeholder="item.placeholder || item.label"
- :hint="item.hint"
- :rules="item.rules"
- :label="item.label"
- :persistent-hint="item.persistentHint"
- :loading= "item.loading"
- :disabled="item.disabled"
- :multiple="item.multiple"
- :success="item.success"
- :error="item.error"
- :accept="item.accept || '.xlsx, .xls, .csv, .pdf, .txt, .doc'"
- @change="handleChange(item)"
- >
- <template v-if="item.selfAppend" #append>
- <slot :name="item.selfAppend" :data="item.value"></slot>
- </template>
- </v-file-input>
- <v-color-picker
- v-if="item.type === 'colorPicker'"
- class="mb-5"
- v-model="item.value"
- :elevation="item.elevation || 5"
- :dot-size="item.dotSize || 25"
- :show-swatches="item.showSwatches || false"
- swatches-max-height="200"
- :mode="item.mode || 'hexa'"
- :hide-mode-switch="true"
- @input="item.change"
- />
- <template v-if="item.type === 'switch'">
- <span v-if="item.describe"> {{ item.describe }} </span>
- <span class="ml-2" v-if="item.trueLabel"> {{ item.trueLabel }}</span>
- <v-switch
- dense hide-details class="mt-0 ml-2 pa-0"
- v-model="item.value"
- :label="item.label"
- :disabled="item.disabled || false"
- :color="item.color || 'primary'"
- :true-value="(item.trueValue !== undefined) ? item.trueValue : true"
- :false-value="(item.falseValue !== undefined) ? item.falseValue : false"
- ></v-switch>
- <span v-if="item.falseLabel"> {{ item.falseLabel }} </span>
- </template>
- <template v-if="item.type === 'date'">
- <div class="d-flex" style="margin-bottom: 22px;">
- <span class="label d-flex align-center" :style="`width: ${item.width || 120}px;`">{{ item.label }}</span>
- <!-- <date-picker
- :is-valid="isValid"
- :option="{ ...item.option, disabled: item.disabled }"
- v-model="item.value"
- :style="item.style"
- @change="item.value = $event; handleChange(item); handleCheck(item)"></date-picker> -->
- </div>
- </template>
- <template v-if="item.slotName">
- <slot :name="item.slotName" :item="item"></slot>
- </template>
- </div>
- </v-col>
- </template>
- </v-row>
- </div>
- <slot></slot>
- </v-form>
- </template>
- <script setup>
- // import DatePicker from '@/components/Form/datePicker.vue'
- import { ref, defineEmits } from 'vue'
- defineOptions({ name: 'form-index' })
- const props = defineProps({items: Object})
- const inputUpdateValue = ref('')
- const form = ref()
- const valid = ref(false)
- const isValid = ref(true)
- const emit = defineEmits(['inputUpdateAutocomplete', 'change'])
- const handleWheel = (event, item) => {
- if (item.type !== 'number') return
- event.preventDefault()
- if (event.deltaY > 0) {
- item.value--
- } else {
- item.value++
- }
- handleChange(item)
- }
- const handleCheck = (e) => {
- if (e.type !== 'date' || e.hide || !e.rules) return
- const rules = e.rules[0]
- const check = rules(e.value)
- if (typeof check === 'string') {
- e.option.error = true
- e.option.errorMsg = check
- return
- }
- e.option.error = false
- e.option.errorMsg = null
- }
- const validateTime = () => {
- isValid.value = true
- props.items.options.forEach((e) => {
- if (e.type !== 'date' || e.hide || !e.rules) return
- const rules = e.rules[0]
- const check = rules(e.value)
- if (typeof check === 'string') {
- isValid.value = false
- e.option.error = true
- e.option.errorMsg = check
- } else {
- e.option.error = false
- e.option.errorMsg = null
- }
- })
- return isValid.value
- }
- const validate = () => {
- const form = form.value.validate()
- const time = validateTime()
- return form && time
- }
- const inputUpdateAutocomplete = (val) => {
- emit('inputUpdateAutocomplete', val)
- }
- const resetValidation = () => {
- form.value.resetValidation()
- }
- const reset = () => {
- form.value.reset()
- }
- const handleChange = (item) => {
- if (item.type === 'date' && item.value) item.option.validate = false
- if (item?.change) item.change(item.value, item)
- emit('change', false)
- }
- </script>
- <style lang="scss" scoped>
- .position {
- position: relative;
- }
- .label {
- font-size: 14px;
- color: rgba(0, 0, 0, .6);
- }
- </style>
|