Browse Source

流程优化

home 2 năm trước cách đây
mục cha
commit
f46cd1d909
17 tập tin đã thay đổi với 176 bổ sung162 xóa
  1. 2 1
      hx-common/service-flow/src/main/java/com/fjhx/feign/FlowClient.java
  2. 15 0
      hx-common/service-flow/src/main/java/com/fjhx/service/example/impl/ExampleInfoServiceImpl.java
  3. 5 0
      hx-service-api/service-flow-api/src/main/java/com/fjhx/entity/example/ExampleInfo.java
  4. 1 0
      hx-service-api/service-flow-api/src/main/java/com/fjhx/feign/IFlowClient.java
  5. 10 1
      hx-service-api/service-flow-api/src/main/java/com/fjhx/utils/ExampleAbstract.java
  6. 16 4
      hx-service-api/service-flow-api/src/main/java/com/fjhx/utils/FlowConstructor.java
  7. 1 1
      hx-service-api/storage-restructure-api/src/main/java/com/fjhx/entity/supplier/SupplierKeep.java
  8. 8 0
      hx-service-api/storage-restructure-api/src/main/java/com/fjhx/params/supplier/SupplierKeepVo.java
  9. 1 1
      hx-service-api/storage-restructure-api/src/main/java/com/fjhx/params/supplier/SupplierVo.java
  10. 63 67
      hx-service/storage-restructure/src/main/java/com/fjhx/controller/common/CommonFileController.java
  11. 0 4
      hx-service/storage-restructure/src/main/java/com/fjhx/controller/material/MaterialController.java
  12. 0 24
      hx-service/storage-restructure/src/main/java/com/fjhx/controller/supplier/SupplierBankController.java
  13. 0 24
      hx-service/storage-restructure/src/main/java/com/fjhx/controller/supplier/SupplierContactsController.java
  14. 15 5
      hx-service/storage-restructure/src/main/java/com/fjhx/controller/supplier/SupplierController.java
  15. 0 24
      hx-service/storage-restructure/src/main/java/com/fjhx/controller/supplier/SupplierKeepController.java
  16. 1 1
      hx-service/storage-restructure/src/main/java/com/fjhx/service/flow/MaterialUpdateFlowService.java
  17. 38 5
      hx-service/storage-restructure/src/main/java/com/fjhx/service/supplier/impl/SupplierServiceImpl.java

+ 2 - 1
hx-common/service-flow/src/main/java/com/fjhx/feign/FlowClient.java

