From e29f147aab5b0b0b794d611b522b67b94423e3cf Mon Sep 17 00:00:00 2001
From: Fixiaobai <fixiaobai@163.com>
Date: 星期四, 07 九月 2023 17:56:57 +0800
Subject: [PATCH] 修改bug

---
 framework/src/main/java/com/yuanchu/limslaboratory/handler/GlobalExceptionHandler.java        |    7 +
 inspection-server/src/main/java/com/yuanchu/limslaboratory/service/PlanService.java           |    2 
 user-server/src/main/java/com/yuanchu/limslaboratory/mapper/RoleManageMapper.java             |    2 
 sys/src/test/java/com/yuanchu/limslaboratory/SysApplicationTests.java                         |    6 -
 inspection-server/src/main/resources/mapper/PlanMapper.xml                                    |    7 +
 inspection-server/src/main/java/com/yuanchu/limslaboratory/mapper/InspectionMapper.java       |    2 
 user-server/src/main/java/com/yuanchu/limslaboratory/clients/UserLoginUtils.java              |   86 ++++++++++++++-------
 inspection-server/src/main/java/com/yuanchu/limslaboratory/mapper/PlanMapper.java             |    2 
 inspection-server/src/main/resources/mapper/InspectionMapper.xml                              |   21 +++++
 user-server/src/main/resources/mapper/RoleManangeMapper.xml                                   |    6 +
 inspection-server/src/main/java/com/yuanchu/limslaboratory/service/impl/PlanServiceImpl.java  |   43 +++++++++-
 sys/src/main/java/com/yuanchu/limslaboratory/aop/AuthRequestAspect.java                       |    2 
 inspection-server/src/main/java/com/yuanchu/limslaboratory/controller/PlanController.java     |    7 +
 inspection-server/src/main/java/com/yuanchu/limslaboratory/pojo/NonConformanceReview.java     |    7 +
 user-server/src/main/java/com/yuanchu/limslaboratory/service/impl/RoleManagerServiceImpl.java |    2 
 15 files changed, 152 insertions(+), 50 deletions(-)

diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/handler/GlobalExceptionHandler.java b/framework/src/main/java/com/yuanchu/limslaboratory/handler/GlobalExceptionHandler.java
index 340de5b..d449a4e 100644
--- a/framework/src/main/java/com/yuanchu/limslaboratory/handler/GlobalExceptionHandler.java
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/handler/GlobalExceptionHandler.java
@@ -103,6 +103,7 @@
         e.printStackTrace();
         return Result.fail("鏁板瓧鏍煎紡寮傚父");
     }
+
     /** 瀹夊叏寮傚父 */
     @ExceptionHandler(SecurityException.class)
     public Result<?> SecurityException(SecurityException e) {
@@ -137,6 +138,7 @@
         e.printStackTrace();
         return Result.fail("鏁扮粍瓒婄晫寮傚父");
     }
+
     /** sql璇硶閿欒寮傚父 */
     @ExceptionHandler(BadSqlGrammarException.class)
     public Result<?> BadSqlGrammarException(BadSqlGrammarException e) {
@@ -226,6 +228,11 @@
         return Result.fail("缃戠粶杩炴帴澶辫触锛岃閫�鍑哄悗鍐嶈瘯");
     }
 
+    /**
+     * 鏉冮檺
+     * @param e
+     * @return
+     */
     @ExceptionHandler({AuthException.class})
     public Result<?> noAuth(AuthException e){
         return Result.fail(Integer.valueOf(e.getCode()),e.getMsg());
diff --git a/inspection-server/src/main/java/com/yuanchu/limslaboratory/controller/PlanController.java b/inspection-server/src/main/java/com/yuanchu/limslaboratory/controller/PlanController.java
index 3c3edc2..5dca2be 100644
--- a/inspection-server/src/main/java/com/yuanchu/limslaboratory/controller/PlanController.java
+++ b/inspection-server/src/main/java/com/yuanchu/limslaboratory/controller/PlanController.java
@@ -36,12 +36,13 @@
             @ApiImplicitParam(name = "code", value = "鐢宠鍗曠紪鍙�", dataTypeClass = String.class),
             @ApiImplicitParam(name = "beginTime", value = "妫�楠屽紑濮嬫椂闂�", dataTypeClass = String.class),
             @ApiImplicitParam(name = "endTime", value = "妫�楠岀粨鏉熸椂闂�", dataTypeClass = String.class),
-            @ApiImplicitParam(name = "status", value = "妫�楠岀粨鏋�", dataTypeClass = Integer.class)
+            @ApiImplicitParam(name = "status", value = "妫�楠岀粨鏋�", dataTypeClass = Integer.class),
+            @ApiImplicitParam(name = "isLookMe", value = "鏄惁鍙湅鎴�", dataTypeClass = Boolean.class)
     })
     @GetMapping("/selectAllPlan")
     @AuthHandler
