|
|
@@ -0,0 +1,178 @@
|
|
|
+import '../style.css';
|
|
|
+
|
|
|
+import {computed, defineComponent, ref} from 'vue';
|
|
|
+import {selectProps, NSelect, NEmpty, NButton, useMessage} from 'naive-ui';
|
|
|
+import {useField} from 'vee-validate';
|
|
|
+import {debounce} from 'lodash-es';
|
|
|
+import { useI18n } from 'vue-i18n';
|
|
|
+import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query';
|
|
|
+
|
|
|
+async function mockGetList() {
|
|
|
+ return await new Promise<{msg: '200', data: {id: string, name:string}[]}>(function(res){
|
|
|
+ setTimeout(function() {
|
|
|
+ res({
|
|
|
+ msg: '200',
|
|
|
+ data: [{id: '1', name: 'simon'}, {id: '2', name: 'david'}]
|
|
|
+ });
|
|
|
+ }, 2000);
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+async function mockAdd(name: string){
|
|
|
+ return await new Promise<{msg: '200', data: string}>(function(res){
|
|
|
+ setTimeout(function() {
|
|
|
+ res({
|
|
|
+ msg: '200',
|
|
|
+ data: '12',
|
|
|
+ });
|
|
|
+ }, 2000);
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+export default defineComponent({
|
|
|
+ name: 'LDModalInput',
|
|
|
+ props: {
|
|
|
+ name: {
|
|
|
+ type: String,
|
|
|
+ required: true,
|
|
|
+ },
|
|
|
+ label: {
|
|
|
+ type: String,
|
|
|
+ required: true,
|
|
|
+ },
|
|
|
+ optional: Boolean,
|
|
|
+ multiple: selectProps.multiple,
|
|
|
+ },
|
|
|
+ setup(props) {
|
|
|
+ const {value, setValue, errorMessage} = useField<string | string[]>(
|
|
|
+ props.name,
|
|
|
+ void 0,
|
|
|
+ {validateOnMount: false, validateOnValueUpdate: false},
|
|
|
+ );
|
|
|
+
|
|
|
+ const showOptions = ref(false);
|
|
|
+
|
|
|
+ const {isFetching, data} = useQuery({
|
|
|
+ queryKey: [mockGetList.name],
|
|
|
+ async queryFn () {
|
|
|
+ const data = await mockGetList();
|
|
|
+
|
|
|
+ if(data.msg === '200') return data.data.map(function({id, name}) {
|
|
|
+ return {label: name, value: id};
|
|
|
+ });
|
|
|
+
|
|
|
+ return [];
|
|
|
+ },
|
|
|
+ initialData: [],
|
|
|
+ })
|
|
|
+
|
|
|
+ const client = useQueryClient();
|
|
|
+ const {isLoading, mutate} = useMutation({
|
|
|
+ mutationFn: mockAdd,
|
|
|
+ onSuccess(data, variables){
|
|
|
+ if(data.msg === '200'){
|
|
|
+ const id = data.data;
|
|
|
+ const name = variables;
|
|
|
+
|
|
|
+ client.setQueryData<{label: string, value: string}[]>(
|
|
|
+ [mockGetList.name],
|
|
|
+ function(data) {
|
|
|
+ return [...(data ?? []), {label: name, value: id}];
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ setValue(id);
|
|
|
+ showOptions.value = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ const message = useMessage();
|
|
|
+ function onAdd() {
|
|
|
+ if(!filterValue.value) return message.warning('请输入客户名称');
|
|
|
+
|
|
|
+ mutate(filterValue.value);
|
|
|
+ }
|
|
|
+ const filterValue = ref<string>('');
|
|
|
+ const filterOptions = computed(function() {
|
|
|
+ const options = data.value;
|
|
|
+
|
|
|
+ if (!filterValue.value) return options;
|
|
|
+
|
|
|
+ return options.filter(function(val) {
|
|
|
+ return (val?.label as string ?? '').includes(filterValue.value)
|
|
|
+ || (val?.value as string ?? '').includes(filterValue.value);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ const onDefaultSearch = debounce(
|
|
|
+ function(value: string) {
|
|
|
+ filterValue.value = value;
|
|
|
+ },
|
|
|
+ 0,
|
|
|
+ {
|
|
|
+ trailing: true,
|
|
|
+ leading: false,
|
|
|
+ },
|
|
|
+ );
|
|
|
+ // 失去焦点之后判断是否有搜索结果
|
|
|
+ // 如果没有搜索结果将搜索值清空
|
|
|
+ // 防止没搜索到之后失去焦点再返回会显示空选项
|
|
|
+ function onBlur() {
|
|
|
+ filterOptions.value.length === 0
|
|
|
+ && filterValue.value.length > 0
|
|
|
+ && !isLoading.value
|
|
|
+ && (filterValue.value = '');
|
|
|
+ }
|
|
|
+
|
|
|
+ const {t} = useI18n();
|
|
|
+
|
|
|
+ function onUpdateShow(state: boolean) {
|
|
|
+ if(isLoading.value) return;
|
|
|
+
|
|
|
+ showOptions.value = state;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return () => (
|
|
|
+ <div class="ld-modal-field-wrapper">
|
|
|
+ <div class="ld-modal-field-group">
|
|
|
+ <label class={props?.optional ? 'optional' : ''}>{props.label}</label>
|
|
|
+ <NSelect
|
|
|
+ show={showOptions.value}
|
|
|
+ multiple={props.multiple}
|
|
|
+ bordered={false}
|
|
|
+ filterable
|
|
|
+ remote
|
|
|
+ loading={isFetching.value}
|
|
|
+ onClear={() => {
|
|
|
+ setValue('');
|
|
|
+ onDefaultSearch('');
|
|
|
+ }}
|
|
|
+ options={filterOptions.value}
|
|
|
+ // 防止空字符串没有placeholder
|
|
|
+ value={value.value || null}
|
|
|
+ onUpdateValue={setValue}
|
|
|
+ onSearch={onDefaultSearch}
|
|
|
+ onBlur={onBlur}
|
|
|
+ on-update:show={onUpdateShow}
|
|
|
+ >
|
|
|
+ {{empty() {
|
|
|
+ return <NEmpty description="未查到客户,点击新增按钮新增客户信息">
|
|
|
+ {{extra() {
|
|
|
+ return <NButton
|
|
|
+ disabled={isLoading.value}
|
|
|
+ loading={isLoading.value}
|
|
|
+ onClick={onAdd}
|
|
|
+ >
|
|
|
+ 新增
|
|
|
+ </NButton>
|
|
|
+ }}}
|
|
|
+ </NEmpty>
|
|
|
+ }}}
|
|
|
+ </NSelect>
|
|
|
+ </div>
|
|
|
+ <p class="ld-modal-filed-error">{errorMessage.value && t(errorMessage.value)}</p>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ },
|
|
|
+});
|