|
|
@ -1,8 +1,8 @@ |
|
|
|
<template> |
|
|
|
<div v-show="fieldMethodsClass.getShow(props, modelValue)"> |
|
|
|
<q-input |
|
|
|
<q-field |
|
|
|
ref="textSelectRef" |
|
|
|
v-model="displayValueComputed" |
|
|
|
v-model="modelValue" |
|
|
|
:hide-bottom-space="true" |
|
|
|
:hide-hint="true" |
|
|
|
:outlined="true" |
|
|
@ -10,28 +10,26 @@ |
|
|
|
:autogrow="true" |
|
|
|
v-bind="attrs" |
|
|
|
:bottom-slots="counter" |
|
|
|
:stack-label="!Tools.isEmpty(displayValueComputed)" |
|
|
|
type="text" |
|
|
|
:rules="fieldMethodsClass.getRules(props, { value: modelValue, displayValue: displayValueComputed }, textSelectRef, undefined)" |
|
|
|
:readonly="fieldMethodsClass.getReadOnly(props, { value: modelValue, displayValue: displayValueComputed })" |
|
|
|
:disable="fieldMethodsClass.getDisable(props, { value: modelValue, displayValue: displayValueComputed })" |
|
|
|
:clearable="false" |
|
|
|
@focus=" |
|
|
|
() => { |
|
|
|
textSelectRef?.blur(); |
|
|
|
} |
|
|
|
" |
|
|
|
> |
|
|
|
<template #control> |
|
|
|
<div>{{ displayValueComputed }}</div> |
|
|
|
</template> |
|
|
|
<!-- label --> |
|
|
|
<template #label><w-label :required="fieldMethodsClass.getRequired(props, modelValue)" :label="attrs.label"></w-label></template> |
|
|
|
|
|
|
|
<template v-if="!props['form'] || (props['form'] && props['form'].getStatus() !== 'view')" #append> |
|
|
|
<q-btn v-if="!Tools.isEmpty(displayValueComputed)" flat square unelevated dense icon="cancel" @click="fieldMethodsClass.clearValue"></q-btn> |
|
|
|
<q-btn flat square unelevated dense icon="manage_search"> |
|
|
|
<q-popup-proxy v-model:model-value="isShow" anchor="bottom right" self="top right" :offset="[0, 10]"> |
|
|
|
<div style="width: 700px; height: 300px"> |
|
|
|
<div :style="popupProxyStyleComputed"> |
|
|
|
<w-grid |
|
|
|
ref="gridRef" |
|
|
|
v-bind="{ ...props.grid, onRowClick: undefined }" |
|
|
|
v-bind="{ ...props.grid, onRowClick: undefined, height: undefined, width: undefined }" |
|
|
|
db-click-operation="none" |
|
|
|
:checkbox-selection="props.multiple || false" |
|
|
|
:dense="true" |
|
|
@ -52,33 +50,42 @@ |
|
|
|
<template v-if="counter" #counter> |
|
|
|
<div>{{ modelValue?.length }}</div> |
|
|
|
</template> |
|
|
|
</q-input> |
|
|
|
</q-field> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script setup lang="ts"> |
|
|
|
import { ref, computed, useAttrs, toRaw, watch, onMounted } from 'vue'; |
|
|
|
import { ref, computed, useAttrs, toRaw, watch, onMounted, nextTick } from 'vue'; |
|
|
|
import { Tools, axios } from '@/platform'; |
|
|
|
import { FormFieldProps } from '@/platform/components/form/FormField.ts'; |
|
|
|
import { FormFieldMethods } from '../form/FormField'; |
|
|
|
|
|
|
|
const textSelectRef = ref(); |
|
|
|
const gridRef = ref(); |
|
|
|
const attrs = useAttrs(); |
|
|
|
const modelValue = defineModel<string | Array<string>>(); |
|
|
|
const modelValue = defineModel<string | Array<string>>(); // 模型值 |
|
|
|
const modelDisplayValue = ref(''); // 模型显示值(通过下拉按钮打开表格后选择的) |
|
|
|
const customDisplayValue = ref(''); // 客户自定义显示值(通过setDisplayValue设置的) |
|
|
|
const modelObjectValue = ref(<any>[]); // 模型值包含实际值与显示值的对象集合。 |
|
|
|
const isShow = ref(false); // 是否显示下拉表格 |
|
|
|
const needFetchData = ref(true); // 模型值更改时是否需要去后台加载数据用以设置显示值 |
|
|
|
|
|
|
|
// { value: xxx, displayvalue: xxx } |
|
|
|
// { value: xxx, displayvalue: xxx } |
|
|
|
|
|
|
|
const gridRef = ref(); |
|
|
|
|
|
|
|
const isShow = ref(false); |
|
|
|
/** |
|
|
|
* 当用户调用setDisplayValue后以customDisplayValue变量为显示值,否则使用customDisplayValue |
|
|
|
*/ |
|
|
|
const displayValueComputed = computed(() => { |
|
|
|
if (!Tools.isEmpty(customDisplayValue.value)) { |
|
|
|
return customDisplayValue.value; |
|
|
|
} |
|
|
|
return modelDisplayValue.value; |
|
|
|
}); |
|
|
|
|
|
|
|
interface FieldProps extends FormFieldProps { |
|
|
|
multiple?: boolean; |
|
|
|
counter?: boolean; |
|
|
|
displayValue: string | ((args: object) => ''); |
|
|
|
grid: object; // 表格配置项 |
|
|
|
selectableIf?: (args: object) => ''; |
|
|
|
} |
|
|
|
const props = withDefaults(defineProps<FieldProps>(), { |
|
|
|
showIf: true, |
|
|
@ -93,6 +100,7 @@ const props = withDefaults(defineProps<FieldProps>(), { |
|
|
|
* } |
|
|
|
*/ |
|
|
|
displayValue: '', |
|
|
|
selectableIf: undefined, |
|
|
|
}); |
|
|
|
class FieldMethods extends FormFieldMethods { |
|
|
|
// 组件值改变事件调用的方法 |
|
|
@ -101,6 +109,7 @@ class FieldMethods extends FormFieldMethods { |
|
|
|
props['onUpdateValue']({ |
|
|
|
value: value_, |
|
|
|
displayValue: displayValueComputed.value, |
|
|
|
row: getRow(value_), |
|
|
|
form: props['form'], |
|
|
|
}); |
|
|
|
} |
|
|
@ -111,14 +120,12 @@ class FieldMethods extends FormFieldMethods { |
|
|
|
}; |
|
|
|
|
|
|
|
// 组件设置值 |
|
|
|
setValue = (value) => { |
|
|
|
setValue = async (value) => { |
|
|
|
if (props.multiple && Array.isArray(value) && Array.isArray(modelValue.value)) { |
|
|
|
fieldMethodsClass.clearValue(); |
|
|
|
modelValue.value.push(...value); |
|
|
|
setObjectValueByValue(value); |
|
|
|
modelValue.value = [...value]; |
|
|
|
} else if (!props.multiple && !Array.isArray(value)) { |
|
|
|
modelValue.value = value; |
|
|
|
setObjectValueByValue(value); |
|
|
|
} else { |
|
|
|
console.info('error========模型值不匹配'); |
|
|
|
} |
|
|
@ -127,6 +134,10 @@ class FieldMethods extends FormFieldMethods { |
|
|
|
getValue = () => { |
|
|
|
return modelValue.value; |
|
|
|
}; |
|
|
|
// 设置显示值 |
|
|
|
setDisplayValue = (value) => { |
|
|
|
customDisplayValue.value = value; |
|
|
|
}; |
|
|
|
// 获取组件包含实际与显示值的对象 |
|
|
|
getObjectValue = () => { |
|
|
|
return modelObjectValue.value; |
|
|
@ -134,21 +145,43 @@ class FieldMethods extends FormFieldMethods { |
|
|
|
// 组件清空值 |
|
|
|
clearValue = () => { |
|
|
|
if (props.multiple && Array.isArray(modelValue.value)) { |
|
|
|
modelValue.value.splice(0, modelValue.value.length); |
|
|
|
modelValue.value = []; |
|
|
|
} else { |
|
|
|
modelValue.value = undefined; |
|
|
|
} |
|
|
|
fieldMethodsClass.clearObjectValue(); |
|
|
|
_setDisplayValue(); |
|
|
|
customDisplayValue.value = ''; |
|
|
|
}; |
|
|
|
// 清空显示值 |
|
|
|
clearObjectValue = () => { |
|
|
|
modelObjectValue.value.splice(0, modelObjectValue.value.length); |
|
|
|
modelObjectValue.value = []; |
|
|
|
}; |
|
|
|
} |
|
|
|
const fieldMethodsClass = new FieldMethods(); |
|
|
|
const valueUseColumnName = props.grid['primaryKey'] || 'id'; |
|
|
|
|
|
|
|
const displayValueComputed = computed(() => { |
|
|
|
const popupProxyStyleComputed = computed(() => { |
|
|
|
let height = '300px'; |
|
|
|
let width = '700px'; |
|
|
|
if (!Tools.isEmpty(props.grid['height'])) { |
|
|
|
if (typeof props.grid['height'] === 'number') { |
|
|
|
height = props.grid['height'] + 'px'; |
|
|
|
} else { |
|
|
|
height = props.grid['height']; |
|
|
|
} |
|
|
|
} |
|
|
|
if (!Tools.isEmpty(props.grid['width'])) { |
|
|
|
if (typeof props.grid['width'] === 'number') { |
|
|
|
width = props.grid['width'] + 'px'; |
|
|
|
} else { |
|
|
|
width = props.grid['width']; |
|
|
|
} |
|
|
|
} |
|
|
|
return { height, width }; |
|
|
|
}); |
|
|
|
|
|
|
|
const _setDisplayValue = () => { |
|
|
|
let result = ''; |
|
|
|
if (modelObjectValue.value.length > 0) { |
|
|
|
modelObjectValue.value.forEach((item) => { |
|
|
@ -156,11 +189,27 @@ const displayValueComputed = computed(() => { |
|
|
|
}); |
|
|
|
result = result.substring(1, result.length); |
|
|
|
} |
|
|
|
return result; |
|
|
|
}); |
|
|
|
modelDisplayValue.value = result; |
|
|
|
}; |
|
|
|
|
|
|
|
// 根据实际值获取行数据 |
|
|
|
const getRow = (value_) => { |
|
|
|
if (Array.isArray(value_)) { |
|
|
|
const row = {}; |
|
|
|
value_.forEach((v) => { |
|
|
|
const findRow = modelObjectValue.value.find((item) => item.value === v); |
|
|
|
row[v] = findRow?.row; |
|
|
|
}); |
|
|
|
return row; |
|
|
|
} else { |
|
|
|
const findRow = modelObjectValue.value.find((item) => item.value === value_); |
|
|
|
const row = findRow?.row; |
|
|
|
return row; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// 获取最终显示在页面上的显示值 |
|
|
|
const getActualDisplayValue = (row) => { |
|
|
|
// 格式化每个最终显示在页面上的显示值 |
|
|
|
const formatDisplayValue = (row) => { |
|
|
|
if (!Tools.isEmpty(props.displayValue) && typeof props.displayValue === 'function') { |
|
|
|
return props.displayValue({ |
|
|
|
data: toRaw(row), |
|
|
@ -174,17 +223,34 @@ const getActualDisplayValue = (row) => { |
|
|
|
|
|
|
|
// 修改列头checkbox的状态事件 |
|
|
|
const updateTickeds = (args) => { |
|
|
|
if (props.selectableIf && typeof props.selectableIf === 'function') { |
|
|
|
if (!props.selectableIf(args)) { |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
needFetchData.value = false; |
|
|
|
customDisplayValue.value = ''; |
|
|
|
fieldMethodsClass.clearValue(); |
|
|
|
if (args.value && Array.isArray(modelValue.value)) { |
|
|
|
const rows = gridRef.value.getRows(); |
|
|
|
const tickeds = <any>[]; |
|
|
|
rows.forEach((item) => { |
|
|
|
modelValue.value.push(item[valueUseColumnName]); |
|
|
|
modelObjectValue.value.push({ value: item[valueUseColumnName], displayValue: getActualDisplayValue(item) }); |
|
|
|
tickeds.push(item[valueUseColumnName]); |
|
|
|
modelObjectValue.value.push({ value: item[valueUseColumnName], displayValue: formatDisplayValue(item), row: toRaw(item) }); |
|
|
|
}); |
|
|
|
modelValue.value = tickeds; |
|
|
|
} |
|
|
|
_setDisplayValue(); |
|
|
|
}; |
|
|
|
// 修改行数据checkbox的状态事件 |
|
|
|
const updateTicked = (args) => { |
|
|
|
if (props.selectableIf && typeof props.selectableIf === 'function') { |
|
|
|
if (!props.selectableIf(args)) { |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
needFetchData.value = false; |
|
|
|
customDisplayValue.value = ''; |
|
|
|
if (Array.isArray(modelValue.value)) { |
|
|
|
if (props.grid['tree']) { |
|
|
|
fieldMethodsClass.clearValue(); |
|
|
@ -192,8 +258,8 @@ const updateTicked = (args) => { |
|
|
|
const rows = gridRef.value.getTickedRows(); |
|
|
|
if (rows?.length > 0) { |
|
|
|
rows.forEach((item) => { |
|
|
|
modelValue.value.push(item[valueUseColumnName]); |
|
|
|
modelObjectValue.value.push({ value: item[valueUseColumnName], displayValue: getActualDisplayValue(item) }); |
|
|
|
modelValue.value = [...modelValue.value, item[valueUseColumnName]]; |
|
|
|
modelObjectValue.value.push({ value: item[valueUseColumnName], displayValue: formatDisplayValue(item), row: toRaw(item) }); |
|
|
|
}); |
|
|
|
} |
|
|
|
} else { |
|
|
@ -202,26 +268,38 @@ const updateTicked = (args) => { |
|
|
|
}); |
|
|
|
if (args.row['ticked']) { |
|
|
|
if (index < 0) { |
|
|
|
modelValue.value.push(args.row[valueUseColumnName]); |
|
|
|
modelObjectValue.value.push({ value: args.row[valueUseColumnName], displayValue: getActualDisplayValue(args.row) }); |
|
|
|
modelValue.value = [...modelValue.value, args.row[valueUseColumnName]]; |
|
|
|
modelObjectValue.value.push({ value: args.row[valueUseColumnName], displayValue: formatDisplayValue(args.row), row: toRaw(args.row) }); |
|
|
|
} |
|
|
|
} else { |
|
|
|
modelValue.value.splice(index, 1); |
|
|
|
removeItem(index); |
|
|
|
modelObjectValue.value.splice(index, 1); |
|
|
|
} |
|
|
|
} |
|
|
|
_setDisplayValue(); |
|
|
|
} |
|
|
|
}; |
|
|
|
const removeItem = (index) => { |
|
|
|
const result = modelValue.value.filter((item, index_) => index !== index_); |
|
|
|
modelValue.value = result; |
|
|
|
}; |
|
|
|
const rowClick = (args) => { |
|
|
|
if (props.selectableIf && typeof props.selectableIf === 'function') { |
|
|
|
if (!props.selectableIf(args)) { |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
needFetchData.value = false; |
|
|
|
customDisplayValue.value = ''; |
|
|
|
const modelValue_ = args.row[valueUseColumnName]; |
|
|
|
if (props.multiple && Array.isArray(modelValue.value)) { |
|
|
|
fieldMethodsClass.clearValue(); |
|
|
|
modelValue.value.push(modelValue_); |
|
|
|
modelObjectValue.value.push({ value: modelValue_, displayValue: getActualDisplayValue(args.row) }); |
|
|
|
modelValue.value = [modelValue_]; |
|
|
|
modelObjectValue.value.push({ value: modelValue_, displayValue: formatDisplayValue(args.row), row: toRaw(args.row) }); |
|
|
|
} else if (!props.multiple) { |
|
|
|
fieldMethodsClass.clearValue(); |
|
|
|
modelValue.value = modelValue_; |
|
|
|
modelObjectValue.value.push({ value: modelValue_, displayValue: getActualDisplayValue(args.row) }); |
|
|
|
modelObjectValue.value.push({ value: modelValue_, displayValue: formatDisplayValue(args.row), row: toRaw(args.row) }); |
|
|
|
} else { |
|
|
|
console.info('error========模型值不匹配'); |
|
|
|
} |
|
|
@ -229,31 +307,23 @@ const rowClick = (args) => { |
|
|
|
if (props.grid['onRowClick'] && typeof props.grid['onRowClick'] === 'function') { |
|
|
|
props.grid['onRowClick'](args); |
|
|
|
} |
|
|
|
_setDisplayValue(); |
|
|
|
}; |
|
|
|
|
|
|
|
watch( |
|
|
|
() => modelValue.value, |
|
|
|
(newVal, oldVal) => { |
|
|
|
if (newVal !== oldVal) { |
|
|
|
fieldMethodsClass.updateValue(newVal); |
|
|
|
} |
|
|
|
fieldMethodsClass.updateValue(newVal); |
|
|
|
if (Tools.isEmpty(newVal)) { |
|
|
|
fieldMethodsClass.clearObjectValue(); |
|
|
|
} else if (newVal !== oldVal) { |
|
|
|
if (modelObjectValue.value.length > 0) { |
|
|
|
const tempValue = modelObjectValue.value.find((item) => item.value === newVal); |
|
|
|
if (!tempValue) { |
|
|
|
setObjectValueByValue(newVal); |
|
|
|
} |
|
|
|
} else { |
|
|
|
setObjectValueByValue(newVal); |
|
|
|
} |
|
|
|
} else if (newVal !== oldVal && needFetchData.value) { |
|
|
|
fetchData(newVal); |
|
|
|
} |
|
|
|
}, |
|
|
|
); |
|
|
|
|
|
|
|
// 根据实际值设置显示值 |
|
|
|
const setObjectValueByValue = async (value) => { |
|
|
|
// 根据值查询后台数据 |
|
|
|
const fetchData = async (value) => { |
|
|
|
if ((Array.isArray(value) && value.length > 0) || (typeof value === 'string' && !Tools.isEmpty(value))) { |
|
|
|
fieldMethodsClass.clearObjectValue(); |
|
|
|
const urlSearchParams = new URLSearchParams(); |
|
|
@ -272,25 +342,27 @@ const setObjectValueByValue = async (value) => { |
|
|
|
const responseData = resp.data; |
|
|
|
if (Array.isArray(responseData) && responseData.length > 0) { |
|
|
|
responseData.forEach((item) => { |
|
|
|
modelObjectValue.value.push({ value: item[valueUseColumnName], displayValue: getActualDisplayValue(item) }); |
|
|
|
modelObjectValue.value.push({ value: item[valueUseColumnName], displayValue: formatDisplayValue(item), row: item }); |
|
|
|
}); |
|
|
|
} else if (typeof responseData === 'object' && responseData.content?.length > 0) { |
|
|
|
responseData.content.forEach((item) => { |
|
|
|
modelObjectValue.value.push({ value: item[valueUseColumnName], displayValue: getActualDisplayValue(item) }); |
|
|
|
modelObjectValue.value.push({ value: item[valueUseColumnName], displayValue: formatDisplayValue(item), row: item }); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
_setDisplayValue(); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
onMounted(() => { |
|
|
|
setObjectValueByValue(modelValue.value); |
|
|
|
fetchData(modelValue.value); |
|
|
|
}); |
|
|
|
|
|
|
|
defineExpose({ |
|
|
|
validate: fieldMethodsClass.validate, |
|
|
|
setValue: fieldMethodsClass.setValue, |
|
|
|
getValue: fieldMethodsClass.getValue, |
|
|
|
setDisplayValue: fieldMethodsClass.setDisplayValue, |
|
|
|
getObjectValue: fieldMethodsClass.getObjectValue, |
|
|
|
clearValue: fieldMethodsClass.clearValue, |
|
|
|
}); |
|
|
|