From 3dbf4a9fa6b78101e746adb155fc540cc5337952 Mon Sep 17 00:00:00 2001 From: liuxiao <1732399289qq.com> Date: Thu, 20 Jun 2024 14:46:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=98=E7=BD=91=20=20=20=E6=8B=9B=E8=81=98?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E8=A1=A8=E5=9F=BA=E7=A1=80=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/system/SysOssController.java | 44 ++ .../controller/GwJobInfoController.java | 114 ++++++ .../com/ruoyi/official/domain/GwJobInfo.java | 68 ++++ .../ruoyi/official/domain/bo/GwJobInfoBo.java | 86 ++++ .../ruoyi/official/domain/vo/GwJobInfoVo.java | 86 ++++ .../official/mapper/GwJobInfoMapper.java | 16 + .../official/service/IGwJobInfoService.java | 54 +++ .../service/impl/GwJobInfoServiceImpl.java | 118 ++++++ .../mapper/official/GwJobInfoMapper.xml | 25 ++ ruoyi-ui/src/api/official/jobInfo.js | 49 +++ ruoyi-ui/src/views/official/jobInfo/index.vue | 384 ++++++++++++++++++ 11 files changed, 1044 insertions(+) create mode 100644 ruoyi-system/src/main/java/com/ruoyi/official/controller/GwJobInfoController.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/official/domain/GwJobInfo.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/official/domain/bo/GwJobInfoBo.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/official/domain/vo/GwJobInfoVo.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/official/mapper/GwJobInfoMapper.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/official/service/IGwJobInfoService.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/official/service/impl/GwJobInfoServiceImpl.java create mode 100644 ruoyi-system/src/main/resources/mapper/official/GwJobInfoMapper.xml create mode 100644 ruoyi-ui/src/api/official/jobInfo.js create mode 100644 ruoyi-ui/src/views/official/jobInfo/index.vue diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java index 2a7cc11..ce4e3f8 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java @@ -14,6 +14,8 @@ import com.ruoyi.system.domain.bo.SysOssBo; import com.ruoyi.system.domain.vo.SysOssVo; import com.ruoyi.system.service.ISysOssService; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -21,6 +23,7 @@ import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.NotEmpty; +import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; @@ -35,9 +38,13 @@ import java.util.Map; @Validated @RequiredArgsConstructor @RestController +@Slf4j @RequestMapping("/system/oss") public class SysOssController extends BaseController { + @Value("${file.BASE_FILE_SAVE_PATH}") + private String filePath; + private final ISysOssService iSysOssService; /** @@ -82,6 +89,43 @@ public class SysOssController extends BaseController { return R.ok(map); } + @Log(title = "OSS对象存储", businessType = BusinessType.INSERT) + @PostMapping("/addPartsUpload") + public R> addPartsUpload(@RequestPart("file") MultipartFile file) { + Map map=new HashMap<>(); + log.info("上传的文件名称:{}",file.getOriginalFilename()); + //文件上传的地址从配置文件中获取 + log.info("上传的文件地址:{}",filePath); + try { + if (file.isEmpty()) { + return R.fail("上传文件不能为空"); + } + + String fileName = System.currentTimeMillis()+"-"+file.getOriginalFilename(); + //文件上传的路径(当前项目的根目录) + + System.err.println(filePath); + // 创建目标目录(如果不存在) + File directory = new File(filePath); + if (!directory.exists()) { + directory.mkdirs(); + } + // 保存文件到目标目录 + File uploadFile = new File(directory.getAbsolutePath() + File.separator + fileName); + file.transferTo(uploadFile); + String pathFan=filePath.replace("\\","/"); + //filePath获取到的地址斜杠是“ \ ”的(单斜杠是特殊符号,得用双斜杠代替),得换成“ / ”才能访问到 + + map.put("fileName",pathFan+fileName); + log.info("替换后的文件名称:{}",pathFan+fileName); + //修改数据库 + return R.ok(map); + } catch (IOException e) { + return R.fail("文件上传失败: "+e); + } + + } + /** * 下载OSS对象 * diff --git a/ruoyi-system/src/main/java/com/ruoyi/official/controller/GwJobInfoController.java b/ruoyi-system/src/main/java/com/ruoyi/official/controller/GwJobInfoController.java new file mode 100644 index 0000000..460f1f6 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/official/controller/GwJobInfoController.java @@ -0,0 +1,114 @@ +package com.ruoyi.official.controller; + +import java.util.List; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import lombok.RequiredArgsConstructor; +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.PageQuery; +import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.core.validate.QueryGroup; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.official.domain.vo.GwJobInfoVo; +import com.ruoyi.official.domain.bo.GwJobInfoBo; +import com.ruoyi.official.service.IGwJobInfoService; +import com.ruoyi.common.core.page.TableDataInfo; + +/** + * 招聘信息 + + * + * @author ruoyi + * @date 2024-06-20 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/official/jobInfo") +public class GwJobInfoController extends BaseController { + + private final IGwJobInfoService iGwJobInfoService; + + /** + * 查询招聘信息 +列表 + */ + @SaCheckPermission("official:jobInfo:list") + @GetMapping("/list") + public TableDataInfo list(GwJobInfoBo bo, PageQuery pageQuery) { + return iGwJobInfoService.queryPageList(bo, pageQuery); + } + + /** + * 导出招聘信息 +列表 + */ + @SaCheckPermission("official:jobInfo:export") + @Log(title = "招聘信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(GwJobInfoBo bo, HttpServletResponse response) { + List list = iGwJobInfoService.queryList(bo); + ExcelUtil.exportExcel(list, "招聘信息", GwJobInfoVo.class, response); + } + + /** + * 获取招聘信息 +详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("official:jobInfo:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) { + return R.ok(iGwJobInfoService.queryById(id)); + } + + /** + * 新增招聘信息 + + */ + @SaCheckPermission("official:jobInfo:add") + @Log(title = "招聘信息", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody GwJobInfoBo bo) { + return toAjax(iGwJobInfoService.insertByBo(bo)); + } + + /** + * 修改招聘信息 + + */ + @SaCheckPermission("official:jobInfo:edit") + @Log(title = "招聘信息", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody GwJobInfoBo bo) { + return toAjax(iGwJobInfoService.updateByBo(bo)); + } + + /** + * 删除招聘信息 + + * + * @param ids 主键串 + */ + @SaCheckPermission("official:jobInfo:remove") + @Log(title = "招聘信息 ", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(iGwJobInfoService.deleteWithValidByIds(Arrays.asList(ids), true)); + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/official/domain/GwJobInfo.java b/ruoyi-system/src/main/java/com/ruoyi/official/domain/GwJobInfo.java new file mode 100644 index 0000000..925250b --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/official/domain/GwJobInfo.java @@ -0,0 +1,68 @@ +package com.ruoyi.official.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.io.Serializable; +import java.util.Date; +import java.math.BigDecimal; + +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * 招聘信息 +对象 gw_job_info + * + * @author ruoyi + * @date 2024-06-20 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("gw_job_info") +public class GwJobInfo extends BaseEntity { + + private static final long serialVersionUID=1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + /** + * 标签id + */ + private Long lableId; + /** + * 招聘岗位 + */ + private String jobPost; + /** + * 岗位类型 + */ + private String postType; + /** + * 招聘类型 + */ + private String jobType; + /** + * 工作地点 + */ + private String baseSite; + /** + * 工作职责 + */ + private String jobDuties; + /** + * 任职资格 + */ + private String qualification; + /** + * 创建者id + */ + private Long createUserId; + /** + * 更新者id + */ + private Long updateUserId; + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/official/domain/bo/GwJobInfoBo.java b/ruoyi-system/src/main/java/com/ruoyi/official/domain/bo/GwJobInfoBo.java new file mode 100644 index 0000000..6849fae --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/official/domain/bo/GwJobInfoBo.java @@ -0,0 +1,86 @@ +package com.ruoyi.official.domain.bo; + +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; +import javax.validation.constraints.*; + +import java.util.Date; + +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * 招聘信息 +业务对象 gw_job_info + * + * @author ruoyi + * @date 2024-06-20 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class GwJobInfoBo extends BaseEntity { + + /** + * 主键id + */ + @NotNull(message = "主键id不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 标签id + */ + @NotNull(message = "标签id不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long lableId; + + /** + * 招聘岗位 + */ + @NotBlank(message = "招聘岗位不能为空", groups = { AddGroup.class, EditGroup.class }) + private String jobPost; + + /** + * 岗位类型 + */ + @NotBlank(message = "岗位类型不能为空", groups = { AddGroup.class, EditGroup.class }) + private String postType; + + /** + * 招聘类型 + */ + @NotBlank(message = "招聘类型不能为空", groups = { AddGroup.class, EditGroup.class }) + private String jobType; + + /** + * 工作地点 + */ + @NotBlank(message = "工作地点不能为空", groups = { AddGroup.class, EditGroup.class }) + private String baseSite; + + /** + * 工作职责 + */ + @NotBlank(message = "工作职责不能为空", groups = { AddGroup.class, EditGroup.class }) + private String jobDuties; + + /** + * 任职资格 + */ + @NotBlank(message = "任职资格不能为空", groups = { AddGroup.class, EditGroup.class }) + private String qualification; + + /** + * 创建者id + */ + @NotNull(message = "创建者id不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long createUserId; + + /** + * 更新者id + */ + @NotNull(message = "更新者id不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long updateUserId; + + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/official/domain/vo/GwJobInfoVo.java b/ruoyi-system/src/main/java/com/ruoyi/official/domain/vo/GwJobInfoVo.java new file mode 100644 index 0000000..1cb001a --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/official/domain/vo/GwJobInfoVo.java @@ -0,0 +1,86 @@ +package com.ruoyi.official.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.annotation.ExcelDictFormat; +import com.ruoyi.common.convert.ExcelDictConvert; +import lombok.Data; +import java.util.Date; + + + +/** + * 招聘信息 +视图对象 gw_job_info + * + * @author ruoyi + * @date 2024-06-20 + */ +@Data +@ExcelIgnoreUnannotated +public class GwJobInfoVo { + + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @ExcelProperty(value = "主键id") + private Long id; + + /** + * 标签id + */ + @ExcelProperty(value = "标签id") + private Long lableId; + + /** + * 招聘岗位 + */ + @ExcelProperty(value = "招聘岗位") + private String jobPost; + + /** + * 岗位类型 + */ + @ExcelProperty(value = "岗位类型") + private String postType; + + /** + * 招聘类型 + */ + @ExcelProperty(value = "招聘类型") + private String jobType; + + /** + * 工作地点 + */ + @ExcelProperty(value = "工作地点") + private String baseSite; + + /** + * 工作职责 + */ + @ExcelProperty(value = "工作职责") + private String jobDuties; + + /** + * 任职资格 + */ + @ExcelProperty(value = "任职资格") + private String qualification; + + /** + * 创建者id + */ + @ExcelProperty(value = "创建者id") + private Long createUserId; + + /** + * 更新者id + */ + @ExcelProperty(value = "更新者id") + private Long updateUserId; + + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/official/mapper/GwJobInfoMapper.java b/ruoyi-system/src/main/java/com/ruoyi/official/mapper/GwJobInfoMapper.java new file mode 100644 index 0000000..16583ac --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/official/mapper/GwJobInfoMapper.java @@ -0,0 +1,16 @@ +package com.ruoyi.official.mapper; + +import com.ruoyi.official.domain.GwJobInfo; +import com.ruoyi.official.domain.vo.GwJobInfoVo; +import com.ruoyi.common.core.mapper.BaseMapperPlus; + +/** + * 招聘信息 +Mapper接口 + * + * @author ruoyi + * @date 2024-06-20 + */ +public interface GwJobInfoMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/official/service/IGwJobInfoService.java b/ruoyi-system/src/main/java/com/ruoyi/official/service/IGwJobInfoService.java new file mode 100644 index 0000000..d5fbb7d --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/official/service/IGwJobInfoService.java @@ -0,0 +1,54 @@ +package com.ruoyi.official.service; + + +import com.ruoyi.official.domain.vo.GwJobInfoVo; +import com.ruoyi.official.domain.bo.GwJobInfoBo; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.domain.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 招聘信息 +Service接口 + * + * @author ruoyi + * @date 2024-06-20 + */ +public interface IGwJobInfoService { + + /** + * 查询招聘信息 + + */ + GwJobInfoVo queryById(Long id); + + /** + * 查询招聘信息列表 + */ + TableDataInfo queryPageList(GwJobInfoBo bo, PageQuery pageQuery); + + /** + * 查询招聘信息 +列表 + */ + List queryList(GwJobInfoBo bo); + + /** + * 新增招聘信息 + + */ + Boolean insertByBo(GwJobInfoBo bo); + + /** + * 修改招聘信息 + + */ + Boolean updateByBo(GwJobInfoBo bo); + + /** + * 校验并批量删除招聘信息信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/official/service/impl/GwJobInfoServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/official/service/impl/GwJobInfoServiceImpl.java new file mode 100644 index 0000000..9471e35 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/official/service/impl/GwJobInfoServiceImpl.java @@ -0,0 +1,118 @@ +package com.ruoyi.official.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.domain.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import com.ruoyi.official.domain.bo.GwJobInfoBo; +import com.ruoyi.official.domain.vo.GwJobInfoVo; +import com.ruoyi.official.domain.GwJobInfo; +import com.ruoyi.official.mapper.GwJobInfoMapper; +import com.ruoyi.official.service.IGwJobInfoService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 招聘信息Service业务层处理 + * + * @author ruoyi + * @date 2024-06-20 + */ +@RequiredArgsConstructor +@Service +public class GwJobInfoServiceImpl implements IGwJobInfoService { + + private final GwJobInfoMapper baseMapper; + + /** + * 查询招聘信息 + */ + @Override + public GwJobInfoVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 查询招聘信息列表 + */ + @Override + public TableDataInfo queryPageList(GwJobInfoBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询招聘信息列表 + */ + @Override + public List queryList(GwJobInfoBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(GwJobInfoBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(bo.getLableId() != null, GwJobInfo::getLableId, bo.getLableId()); + lqw.eq(StringUtils.isNotBlank(bo.getJobPost()), GwJobInfo::getJobPost, bo.getJobPost()); + lqw.eq(StringUtils.isNotBlank(bo.getPostType()), GwJobInfo::getPostType, bo.getPostType()); + lqw.eq(StringUtils.isNotBlank(bo.getJobType()), GwJobInfo::getJobType, bo.getJobType()); + lqw.eq(StringUtils.isNotBlank(bo.getBaseSite()), GwJobInfo::getBaseSite, bo.getBaseSite()); + lqw.eq(StringUtils.isNotBlank(bo.getJobDuties()), GwJobInfo::getJobDuties, bo.getJobDuties()); + lqw.eq(StringUtils.isNotBlank(bo.getQualification()), GwJobInfo::getQualification, bo.getQualification()); + lqw.eq(bo.getCreateUserId() != null, GwJobInfo::getCreateUserId, bo.getCreateUserId()); + lqw.eq(bo.getUpdateUserId() != null, GwJobInfo::getUpdateUserId, bo.getUpdateUserId()); + return lqw; + } + + /** + * 新增招聘信息 + */ + @Override + public Boolean insertByBo(GwJobInfoBo bo) { + GwJobInfo add = BeanUtil.toBean(bo, GwJobInfo.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改招聘信息 + */ + @Override + public Boolean updateByBo(GwJobInfoBo bo) { + GwJobInfo update = BeanUtil.toBean(bo, GwJobInfo.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(GwJobInfo entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 批量删除招聘信息 + + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } +} diff --git a/ruoyi-system/src/main/resources/mapper/official/GwJobInfoMapper.xml b/ruoyi-system/src/main/resources/mapper/official/GwJobInfoMapper.xml new file mode 100644 index 0000000..4e442a0 --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/official/GwJobInfoMapper.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-ui/src/api/official/jobInfo.js b/ruoyi-ui/src/api/official/jobInfo.js new file mode 100644 index 0000000..ffe1069 --- /dev/null +++ b/ruoyi-ui/src/api/official/jobInfo.js @@ -0,0 +1,49 @@ +import request from '@/utils/request' + +// 查询招聘信息 +列表 +export function listJobInfo(query) { + return request({ + url: '/official/jobInfo/list', + method: 'get', + params: query + }) +} + +// 查询招聘信息 +详细 +export function getJobInfo(id) { + return request({ + url: '/official/jobInfo/' + id, + method: 'get' + }) +} + +// 新增招聘信息 + +export function addJobInfo(data) { + return request({ + url: '/official/jobInfo', + method: 'post', + data: data + }) +} + +// 修改招聘信息 + +export function updateJobInfo(data) { + return request({ + url: '/official/jobInfo', + method: 'put', + data: data + }) +} + +// 删除招聘信息 + +export function delJobInfo(id) { + return request({ + url: '/official/jobInfo/' + id, + method: 'delete' + }) +} diff --git a/ruoyi-ui/src/views/official/jobInfo/index.vue b/ruoyi-ui/src/views/official/jobInfo/index.vue new file mode 100644 index 0000000..4027be7 --- /dev/null +++ b/ruoyi-ui/src/views/official/jobInfo/index.vue @@ -0,0 +1,384 @@ + + +