init
This commit is contained in:
260
src/iview/form/IViewFormCheckbox.vue
Normal file
260
src/iview/form/IViewFormCheckbox.vue
Normal file
@@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<div class="iview-form-checkbox-container">
|
||||
<a-input
|
||||
type="text"
|
||||
style="display: none"
|
||||
:id="'form_item_' + formatFieldName(field.name)"
|
||||
/>
|
||||
<a-form-item-rest>
|
||||
<div v-if="supportedRemoteSearch" style="margin-bottom: 8px">
|
||||
<a-input-search
|
||||
v-model:value="searchInputValue"
|
||||
:placeholder="field.searchPlaceholder || '输入关键字搜索'"
|
||||
:loading="remoteSearchLoading"
|
||||
allow-clear
|
||||
@search="handleSearch"
|
||||
@input="handleSearchInput"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="remoteSearchLoading || remoteOptionsLoading" style="padding: 8px 0">
|
||||
<a-spin size="small" />
|
||||
</div>
|
||||
<div
|
||||
v-else-if="remoteSearchErrorMsg || remoteOptionsErrorMsg"
|
||||
style="padding: 8px 0; color: #ff4d4f"
|
||||
>
|
||||
{{ remoteSearchErrorMsg || remoteOptionsErrorMsg }}
|
||||
<a-button
|
||||
size="small"
|
||||
type="default"
|
||||
style="margin-left: 8px"
|
||||
@click="handleRefresh"
|
||||
>
|
||||
刷新
|
||||
</a-button>
|
||||
</div>
|
||||
<a-checkbox-group
|
||||
v-else
|
||||
v-model:value="vModel[formatFieldName(field.name)]"
|
||||
:disabled="readOnly"
|
||||
>
|
||||
<a-checkbox
|
||||
v-for="option in parseOptions(field.options)"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
>
|
||||
{{ readLabel(option.label) }}
|
||||
<template v-if="showValueTag">
|
||||
<span style="color: #999; font-size: 12px"> {{ option.value }} </span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span v-if="!!readTag(option.label)" style="color: #999; font-size: 12px">
|
||||
{{ readTag(option.label) }}
|
||||
</span>
|
||||
</template>
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</a-form-item-rest>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { useVModel } from "@/iview/utils/useModel";
|
||||
import { delayCall } from "@/iview/utils/delayCall";
|
||||
import { callFunc } from "@/iview/utils/func";
|
||||
|
||||
const props = defineProps({
|
||||
field: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
fieldPrefix: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
modelValue: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
rawFormData: {
|
||||
type: Object,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
const vModel = useVModel(props, "modelValue", emit);
|
||||
|
||||
const remoteOptionsData = ref([]);
|
||||
const remoteOptionsLoading = ref(false);
|
||||
const remoteOptionsErrorMsg = ref(null);
|
||||
|
||||
const remoteSearchValue = ref("");
|
||||
const remoteSearchData = ref([]);
|
||||
const remoteSearchLoading = ref(false);
|
||||
const remoteSearchErrorMsg = ref(null);
|
||||
const remoteSearchId = ref(0);
|
||||
const searchInputValue = ref("");
|
||||
|
||||
const supportedRemoteSearch = computed(() => {
|
||||
return (
|
||||
!!props.field.remoteSearchMethod &&
|
||||
typeof props.field.remoteSearchMethod === "function"
|
||||
);
|
||||
});
|
||||
|
||||
const supportedRemoteOptions = computed(() => {
|
||||
return (
|
||||
!!props.field.remoteOptionsMethod &&
|
||||
typeof props.field.remoteOptionsMethod === "function"
|
||||
);
|
||||
});
|
||||
|
||||
const showValueTag = computed(() => {
|
||||
return !!props.field.showValueTag;
|
||||
});
|
||||
|
||||
// 解析选项字符串或数组
|
||||
const parseOptions = (options) => {
|
||||
if (remoteSearchData.value && remoteSearchData.value.length > 0) {
|
||||
return remoteSearchData.value;
|
||||
}
|
||||
if (remoteOptionsData.value && remoteOptionsData.value.length > 0) {
|
||||
return remoteOptionsData.value;
|
||||
}
|
||||
if (!options) return [];
|
||||
|
||||
if (Array.isArray(options)) {
|
||||
return options;
|
||||
}
|
||||
|
||||
if (typeof options === "string") {
|
||||
return options
|
||||
.split("\n")
|
||||
.filter((line) => line.trim() !== "")
|
||||
.map((line) => {
|
||||
const parts = line.split("|");
|
||||
return {
|
||||
label: parts[0]?.trim() || "",
|
||||
value: parts[1]?.trim() || parts[0]?.trim() || "",
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
const formatFieldName = (name) => {
|
||||
if (!props.fieldPrefix) {
|
||||
return name;
|
||||
}
|
||||
return props.fieldPrefix + "-" + name;
|
||||
};
|
||||
|
||||
const readLabel = (value) => {
|
||||
return `${value}`.split("#")[0];
|
||||
};
|
||||
|
||||
const readTag = (value) => {
|
||||
return `${value}`.split("#")[1];
|
||||
};
|
||||
|
||||
const handleRemoteOptions = () => {
|
||||
if (!supportedRemoteOptions.value) {
|
||||
return;
|
||||
}
|
||||
remoteOptionsLoading.value = true;
|
||||
remoteOptionsErrorMsg.value = null;
|
||||
Promise.resolve()
|
||||
.then(() => {
|
||||
let remoteOptionsMethod = props.field.remoteOptionsMethod;
|
||||
return callFunc([], [], remoteOptionsMethod, []);
|
||||
})
|
||||
.then((data) => {
|
||||
remoteOptionsData.value = data || [];
|
||||
remoteOptionsLoading.value = false;
|
||||
})
|
||||
.catch((err) => {
|
||||
remoteOptionsErrorMsg.value =
|
||||
(err && err.msg) || (err && err.message) || "连接服务器失败,请检查网络";
|
||||
remoteOptionsLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const handleRemoteSearchValue = delayCall((value) => {
|
||||
remoteSearchId.value += 1;
|
||||
remoteSearchValue.value = value;
|
||||
const currentRemoteSearchId = remoteSearchId.value;
|
||||
remoteSearchLoading.value = true;
|
||||
remoteSearchErrorMsg.value = null;
|
||||
remoteSearchData.value = [];
|
||||
Promise.resolve()
|
||||
.then(() => {
|
||||
let remoteSearchMethod = props.field.remoteSearchMethod;
|
||||
return callFunc(["value"], [value], remoteSearchMethod, []);
|
||||
})
|
||||
.then((data) => {
|
||||
if (currentRemoteSearchId !== remoteSearchId.value) {
|
||||
return;
|
||||
}
|
||||
remoteSearchData.value = data || [];
|
||||
remoteSearchLoading.value = false;
|
||||
remoteSearchValue.value = null;
|
||||
})
|
||||
.catch((err) => {
|
||||
remoteSearchErrorMsg.value =
|
||||
(err && err.msg) || (err && err.message) || "连接服务器失败,请检查网络";
|
||||
remoteSearchLoading.value = false;
|
||||
});
|
||||
}, 300);
|
||||
|
||||
const handleSearch = (value) => {
|
||||
if (supportedRemoteSearch.value && value) {
|
||||
handleRemoteSearchValue(value);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSearchInput = (e) => {
|
||||
const value = e.target.value;
|
||||
if (supportedRemoteSearch.value) {
|
||||
if (value) {
|
||||
handleRemoteSearchValue(value);
|
||||
} else {
|
||||
remoteSearchData.value = [];
|
||||
remoteSearchErrorMsg.value = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleRefresh = () => {
|
||||
if (supportedRemoteSearch.value && !!remoteSearchValue.value) {
|
||||
handleRemoteSearchValue(remoteSearchValue.value);
|
||||
}
|
||||
if (supportedRemoteOptions.value) {
|
||||
handleRemoteOptions();
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
handleRemoteOptions();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.ant-checkbox-group) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
:deep(.ant-checkbox-wrapper) {
|
||||
margin-left: 0;
|
||||
margin-right: 16px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user