-    public Result selectAllPlan(String code, String beginTime, String endTime, Integer status) {
-        return Result.success(planService.selectAllPlan(code, beginTime, endTime, status));
+    public Result selectAllPlan(String code, String beginTime, String endTime, Integer status,boolean isLookMe) {
+        return Result.success(planService.selectAllPlan(code, beginTime, endTime, status,isLookMe));
     }
 
     @ApiOperation("鍒嗛厤-->閫夋嫨妫�楠屼汉")
diff --git a/inspection-server/src/main/java/com/yuanchu/limslaboratory/mapper/InspectionMapper.java b/inspection-server/src/main/java/com/yuanchu/limslaboratory/mapper/InspectionMapper.java
index 91ab2b5..3988c98 100644
--- a/inspection-server/src/main/java/com/yuanchu/limslaboratory/mapper/InspectionMapper.java
+++ b/inspection-server/src/main/java/com/yuanchu/limslaboratory/mapper/InspectionMapper.java
@@ -77,6 +77,8 @@
     //鏌ヨ璇ユ湀鐨勬垚鍝佸悎鏍肩巼
     Long getOkFinByMonth(String monthofYear);
 
+    List<Map<String, Object>>getInspectionMaterials(Long id);
 
+    Map<String, Object> selectImAndUserName(Integer id);
 }
 
diff --git a/inspection-server/src/main/java/com/yuanchu/limslaboratory/mapper/PlanMapper.java b/inspection-server/src/main/java/com/yuanchu/limslaboratory/mapper/PlanMapper.java
index 7112d03..353ddec 100644
--- a/inspection-server/src/main/java/com/yuanchu/limslaboratory/mapper/PlanMapper.java
+++ b/inspection-server/src/main/java/com/yuanchu/limslaboratory/mapper/PlanMapper.java
@@ -6,5 +6,5 @@
 public interface PlanMapper {
 
     //鏌ヨ妫�楠岃鍒�
-    List<Map<String, Object>> selectAllPlan(String code, String beginTime, String endTime,Integer status);
+    List<Map<String, Object>> selectAllPlan(String code, String beginTime, String endTime,Integer status,Boolean isLookMe,Integer id);
 }
diff --git a/inspection-server/src/main/java/com/yuanchu/limslaboratory/pojo/NonConformanceReview.java b/inspection-server/src/main/java/com/yuanchu/limslaboratory/pojo/NonConformanceReview.java
index 71b1e6c..eb550df 100644
--- a/inspection-server/src/main/java/com/yuanchu/limslaboratory/pojo/NonConformanceReview.java
+++ b/inspection-server/src/main/java/com/yuanchu/limslaboratory/pojo/NonConformanceReview.java
@@ -11,8 +11,8 @@
 import org.springframework.format.annotation.DateTimeFormat;
 
 import java.io.Serializable;
-import java.sql.Date;
 import java.time.LocalDateTime;
+import java.util.Date;
 
 /**
  * @Author 寮犲
@@ -62,6 +62,11 @@
     private String specifications;
 
     /**
+     * 瑙勬牸鍨嬪彿
+     */
+    private Integer specificationsId;
+
+    /**
      * 鍒涘缓浜�
      */
     private String createdUser;
