mirror of
https://github.com/fugary/simple-element-plus-template.git
synced 2025-11-12 14:27:49 +00:00
search表单
This commit is contained in:
@@ -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%
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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: ''
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user