前端篇 文件上传组件 上传附件 返回附件的url
uploadMode: 可以指定上传模式,默认为file; 其中可选 file || video || drag || image
1 2 3 4 5 6 7 8 9 <a-col :xs ="24" :sm ="24" :md ="24" :lg ="24" :xl ="24" > <a-form-item label ="封面" name ="workCoverUrl" > <xn-upload v-model:value ="formData.workCoverUrl" uploadMode ="image" uploadText ="上传封面" /> </a-form-item > </a-col >
附件上传获取附件返回的详情信息
下面是获取附件上传返回的详情信息 如文件上传名称、文件格式、文件大小等信息 通过@onSuccessful的函数进行赋值注意 : :uploadNumber=1 是指定文件上传数量
1 2 3 4 5 6 7 8 <a-form-item label ="附件上传" > <xn-upload v-model:value ="fileData" uploadResultCategory ="array" :uploadNumber =1 @onSuccessful ="handleUploadSuccess" /> </a-form-item >
1 2 3 4 5 6 7 8 9 const handleUploadSuccess = (data ) => { if (data && data.length > 0 ) { formData.value .fileUrl = data[0 ].response ?.data || data[0 ].url || '' formData.value .fileName = data[0 ].name || '' formData.value .fileType = data[0 ].name ? data[0 ].name .split ('.' ).pop () : '' formData.value .fileSize = data[0 ].size ? formatFileSize (data[0 ].size ) : '' } }
下拉框 字典类型的下拉框
1 import tool from '@/utils/tool'
1 2 3 const gradeLevelNameOptions = ref ([]);const gradeLevelNameOptions = tool.dictList ('EDU_LEVEL' )
1 2 3 4 <a-select v-model:value ="searchFormState.gradeLevelName" placeholder ="请选择学段" :options ="gradeLevelNameOptions" />
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <a-col :xs ="8" :sm ="8" :md ="8" :lg ="8" :xl ="8" > <a-form-item label ="学段" name ="gradeLevelName" > <a-select v-model:value ="formData.gradeLevelName" placeholder ="请选择学段" :options ="gradeLevelNameOptions" allow-clear /> </a-form-item > </a-col > <a-col :xs ="8" :sm ="8" :md ="8" :lg ="8" :xl ="8" > <a-form-item label ="年级" name ="gradeName" > <a-select v-model:value ="formData.gradeName" placeholder ="请选择年级" :options ="gradeNameOptions" allow-clear /> </a-form-item > </a-col > <a-col :xs ="8" :sm ="8" :md ="8" :lg ="8" :xl ="8" > <a-form-item label ="学科" name ="subjectName" > <a-select v-model:value ="formData.subjectName" placeholder ="请选择学科" :options ="subjectNameOptions" allow-clear /> </a-form-item > </a-col >
1 2 3 4 5 6 7 8 9 10 11 const gradeLevelNameOptions = ref ([])const gradeNameOptions = ref ([])const subjectNameOptions = ref ([])const initOptions = ( ) => { gradeLevelNameOptions.value = tool.dictList ('EDU_LEVEL' ) gradeNameOptions.value = tool.dictList ('YEAR_PERIOD' ) subjectNameOptions.value = tool.dictList ('SUBJECT' ) }
自定义key和value的下拉框
这里就是将后端返回的值都赋值给了itemTypeData 后面通过:field-names属性指定key和value进行复制 这里的 @change="handleItemTypeChange" 是来监听下拉框的change事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <a-col :xs ="24" :sm ="24" :md ="24" :lg ="24" :xl ="24" > <a-form-item label ="作品类型" name ="itemTypeId" > <a-select v-model:value ="formData.itemTypeId" show-search style ="width: 100%" placeholder ="请选择作品类型" allow-clear :options ="itemTypeData" :field-names ="{ value: 'itemTypeId', label: 'itemTypeName' }" @change ="handleItemTypeChange" > </a-select > </a-form-item > </a-col >
1 2 3 4 5 6 7 8 9 10 const loadItemTypeData = ( ) => { trfrontProjectApi.itemTypeListByProjectId ({ projectId : projectId.value }).then ((res ) => { console .log ('作品类型数据:' , res) itemTypeData.value = res || [] }).catch ((error ) => { console .error ('获取作品类型失败:' , error) itemTypeData.value = [] }) }
1 2 3 4 5 6 7 const handleItemTypeChange = (value ) => { const selectedItem = itemTypeData.value .find (item => item.itemTypeId === value) if (selectedItem) { formData.value .itemTypeName = selectedItem.itemTypeName } }
其他 Ant Design Vue Modal 防止误关闭配置
在表单编辑场景中,用户填写表单时,误点击模态框外部区域可能导致、表单意外关闭、已填写数据丢失、用户需要重新输入、影响用户体验 因此需要阻止模态框外部区域点击关闭模态框
属性 : :maskClosable="false" 添加这个属性即可
1 2 3 4 5 6 7 <a-modal v-model:open ="open" title ="编辑教师信息" :width ="800" :footer ="null" :maskClosable ="false" <!-- 关键属性 -- > >
路由参数的接收和路由页面的跳转
在开发过程中,经常需要进行页面之间的跳转以及页面之间传递数据,例如从列表页点击”编辑”按钮跳转到详情页并携带id, 或者在详情页获取url中的参数来请求数据等场景
基础引入 1 2 3 4 import { useRoute, useRouter } from "vue-router"; const route = useRoute() // 用于获取当前路由信息(接收参数) const router = useRouter() // 用于进行路由跳转(发送参数)
路由跳转 方式1:path 跳转 + query 传参(URL可见参数)
1 2 3 4 5 6 7 8 9 10 // 跳转并传递参数(参数会显示在 URL 中) router.push({ path: '/targetPage', query: { id: '123', name: '张三', type: 'edit' } }) // URL 效果: /targetPage?id=123&name=张三&type=edit
方式2:name 跳转 + params 传参(URL不可见参数)
1 2 3 4 5 6 7 8 9 // 跳转并传递参数(参数不会显示在 URL 中,需配合动态路由使用) router.push({ name: 'TargetPageName', params: { id: '123' } }) // 注意:使用 params 时,需要在路由配置中定义动态路径如:/targetPage/:id
方式3:字符串简写形式
1 2 3 4 5 // 简单跳转 router.push('/home') // 带 query 参数的简写 router.push('/detail?id=123&name=测试')
路由接收(获取参数) 接收 query 参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import { useRoute } from "vue-router"; const route = useRoute() // 获取单个参数 const id = route.query.id const name = route.query.name // 在 onMounted 中使用 onMounted(() => { if (route.query.id) { // 根据id请求详情数据 loadDetailData(route.query.id) } })
接收 params 参数
1 2 3 4 5 6 7 import { useRoute } from "vue-router"; const route = useRoute() // 获取 params 参数 const id = route.params.id
后端篇 将实体类列表转换为map列表
通过BeanUtil.beanToMap(实体类) 转换为map的形式
1 2 3 4 5 6 7 8 public List<Map<String, Object>> itemTypeListByProjectId (String projectId) { List<Map<String, Object>> result = new ArrayList <>(); List<TrcProjectItemType> list = trcProjectItemTypeService.list(new LambdaQueryWrapper <TrcProjectItemType>().eq(TrcProjectItemType::getProjectId, projectId)); for (TrcProjectItemType project : list) { result.add(BeanUtil.beanToMap(project)); } return result; }
获取当前登录人的userId 1 2 SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();String userId = loginUser.getId();
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Component public class TeacherMessageUtil { @Resource private AuthApi authApi; public String getTeacherId () { SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser(); String userId = loginUser.getId(); AuthThirdUserVo authThirdUserVo = authApi.queryByUserId(userId); if (ObjectUtil.isEmpty(authThirdUserVo)){ return null ; } String teacherId = authThirdUserVo.getThirdId(); return teacherId; } }
跨模块调用:实体类与Map转换的解决方案
最近在开发教研系统过程中,由于我开发的是前台部分(snowy-plugin-trfont)模块,这时候前台数据需要获取教师的数据,而教师的数据在(snowy-pugin-trc)模块下, 因此我需要在(snowy-plugin-trc-api)模块下调用(snowy-plugin-trc)模块下的接口,这时候就设计到一个问题就是(snowy-plugin-trc-api)模块不能直接引用(snowy-pugin-trc)模块 的实体类,这时候需要有两种方式来解决?第一种就是在(snowy-plugin-trc-api)模块下定义对应的实体类来接受,第二种就是通过map来进行转换,我采用的是第二种,比较方便
核心代码 Map转换实体类(入参)
1 2 3 4 5 TrcProjectPageParam trcProjectPageParam = new TrcProjectPageParam ();BeanUtil.copyProperties(param, trcProjectPageParam);
实体类转Map(出参)
1 2 3 4 5 6 7 BeanUtil.beanToMap(project); page.getRecords().stream() .map(BeanUtil::beanToMap) .collect(Collectors.toList());
完整代码示例 Controller层(调用方)
1 2 3 4 5 6 7 8 9 10 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;@GetMapping("/trfront/project/pageProject") public CommonResult<Page<Map<String, Object>>> pageProject (@RequestParam Map<String, Object> request) { return CommonResult.data(trcProjectApi.pageProject(request)); }
API接口定义
1 2 3 4 5 6 Page<Map<String, Object>> pageProject (Map<String, Object> param) ;
API实现层(关键转换逻辑)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Override public Page<Map<String, Object>> pageProject (Map<String, Object> param) { TrcProjectPageParam trcProjectPageParam = new TrcProjectPageParam (); BeanUtil.copyProperties(param, trcProjectPageParam); Page<TrcProject> page = trcProjectService.page(trcProjectPageParam); List<Map<String, Object>> result = new ArrayList <>(); for (TrcProject project : page.getRecords()) { result.add(BeanUtil.beanToMap(project)); } Page<Map<String, Object>> pageResult = new Page <>( page.getCurrent(), page.getSize(), page.getTotal() ); pageResult.setRecords(result); return pageResult; }
自定义sql 如何实现分页功能
Page page = CommonPageRequest.defaultPage(); 这个是snowy框架封装的方法 直接调用即可,T 为对应的数据结构
核心代码 service层
1 2 3 4 5 6 7 8 9 10 Page<T> page = CommonPageRequest.defaultPage(); @Resource private SchoolMapper schoolMapper;public Page<SchoolMessage> pageSchool (SchoolPageParm schoolPageParm) { Page<SchoolMessage> page = CommonPageRequest.defaultPage(); Page<SchoolMessage> schoolMessageList = schoolMapper.pageSchoolMessage(page, schoolPageParm); }
mapper层
1 2 Page<SchoolMessage> pageSchoolMessage (@Param("page") Page<SchoolMessage> page, @Param("param") SchoolPageParm schoolPageParm) ;
mapper.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <!-- 分页查询学校信息 --> <select id="pageSchoolMessage" resultType="com.example.school.dto.response.SchoolMessage"> SELECT id, school_name AS schoolName, address, phone, principal, create_time AS createTime, update_time AS updateTime FROM t_school WHERE is_deleted = 0 <if test="param.schoolName != null and param.schoolName != ''"> AND school_name LIKE CONCAT('%', #{param.schoolName}, '%') </if> <if test="param.address != null and param.address != ''"> AND address LIKE CONCAT('%', #{param.address}, '%') </if> <if test="param.principal != null and param.principal != ''"> AND principal LIKE CONCAT('%', #{param.principal}, '%') </if> </select>