You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

397 lines
12 KiB

<script lang="ts" setup>
import { PropType } from 'vue'
import { propTypes } from '@/utils/propTypes'
import { useForm } from '@/hooks/web/useForm'
import { findIndex } from '@/utils'
import { cloneDeep } from 'lodash-es'
import { FormSchema } from '@/types/form'
import { useCache } from '@/hooks/web/useCache'
const { wsCache } = useCache()
const message = useMessage() // 消息弹窗
defineOptions({ name: 'Search' })
const { t } = useI18n()
const props = defineProps({
// 生成Form的布局结构数组
schema: {
type: Array as PropType<FormSchema[]>,
default: () => []
},
// 是否需要栅格布局
isCol: propTypes.bool.def(false),
// 表单label宽度
labelWidth: propTypes.oneOfType([String, Number]).def('auto'),
// 操作按钮风格位置
layout: propTypes.string.validate((v: string) => ['inline', 'bottom'].includes(v)).def('inline'),
// 底部按钮的对齐方式
buttomPosition: propTypes.string
.validate((v: string) => ['left', 'center', 'right'].includes(v))
.def('center'),
showSearch: propTypes.bool.def(true),
showReset: propTypes.bool.def(true),
// 是否显示伸缩
expand: propTypes.bool.def(false),
// 伸缩的界限字段
expandField: propTypes.string.def(''),
inline: propTypes.bool.def(true),
model: {
type: Object as PropType<Recordable>,
default: () => ({})
},
// 详情数据
detailData: {
type: Object,
required: true,
default: null
},
hiddenFilterBtnFields:{
type: Array,
required: false,
default: []
},
showSearchTableQueryFields:{
type: Array,
required: false,
default: []
},
formClassNames:{
type: Array,
required: false,
default: []
},
//回车触发搜索。默认true
enterSearch:{
type: Boolean,
required: false,
default: true
},
})
const emit = defineEmits(['search', 'reset','onInput','onChange','onEnter','searchTableSuccess','onBlur'])
const visible = ref(true)
const newSchema = computed(() => {
let schema: FormSchema[] = cloneDeep(props.schema)
if (!wsCache.get('ShowPackingNumber')) {
if (schema) {
schema = schema.filter(item => item.field != 'packingNumber')
}
}
if (props.expand && props.expandField && !unref(visible)) {
const index = findIndex(schema, (v: FormSchema) => v.field === props.expandField)
if (index > -1) {
const length = schema.length
schema.splice(index + 1, length)
}
}
if (props.layout === 'inline') {
schema = schema.concat([
{
field: 'action',
formItemProps: {
labelWidth: '0px'
}
}
])
}
updateSort(schema)
return schema
})
const updateSort= (val)=>{
val.forEach(item=>{
if(!item.sortSearchDefault){
if(item.field=="action"){
item.sortSearchDefault = 9999 // 查询重置等操作按钮
}else{
item.sortSearchDefault = 999 // 默认999
}
}
})
val.sort((column1,column2)=>{
return column1.sortSearchDefault - column2.sortSearchDefault
})
}
const { register, elFormRef, methods } = useForm({
model: props.model || {}
})
const onInput = (field,value) => {
emit('onInput', field,value)
}
const onChange = (field, value)=>{
emit('onChange', field,value)
}
const onSubmit = (e) => {
e.preventDefault();
}
const onEnter = async (field, value, e) => {
if(props.enterSearch){
search()
}else{
emit('onEnter', field, value, e)
}
}
const searchTableRef = ref()
const opensearchTable = (
formField,
searchField,
searchTitle,
searchAllSchemas,
searchPage,
searchCondition,
multiple,
type,
row,
isConcatDetailSchemas=false,
searchDetailSchemas: any
) => {
const _searchCondition = {}
// 判断查询条件中,是否存在指向主表的数据
if (searchCondition && searchCondition.length > 0) {
// 转换筛选条件所需
let filters: any[] = []
for (var i=0; i< searchCondition.length; i++ ) {
// searchCondition.forEach((item) => {
// 查询条件为主表某字段,需要赋值主表数据,数据来源是详情的,赋值需要从row中获取
if (searchCondition[i].isMainValue) {
let keyValue = formRef.value.formModel[searchCondition[i].value]
? formRef.value.formModel[searchCondition[i].value]
: props.detailData
? props.detailData[searchCondition[i].value]
: row
? row[searchCondition[i].value]
: ''
if(searchCondition[i].isCSV&&keyValue){
//用逗号分隔取参数
if(Array.isArray(keyValue)){
keyValue = keyValue.join(',')
}else{
keyValue = keyValue.split(' ')
keyValue.forEach(item=>{item = item.trim()})
keyValue = keyValue.join(',')
}
console.log('keyValue',keyValue)
}
_searchCondition[searchCondition[i].key] = keyValue
if(searchCondition[i].required){
// 是否含有空参数情况
let isNull = false
if (_searchCondition[searchCondition[i].key] == '' || _searchCondition[searchCondition[i].key] == undefined) {
isNull = true
}
if (isNull) {
message.warning(searchCondition[i].message?searchCondition[i].message:'前置条件未选择!')
return
}
}
}else if(searchCondition[i].isTableRowValue){
if(searchCondition[i].required){
if (row[searchCondition[i].value] == '' ||row[searchCondition[i].value] == undefined) {
message.warning(searchCondition[i].message?searchCondition[i].message:'前置条件未选择!')
return
}
}
row[searchCondition[i].value]
//查询当前table表数据的值
_searchCondition[searchCondition[i].key] = row[searchCondition[i].value]
} else {
// 扩展 转换为筛选条件进行查询
if (searchCondition[i].isSearch) {
if (searchCondition[i].isFormModel) {
//用formModel中的值
if(searchCondition[i].required){
if (formRef.value.formModel[searchCondition[i].value] == '' ||formRef.value.formModel[searchCondition[i].value] == undefined) {
message.warning(searchCondition[i].message?searchCondition[i].message:'前置条件未选择!')
return
}
}
filters.push({
action: searchCondition[i].action,
column: searchCondition[i].key,
value: formRef.value.formModel[searchCondition[i].value]
})
}else{
filters.push({
action: searchCondition[i].action,
column: searchCondition[i].key,
value: searchCondition[i].value
})
}
} else {
_searchCondition[searchCondition[i].key] = searchCondition[i].value
}
}
}
if (filters.length > 0) {
_searchCondition.isSearch = true
_searchCondition.filters = filters
}
}
const _searchTableTitle = searchTitle
const _searchTableAllSchemas = searchAllSchemas
const _searchTablePage = searchPage
searchTableRef.value.open(
_searchTableTitle,
_searchTableAllSchemas,
_searchTablePage,
formField,
searchField,
multiple,
type,
row,
_searchCondition,
undefined,
isConcatDetailSchemas,
searchDetailSchemas
)
}
const formRef = ref()
const setFormValues = (formData)=>{
formRef.value.setValues(formData)
}
const search = async () => {
await unref(elFormRef)?.validate(async (isValid) => {
if (isValid) {
const { getFormData } = methods
const model = await getFormData()
console.log(model)
emit('search', model)
}
})
}
const reset = async () => {
unref(elFormRef)?.resetFields()
const { getFormData } = methods
const model = await getFormData()
emit('reset', model)
}
const bottonButtonStyle = computed(() => {
return {
textAlign: props.buttomPosition as unknown as 'left' | 'center' | 'right'
}
})
const setVisible = () => {
unref(elFormRef)?.resetFields()
visible.value = !unref(visible)
}
// 弹层确定返回所选数据
// val : 弹层列表row 数据
const searchTableSuccess = (formField, searchField, val, type, row) => {
emit('searchTableSuccess', formField, searchField, val, formRef.value, type, row)
}
const onBlur = async (field, e) => {
emit('onBlur', field, e)
}
const Search = ref()
onMounted(() => {})
defineExpose({setFormValues,search}) // 提供 open 方法,用于打开弹窗
</script>
<template>
<!-- update by 芋艿class="-mb-15px" 用于降低和 ContentWrap 组件的底部距离避免空隙过大 -->
<div ref="Search">
<Form ref="formRef"
:inline="inline"
:is-col="isCol"
:is-custom="false"
:label-width="labelWidth"
:schema="newSchema"
class="-mb-15px search"
:class="formClassNames"
hide-required-asterisk
@register="register"
@onInput="onInput"
@opensearchTable="opensearchTable"
@onChange="onChange"
@onEnter="onEnter"
@onSubmit="onSubmit"
@onBlur="onBlur"
>
<template #action>
<div v-if="layout === 'inline'">
<!-- update by 芋艿:去除搜索的 type="primary",颜色变淡一点 -->
<ElButton type="info" plain v-if="showSearch" @click="search">
<Icon class="mr-5px" icon="ep:search" />
{{ t('common.query') }}
</ElButton>
<!-- update by 芋艿:将 icon="ep:refresh-right" 修改成 icon="ep:refresh",和 ruoyi-vue 搜索保持一致 -->
<ElButton type="info" plain v-if="showReset" @click="reset">
<Icon class="mr-5px" icon="ep:refresh" />
{{ t('common.reset') }}
</ElButton>
<ElButton type="info" plain v-if="expand" text @click="setVisible">
{{ t(visible ? 'common.shrink' : 'common.expand') }}
<Icon :icon="visible ? 'ep:arrow-up' : 'ep:arrow-down'" />
</ElButton>
<!-- add by 芋艿:补充在搜索后的按钮 -->
<slot name="actionMore"></slot>
</div>
</template>
<template v-for="name in Object.keys($slots)" :key="name" #[name]>
<slot :name="name"></slot>
</template>
</Form>
</div>
<template v-if="layout === 'bottom'">
<div :style="bottonButtonStyle">
<ElButton v-if="showSearch" type="primary" @click="search">
<Icon class="mr-5px" icon="ep:search" />
{{ t('common.query') }}
</ElButton>
<ElButton v-if="showReset" @click="reset">
<Icon class="mr-5px" icon="ep:refresh-right" />
{{ t('common.reset') }}
</ElButton>
<ElButton v-if="expand" text @click="setVisible">
{{ t(visible ? 'common.shrink' : 'common.expand') }}
<Icon :icon="visible ? 'ep:arrow-up' : 'ep:arrow-down'" />
</ElButton>
<!-- add by 芋艿:补充在搜索后的按钮 -->
<slot name="actionMore"></slot>
</div>
</template>
<SearchTable ref="searchTableRef" :hiddenFilterBtnFields="hiddenFilterBtnFields" :showSearchTableQueryFields="showSearchTableQueryFields" @searchTableSuccess="searchTableSuccess" />
</template>
<style lang="scss" scoped>
.search ::v-deep(.el-form-item) {
margin-right: 1%;
width: 24%;
}
.dateSearch ::v-deep(.el-form-item) {
margin-right: 1%;
min-width: 320px;
width:32%;
}
.search ::v-deep(.el-form-item:nth-last-child(1)) {
margin-right: 0px;
width: auto;
.el-form-item__content {
flex: 1;
>div{
flex: 1;
button {
width: 46%;
max-width: 80px;
}
}
}
}
</style>