vebn的BasicForm和a-select的下拉选择模糊搜索

本文介绍了如何在VBen框架中使用BasicForm组件来控制数据,以及如何通过API集成a-select组件进行搜索。作者分享了如何从schemas数据中获取和操作特定数据,以及如何通过`componentProps`实现组件的props控制。

前言:固定的api了解即可,写过一次就可以掌握。

BasicForm

首先我们使用BasicForm组件,这个是vben自带的,我们只需要控制数据即可,在schemas数据里,对于想控制的那一个数据,进行单独的处理。

我这里是把schemas的数据维护在另一个txs文件里,然后我只需要在数据里找到相对应的数据,然后进行控制单独的一条数据就好了,通过componentProps控制数据所渲染的组件的 props,控制showSearch为true,filterOption是我写的一个js搜素,仅供参考

a-select

a-select是and的组件,这个也是调用相对的api即可,分别是引入,注册,,使用。

引入组件注册

使用

然后就可以搜索了

效果图奉上

结束语:有错请指点,有问题多多包涵,仅供参考,记录日迹

<template> <BasicModal width="900px" :height="600" v-bind="$attrs" @register="register" :title="modalType === 'add' ? '新增' : '编辑'" @ok="handleok" :confirmLoading="loading" :footer="modalType !== 'check' && undefined" > <div class="pt-3px pr-3px" v-if="modalType !== 'lizhi'"> <BasicForm @register="registerForm"> <template #userCode="{ model, slot }"> <a-input v-model:value="model.userCode" :disabled="modalType === 'edit' && !userStore.getUserRole" placeholder="请输入" ></a-input> </template> <template #laborType="{ model, field }"> <a-select ref="select" v-model:value="model[field]" show-search allow-clear> <a-select-option v-for="item in personLaborTypeListRef" :key="item.dataCode" :value="item.dataCode">{{ item.dataNameCode }}</a-select-option> </a-select> </template> </BasicForm> <Form> <a-row> <a-col :span="10" :offset="2"> <FormItem label="部门" name="type"> <a-select @change="changeOA" :disabled="modalType === 'edit' && !userStore.getUserRole" ref="select" v-model:value="OAitem" show-search> <a-select-option v-for="item in OAList" :key="item.id" :value="item.id">{{ item.name }}</a-select-option> </a-select> </FormItem> </a-col> <a-col :span="10" :offset="2"> <FormItem label="班组" name="type"> <a-select @change="changeOB" ref="select" v-model:value="OBitem" show-search allow-clear :filter-option="(input,option)=>{ return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0 }"> <a-select-option v-for="item in OBList" :key="item.id" :label="item.name" :value="item.id">{{ item.name }}</a-select-option> </a-select> </FormItem> </a-col> <a-col :span="10" :offset="2"> <FormItem label="岗位类别" name="type"> <a-select ref="select" v-model:value="positionCategory" show-search allow-clear> <a-select-option v-for="item in positionCategoryListRef" :key="item.dataCode" :value="item.dataCode">{{ item.dataNameCode }}</a-select-option> </a-select> </FormItem> </a-col> <a-col :span="10" :offset="2"> <FormItem label="岗位" name="type"> <a-select ref="select" v-model:value="userRole" show-search placeholder="请选择岗位"> <a-select-option v-for="item in UserRoleList" :key="item.id" :value="item.dataCode"> {{item.dataNameCode}} </a-select-option> </a-select> </FormItem> </a-col> </a-row> <a-row> <a-col :span="10" :offset="2"> <FormItem label="职务" name="type"> <a-select ref="select" v-model:value="userDuty" show-search allow-clear> <a-select-option v-for="item in userDutyList" :key="item.value" :value="item.value">{{ item.label }}</a-select-option> </a-select> </FormItem> </a-col> </a-row> <a-row v-if="editPhoto"> <a-col :span="10" :offset="2"> <FormItem label="上传脸卡" name="type"> <a-button style="position: relative; margin-right: 10px"> 选择文件(小于200kb) <input type="file" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0" @change="handleImageUpload" accept="image/*" /> <div id="ths90"> </div> </a-button> <a-image v-if="base64Image" :src="'data:image/png;base64,' + base64Image" alt="预览图片" style="width: 200px; height: auto" /> <canvas style="display: none" id="canvasCamera" :width="videoWidth" :height="videoHeight" ></canvas> </FormItem> </a-col> <a-col :span="10" :offset="2"> <FormItem label="拍照" > <div style="display: flex; margin-bottom: 5px"> <a-button @click="openPhotoDialog">开启拍照</a-button> <a-button class="ml-2" type="primary" @click="setImage">拍照</a-button> <a-button class="ml-2" type="primary" @click="stopNavigator">完成关闭</a-button> </div> <div style="display: flex;" v-show="flag"> <video id="videoCamera" :width="videoWidth" :height="videoHeight" autoplay ></video> </div> </FormItem> </a-col> </a-row> <a-row> </a-row> </Form> </div> <div v-if="modalType === 'lizhi'"> <a-form-item style="margin-left: 20px" label="离职时间"> <a-date-picker style="width: 100%" valueFormat="YYYY-MM-DD" :format="'YYYY-MM-DD'" v-model:value="liTime" /> </a-form-item> <a-form-item style="margin-left: 20px" label="离职原因"> <Textarea style="width: 100%" :rows="4" v-model:value="remark" allow-clear placeholder="离职原因" /> </a-form-item> </div> </BasicModal> </template> <script lang="ts" setup> import { ref, nextTick, inject, onMounted } from 'vue'; import { update, quit, add } from '@/api/classManagement/personalManagement'; import { oaList, obList } from '@/api/personnel/tables'; import { BasicModal, useModalInner } from '@/components/Modal'; import { Form, FormItem, message ,Textarea } from 'ant-design-vue'; import { BasicForm, FormSchema, useForm } from '@/components/Form'; import {listChildren} from "@/api/glossary/tables"; import { useDictStore } from '@/store/modules/dict'; import { useUserStore } from '@/store/modules/user'; const editPhoto = ref(true) const dictStore = useDictStore(); // import { add } from 'xe-utils'; // import { list as listQueStionStore } from '@/api/questionBank/tables'; const pid = ref(''); const liTime = ref(''); const remark = ref(''); const modalType = ref(); const userStore: any = useUserStore(); const userDutyList = ref([ { value: 'ME', label: 'ME' }, { value: 'FQC', label: 'FQC' }, { value: 'IPQC', label: 'IPQC' }]) const schemas: FormSchema[] = [ { field: 'inTime', component: 'DatePicker', label: '入职时间', required: true, colProps: { span: 12, }, componentProps: { disabled: modalType.value === 'edit' && !userStore.getUserRole, style: { width: '100%' }, valueFormat: 'YYYY-MM-DD', }, }, { field: 'quitDate', component: 'DatePicker', label: '离职时间', colProps: { span: 12, }, componentProps: { style: { width: '100%' }, valueFormat: 'YYYY-MM-DD', }, }, { field: 'userName', component: 'Input', label: '姓名', required: true, colProps: { span: 12, }, }, { field: 'userCode', label: '工号', required: true, slot: 'userCode', colProps: { span: 12, }, }, { field: 'phone', component: 'Input', label: '电话', required: true, rules: [ // { // required: true, // message: '请输入电话号码', // }, { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', } ], colProps: { span: 12, }, }, { field: 'card', component: 'Input', label: '身份证号', colProps: { span: 12, }, }, { field: 'gender', component: 'Select', label: '性别', required: true, colProps: { span: 12, }, componentProps: { options: [ { value: '男', label: '男' }, { value: '女', label: '女' }, ], }, }, { field: 'userCategory', component: 'Select', label: '类别', colProps: { span: 12, }, componentProps: { options: [ { value: 10, label: '二线人员' }, { value: 0, label: '一线人员' }, ], onChange:(e)=> changeCategory(e), }, }, { field: 'focus', component: 'Select', label: '是否内训师', colProps: { span: 12, }, componentProps: { options: [ { value: 1, label: '是' }, { value: 0, label: '否' }, ], }, }, { field: 'hours', component: 'Input', label: '应学学时', colProps: { span: 12, }, }, { field: 'userState', component: 'Select', defaultValue: 0, label: '在职状态', colProps: { span: 12, }, componentProps: { disabled: true, options: [ // { value: 10, label: '新员工' }, { value: 0, label: '在职' }, { value: 20, label: '离职' }, ], }, }, { field: 'laborType', // component: 'ApiSelect', label: '劳务类型', colProps: { span: 12, }, slot: 'laborType', required: true, // componentProps: { // api: () => dictStore.getDictList('personLaborType'), // resultField: 'data', // labelField: 'dataNameCode', // valueField: 'dataCode', // }, // required: true, }, ]; const initFormData = { focus: 0, gender: '', groupId: '', hours: 0, inTime: '', orgId: '', phone: '', photo: '', userCategory: 10, userCode: '', userDuty: '', positionCategory:'', userRole: '', userName: '', }; const OBitem = ref(''); const OAitem = ref(''); const UserCode = ref(''); const userDuty = ref(''); const positionCategory = ref(''); const userRole = ref(''); const OAList: any = ref([]); const OBList: any = ref([]); const positionCategoryList: any = ref([]); const personLaborTypeList: any = ref([]); const UserRoleList: any = ref([]); onMounted(async () => { await getOaLsit(); await getDictList() const res = await listChildren({ parentCode: 'UserRole' }); UserRoleList.value = res.data }); const positionCategoryListRef:any = ref([]); const personLaborTypeListRef:any = ref([]); // 过滤岗位类别劳务类型 const changeCategory = (val) => { // 二线 if (val === 10) { positionCategoryListRef.value = positionCategoryList.value.filter(item=>item.dataValue ==='10' || item.dataValue === '3') personLaborTypeListRef.value = personLaborTypeList.value.filter(item=>item.dataValue ==='10' || item.dataValue === '3') } else { // 一线 positionCategoryListRef.value = positionCategoryList.value.filter(item=>item.dataValue ==='0'|| item.dataValue ==='3') personLaborTypeListRef.value = personLaborTypeList.value.filter(item=>item.dataValue === '0'|| item.dataValue ==='3' ) } }; const base64Image = ref(); // 存储 Base64 图片数据 const MAX_SIZE = 200 * 1024; // 200kb 的大小限制 const isPhotoDialogVisible = ref(false); // 处理文件上传并将其转换为 Base64 const handleImageUpload = (event) => { const file = event.target.files[0]; // 获取上传的文件 if (file) { // 检查文件大小 if (file.size > MAX_SIZE) { console.log(file.size); message.error('图片大小不能超过 200kb'); // 使用Ant Design的message组件提示 return; // 直接返回,停止后续处理 } const reader = new FileReader(); // 当读取成功时,将结果赋值给 base64Image reader.onload = () => { let res:any = reader.result; // reader.result 是 Base64 数据 base64Image.value = res.split(',')[1] console.log(base64Image.value); }; // 将文件读取为 Data URL (Base64) reader.readAsDataURL(file); event.target.value = ''; } }; const getObLsit = async (id) => { const res = await obList({ orgId: id }); OBList.value = res.data; }; const getOaLsit = async () => { const res = await oaList({pageIndex:1,pageSize:999 }); OAList.value = res.data.list; }; // 获取岗位类别 const getDictList = async () => { const res = await dictStore.getDictList('personPositionCategory'); const resList = await dictStore.getDictList('personLaborType'); console.log(res,resList); positionCategoryList.value = res; personLaborTypeList.value = resList; }; const changeOA = async () => { OBitem.value = '' getObLsit(OAitem.value); }; const changeOB = async () => {}; // const getList = inject('refreshInfoList') as Function; const reload = inject('reload') as Function; const originEdit = ref(); const [registerForm, formBox] = useForm({ labelWidth: 120, schemas, showActionButtonGroup: false, actionColOptions: { span: 24, }, }); const [register, modalBox] = useModalInner((params) => { formBox.resetFields() liTime.value = '' remark.value = '' const { data, type } = params; modalType.value = type; console.log("modalType.value",); pid.value = data.id; // 方式1; if (modalType.value === 'edit') { editPhoto.value = false originEdit.value = {}; originEdit.value = data; OAitem.value = data.orgId; UserCode.value = data.userCode; userRole.value = data.userRole; userDuty.value = data.userDuty; positionCategory.value = data.positionCategory; getObLsit(OAitem.value); OBitem.value = data.groupId; // base64Image.value = data.photo; setTimeout(() => { formBox.setFieldsValue(initFormData); formBox.setFieldsValue(data); }, 0); } else { formBox.resetFields(); formBox.setFieldsValue(initFormData); editPhoto.value = true OAitem.value = ''; UserCode.value = ''; userDuty.value = ''; positionCategory.value = ''; userRole.value = ''; OBitem.value = ''; base64Image.value = ''; } }); const loading = ref(false); const handleok = async () => { if (loading.value) return; try { loading.value = true; if (modalType.value === 'add') { // 新增时额外校验部门班组 if (!OAitem.value) { message.error('请选择部门'); return; } if (!OBitem.value) { message.error('请选择班组'); return; } } if (modalType.value === 'edit') { const val = await formBox.validateFields(); originEdit.value.orgId = OAitem.value; originEdit.value.userRole = UserCode.value; originEdit.value.userDuty = userDuty.value || ""; originEdit.value.positionCategory = positionCategory.value || ""; originEdit.value.userRole = userRole.value || ""; originEdit.value.groupId = OBitem.value; val.photo = base64Image.value; const res = await update({ ...(originEdit.value || {}), ...val, }); if (res.code == 0) { message.success(res.message || '操作成功'); reload(); formBox.resetFields(); modalBox.closeModal(); } else { message.error(res.message || '操作失败'); } } if (modalType.value === 'add') { const val = await formBox.validateFields(); val.orgId = OAitem.value; val.userRole = userRole.value; val.groupId = OBitem.value; val.userDuty = userDuty.value; val.positionCategory = positionCategory.value; val.photo = base64Image.value; val.syncState = 0; const res = await add({ ...(originEdit.value || {}), ...val, }); if (res.code === 0) { reload(); formBox.resetFields(); modalBox.closeModal(); message.success(res?.message || '操作成功'); } else { message.error(res?.message || '操作失败'); } } if (modalType.value === 'lizhi') { const res = await quit({ idList: [pid.value], quitDate: liTime.value, quitReason: remark.value, }); if (res.code === 0) { reload(); formBox.resetFields(); modalBox.closeModal(); message.success(res?.message || '登记成功'); } else { message.error(res?.message || '登记失败'); } } } catch (error) { message.error('请填写必填项'); } finally { loading.value = false; } }; const formData:any = ref(null) const videoWidth:any = ref(195) const videoHeight:any = ref(260) const imgSrc:any = ref("") const thisCancas:any = ref(null) const thisContext:any = ref(null) const thisVideo:any = ref(null) const flag = ref(false) // 打开弹框 const openPhotoDialog = () => { nextTick(() => { getCompetence() }) } // 调用权限(打开摄像头功能) const getCompetence = () => { thisCancas.value = document.getElementById("canvasCamera") console.log("thisCancas", thisCancas.value) thisContext.value = thisCancas.value?.getContext("2d") thisVideo.value = document.getElementById("videoCamera") as HTMLVideoElement // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象 if (navigator.mediaDevices === undefined) { navigator.mediaDevices = {} } // 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象 // 使用getUserMedia,因为它会覆盖现有的属性。 // 这里,如果缺少getUserMedia属性,就添加它。 if (navigator.mediaDevices.getUserMedia === undefined) { navigator.mediaDevices.getUserMedia = (constraints) => { // 首先获取现存的getUserMedia(如果存在) const getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia // 有些浏览器不支持,会返回错误信息 // 保持接口一致 if (!getUserMedia) { return Promise.reject( new Error("getUserMedia is not implemented in this browser") ) } // 否则,使用Promise将调用包装到旧的navigator.getUserMedia return new Promise((resolve, reject) => { getUserMedia.call(navigator, constraints, resolve, reject) }) } } const constraints = { audio: false, video: { width: videoWidth.value, height: videoHeight.value, transform: "scaleX(-1)", }, } navigator.mediaDevices.getUserMedia(constraints) .then((stream) => { console.log("stream",stream) // 旧的浏览器可能没有srcObject if ("srcObject" in thisVideo.value) { thisVideo.value.srcObject = stream } else { // 避免在新的浏览器中使用它,因为它正在被弃用。 thisVideo.value.src = window.URL.createObjectURL(stream) } thisVideo.value.onloadedmetadata = () => { thisVideo.value.play() } flag.value = true }) .catch((err) => { flag.value = false message.error("打开失败,未检测到摄像头信息!") console.log(err) }) } // 绘制图片(拍照功能) const setImage = () => { console.log("thisCancas", thisCancas.value) if (thisCancas.value === null) { return } else { console.log("thisContext", thisContext.value) if (thisContext.value === null) { return } else { thisContext.value.drawImage( thisVideo.value, 0, 0, videoWidth.value, videoHeight.value ) // 获取图片base64链接 const image = thisCancas.value.toDataURL("image/png") imgSrc.value = image base64Image.value = imgSrc.value.split(',')[1] // 更新base64Image console.log("imgSrc", imgSrc.value) // emit("refreshDataList", imgSrc.value) // submit() } } } // base64转文件 const dataURLtoFile = (dataurl, filename) => { const arr = dataurl.split(",") const mime = arr[0].match(/:(.*?);/)[1] const bstr = atob(arr[1]) const n = bstr.length const u8arr = new Uint8Array(n) for (let i = 0; i < n; i++) { u8arr[i] = bstr.charCodeAt(i) } return new File([u8arr], filename, { type: mime }) } // 关闭摄像头 const stopNavigator = () => { thisVideo.value.srcObject?.getTracks()[0].stop() // 隐藏摄像头 flag.value = false } // qrBase64是后台传回来的base64数据 const handleDownloadQrIMg = () => { const qrBase64 = formData.value?.photo // 这里是获取到的图片base64编码,这里只是个例子哈,要自行编码图片替换这里才能测试看到效果 const imgUrl = `data:image/png;base64,${qrBase64}` // 如果浏览器支持msSaveOrOpenBlob方法(也就是使用IE浏览器的时候),那么调用该方法去下载图片 if (window.navigator.msSaveOrOpenBlob) { const bstr = atob(imgUrl.split(",")[1]) const n = bstr.length const u8arr = new Uint8Array(n) for (let i = 0; i < n; i++) { u8arr[i] = bstr.charCodeAt(i) } const blob = new Blob([u8arr]) window.navigator.msSaveOrOpenBlob(blob, "chart-download" + "." + "png") } else { // 这里就按照chrome等新版浏览器来处理 const a = document.createElement("a") a.href = imgUrl a.setAttribute( "download", `${dialogData.value.code}` + `+` + `${dialogData.value.name}` ) a.click() } } const closePhotoDialog = async () => { isPhotoDialogVisible.value = false }; </script> 这段代码的含义
09-04
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值