From c3207c8517780ec2019bd1e0943a62cc29b265d0 Mon Sep 17 00:00:00 2001 From: zhengyiming <540361168@qq.com> Date: 星期二, 18 二月 2025 14:58:32 +0800 Subject: [PATCH] feat: api --- src/constants/dic.ts | 23 ++ src/hooks/dic.ts | 55 ++++++ src/services/api/typings.d.ts | 1 src/constants/enum.ts | 5 src/constants/index.ts | 1 src/views/DictionaryManage/SearchSetting.vue | 244 ++++++++++++++++++++++++++++++ src/hooks/index.ts | 1 src/views/DictionaryManage/components/AddOrEditSearchSetting.vue | 147 ++++++++++++++++++ src/utils/request/index.ts | 1 9 files changed, 477 insertions(+), 1 deletions(-) diff --git a/src/constants/dic.ts b/src/constants/dic.ts new file mode 100644 index 0000000..3ad3406 --- /dev/null +++ b/src/constants/dic.ts @@ -0,0 +1,23 @@ +export enum SearchType { + /**韬唤 */ + Identity = 210, + /**瀛﹀巻 */ + Education = 220, + /**宀椾綅 */ + Position = 230, + /**璇佷功绫诲瀷 */ + CertificateType = 240, + /**绂忓埄 */ + Welfare = 250, + /**琛屼笟绫诲瀷 */ + IndustryCategory = 260, +} + +export const SearchTypeText = { + [SearchType.Identity]: '韬唤', + [SearchType.Education]: '瀛﹀巻', + [SearchType.Position]: '宀椾綅', + [SearchType.CertificateType]: '璇佷功绫诲瀷', + [SearchType.Welfare]: '绂忓埄', + [SearchType.IndustryCategory]: '琛屼笟绫诲瀷', +}; diff --git a/src/constants/enum.ts b/src/constants/enum.ts index 936694e..e403f0e 100644 --- a/src/constants/enum.ts +++ b/src/constants/enum.ts @@ -38,3 +38,8 @@ Role = 1, User, } + +export const BooleanOptions = [ + { label: '鏄�', value: true }, + { label: '鍚�', value: false }, +]; diff --git a/src/constants/index.ts b/src/constants/index.ts index fa61beb..303e5a6 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -9,3 +9,4 @@ export * from './menu'; export * from './role'; export * from './app'; +export * from './dic'; diff --git a/src/hooks/dic.ts b/src/hooks/dic.ts new file mode 100644 index 0000000..d55c72f --- /dev/null +++ b/src/hooks/dic.ts @@ -0,0 +1,55 @@ +import * as searchSettingServices from '@/services/api/SearchSetting'; +import { useQuery } from '@tanstack/vue-query'; +import { useQueryClient } from '@tanstack/vue-query'; +import { SearchType } from '@/constants'; + +type UseSearchSettingTypeOptions = { + searchType: number; + belongType?: number; + onSuccess?: (data: API.GetTypeSearchSettingList[]) => any; +}; + +export function useSearchSettingType({ + searchType, + belongType = null, + onSuccess, +}: UseSearchSettingTypeOptions) { + const { data, refetch } = useQuery({ + queryKey: ['searchSettingServices/getTypeSearchSettingList', { searchType, belongType }], + queryFn: async () => { + return await searchSettingServices.getTypeSearchSettingList( + { + searchType: searchType, + belongType: belongType, + }, + { showLoading: false } + ); + }, + placeholderData: () => [] as API.GetTypeSearchSettingList[], + onSuccess(data) { + onSuccess?.(data); + }, + }); + + const queryClient = useQueryClient(); + + async function ensureSearchSettingType() { + return await queryClient.ensureQueryData({ + queryKey: [ + 'searchSettingServices/getTypeSearchSettingList', + { searchType: searchType, belongType: belongType }, + ], + }); + } + + function getSearchSettingTypeNameById(id: string) { + return data.value.find((x) => x.id === id)?.name ?? ''; + } + + return { + searchSettingTypeList: data, + ensureSearchSettingType, + refetchSearchSettingType: refetch, + getSearchSettingTypeNameById, + }; +} diff --git a/src/hooks/index.ts b/src/hooks/index.ts index cbe1cbd..bc2b519 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -6,3 +6,4 @@ export * from './useEvent'; export * from './useUser'; export * from './help'; +export * from './dic'; diff --git a/src/services/api/typings.d.ts b/src/services/api/typings.d.ts index efb90c7..cd366cf 100644 --- a/src/services/api/typings.d.ts +++ b/src/services/api/typings.d.ts @@ -713,6 +713,7 @@ clickCount?: number; src?: string; isRecommend?: boolean; + searchType?: number; } interface GetSearchSettingListInput { diff --git a/src/utils/request/index.ts b/src/utils/request/index.ts index 3c654d4..3ebb819 100644 --- a/src/utils/request/index.ts +++ b/src/utils/request/index.ts @@ -170,7 +170,6 @@ requestInterceptors: [ [ (config) => { - console.log('req config: ', config); const $config = config; // 寮�鍚繘搴︽潯鍔ㄧ敾 if (config.needNProcess) { diff --git a/src/views/DictionaryManage/SearchSetting.vue b/src/views/DictionaryManage/SearchSetting.vue new file mode 100644 index 0000000..a23b025 --- /dev/null +++ b/src/views/DictionaryManage/SearchSetting.vue @@ -0,0 +1,244 @@ +<template> + <LoadingLayout :loading="state.loading"> + <AppContainer> + <ProTableQueryFilterBar @on-reset="reset"> + <template #query> + <QueryFilterItem> + <FieldSelect + v-model="extraParamState.searchType" + @change="getList()" + :value-enum="SearchTypeText" + placeholder="璇烽�夋嫨鎵�灞炵被鍒�" + ></FieldSelect> + </QueryFilterItem> + <QueryFilterItem v-if="extraParamState.searchType === SearchType.Position"> + <FieldSelect + v-model="extraParamState.parentId" + @change="getList()" + :value-enum="typeList" + enum-label-key="name" + enum-value-key="id" + placeholder="璇烽�夋嫨琛屼笟绫诲瀷" + clearable + ></FieldSelect> + </QueryFilterItem> + <QueryFilterItem> + <SearchInput + v-model="extraParamState.name" + style="width: 200px" + placeholder="璇疯緭鍏ュ悕绉�" + @on-click-search="getList" + @keyup.enter="getList()" + > + </SearchInput> + </QueryFilterItem> + </template> + <template #btn> + <el-button + v-if="checkSubModuleItemShow('pageButton', 'addBtn')" + @click="openDialog()" + icon="Plus" + type="primary" + >鏂板</el-button + > + </template> + </ProTableQueryFilterBar> + <ProTableV2 v-bind="proTableProps" :columns="column" :operationBtns="operationBtns"> + <template #columns="{ row, column }"> + <template v-if="column.property === 'status'"> + <FieldSwitch + v-model="row.status" + active-text="鏄剧ず" + inactive-text="闅愯棌" + :before-change="() => setCategoryVis(row)" + /> + </template> + </template> + </ProTableV2> + </AppContainer> + <AddOrEditSearchSetting v-bind="dialogProps" :typeList="typeList" /> + </LoadingLayout> +</template> + +<script setup lang="ts"> +import { + ProTableQueryFilterBar, + OperationBtnType, + ProTableV2, + SearchInput, + LoadingLayout, + AppContainer, + QueryFilterItem, + useTable, + useFormDialog, + UploadUserFile, + FieldSwitch, + FieldSelect, + FieldRadio, +} from '@bole-core/components'; +import { useAccess } from '@/hooks'; +import * as searchSettingServices from '@/services/api/SearchSetting'; +import { + SearchType, + SearchTypeText, + // BelongType, + // BelongTypeText, + BooleanOptions, +} from '@/constants'; +import { OrderInputType, Message } from '@bole-core/core'; +import AddOrEditSearchSetting from './components/AddOrEditSearchSetting.vue'; +import { convertApi2FormUrl } from '@/utils'; +import { useQueryClient } from '@tanstack/vue-query'; +import { useSearchSettingType } from '@/hooks'; + +defineOptions({ + name: 'SearchSetting', +}); + +const operationBtnMap: Record<string, OperationBtnType> = { + editBtn: { emits: { onClick: (role) => openDialog(role) } }, +}; + +const { checkSubModuleItemShow, column, operationBtns } = useAccess({ + operationBtnMap, +}); + +const BaseState = { + loading: true, +}; +const queryClient = useQueryClient(); +const { searchSettingTypeList: typeList } = useSearchSettingType({ + searchType: SearchType.IndustryCategory, +}); +const state = reactive({ ...BaseState }); + +onMounted(async () => { + await getList(); + state.loading = false; +}); + +const { + getDataSource: getList, + proTableProps, + paginationState, + extraParamState, + reset, +} = useTable( + async ({ pageIndex, pageSize }, extraParamState) => { + try { + let params: API.GetSearchSettingListInput = { + pageModel: { + rows: pageSize, + page: pageIndex, + orderInput: extraParamState.orderInput, + }, + name: extraParamState.name, + // belongType: Number(extraParamState.belongType), + searchType: Number(extraParamState.searchType), + status: extraParamState.status, + }; + + if (extraParamState.searchType === SearchType.Position) { + params.isRecommend = extraParamState.isRecommend; + params.parentId = extraParamState.parentId; + } + let res = await searchSettingServices.getSearchSettingList(params, { + showLoading: !state.loading, + }); + return res; + } catch (error) { + console.log('error: ', error); + } + }, + { + defaultExtraParams: { + name: '', + searchType: SearchType.Identity, + orderInput: [{ property: 'sort', order: OrderInputType.Asc }], + status: '' as any as boolean, + isRecommend: '' as any as boolean, + parentId: '', + }, + queryKey: ['searchSettingServices/getSearchSettingList'], + columnsRenderProps: { + searchType: { type: 'enum', valueEnum: SearchTypeText }, + }, + } +); + +function openDialog(row?: API.GetSearchSettingList) { + if (row) { + handleEdit({ + id: row.id, + searchType: extraParamState.searchType, + name: row.name, + sort: row.sort, + status: row.status, + src: row.src?.length ? [convertApi2FormUrl(row.src)] : [], + parentId: row.parentId ?? '', + }); + } else { + handleAdd({ + searchType: extraParamState.searchType, + }); + } +} + +const { dialogProps, handleAdd, handleEdit, editForm, dialogState } = useFormDialog({ + onConfirm: handleAddOrEdit, + defaultFormParams: { + id: '', + searchType: SearchType.Identity, + name: '', + sort: 0, + status: true, + src: [] as UploadUserFile[], + parentId: '', + }, +}); + +async function handleAddOrEdit() { + try { + let params: API.CreateOrEditSearchInput = { + searchType: extraParamState.searchType, + name: editForm.name, + sort: editForm.sort, + status: editForm.status, + src: editForm.src?.[0]?.path ?? '', + parentId: editForm.parentId ?? '', + }; + if (editForm.id) { + params.id = editForm.id; + } + let res = await searchSettingServices.createOrEditSearchSetting(params); + if (res) { + Message.successMessage('鎿嶄綔鎴愬姛'); + getList(paginationState.pageIndex); + dialogState.dialogVisible = false; + updateCategoryMenu(); + } + } catch (error) {} +} + +function updateCategoryMenu() { + queryClient.invalidateQueries({ + queryKey: [ + 'searchSettingServices/getTypeSearchSettingList', + { searchType: extraParamState.searchType, belongType: null }, + ], + }); +} + +async function setCategoryVis(row: API.GetSearchSettingList) { + try { + let params: API.EnableSearchSettingInput = { + id: row.id, + status: !row.status, + }; + let res = await searchSettingServices.enableSearchSetting(params); + updateCategoryMenu(); + getList(paginationState.pageIndex); + return !!res; + } catch (error) {} +} +</script> diff --git a/src/views/DictionaryManage/components/AddOrEditSearchSetting.vue b/src/views/DictionaryManage/components/AddOrEditSearchSetting.vue new file mode 100644 index 0000000..1eab56d --- /dev/null +++ b/src/views/DictionaryManage/components/AddOrEditSearchSetting.vue @@ -0,0 +1,147 @@ +<template> + <ProDialog + :title="innerForm.title" + v-model="innerVisible" + @close="onDialogClose" + destroy-on-close + draggable + > + <ProForm :rules="rules" :model="innerForm" ref="dialogForm" label-width="90px"> + <ProFormItemV2 label="琛屼笟绫诲瀷:" prop="parentId" v-if="showWorkSearchType"> + <ProFormSelect + v-model="innerForm.parentId" + :value-enum="typeList" + enum-value-key="id" + enum-label-key="name" + /> + </ProFormItemV2> + <ProFormItemV2 label="鍚嶇О:" prop="name"> + <ProFormText + placeholder="璇疯緭鍏ュ悕绉�" + v-model.trim="innerForm.name" + :maxlength="15" + ></ProFormText> + </ProFormItemV2> + <ProFormItemV2 label="鎺掑簭:" prop="sort" required> + <ProFormInputNumber + v-model="innerForm.sort" + :controls="false" + :min="0" + :max="999" + ></ProFormInputNumber> + </ProFormItemV2> + <ProFormItemV2 + label="绫诲埆鍥炬爣:" + prop="src" + :check-rules="[{ type: 'upload', required: false }]" + > + <ProFormImageUpload + v-model:file-url="innerForm.src" + :limitFileCount="1" + ></ProFormImageUpload> + </ProFormItemV2> + <ProFormItemV2 label="鐘舵��:" prop="status" required> + <el-radio-group v-model="innerForm.status"> + <el-radio-button :value="true">鏄剧ず</el-radio-button> + <el-radio-button :value="false">闅愯棌</el-radio-button> + </el-radio-group> + </ProFormItemV2> + </ProForm> + <template #footer> + <span class="dialog-footer"> + <el-button @click="emit('onCancel')">鍙� 娑�</el-button> + <el-button type="primary" @click="handleConfirm">纭� 瀹�</el-button> + </span> + </template> + </ProDialog> +</template> + +<script setup lang="ts"> +import { FormRules, FormInstance } from 'element-plus'; +import { SearchType } from '@/constants'; +import { + ProDialog, + ProForm, + ProFormItemV2, + ProFormRadio, + ProFormText, + ProFormInputNumber, + ProFormImageUpload, + UploadUserFile, + ProFormSelect, +} from '@bole-core/components'; + +defineOptions({ + name: 'AddOrEditSearchSetting', +}); + +type Props = { + modelValue: boolean; + form?: { + title?: string; + searchType: number; + name: string; + sort: number; + status: boolean; + src: UploadUserFile[]; + parentId?: string; + }; + typeList: API.GetTypeSearchSettingList[]; +}; + +const props = withDefaults(defineProps<Props>(), { + modelValue: false, +}); + +const showWorkSearchType = computed(() => props.form.searchType === SearchType.Position); + +const emit = defineEmits<{ + (e: 'update:modelValue', value: boolean): void; + (e: 'update:form', value: Props['form']): void; + (e: 'onConfirm'): void; + (e: 'onCancel'): void; +}>(); + +const dialogForm = ref<FormInstance>(); + +const innerVisible = computed({ + get() { + return props.modelValue; + }, + set(val) { + emit('update:modelValue', val); + }, +}); + +const innerForm = computed({ + get() { + return props.form; + }, + set(val) { + emit('update:form', val); + }, +}); + +const rules = reactive<FormRules>({ + status: [{ required: true, message: '璇烽�夋嫨鐘舵��', trigger: 'change' }], + name: [{ required: true, message: '璇疯緭鍏ュ悕绉�', trigger: 'blur' }], + sort: [{ required: true, message: '璇疯緭鍏ユ帓搴�', trigger: 'blur' }], + parentId: [{ required: true, message: '璇烽�夋嫨鎵�灞炵被鍒�', trigger: 'change' }], +}); + +function onDialogClose() { + if (!dialogForm.value) return; + dialogForm.value.resetFields(); +} + +function handleConfirm() { + if (!dialogForm.value) return; + dialogForm.value.validate((valid) => { + if (valid) { + emit('onConfirm'); + } else { + return; + } + }); +} +</script> -- Gitblit v1.9.1