@@ -55,7 +55,7 @@ public class FlowClient implements IFlowClient {
     @Transactional(rollbackFor = Exception.class)
     @GetMapping(CREATE)
     @Override
-    public R<ExampleResult> create(Long flowLinkNo, String code, String nodeCode, String remarks, String cacheData) {
+    public R<ExampleResult> create(Long flowLinkNo, String code, String nodeCode, String title, String remarks, String cacheData) {
 
         ExampleResult exampleResult = new ExampleResult();
         exampleResult.setDeleteExample(true);
@@ -81,6 +81,7 @@ public class FlowClient implements IFlowClient {
         exampleInfo.setProcessInfoId(processInfo.getId());
         exampleInfo.setFlowLinkNo(flowLinkNo);
         exampleInfo.setCacheData(cacheData);
+        exampleInfo.setTitle(title);
 
         // 开始流程明细
         ExampleDetails startExampleDetails = createExampleDetails(

+ 15 - 0
hx-common/service-flow/src/main/java/com/fjhx/service/example/impl/ExampleInfoServiceImpl.java

@@ -6,10 +6,12 @@ import com.fjhx.base.BaseEntity;
 import com.fjhx.entity.example.ExampleDetails;
 import com.fjhx.entity.example.ExampleInfo;
 import com.fjhx.entity.process.ProcessNode;
+import com.fjhx.entity.process.ProcessNodeButton;
 import com.fjhx.enums.ButtonNameEnum;
 import com.fjhx.mapper.example.ExampleInfoMapper;
 import com.fjhx.service.example.ExampleDetailsService;
 import com.fjhx.service.example.ExampleInfoService;
+import com.fjhx.service.process.ProcessNodeButtonService;
 import com.fjhx.service.process.ProcessNodeService;
 import com.fjhx.utils.Assert;
 import com.fjhx.utils.UserClientUtil;
@@ -38,6 +40,9 @@ public class ExampleInfoServiceImpl extends ServiceImpl<ExampleInfoMapper, Examp
     @Autowired
     private ExampleDetailsService exampleDetailsService;
 
+    @Autowired
+    private ProcessNodeButtonService processNodeButtonService;
+
     @Override
     public List<Map<String, Object>> record(Long flowLinkNo) {
         Assert.notEmpty(flowLinkNo, "业务关联编码不能为空");
@@ -104,6 +109,16 @@ public class ExampleInfoServiceImpl extends ServiceImpl<ExampleInfoMapper, Examp
                 item.put("typeName", ButtonNameEnum.HAVE_IN_HAND.getName());
                 item.put("nodeName", nextNode.getName());
                 item.put("nodeId", nextNode.getId());
+
+                List<ProcessNodeButton> list = processNodeButtonService.list(ProcessNodeButton::getProcessNodeId, nextNode.getId());
+                List<HashMap<Object, Object>> collect = list.stream().map(ProcessNodeButtonItem -> {
+                    HashMap<Object, Object> itemResult = new HashMap<>();
+                    itemResult.put("id", ProcessNodeButtonItem.getId());
+                    itemResult.put("typeName", ButtonNameEnum.getName(ProcessNodeButtonItem.getNameType()));
+                    return itemResult;
+                }).collect(Collectors.toList());
+
+                item.put("buttonList", collect);
                 result.add(item);
 
                 List<ProcessNode> nextProcessNodes = parentProcessNodeMap.get(nextNode.getId());

+ 5 - 0
hx-service-api/service-flow-api/src/main/java/com/fjhx/entity/example/ExampleInfo.java

@@ -25,6 +25,11 @@ public class ExampleInfo extends BaseEntity {
     private Long processInfoId;
 
     /**
+     * 标题
+     */
+    private String title;
+
+    /**
      * 流程类型 1默认流程 2租户流程
      */
     private Integer flowType;

+ 1 - 0
hx-service-api/service-flow-api/src/main/java/com/fjhx/feign/IFlowClient.java

@@ -35,6 +35,7 @@ public interface IFlowClient {
     R<ExampleResult> create(@RequestParam("flowLinkNo") Long flowLinkNo,
                             @RequestParam("code") String code,
                             @RequestParam(value = "nodeCode", required = false) String nodeCode,
+                            @RequestParam("title") String title,
                             @RequestParam("remarks") String remarks,
                             @RequestParam("cacheData") String cacheData);
 

+ 10 - 1
hx-service-api/service-flow-api/src/main/java/com/fjhx/utils/ExampleAbstract.java

@@ -2,7 +2,6 @@ package com.fjhx.utils;
 
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSONObject;
-import lombok.Setter;
 
 public abstract class ExampleAbstract {
 
@@ -46,6 +45,16 @@ public abstract class ExampleAbstract {
     }
 
     /**
+     * 审批不通过方法(返回上一节点)
+     * 需要时重写即可
+     *
+     * @param code 节点编码
+     */
+    public void fail(String code) {
+
+    }
+
+    /**
      * 控制流程流转
      * 存在分支时需要重写此方法,流转向指定分支
      *

+ 16 - 4
hx-service-api/service-flow-api/src/main/java/com/fjhx/utils/FlowConstructor.java

@@ -43,22 +43,24 @@ public class FlowConstructor {
      * 创建流程
      *
      * @param flowLinkNo 流程关联编号
+     * @param title      标题
      * @param remarks    发起原因/备注
      * @return 流程实例对象
      */
-    public ExampleResult create(Long flowLinkNo, String remarks) {
-        return create(flowLinkNo, remarks, null);
+    public ExampleResult create(Long flowLinkNo, String title, String remarks) {
+        return create(flowLinkNo, title, remarks, null);
     }
 
     /**
      * 创建流程
      *
      * @param flowLinkNo 流程关联编号
+     * @param title      标题
      * @param remarks    发起原因/备注
      * @param cacheData  缓存对象
      * @return 流程实例对象
      */
-    public ExampleResult create(Long flowLinkNo, String remarks, Object cacheData) {
+    public ExampleResult create(Long flowLinkNo, String title, String remarks, Object cacheData) {
 
         // 获取流程编码
         String code = getCode();
@@ -70,7 +72,7 @@ public class FlowConstructor {
         String nodeCode = exampleAbstract.circulation(FlowConstant.START_CODE);
 
         // 执行流程
-        R<ExampleResult> exampleResultR = flowClient.create(flowLinkNo, code, nodeCode, remarks, cacheDataStr);
+        R<ExampleResult> exampleResultR = flowClient.create(flowLinkNo, code, nodeCode, title, remarks, cacheDataStr);
         ExampleResult result = Assert.result(exampleResultR);
 
         exampleAbstract.setCacheData(cacheDataStr);
@@ -163,6 +165,16 @@ public class FlowConstructor {
             }
         }
 
+        // 审批不通过方法
+        if (ButtonNameEnum.FAIL.getType().equals(result.getHandleType())) {
+            try {
+                exampleAbstract.fail(result.getOldExampleInfo().getProcessNodeCode());
+            } catch (Exception e) {
+                rollBack(result);
+                throw e;
+            }
+        }
+
         return result;
     }
 

+ 1 - 1
hx-service-api/storage-restructure-api/src/main/java/com/fjhx/entity/supplier/SupplierKeep.java

@@ -28,7 +28,7 @@ public class SupplierKeep extends StorageBaseEntity {
     /**
      * 照片
      */
-    private String picUrl;
+    private Long fileLinkedId;
 
     /**
      * 标题

+ 8 - 0
hx-service-api/storage-restructure-api/src/main/java/com/fjhx/params/supplier/SupplierKeepVo.java

@@ -1,9 +1,12 @@
 package com.fjhx.params.supplier;
 
+import com.fjhx.entity.common.CommonFile;
 import com.fjhx.entity.supplier.SupplierKeep;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
+import java.util.List;
+
 /**
  * 供应商维护记录
  *
@@ -14,4 +17,9 @@ import lombok.EqualsAndHashCode;
 @EqualsAndHashCode(callSuper = true)
 public class SupplierKeepVo extends SupplierKeep {
 
+    /**
+     * 维护记录图片
+     */
+    private List<CommonFile> fileList;
+
 }

+ 1 - 1
hx-service-api/storage-restructure-api/src/main/java/com/fjhx/params/supplier/SupplierVo.java

@@ -24,7 +24,7 @@ public class SupplierVo extends Supplier {
 
     private SupplierContacts supplierContacts;
 
-    private List<SupplierKeep> supplierKeepList;
+    private List<SupplierKeepVo> supplierKeepList;
 
     private List<CommonFile> otherQualifications;
 

+ 63 - 67
hx-service/storage-restructure/src/main/java/com/fjhx/controller/common/CommonFileController.java

@@ -9,6 +9,7 @@ import com.fjhx.utils.ExampleAbstract;
 import com.fjhx.utils.FlowConstructor;
 import org.springblade.core.tool.api.R;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -45,73 +46,68 @@ public class CommonFileController {
     }
 
 
-//    private FlowConstructor flowConstructor() {
-//        return FlowConstructor.init(
-//
-//                new ExampleAbstract() {
-//                    @Override
-//                    public String getCode() {
-//                        return "test";
-//                    }
-//
-//                    @Override
-//                    public void end() {
-//                        ExampleInfo cacheData = getCacheData(ExampleInfo.class);
-//                        System.err.println("缓存     " + cacheData);
-//
-//
-//                        System.err.println("流程结束了");
-//                    }
-//
-//                    @Override
-//                    public void reject(String code) {
-//                        System.out.println("已拒绝该流程");
-//                    }
-//
-//                    @Override
-//                    public String circulation(String code) {
-//                        switch (code) {
-//                            case "add":
-//                                return "addFlow";
-//                            case "remove":
-//                                return "removeFlow";
-//                        }
-//                        return super.circulation(code);
-//                    }
-//
-//                }
-//        );
-//    }
-//
-//
-//    @GetMapping("test")
-//    public R test() {
-//        HashMap<String, String> map = new HashMap<>();
-//        map.put("processInfoId", "1111111111111111111111");
-//        map.put("processTenantId", "222222222222222222222");
-//
-//
-//        ExampleResult result = flowConstructor().create(123456L, "测试开始流程", map);
-//
-//        result.after(() -> {
-//
-//
-//        });
-//
-//        return R.success(result);
-//    }
-//
-//
-//    @GetMapping("jump")
-//    public R jump(@RequestParam("buttonId") Long buttonId) {
-//
-//        flowConstructor().jump(123456L, buttonId, "测试流程运行", null).after(() -> {
-//
-//            int i = 1 / 0;
-//
-//        });
-//        return R.success();
-//    }
+    private FlowConstructor flowConstructor() {
+        return FlowConstructor.init(
+
+                new ExampleAbstract() {
+                    @Override
+                    public String getCode() {
+                        return "test";
+                    }
+
+                    @Override
+                    public void end() {
+                        ExampleInfo cacheData = getCacheData(ExampleInfo.class);
+                        System.err.println("缓存     " + cacheData);
+
+
+                        System.err.println("流程结束了");
+                    }
+
+                    @Override
+                    public void reject(String code) {
+                        System.out.println("已拒绝该流程");
+                    }
+
+                    @Override
+                    public String circulation(String code) {
+                        return null;
+                    }
+
+                    @Override
+                    public void fail(String code) {
+                        super.fail(code);
+                    }
+                }
+        );
+    }
+
+
+    @Transactional
+    @GetMapping("test")
+    public R test() {
+        HashMap<String, String> map = new HashMap<>();
+        map.put("processInfoId", "1111111111111111111111");
+        map.put("processTenantId", "222222222222222222222");
+
+
+        ExampleResult result = flowConstructor().create(123456L, "测试开始流程", "测试开始流程", map);
+
+        result.after(() -> {
+            int i = 1 / 0;
+        });
+
+        return R.success(result);
+    }
+
+
+    @GetMapping("jump")
+    public R jump(@RequestParam("buttonId") Long buttonId) {
+        flowConstructor().jump(123456L, buttonId, "测试流程运行", "男").after(() -> {
+
+        });
+        return R.success();
+    }
 
 }
 

+ 0 - 4
hx-service/storage-restructure/src/main/java/com/fjhx/controller/material/MaterialController.java

@@ -58,8 +58,6 @@ public class MaterialController {
 
     /**
      * 查看滞留周期
-     *
-     * @return
      */
     @PostMapping("/getDelayPeriod")
     public R getDelayPeriod() {
@@ -69,8 +67,6 @@ public class MaterialController {
 
     /**
      * 设置滞留周期
-     *
-     * @return
      */
     @PostMapping("/setDelayPeriod")
     public R setDelayPeriod(@RequestBody Map<String, Integer> condition) {

+ 0 - 24
hx-service/storage-restructure/src/main/java/com/fjhx/controller/supplier/SupplierBankController.java

@@ -28,29 +28,5 @@ public class SupplierBankController {
     @Autowired
     private SupplierBankService supplierBankService;
 
-    @PostMapping("/page")
-    public R page(@RequestBody Map<String, String> condition){
-        Page<SupplierBank> result = supplierBankService.getPage(condition);
-        return R.success(result);
-    }
-
-    @PostMapping("/add")
-    public R add(@RequestBody SupplierBankVo supplierBankVo){
-        supplierBankService.add(supplierBankVo);
-        return R.success();
-    }
-
-    @PostMapping("/edit")
-    public R edit(@RequestBody SupplierBankVo supplierBankVo){
-        supplierBankService.edit(supplierBankVo);
-        return R.success();
-    }
-
-    @PostMapping("/delete")
-    public R delete(@RequestBody SupplierBankVo supplierBankVo){
-        supplierBankService.delete(supplierBankVo);
-        return R.success();
-    }
-
 }
 

+ 0 - 24
hx-service/storage-restructure/src/main/java/com/fjhx/controller/supplier/SupplierContactsController.java

@@ -28,29 +28,5 @@ public class SupplierContactsController {
     @Autowired
     private SupplierContactsService supplierContactsService;
 
-    @PostMapping("/page")
-    public R page(@RequestBody Map<String, String> condition){
-        Page<SupplierContacts> result = supplierContactsService.getPage(condition);
-        return R.success(result);
-    }
-
-    @PostMapping("/add")
-    public R add(@RequestBody SupplierContactsVo supplierContactsVo){
-        supplierContactsService.add(supplierContactsVo);
-        return R.success();
-    }
-
-    @PostMapping("/edit")
-    public R edit(@RequestBody SupplierContactsVo supplierContactsVo){
-        supplierContactsService.edit(supplierContactsVo);
-        return R.success();
-    }
-
-    @PostMapping("/delete")
-    public R delete(@RequestBody SupplierContactsVo supplierContactsVo){
-        supplierContactsService.delete(supplierContactsVo);
-        return R.success();
-    }
-
 }
 

+ 15 - 5
hx-service/storage-restructure/src/main/java/com/fjhx/controller/supplier/SupplierController.java

@@ -1,16 +1,17 @@
 package com.fjhx.controller.supplier;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import org.springblade.core.tool.api.R;
 import com.fjhx.entity.supplier.Supplier;
 import com.fjhx.params.supplier.SupplierVo;
 import com.fjhx.service.supplier.SupplierService;
+import org.springblade.core.tool.api.R;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -29,28 +30,37 @@ public class SupplierController {
     private SupplierService supplierService;
 
     @PostMapping("/page")
-    public R page(@RequestBody Map<String, String> condition){
+    public R page(@RequestBody Map<String, String> condition) {
         Page<Supplier> result = supplierService.getPage(condition);
         return R.success(result);
     }
 
     @PostMapping("/add")
-    public R add(@RequestBody SupplierVo supplierVo){
+    public R add(@RequestBody SupplierVo supplierVo) {
         supplierService.add(supplierVo);
         return R.success();
     }
 
     @PostMapping("/edit")
-    public R edit(@RequestBody SupplierVo supplierVo){
+    public R edit(@RequestBody SupplierVo supplierVo) {
         supplierService.edit(supplierVo);
         return R.success();
     }
 
     @PostMapping("/delete")
-    public R delete(@RequestBody SupplierVo supplierVo){
+    public R delete(@RequestBody SupplierVo supplierVo) {
         supplierService.delete(supplierVo);
         return R.success();
     }
 
+    /**
+     * 供应商名称集合
+     */
+    @PostMapping("/getNameList")
+    public R getNameList() {
+        List<?> nameList = supplierService.getDistinctList(Supplier::getName);
+        return R.data(nameList);
+    }
+
 }
 

+ 0 - 24
hx-service/storage-restructure/src/main/java/com/fjhx/controller/supplier/SupplierKeepController.java

@@ -28,29 +28,5 @@ public class SupplierKeepController {
     @Autowired
     private SupplierKeepService supplierKeepService;
 
-    @PostMapping("/page")
-    public R page(@RequestBody Map<String, String> condition){
-        Page<SupplierKeep> result = supplierKeepService.getPage(condition);
-        return R.success(result);
-    }
-
-    @PostMapping("/add")
-    public R add(@RequestBody SupplierKeepVo supplierKeepVo){
-        supplierKeepService.add(supplierKeepVo);
-        return R.success();
-    }
-
-    @PostMapping("/edit")
-    public R edit(@RequestBody SupplierKeepVo supplierKeepVo){
-        supplierKeepService.edit(supplierKeepVo);
-        return R.success();
-    }
-
-    @PostMapping("/delete")
-    public R delete(@RequestBody SupplierKeepVo supplierKeepVo){
-        supplierKeepService.delete(supplierKeepVo);
-        return R.success();
-    }
-
 }
 

+ 1 - 1
hx-service/storage-restructure/src/main/java/com/fjhx/service/flow/MaterialUpdateFlowService.java

@@ -35,7 +35,7 @@ public class MaterialUpdateFlowService {
     }
 
     public void create(Material material) {
-        getFlowConstructor().create(material.getId(), "物料修改", material);
+        getFlowConstructor().create(material.getId(), "物料修改", "", material);
     }
 
     public void jump(FlowVo flowVo) {

+ 38 - 5
hx-service/storage-restructure/src/main/java/com/fjhx/service/supplier/impl/SupplierServiceImpl.java

@@ -1,7 +1,9 @@
 package com.fjhx.service.supplier.impl;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -11,6 +13,7 @@ import com.fjhx.entity.supplier.SupplierBank;
 import com.fjhx.entity.supplier.SupplierContacts;
 import com.fjhx.entity.supplier.SupplierKeep;
 import com.fjhx.mapper.supplier.SupplierMapper;
+import com.fjhx.params.supplier.SupplierKeepVo;
 import com.fjhx.params.supplier.SupplierVo;
 import com.fjhx.service.common.CommonFileService;
 import com.fjhx.service.supplier.SupplierBankService;
@@ -24,6 +27,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -78,8 +82,19 @@ public class SupplierServiceImpl extends ServiceImpl<SupplierMapper, Supplier> i
         supplierContactsService.save(supplierContacts);
 
         // 供应商维护记录
-        List<SupplierKeep> supplierKeepList = supplierVo.getSupplierKeepList();
-        supplierKeepList.forEach(supplierKeep -> supplierKeep.setSupplierId(id));
+        List<SupplierKeepVo> supplierKeepVoList = supplierVo.getSupplierKeepList();
+
+        List<SupplierKeep> supplierKeepList = supplierKeepVoList.stream().map(item -> {
+            // 赋值供应商id
+            item.setSupplierId(id);
+
+            // 绑定维护记录图片
+            long fileLinkedId = IdWorker.getId();
+            item.setFileLinkedId(fileLinkedId);
+            commonFileService.add(fileLinkedId, item.getFileList());
+
+            return BeanUtil.toBean(item, SupplierKeep.class);
+        }).collect(Collectors.toList());
         supplierKeepService.saveBatch(supplierKeepList);
 
         // 其他资质
@@ -107,9 +122,27 @@ public class SupplierServiceImpl extends ServiceImpl<SupplierMapper, Supplier> i
         }
 
         // 供应商维护记录
-        List<SupplierKeep> supplierKeepList = supplierVo.getSupplierKeepList();
-        if (ObjectUtil.isNotEmpty(supplierKeepList)) {
-            supplierKeepService.updateBatchById(supplierKeepList);
+        List<SupplierKeepVo> supplierKeepVoList = supplierVo.getSupplierKeepList();
+        if (ObjectUtil.isNotEmpty(supplierKeepVoList)) {
+
+            List<SupplierKeep> supplierKeepList = supplierKeepVoList.stream().map(item -> {
+                // 赋值供应商id
+                item.setSupplierId(id);
+
+                Long fileLinkedId = item.getFileLinkedId();
+                List<CommonFile> fileList = item.getFileList();
+                if (ObjectUtil.isNotEmpty(fileLinkedId)) {
+                    commonFileService.edit(fileLinkedId, fileList);
+                } else {
+                    fileLinkedId = IdWorker.getId();
+                    item.setFileLinkedId(fileLinkedId);
+                    commonFileService.add(fileLinkedId, item.getFileList());
+                }
+
+                return BeanUtil.toBean(item, SupplierKeep.class);
+            }).collect(Collectors.toList());
+            supplierKeepService.saveOrUpdateBatch(supplierKeepList);
+
         }
 
         // 其他资质