diff --git a/inspection-server/src/main/java/com/yuanchu/limslaboratory/service/PlanService.java b/inspection-server/src/main/java/com/yuanchu/limslaboratory/service/PlanService.java
index b519e38..92bbbb2 100644
--- a/inspection-server/src/main/java/com/yuanchu/limslaboratory/service/PlanService.java
+++ b/inspection-server/src/main/java/com/yuanchu/limslaboratory/service/PlanService.java
@@ -16,7 +16,7 @@
      * 鏌ヨ妫�楠岃鍒�
      * @return
      */
-    List<Map<String,Object>> selectAllPlan(String code , String beginTime, String endTime,Integer status);
+    List<Map<String,Object>> selectAllPlan(String code , String beginTime, String endTime,Integer status,Boolean isLookMe);
 
     /**
      * 鍒嗛厤-->閫夋嫨妫�楠屼汉
diff --git a/inspection-server/src/main/java/com/yuanchu/limslaboratory/service/impl/PlanServiceImpl.java b/inspection-server/src/main/java/com/yuanchu/limslaboratory/service/impl/PlanServiceImpl.java
index 706aff9..4d23c99 100644
--- a/inspection-server/src/main/java/com/yuanchu/limslaboratory/service/impl/PlanServiceImpl.java
+++ b/inspection-server/src/main/java/com/yuanchu/limslaboratory/service/impl/PlanServiceImpl.java
@@ -1,20 +1,26 @@
 package com.yuanchu.limslaboratory.service.impl;
 
 
+import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.yuanchu.limslaboratory.mapper.*;
-import com.yuanchu.limslaboratory.pojo.Inspection;
-import com.yuanchu.limslaboratory.pojo.InspectionProduct;
-import com.yuanchu.limslaboratory.pojo.NonConformanceReview;
-import com.yuanchu.limslaboratory.pojo.Report;
+import com.yuanchu.limslaboratory.pojo.*;
 import com.yuanchu.limslaboratory.service.PlanService;
 import com.yuanchu.limslaboratory.utils.MyUtil;
+import com.yuanchu.limslaboratory.utils.RedisUtil;
+import com.yuanchu.limslaboratory.utils.ServletUtils;
+import org.apache.commons.lang3.time.DateUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.ObjectUtils;
 
 import javax.annotation.Resource;
 import java.time.LocalDateTime;
 import java.util.Arrays;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -59,8 +65,14 @@
 
     //鏌ヨ妫�楠岃鍒�
     @Override
-    public List<Map<String, Object>> selectAllPlan(String code, String beginTime, String endTime, Integer status) {
-        return planMapper.selectAllPlan(code, beginTime, endTime, status);
+    public List<Map<String, Object>> selectAllPlan(String code, String beginTime, String endTime, Integer status,Boolean isLookMe) {
+        Object obj = RedisUtil.get(ServletUtils.getRequest().getHeader("X-Token"));
+        Integer id=null;
+        if(isLookMe&&!ObjectUtils.isEmpty(obj)){
+                Map loginUser = (Map) obj;
+                id=Integer.parseInt(String.valueOf(loginUser.get("id")));
+        }
+        return planMapper.selectAllPlan(code, beginTime, endTime, status,isLookMe,id);
     }
 
     //鍒嗛厤-->閫夋嫨妫�楠屼汉
@@ -131,10 +143,29 @@
             //鏇存柊妫�楠屽崟
             inspectionMapper.updateById(inspection);
             //娣诲姞涓嶅悎鏍间俊鎭埌璇勫
+            Map<String, Object> map = inspectionMapper.selectImAndUserName(id);
             NonConformanceReview nonConformanceReview = new NonConformanceReview();
             LocalDateTime localDateTime = DateUtil.toLocalDateTime(DateUtil.date());
             nonConformanceReview.setCreatedTime(localDateTime);
             nonConformanceReview.setUpdatedTime(localDateTime);
+            nonConformanceReview.setMaterialCode(String.valueOf(map.get("code")));
+            nonConformanceReview.setInspectionCode(String.valueOf(map.get("iCode")));
+            nonConformanceReview.setMaterialName(String.valueOf(map.get("name")));
+            nonConformanceReview.setSpecifications(String.valueOf(map.get("specifications")));
+            nonConformanceReview.setSpecificationsId(Integer.valueOf(String.valueOf(map.get("specificationsId"))));
+            nonConformanceReview.setState(1);
+            Date iCreateTime = DateUtil.parse(String.valueOf(map.get("iCreateTime")));
+            nonConformanceReview.setCreateTime(iCreateTime);
+            nonConformanceReview.setTestManager(String.valueOf(map.get("uName")));
+            Object obj = RedisUtil.get(ServletUtils.getRequest().getHeader("X-Token"));
+            if (!ObjectUtils.isEmpty(obj)) {
+                Map loginUser = (Map) obj;
+                nonConformanceReview.setCreatedUser(String.valueOf(loginUser.get("id")));
+            }
+            int insert = nonConformanceReviewMapper.insert(nonConformanceReview);
+            if(insert<1){
+                return "涓婃姤澶辫触";
+            }
         } else if (count == results.size()) {
             Inspection inspection = new Inspection();
             inspection.setId(id);
diff --git a/inspection-server/src/main/resources/mapper/InspectionMapper.xml b/inspection-server/src/main/resources/mapper/InspectionMapper.xml
index 3218545..f67ae4e 100644
--- a/inspection-server/src/main/resources/mapper/InspectionMapper.xml
+++ b/inspection-server/src/main/resources/mapper/InspectionMapper.xml
@@ -179,4 +179,25 @@
           and inspection_status = 1
           and DATE_FORMAT(end_time, '%Y-%m') = #{monthofYear}
     </select>
+    <select id="getInspectionMaterials" resultType="java.util.Map">
+
+    </select>
+    <select id="selectImAndUserName" resultType="java.util.Map">
+        SELECT
+            im.`code`,
+            im.`name`,
+            i.`code` iCode,
+            i.create_time iCreateTime,
+            im.specifications_id specificationsId,
+            im.specifications specifications,
+            u.`name` uName
+        FROM
+            inspection i,
+            inspection_material im,
+            `user` u
+        WHERE
+            i.id = im.inspection_id
+          AND i.user_id=u.id
+          AND i.id=#{id}
+    </select>
 </mapper>
\ No newline at end of file
diff --git a/inspection-server/src/main/resources/mapper/PlanMapper.xml b/inspection-server/src/main/resources/mapper/PlanMapper.xml
index c0df58e..cf40804 100644
--- a/inspection-server/src/main/resources/mapper/PlanMapper.xml
+++ b/inspection-server/src/main/resources/mapper/PlanMapper.xml
@@ -39,9 +39,9 @@
         internal,
         test_value testValue,
         test_state testState,
-        u.id   uId,
+        u.id uId,
         u.name checker,
-        isu.id  isuId,
+        isu.id isuId,
         isu.classify_id classId,
         equipment_name instrumentname
         from lims_laboratory.inspection_product ip
@@ -59,6 +59,9 @@
             <if test="beginTime != null and endTime != null">
                 and i.start_time between #{beginTime} and #{endTime}
             </if>
+            <if test="isLookMe != false and id != null">
+                and ip.user_id=#{id}
+            </if>
         </where>
     </select>
 </mapper>
diff --git a/sys/src/main/java/com/yuanchu/limslaboratory/aop/AuthRequestAspect.java b/sys/src/main/java/com/yuanchu/limslaboratory/aop/AuthRequestAspect.java
index 54e2372..ed54614 100644
--- a/sys/src/main/java/com/yuanchu/limslaboratory/aop/AuthRequestAspect.java
+++ b/sys/src/main/java/com/yuanchu/limslaboratory/aop/AuthRequestAspect.java
@@ -37,7 +37,7 @@
     public void pointCut() {
     }
 
-    private final static String ADMIN = "f5c8bcb7d5a0fd27e2323280f7e98cad";
+    private final static String ADMIN = "c3284d0f94606de1fd2af172aba15bf3";
 
 
     @Resource
diff --git a/sys/src/test/java/com/yuanchu/limslaboratory/SysApplicationTests.java b/sys/src/test/java/com/yuanchu/limslaboratory/SysApplicationTests.java
index 9e892da..d5a91c3 100644
--- a/sys/src/test/java/com/yuanchu/limslaboratory/SysApplicationTests.java
+++ b/sys/src/test/java/com/yuanchu/limslaboratory/SysApplicationTests.java
@@ -44,12 +44,8 @@
 
     @Test
     void TT2(){
-        String adminMD5 = SecureUtil.md5(SecureUtil.md5("Fixiaobai"));
+        String adminMD5 = SecureUtil.md5(SecureUtil.md5("admin"));
         System.out.println(adminMD5);
-        // 鏋勫缓
-        AES aes = SecureUtil.aes(adminMD5.getBytes(StandardCharsets.UTF_8));
-        String admins = aes.encryptHex("Fixiaobai");
-        System.out.println(SecureUtil.md5(admins));
     }
 
     @Test
diff --git a/user-server/src/main/java/com/yuanchu/limslaboratory/clients/UserLoginUtils.java b/user-server/src/main/java/com/yuanchu/limslaboratory/clients/UserLoginUtils.java
index 43189b1..4c4dc09 100644
--- a/user-server/src/main/java/com/yuanchu/limslaboratory/clients/UserLoginUtils.java
+++ b/user-server/src/main/java/com/yuanchu/limslaboratory/clients/UserLoginUtils.java
@@ -2,51 +2,79 @@
 
 import cn.hutool.crypto.SecureUtil;
 import cn.hutool.crypto.symmetric.AES;
+import com.yuanchu.limslaboratory.mapper.RoleManageMapper;
+import com.yuanchu.limslaboratory.mapper.UserMapper;
+import com.yuanchu.limslaboratory.pojo.Menu;
+import com.yuanchu.limslaboratory.pojo.RoleMenu;
 import com.yuanchu.limslaboratory.pojo.User;
+import com.yuanchu.limslaboratory.pojo.dto.RoleAndMenuDto;
 import com.yuanchu.limslaboratory.shiro.utils.JwtUtils;
+import com.yuanchu.limslaboratory.utils.MyUtil;
 import com.yuanchu.limslaboratory.utils.RedisUtil;
 import com.yuanchu.limslaboratory.vo.Result;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
+import javax.annotation.Resource;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
 
 @Component
 public class UserLoginUtils {
 
-    @Autowired
-    private JwtUtils jwtUtils;
+    @Resource
+    private UserClient userClient;
+
+    @Value("${login.userID}")
+    private String LoginUserID;
+
+    @Value("${login.secret}")
+    private String LoginSecret;
+
 
 
     public Result<Map<String, Object>> LoginExamine(User user){
-        String token = JwtUtils.sign(user.getAccount());
-        HashMap<String, Object> mapRedis = new HashMap<>();
-        mapRedis.put("id", user.getId());
-        mapRedis.put("account", user.getAccount());
-        mapRedis.put("name", user.getName());
-        mapRedis.put("enterpriseId", user.getEnterpriseId());
-
-
-        String adminMD5 = SecureUtil.md5(SecureUtil.md5(user.getAccount()));
-        // 鏋勫缓
-        AES aes = SecureUtil.aes(adminMD5.getBytes(StandardCharsets.UTF_8));
-        String admins = aes.encryptHex(user.getAccount());
-        mapRedis.put("sessionLayerId", SecureUtil.md5(admins));
-        mapRedis.put("roleId",user.getRoleId());
-
-        //瀛樺叆redis,浜屼釜灏忔椂鍚庡垹闄�
-        RedisUtil.set(token, mapRedis, 120);
-        //
-        RedisUtil.set("access_token",token,120);
-        // 灏嗙鍙戠殑 JWT token 杩斿洖缁欏墠绔�
-        HashMap<String, Object> map = new HashMap<>();
-        String refresh = JwtUtils.sign(user.getAccount());
-        map.put("token", token);
-        map.put("refresh", refresh);
-        RedisUtil.set(user.getAccount(), map, 168);
-        return Result.success(map);
+        Map<String, Object> mapData = new HashMap<>();
+        mapData.put("LoginUserID", LoginUserID);
+        mapData.put("LoginSecret", LoginSecret);
+        Result<?> code = userClient.BusynessUserLogin(mapData);
+        if (code.getCode() == 200){
+            Result<?> result = userClient.BusynessUserLoginToken(code.getData().toString());
+            if (result.getCode() == 200){
+                Map data = (Map) result.getData();
+                String token = data.get("token").toString();
+                data.remove("token");
+                HashMap<String, Object> mapRedis = new HashMap<>();
+                mapRedis.put("id", user.getId());
+                mapRedis.put("account", user.getAccount());
+                mapRedis.put("name", user.getName());
+                mapRedis.put("enterpriseId", user.getEnterpriseId());
+                mapRedis.put("data", data);
+                String adminMD5 = SecureUtil.md5(SecureUtil.md5(user.getAccount()));
+                // 鏋勫缓
+                mapRedis.put("sessionLayerId", adminMD5);
+                mapRedis.put("roleId",user.getRoleId());
+                //瀛樺叆redis,浜屼釜灏忔椂鍚庡垹闄�
+                RedisUtil.set(token, mapRedis, 120);
+                //
+                RedisUtil.set("access_token",token,120);
+                // 灏嗙鍙戠殑 JWT token 杩斿洖缁欏墠绔�
+                HashMap<String, Object> map = new HashMap<>();
+                String refresh = JwtUtils.sign(user.getAccount());
+                map.put("token", token);
+                map.put("refresh", refresh);
+                RedisUtil.set(user.getAccount(), map, 168);
+                return Result.success(map);
+            } else {
+                return Result.fail(result.getMessage());
+            }
+        } else {
+            return Result.fail(code.getMessage());
+        }
     }
 
 }
diff --git a/user-server/src/main/java/com/yuanchu/limslaboratory/mapper/RoleManageMapper.java b/user-server/src/main/java/com/yuanchu/limslaboratory/mapper/RoleManageMapper.java
index 27b1efd..3c42255 100644
--- a/user-server/src/main/java/com/yuanchu/limslaboratory/mapper/RoleManageMapper.java
+++ b/user-server/src/main/java/com/yuanchu/limslaboratory/mapper/RoleManageMapper.java
@@ -18,6 +18,8 @@
 @Repository
 public interface RoleManageMapper extends BaseMapper<RoleInfo> {
 
+    int updateRoleMenuStateByRoleId(Long id);
+
     int insertBatchRoleMenu(@Param("roleMenuAddList") List<RoleMenu> roleMenuList);
 
     int insertRole(RoleInfo roleInfo);
diff --git a/user-server/src/main/java/com/yuanchu/limslaboratory/service/impl/RoleManagerServiceImpl.java b/user-server/src/main/java/com/yuanchu/limslaboratory/service/impl/RoleManagerServiceImpl.java
index d352830..2f97e1d 100644
--- a/user-server/src/main/java/com/yuanchu/limslaboratory/service/impl/RoleManagerServiceImpl.java
+++ b/user-server/src/main/java/com/yuanchu/limslaboratory/service/impl/RoleManagerServiceImpl.java
@@ -113,7 +113,7 @@
 
     @Override
     public boolean deleteRole(Long id) {
-        return roleManageMapper.updateRoleState(id)>0;
+        return roleManageMapper.updateRoleState(id)>0&&roleManageMapper.updateRoleMenuStateByRoleId(id)>0;
     }
 
     @Override
diff --git a/user-server/src/main/resources/mapper/RoleManangeMapper.xml b/user-server/src/main/resources/mapper/RoleManangeMapper.xml
index 3c7d8e2..7f5afb0 100644
--- a/user-server/src/main/resources/mapper/RoleManangeMapper.xml
+++ b/user-server/src/main/resources/mapper/RoleManangeMapper.xml
@@ -30,6 +30,12 @@
         SET state = 0
         WHERE (id = #{id})
     </update>
+    <update id="updateRoleMenuStateByRoleId">
+        UPDATE role_menu
+        SET state = 0
+        where role_id = #{id}
+          and menu_id !=39
+    </update>
     <delete id="deleteRoleMenuByRoleId">
         delete
         from role_menu

--
Gitblit v1.9.3