search表单

This commit is contained in:
Gary Fu
2024-01-06 18:11:40 +08:00
parent a32d6b2eac
commit 62f7ad4b9c
5 changed files with 297 additions and 237 deletions

View File

@@ -97,6 +97,10 @@ html, body, #app, .index-container {
padding-top: 20px;
}
.common-form.el-form--inline .el-input{
--el-input-width: 220px;
}
.form-edit-width-70 {
width:70%
}

View File

@@ -29,6 +29,7 @@
* @property {string} labelKey label字段名
* @property {number} debounceTime 防抖时间
* @property {string} autocompleteWidth 宽度
* @property {string} inputWidth input宽度
* @property {CommonSelectPageOption} selectPageConfig 分页
* @property {Number} colSize 显示几列
* @property {string} loadingText 加载提示loading
@@ -36,7 +37,7 @@
* @property {Object} inputAttrs 输入框配置项
*/
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import { debounce } from 'lodash'
import { debounce, isObject } from 'lodash'
import { onClickOutside, onKeyStroke, useVModel } from '@vueuse/core'
import chunk from 'lodash/chunk'
@@ -80,6 +81,10 @@ const props = defineProps({
type: String,
default: '500px'
},
inputWidth: {
type: String,
default: '220px'
},
autocompleteConfig: {
type: Object,
required: true
@@ -122,7 +127,7 @@ const props = defineProps({
}
})
const emit = defineEmits(['update:modelValue', 'onSelectData', 'update:defaultLabel'])
const emit = defineEmits(['update:modelValue', 'change', 'update:defaultLabel'])
// 关键字搜索
const keywords = ref(props.defaultLabel)
// 上次搜索记录
@@ -214,15 +219,32 @@ watch(() => popoverVisible.value, (val) => {
}
})
watch(() => props.modelValue, (value) => {
console.info('=====================value', value)
if (!props.useIdModel) {
setAutocompleteLabel(value && isObject(value) ? value[labelProp.value] : '')
}
vModel.value = value
})
watch(() => props.defaultLabel, (label) => {
setAutocompleteLabel(label)
})
//* ********************数据选择*********************
const vModel = useVModel(props, 'modelValue', emit)
const vAutocompleteLabel = useVModel(props, 'defaultLabel', emit)
const vDefaultLabel = useVModel(props, 'defaultLabel', emit)
const setAutocompleteLabel = label => {
keywords.value = label
vDefaultLabel.value = label
lastAutocompleteLabel.value = label
}
const onSelectData = (row) => {
popoverVisible.value = false
if (!vModel.value && !row) {
console.info('==================', row)
return
}
let label = ''
@@ -231,11 +253,9 @@ const onSelectData = (row) => {
label = row[labelProp.value]
value = props.useIdModel ? row[idProp.value] : row
}
keywords.value = label
vAutocompleteLabel.value = label
lastAutocompleteLabel.value = label
setAutocompleteLabel(label)
vModel.value = value
emit('onSelectData', row)
emit('change', row)
}
// =======================按键处理===================
@@ -316,114 +336,113 @@ const selectPagePaginationChange = (tab, pageNumber) => {
</script>
<template>
<div>
<el-popover
ref="autocompletePopover"
:visible="popoverVisible"
popper-class="common-autocomplete"
placement="bottom-start"
:width="autocompleteWidth"
:title="title||placeholder"
>
<template #reference>
<el-input
v-model="keywords"
:clearable="clearable"
:placeholder="placeholder||title"
:disabled="disabled"
:readonly="readonly"
v-bind="inputAttrs"
@input="onInputKeywords(true)"
@click="onInputKeywords(false)"
/>
</template>
<template #default>
<div v-if="showSelectPage">
<el-tabs
v-model="selectPageTab"
class="common-select-page"
type="border-card"
@tab-click="onInputKeywords(false)"
>
<el-tab-pane
v-for="tab in selectPageConfig.tabs"
:key="tab.id"
:name="tab.id"
>
<template #label>
<span>{{ tab.label }}</span>
</template>
<template #default>
<div
v-loading="loadingData"
:element-loading-text="loadingText"
class="select-page-content"
:style="{minHeight}"
>
<template
v-for="(rowData, index) in parsedSelectPageData[tab.id]"
:key="index"
>
<el-row>
<el-col
v-for="(colData, idx) in rowData"
:key="idx"
:span="24/colSize"
>
<el-button
plain
class="common-select-page-btn is-text"
@click="onSelectData(colData)"
>
{{ colData[labelProp] }}
</el-button>
</el-col>
</el-row>
</template>
<el-pagination
v-if="selectPagePagination(tab)"
:style="{'justify-content':'center'}"
v-bind="selectPageAttrs"
:total="selectPagePageConfig[tab.id].totalCount"
:page-size="selectPagePageConfig[tab.id].pageSize"
:current-page="selectPagePageConfig[tab.id].pageNumber"
@current-change="selectPagePaginationChange(tab, $event)"
/>
</div>
</template>
</el-tab-pane>
</el-tabs>
</div>
<!--自动完成内容-->
<common-table
v-else
ref="tableRef"
v-model:page="autoPage"
:loading="loadingData"
:loading-text="loadingText"
class="autocomplete-table"
:columns="autocompleteConfig.columns"
:empty-text="autocompleteConfig.emptyMessage"
:data="dataList"
:page-attrs="pageAttrs"
@row-click="onSelectData($event)"
@current-page-change="onInputKeywords(false)"
<el-popover
ref="autocompletePopover"
:visible="popoverVisible"
popper-class="common-autocomplete"
placement="bottom-start"
:width="autocompleteWidth"
:title="title||placeholder"
>
<template #reference>
<el-input
v-model="keywords"
:clearable="clearable"
:placeholder="placeholder||title"
:disabled="disabled"
:readonly="readonly"
:style="{width: inputWidth}"
v-bind="inputAttrs"
@input="onInputKeywords(true)"
@click="onInputKeywords(false)"
/>
</template>
<template #default>
<div v-if="showSelectPage">
<el-tabs
v-model="selectPageTab"
class="common-select-page"
type="border-card"
@tab-click="onInputKeywords(false)"
>
<template
v-for="column in autocompleteConfig.columns"
#[column.slot]="scope"
<el-tab-pane
v-for="tab in selectPageConfig.tabs"
:key="tab.id"
:name="tab.id"
>
<slot
v-if="column.slot"
:item="scope.item"
:column-conf="scope.columnConf"
:name="column.slot"
/>
</template>
</common-table>
</template>
</el-popover>
</div>
<template #label>
<span>{{ tab.label }}</span>
</template>
<template #default>
<div
v-loading="loadingData"
:element-loading-text="loadingText"
class="select-page-content"
:style="{minHeight}"
>
<template
v-for="(rowData, index) in parsedSelectPageData[tab.id]"
:key="index"
>
<el-row>
<el-col
v-for="(colData, idx) in rowData"
:key="idx"
:span="24/colSize"
>
<el-button
plain
class="common-select-page-btn is-text"
@click="onSelectData(colData)"
>
{{ colData[labelProp] }}
</el-button>
</el-col>
</el-row>
</template>
<el-pagination
v-if="selectPagePagination(tab)"
:style="{'justify-content':'center'}"
v-bind="selectPageAttrs"
:total="selectPagePageConfig[tab.id].totalCount"
:page-size="selectPagePageConfig[tab.id].pageSize"
:current-page="selectPagePageConfig[tab.id].pageNumber"
@current-change="selectPagePaginationChange(tab, $event)"
/>
</div>
</template>
</el-tab-pane>
</el-tabs>
</div>
<!--自动完成内容-->
<common-table
v-else
ref="tableRef"
v-model:page="autoPage"
:loading="loadingData"
:loading-text="loadingText"
class="autocomplete-table"
:columns="autocompleteConfig.columns"
:empty-text="autocompleteConfig.emptyMessage"
:data="dataList"
:page-attrs="pageAttrs"
@row-click="onSelectData($event)"
@current-page-change="onInputKeywords(false)"
>
<template
v-for="column in autocompleteConfig.columns"
#[column.slot]="scope"
>
<slot
v-if="column.slot"
:item="scope.item"
:column-conf="scope.columnConf"
:name="column.slot"
/>
</template>
</common-table>
</template>
</el-popover>
</template>
<style scoped>

View File

@@ -31,6 +31,10 @@ const props = defineProps({
type: Object,
default: null
},
validateOnRuleChange: {
type: Boolean,
default: false
},
showButtons: {
type: Boolean,
default: true
@@ -99,10 +103,9 @@ const emit = defineEmits(['submitForm', 'update:model'])
const formModel = useVModel(props, 'model', emit)
watch(() => props.options, (options) => {
console.info('=================options', options)
options.forEach(option => {
if (formModel.value && option.value) {
formModel.value[option.prop] = option.value
if (formModel.value) {
formModel.value[option.prop] = option.value || undefined
}
})
rules.value = initRules()
@@ -121,10 +124,12 @@ defineExpose({
<template>
<el-form
ref="form"
class="common-form"
:model="formModel"
:rules="rules"
:label-width="labelWidth"
v-bind="$attrs"
:validate-on-rule-change="validateOnRuleChange"
>
<common-form-control
v-for="(option,index) in options"

View File

@@ -1,125 +1,154 @@
<script setup>
import { ref } from 'vue'
import { computed, ref } from 'vue'
import { useCityAutocompleteConfig, useCitySelectPageConfig } from '@/services/city/CityService'
import { $i18nMsg } from '@/messages'
const defaultCity = ref({})
setTimeout(() => {
defaultCity.value = {
code: 'SHA',
nameCn: '上海',
nameEn: 'Shanghai'
}
}, 1000)
/**
* @type {[CommonFormOption]}
*/
const formOptions = ref([{
label: '用户名',
prop: 'userName',
value: '',
placeholder: '请输入用户名',
required: true,
rules: [
{
min: 2,
max: 6,
message: '用户名在2-6位之间'
const formOptions = computed(() => {
return [{
label: '用户名',
prop: 'userName',
value: '',
placeholder: '请输入用户名',
required: true,
rules: [
{
min: 2,
max: 6,
message: '用户名在2-6位之间'
}
]
}, {
label: '密码',
prop: 'userPassword',
value: '',
placeholder: '请输入密码',
required: true,
pattern: /.{2,6}/,
attrs: {
showPassword: true
}
]
}, {
label: '密码',
prop: 'userPassword',
value: '',
placeholder: '请输入密码',
required: true,
pattern: /.{2,6}/,
attrs: {
showPassword: true
}
}, {
label: '出生日期',
type: 'date-picker',
prop: 'birthday',
value: '',
placeholder: '选择出生日期',
required: true
}, {
label: '兴趣爱好',
type: 'checkbox-group',
prop: 'hobby',
value: '',
required: true,
children: [
{
label: '编程',
value: 'program'
}, {
label: '出生日期',
type: 'date-picker',
prop: 'birthday',
value: '',
placeholder: '选择出生日期',
required: true
}, {
label: '兴趣爱好',
type: 'checkbox-group',
prop: 'hobby',
value: '',
required: true,
children: [
{
label: '编程',
value: 'program'
},
{
label: '吃饭',
value: 'eat'
},
{
label: '睡觉',
value: 'sleep'
}
]
}, {
label: '职业',
type: 'select',
prop: 'career',
value: '',
required: true,
children: [
{
label: '程序员',
value: 'programer'
},
{
label: '无业游民',
value: 'none'
},
{
label: '教师',
value: 'teacher'
}
]
}, {
label: '性别',
type: 'radio-group',
prop: 'gender',
value: '',
required: true,
children: [
{
label: '男',
value: 'male'
},
{
label: '女',
value: 'female'
},
{
label: '保密',
value: 'unknown'
}
]
}, {
label: '图标',
prop: 'icon',
value: '',
type: 'common-icon-select',
required: true
}, {
label: '城市',
prop: 'city',
value: defaultCity.value?.code,
type: 'common-autocomplete',
required: true,
placeholder: '请选择城市',
change: (city) => {
defaultCity.value = city
},
{
label: '吃饭',
value: 'eat'
},
{
label: '睡觉',
value: 'sleep'
attrs: {
defaultLabel: $i18nMsg(defaultCity.value?.nameCn, defaultCity.value?.nameEn),
autocompleteConfig: useCityAutocompleteConfig(),
selectPageConfig: useCitySelectPageConfig()
}
]
}, {
label: '职业',
type: 'select',
prop: 'career',
value: '',
required: true,
children: [
{
label: '程序员',
value: 'programer'
},
{
label: '无业游民',
value: 'none'
},
{
label: '教师',
value: 'teacher'
}, {
label: '城市1',
prop: 'city1',
value: defaultCity,
type: 'common-autocomplete',
required: true,
placeholder: '请选择城市1',
attrs: {
useIdModel: false,
autocompleteConfig: useCityAutocompleteConfig(),
selectPageConfig: useCitySelectPageConfig()
}
]
}, {
label: '性别',
type: 'radio-group',
prop: 'gender',
value: '',
required: true,
children: [
{
label: '男',
value: 'male'
},
{
label: '女',
value: 'female'
},
{
label: '保密',
value: 'unknown'
}, {
label: '地址',
prop: 'address',
value: '',
attrs: {
type: 'textarea'
}
]
}, {
label: '图标',
prop: 'icon',
value: '',
type: 'common-icon-select',
required: true
}, {
label: '城市',
prop: 'city',
value: 'SHA',
type: 'common-autocomplete',
required: true,
placeholder: '请选择城市',
attrs: {
defaultLabel: '上海市',
autocompleteConfig: useCityAutocompleteConfig(),
selectPageConfig: useCitySelectPageConfig()
}
}, {
label: '地址',
prop: 'address',
value: '',
attrs: {
type: 'textarea'
}
}])
}]
})
const userDto = ref({
userName: '',
userPassword: ''

View File

@@ -82,20 +82,22 @@ const searchFormOptions = computed(() => {
{
label: '用户名',
prop: 'nameCn'
},
{
label: '关键字',
prop: 'keywords'
},
{
label: '地址',
prop: 'address'
}, {
label: $i18nMsg('性别', 'Gender'),
type: 'select',
prop: 'gender',
children: [{
type: 'option',
value: '',
label: '请选择'
}, {
type: 'option',
value: 'male',
label: $i18nMsg('男', 'Male')
}, {
type: 'option',
value: 'female',
label: $i18nMsg('女', 'Female')
}]
@@ -106,9 +108,9 @@ const doSearch = form => {
console.info('=================searchParam', searchParam.value)
}
/** *************用户编辑**************/
const currentUser = ref({})
const currentUser = ref(null)
const showEdit = ref(false)
const userFormOptions = ref(useUserFormOptions())
const userFormOptions = computed(() => useUserFormOptions())
const toEditUser = user => {
currentUser.value = { ...user }
showEdit.value = true
@@ -171,6 +173,7 @@ const submitForm = () => {
title="用户编辑"
>
<common-form
v-if="currentUser"
ref="formRef"
class="form-edit-width-100"
:model="currentUser"