Springboot3 + MyBatis-Plus + MySql + Vue + ProTable + TS 实现后台管理商品分类(最新教程附源码)

news2024/11/19 4:44:21

Springboot3 + MyBatis-Plus + MySql + Uniapp 商品加入购物车功能实现(针对上一篇sku)

  • 1、效果展示
  • 2、数据库设计
  • 3、后端源码
    • 3.1 application.yml 方便 AliOssUtil.java 读取
    • 3.2 model 层
    • 3.2.1 BaseEntity
    • 3.2.1 GoodsType
    • 3.2.3 GoodsTypeSonVo
    • 3.3 Controller 层
      • 3.3.1 FileUploadController.java 后端上传图片到阿里云OSS
      • 3.3.2 AliOssUtil.java 后端上传图片到阿里云OSS的工具类
      • 3.3.3 GoodsTypeController.java 商品分类接口
    • 3.4 GoodsTypeService 层
    • 3.5 GoodsTypeServiceImpl 层
  • 4、前端代码
    • 4.1 type.Vue
    • 4.2 type.Vue
    • 4.3 addOrEditType.Vue
    • 4.4 supportTypeDialog.Vue

1、效果展示


QQ2024930-15058

在这里插入图片描述

2、数据库设计


/*
 Navicat Premium Data Transfer

 Source Server         : Test1
 Source Server Type    : MySQL
 Source Server Version : 80200
 Source Host           : localhost:3306
 Source Schema         : yunshangshequ

 Target Server Type    : MySQL
 Target Server Version : 80200
 File Encoding         : 65001

 Date: 30/09/2024 15:08:28
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for goods_type
-- ----------------------------
DROP TABLE IF EXISTS `goods_type`;
CREATE TABLE `goods_type`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '分类名称',
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '分类描述',
  `img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '分类图标',
  `father_id` int NULL DEFAULT NULL COMMENT '如果没有 father_id 则是一级分类',
  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否启用 1 启用 0禁用',
  `type_sort` int NULL DEFAULT NULL COMMENT '排序',
  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
  `is_deleted` tinyint NULL DEFAULT NULL COMMENT '逻辑删除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of goods_type
-- ----------------------------
INSERT INTO `goods_type` VALUES (1, '水果', '所有水果哈哈哈', 'https://yunshangshequ.cn-chengdu.oss.aliyuncs.com/2024.09.30/b648e907-12e1-406d-89cd-d4948b3ed317.png', NULL, '1', 999, NULL, '2024-09-30 15:01:39', 0);
INSERT INTO `goods_type` VALUES (2, '零食', '所有零食', NULL, NULL, '1', 9999, NULL, '2024-09-30 14:48:53', 0);
INSERT INTO `goods_type` VALUES (3, '西瓜', '非常好吃的西瓜', 'https://yunshangshequ.oss-cn-chengdu.aliyuncs.com/icons/icon_3212wanjasr/xiguarang.png', 1, '1', 999999, NULL, '2024-09-30 14:42:36', 0);
INSERT INTO `goods_type` VALUES (4, '葡萄', '非常好吃的葡萄', 'https://yunshangshequ.oss-cn-chengdu.aliyuncs.com/icons/icon_3212wanjasr/putao.png', 1, '1', 20, NULL, NULL, 0);
INSERT INTO `goods_type` VALUES (5, '芒果', '非常好吃的芒果12', 'https://yunshangshequ.oss-cn-chengdu.aliyuncs.com/icons/icon_3212wanjasr/mangguo.png', 1, '1', 5, NULL, '2024-09-30 15:01:17', 1);
INSERT INTO `goods_type` VALUES (6, '坚果', '非常好吃的坚果', NULL, 2, '1', 100, NULL, NULL, 0);
INSERT INTO `goods_type` VALUES (7, '辣条', '非常好吃的辣条', NULL, 2, '1', 20, NULL, NULL, 0);
INSERT INTO `goods_type` VALUES (10, '橘子', '非常好吃的橘子', 'https://yunshangshequ.oss-cn-chengdu.aliyuncs.com/icons/icon_3212wanjasr/juzi.png', 1, '1', 999, '2024-09-30 13:49:02', '2024-09-30 14:36:23', 0);
INSERT INTO `goods_type` VALUES (11, '香蕉', '非常非常好吃的香蕉', 'https://yunshangshequ.cn-chengdu.oss.aliyuncs.com/2024.09.30/404a678d-aae3-4e5b-844f-ba27643d9209.png', 1, '1', 2222, '2024-09-30 13:57:13', '2024-09-30 14:38:53', 1);
INSERT INTO `goods_type` VALUES (12, '火龙果', '非常好吃的火龙果', 'https://yunshangshequ.cn-chengdu.oss.aliyuncs.com/2024.09.30/3c18869e-f0bb-48a7-8c3e-8fd02318bfd5.png', 1, '1', 99999, '2024-09-30 13:58:54', '2024-09-30 14:25:13', 1);
INSERT INTO `goods_type` VALUES (13, '芒果', '非常好吃的芒果', 'https://yunshangshequ.cn-chengdu.oss.aliyuncs.com/2024.09.30/928d56f0-7062-4eaf-a89b-52ba43199322.png', 1, '1', 9999999, '2024-09-30 15:01:33', NULL, 0);

SET FOREIGN_KEY_CHECKS = 1;

3、后端源码

3.1 application.yml 方便 AliOssUtil.java 读取

server:
  port: 8080
spring:
  servlet:
    multipart:
      max-file-size: 40MB
      max-request-size: 40MB
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:mysql://localhost:3306/yunshangshequ?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2b8
    username: root
    password: 123456
    hikari:
      connection-test-query: SELECT 1 # 自动检测连接
      connection-timeout: 60000 #数据库连接超时时间,默认30秒
      idle-timeout: 500000 #空闲连接存活最大时间,默认600000(10分钟)
      max-lifetime: 540000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
      maximum-pool-size: 12 #连接池最大连接数,默认是10
      minimum-idle: 10 #最小空闲连接数量
      pool-name: SPHHikariPool # 连接池名称
  jackson:
    time-zone: GMT+8

  data:
    redis:
      host: localhost
      port: 6379
      database: 0
#用于打印框架生成的sql语句,便于调试
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      logic-delete-field: isDeleted # 全局逻辑删除的实体字段名
      logic-delete-value: 1   # 逻辑已删除的值 默认为 1
      logic-not-delete-value: 0 # 逻辑未删除的值  默认为 0

minio:
  endpoint: http://localhost:9000
  access-key: minioadmin
  secret-key: minioadmin
  bucket-name: yunshangshequ
springdoc:
  default-flat-param-object: true

alioss: # 阿里云配置
  endpoint: "https://cn-chengdu.oss.aliyuncs.com"    # Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
  bucketName: ""  # 填写Bucket名称,例如examplebucket。
  access_key: ""  # 点击头像->Accesskey管理查看 秘钥
  access_key_secret: "" # 密码

3.2 model 层

3.2.1 BaseEntity


package com.zhong.model.entity;


import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

@Data
public class BaseEntity implements Serializable {

    @Schema(description = "主键")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @Schema(description = "创建时间")
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    @JsonIgnore
    private Date createTime;

    @Schema(description = "更新时间")
    @TableField(value = "update_time", fill = FieldFill.UPDATE)
    @JsonIgnore
    private Date updateTime;

    @Schema(description = "逻辑删除")
    @TableField("is_deleted")
    @JsonIgnore
    private Byte isDeleted;

}

3.2.1 GoodsType


package com.zhong.model.entity.goods;

import com.zhong.model.entity.BaseEntity;
import lombok.Data;

/**
 * 商品分类
 * @TableName shop_type
 */
@Data
public class GoodsType extends BaseEntity {

    /**
     /**
     * 分类名称
     */
    private String name;

    /**
     * 分类描述
     */
    private String description;
    /**
     * 排序值
     */
    private Long typeSort;
    /**
     * 分类图标
     */
    private String img;

    /**
     * 如果没有 father_id 则是一级分类
     */
    private Integer fatherId;

    /**
     * 是否启用 1 启用 0禁用
     */
    private Integer status;

    private static final long serialVersionUID = 1L;
}

3.2.3 GoodsTypeSonVo


package com.zhong.vo.small;

import com.zhong.model.entity.goods.GoodsType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.util.List;

/**
 * @ClassName : GoodsTypeVo
 * @Description :
 * @Author : zhx
 * @Date: 2024-09-29 15:08
 */
@Data
public class GoodsTypeSonVo {
   List<GoodsType> fatherType;
   List<GoodsType> sonType;
}

3.3 Controller 层

3.3.1 FileUploadController.java 后端上传图片到阿里云OSS


package com.zhong.controller.apartment;

import com.zhong.result.Result;
import com.zhong.utils.AliOssUtil;
import io.minio.errors.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;


@Tag(name = "文件管理")
@RequestMapping("/admin/file")
@RestController
public class FileUploadController {

    @Autowired
    private AliOssUtil ossUtil;

    @Operation(summary = "上传文件")
    @PostMapping("/upload")
    public Result<String> upload(@RequestParam MultipartFile file) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        // 获取文件原名
        String originalFilename = file.getOriginalFilename();
        // 防止重复上传文件名重复
        String fileName = null;
        if (originalFilename != null) {
            fileName = UUID.randomUUID() + originalFilename.substring(originalFilename.indexOf("."));
        }
        // 把文件储存到本地磁盘
//        file.transferTo(new File("E:\\SpringBootBase\\ProjectOne\\big-event\\src\\main\\resources\\flies\\" + fileName));
        String url = ossUtil.uploadFile(fileName, file.getInputStream());
        System.out.println();
        return Result.ok(url);
    }
}

3.3.2 AliOssUtil.java 后端上传图片到阿里云OSS的工具类


package com.zhong.utils;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.zhong.result.Result;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @ClassName : AliOssUtil
 * @Description : 阿里云上传服务
 * @Author : zhx
 * @Date: 2024-03-1 20:29
 */
@Component
@Service
public class AliOssUtil {
    @Value("${alioss.endpoint}")
    private String ENDPOINT;

    @Value("${alioss.bucketName}")
    private String BUCKETNAME;

    @Value("${alioss.access_key}")
    private String ACCESS_KEY;

    @Value("${alioss.access_key_secret}")
    private String ACCESS_KEY_SECRET;

    public String uploadFile(String objectName, InputStream inputStream) {
        String url = "";
        // 创建OSSClient实例。
        System.out.println(ACCESS_KEY);
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY, ACCESS_KEY_SECRET);
        try {
            // 创建PutObjectRequest对象。
            // 生成日期文件夹路径,例如:2022/04/18
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd");
            String dateStr = dateFormat.format(new Date());
            PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKETNAME, dateStr + "/" + objectName, inputStream);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            // ObjectMetadata metadata = new ObjectMetadata();
            // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            // putObjectRequest.setMetadata(metadata);

            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);

            url = "https://" + BUCKETNAME + "." + ENDPOINT.substring(ENDPOINT.lastIndexOf("/") + 1) + "/" + dateStr + "/" + objectName;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return url;
    }

    public  Result deleteFile(String objectName) {
        System.out.println(objectName);
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY, ACCESS_KEY_SECRET);
        try {
            // 删除文件。
            System.out.println(objectName);
            System.out.println(objectName.replace(",", "/"));
            ossClient.deleteObject(BUCKETNAME, objectName.replace(",", "/"));
            return Result.ok("删除成功!");
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return Result.fail(555,"上传失败!");
    }
}

3.3.3 GoodsTypeController.java 商品分类接口


package com.zhong.controller.small;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zhong.model.entity.enums.BaseStatus;
import com.zhong.model.entity.goods.GoodsType;
import com.zhong.result.Result;
import com.zhong.service.small.GoodsTypeService;
import com.zhong.vo.small.GoodsTypeSonVo;
import com.zhong.vo.small.GoodsTypeVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @ClassName : ShopSpecsController
 * @Description :  商品分类
 * @Author : zhx
 * @Date: 2024-09-28 15:07
 */
@Slf4j
@RestController
@Tag(name = "后台商品分类管理")
@RequestMapping("/admin/goods/type")
public class GoodsTypeController {

    @Autowired
    private GoodsTypeService service;

    @Operation(summary = "分页获商品分类信息")
    @GetMapping("page")
    private Result<IPage<GoodsType>> page(@RequestParam long current, @RequestParam long size, GoodsTypeVo goodsTypeVo) {
        Page<GoodsType> goodsTypePage = new Page<>(current, size);
        Page<GoodsType> page = service.pageItem(goodsTypePage, goodsTypeVo);
        return Result.ok(page);
    }

    @Operation(summary = "获所有商品二级分类信息")
    @GetMapping("page/son")
    private Result<GoodsTypeSonVo> pageSon(@RequestParam long id) {
        GoodsTypeSonVo page = service.list(id);
        return Result.ok(page);
    }

    @Operation(summary = "获所有商品分类信息")
    @GetMapping("list")
    private Result<List<GoodsType>> page() {
        List<GoodsType> page = service.list();
        return Result.ok(page);
    }

    @Operation(summary = "根据ID修改商品分类")
    @PostMapping("saveOrUpdate")
    public Result saveOrUpdateType(@RequestBody GoodsType goodsType) {
        goodsType.setIsDeleted((byte) 0);
        service.saveOrUpdate(goodsType);
        return Result.ok();
    }

    @DeleteMapping("deleteById")
    @Operation(summary = "根据id删除商品分类")
    public Result removeById(@RequestParam Long id) {
        service.removeById(id);
        return Result.ok();
    }

}

3.4 GoodsTypeService 层


package com.zhong.service.small;


import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zhong.model.entity.goods.GoodsType;
import com.zhong.vo.small.GoodsTypeSonVo;
import com.zhong.vo.small.GoodsTypeVo;

import java.util.List;

/**
* @author zhong
* @description 针对表【shop_type(商品分类)】的数据库操作Service
* @createDate 2024-09-15 18:18:13
*/
public interface GoodsTypeService extends IService<GoodsType> {

    Page<GoodsType> pageItem(Page<GoodsType> goodsTypePage, GoodsTypeVo goodsTypeVo);

    GoodsTypeSonVo list(long id);

}

3.5 GoodsTypeServiceImpl 层


package com.zhong.service.small.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.zhong.mapper.small.GoodsTypeMapper;
import com.zhong.model.entity.goods.GoodsSku;
import com.zhong.model.entity.goods.GoodsType;
import com.zhong.service.small.GoodsTypeService;
import com.zhong.vo.small.GoodsTypeSonVo;
import com.zhong.vo.small.GoodsTypeVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author zhong
 * @description 针对表【shop_type(商品分类)】的数据库操作Service实现
 * @createDate 2024-09-15 18:18:13
 */
@Service
public class GoodsTypeServiceImpl extends ServiceImpl<GoodsTypeMapper, GoodsType>
        implements GoodsTypeService {

    @Autowired
    private GoodsTypeMapper mapper;

    @Override
    public Page<GoodsType> pageItem(Page<GoodsType> goodsTypePage, GoodsTypeVo goodsTypeVo) {
        LambdaQueryWrapper<GoodsType> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.isNull(GoodsType::getFatherId)
                .eq(GoodsType::getIsDeleted, 0);
        if (goodsTypeVo.getName() != null) {
            queryWrapper.like(GoodsType::getName, goodsTypeVo.getName());
        }
        if (goodsTypeVo.getId() != null) {
            queryWrapper.like(GoodsType::getId, goodsTypeVo.getId());
        }
        queryWrapper.orderByDesc(GoodsType::getTypeSort);
        return mapper.selectPage(goodsTypePage, queryWrapper);
    }

    @Override
    public GoodsTypeSonVo list(long id) {
        GoodsTypeSonVo goodsTypeSonVo = new GoodsTypeSonVo();

        // 获取父分类
        LambdaQueryWrapper<GoodsType> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(GoodsType::getIsDeleted, 0)
                .eq(GoodsType::getId, id);
        List<GoodsType> goodsTypes = mapper.selectList(queryWrapper);
        goodsTypeSonVo.setFatherType(goodsTypes);

        // 获取子分类
        LambdaQueryWrapper<GoodsType> sonQueryWrapper = new LambdaQueryWrapper<>();
        sonQueryWrapper.eq(GoodsType::getIsDeleted, 0)
                .eq(GoodsType::getFatherId, id)
                .orderByDesc(GoodsType::getTypeSort);
        List<GoodsType> sonGoodsTypes = mapper.selectList(sonQueryWrapper);
        goodsTypeSonVo.setSonType(sonGoodsTypes);

        return goodsTypeSonVo;
    }
}

4、前端代码

4.1 type.Vue


<template>
  <el-upload
    v-bind="$attrs"
    :action="UPLOAD_IMG_URL"
    :on-preview="handlePictureCardPreview"
    :headers="{ 'access-token': useUserStore().token }"
  >
    <el-icon>
      <Plus />
    </el-icon>
  </el-upload>

  <el-dialog v-model="dialogVisible">
    <el-image :src="dialogImageUrl" fit="fill" />
  </el-dialog>
</template>
<script setup lang="ts">
import { UPLOAD_IMG_URL } from '@/api/upload'
import { ref } from 'vue'
import { UploadFile } from 'element-plus/es/components/upload/src/upload'
import { useUserStore } from '@/store/modules/user'

const dialogImageUrl = ref('')
const dialogVisible = ref(false)
function handlePictureCardPreview(uploadFile: UploadFile) {
  dialogImageUrl.value = uploadFile.url!
  dialogVisible.value = true
}
</script>
<style scoped lang="scss"></style>

4.2 type.Vue


<template>
  <div>
    <ProTable ref="proTable" :dataCallback="dataCallback" :columns="columns" :requestApi="getTypeListPageApi"
      :initParam="initParam">
      <template #tableHeader>
        <el-button type="primary" icon="Plus" @click="addHandle">
          添加
        </el-button>
      </template>
      <!-- 表格操作 -->
      <template #operation="scope">
        <el-button type="primary" link icon="Edit" @click="editHandle(scope.row)">
          编辑
        </el-button>
        <el-button type="primary" link icon="Delete" @click="handleDelete(scope.row)">
          删除
        </el-button>
      </template>
    </ProTable>
    <PostDialog ref="DialogRef" />
  </div>
</template>

<script setup lang="tsx">
import { reactive, ref } from 'vue'
import { ColumnProps } from '@/components/ProTable/src/types'
import { useHandleData } from '@/hooks/useHandleData'
import { useRouter } from 'vue-router'
const router = useRouter();
import {
  getTypeListPageApi,
  // addGoodsTypeApi,
  // // updateGoodsTypeStatusApi,
  // updateGoodsTypeApi
} from '@/api/goodsType'

import { PostInterfacesRes } from '@/api/goodsType/types'

// *获取 ProTable 元素,调用其获取刷新数据方法
const proTable = ref()

// *查询参数
const initParam = reactive({})

// 处理返回的数据格式
const dataCallback = (data: any) => {
  return {
    list: data?.records,
    total: data?.total,
  }
}

// 新增商品
// 新增
const addHandle = () => {
  router.push({
    path: '/small/type/addOrEditGoods',
  })
}
// 查看
const editHandle = (row: PostInterfacesRes) => {
  console.log(row)
  router.push({
    path: '/small/type/addOrEditGoods',
    query: {
      id: row.id,
    },
  })
}
// *根据id删除用户
const handleDelete = async (row: PostInterfacesRes) => {
  // await useHandleData(deleteSysPostById, row.id, `删除${row.id}`)
  proTable.value?.getTableList()
}

// *表格配置项
const columns: ColumnProps[] = [
  { type: 'index', label: '序号', width: 100 },
  {
    prop: 'id',
    label: '分类ID',
    search: { el: 'input', props: { placeholder: '请输入分类编码' } },
  },
  {
    prop: 'name',
    label: '分类名称',
    search: { el: 'input', props: { placeholder: '请输入分类名称' } },
  },
  {
    prop: 'description',
    label: '分类描述',
  },
  {
    prop: 'typeSort',
    label: '分类排序',
  },
  {
    prop: 'status',
    label: '状态',
    width: 100,
    enum: [
      { label: '正常', value: 1 },
      { label: '停用', value: 0 },
    ],
    render: ({ row }) => {
      return (
        <el-switch
          active-value={1}
          inactive-value={0}
          v-model={row.status}
          onChange={() => updateGoodsTypeStatusApi(row.id, row.status)}
        ></el-switch>
      )
    },
  },
  { prop: 'operation', label: '操作', fixed: 'right', width: 280 },
]
</script>

4.3 addOrEditType.Vue


<!--
 * @Date: 2024-08-17 14:18:14
 * @LastEditors: zhong
 * @LastEditTime: 2024-09-30 14:57:38
 * @FilePath: \admin\src\views\small\type\components\addOrEditType.vue
-->
<template>
  <el-card>
    <template #header>
      <div class="card-header">
        <span>{{ formData.id ? '修改' : '新增' }}商品分类</span>
      </div>
    </template>

    <el-card>
      <template #header>
        <div class="card-header">
          <span>{{ formData.id ? '修改' : '新增' }}商品一级分类</span>
        </div>
      </template>
      <div style="display: flex;align-items: center;">
        <div style="flex: 1;">
          <el-form ref="typeFormRef" :model="formData" :rules="rules" label-width="120px" style="max-width: 660px"
            status-icon>
            <el-form-item label="分类名称" prop="name">
              <el-input v-model="formData.name" />
            </el-form-item>
            <el-form-item label="分类简介" prop="description">
              <el-input type="textarea" v-model="formData.description" />
            </el-form-item>
            <el-form-item label="分类排序" prop="typeSort">
              <el-input v-model="formData.typeSort" />
            </el-form-item>

            <el-form-item label="是否启用" prop="status">
              <el-radio-group v-model="formData.status" class="ml-4">
                <el-radio :label="UserStatus.DISABLED">
                  {{
                    getLabelByValue(
                      UserStatusMap,
                      UserStatus.DISABLED,
                    )
                  }}
                </el-radio>
                <el-radio :label="UserStatus.NORMAL">
                  {{
                    getLabelByValue(
                      UserStatusMap,
                      UserStatus.NORMAL,
                    )
                  }}
                </el-radio>
              </el-radio-group>
            </el-form-item>
          </el-form>
        </div>

        <!-- 上传操作 -->
        <div style="width: 200px;display: flex;flex-direction: column;padding-bottom: 60px;">
          <text label="商品主图" />
          <upload-img v-model:file-list="formData.img" :on-success="uploadSuccessHandle" :on-remove="uploadRemoveHandle"
            list-type="picture-card" :limit="1" :class="listLengthTag === 1 ? 'hide_box' : ''"></upload-img>
        </div>
      </div>
    </el-card>

    <el-card class="m-t-20">
      <template #header>
        <div class="card-header">
          <span>{{ formData.id ? '修改' : '新增' }}商品二级分类</span>
        </div>
      </template>
      <el-row class="container">
        <el-col :span="2" class="text-center">二级分类</el-col>
        <el-col :span="22" class="item-container">
          <el-popconfirm v-for="item in goodsTypeList || []" :key="item.id" width="220" confirm-button-text="删除"
            cancel-button-text="修改" cancel-button-type="warning" confirm-button-type="danger"
            @confirm="deleteFacilityHandle(item)" @cancel="editTypeHandle(item)" :title="`修改或直接删除${item.name}`">
            <template #reference>
              <div class="item m-r-10 m-t-10 pointer">
                <el-image style="width: 30px; height: 30px" :src="item.img" />
                <span>{{ item.name }}</span>
              </div>
            </template>
          </el-popconfirm>
          <el-icon class="item m-r-10 m-t-5 pointer" :size="35" color="#567722" @click="addTypeDialog(formData)">
            <CirclePlus />
          </el-icon>
        </el-col>
      </el-row>
      <!--   商品二级分类信息修改弹窗管理-->
      <SupportTypeDialog ref="supportTypeDialog" :updateFacility="getTypeListHandle"></SupportTypeDialog>
    </el-card>
    <!--  -->

    <!-- 底部保存或取消按钮 -->
    <div class="flex-center m-t-20">
      <el-button style="width: 150px" type="info" @click="router.back()">
        取消
      </el-button>
      <el-button style="width: 150px" type="primary" @click="submitHandle">
        {{ formData.id ? '保存' : '新增' }}
      </el-button>
    </div>
  </el-card>
</template>

<script setup lang="ts">
import { onMounted, ref, reactive, computed } from 'vue'
import { FacilityInfoInterface } from '@/api/apartmentManagement/types'
// import { PageResponseInterface } from '@/api/type/types'
import {
  deleteGoodsTypeByIdApi,
  getTypeSonListApi,
  saveOrUpdateGoodsTypeApi,

} from '@/api/goodsType'

import {
  getLabelByValue,
  UserStatus,
  UserStatusMap
} from '@/enums/constEnums'

import { UploadFile } from 'element-plus/es/components/upload/src/upload'
import UploadImg from '@/components/uploadImg/uploadImg.vue'
import SupportTypeDialog from "./supportTypeDialog.vue"
import { ElMessage, FormInstance, UploadFiles } from 'element-plus'

import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()

type typeFromData = {
  id: string
  name: string
  description: string
  typeSort: string
  status: string
  img: any[]
}

// 父类分类信息
const formData = ref<typeFromData>({
  id: "",
  name: "",
  description: "",
  typeSort: "",
  status: "",
  img: []
})

const typeFormRef = ref<FormInstance>()
// 清空表单数据的函数
const clearFormData = () => {
  formData.value.id = "";
  formData.value.name = "";
  formData.value.description = "";
  formData.value.typeSort = "";
  formData.value.status = "";
  formData.value.img = [];
};
// 表单验证规则
const rules = reactive({
  name: [{ required: true, message: '请输入分类名称', trigger: 'blur' }],
  description: [
    { required: true, message: '请输入分类介绍', trigger: 'blur' },
  ],
  typeSort: [{ required: true, message: '请输入分类排序数值越大越靠前', trigger: 'blur' }],
})


// 图片上传成功
function uploadSuccessHandle(
  response: any,
  uploadFile: UploadFile,
  uploadFiles: UploadFiles,

) {
  console.log(uploadFile);

  formData.value.img = uploadFiles?.map((item) => {
    return {
      ...item,
      url: (item?.response as any)?.data.url || item.url,
    }
  })
  console.log(formData.value.img);
}
// TODO 控制上传图片数量隐藏上传按钮
const listLengthTag = computed(() => {
  return formData.value.img.length;
});
// 移除图片
const uploadRemoveHandle = (uploadFiles: UploadFiles, uploadFile: UploadFile) => {
  console.log(uploadFiles);
  console.log(uploadFile);
}

const supportTypeDialog = ref<any>()

// 修改后刷新数据
const getTypeListHandle = () => {
  if (route.query?.id) {
    getGoodsInfoList(route.query.id as string)
  }
}

// 子类分类信息
const goodsTypeList = ref<any>([])

// 获取分类信息
async function getGoodsInfoList(id: string | number) {
  try {
    const { data } = await getTypeSonListApi(id);
    console.log(data);
    formData.value = data.fatherType?.[0];
    formData.value.img = [{ name: formData.value.name, url: formData.value.img }];
    console.log(formData.value);
    goodsTypeList.value = data.sonType;
  } catch (error) {
    console.log(error)
  }
}

// 删除分类
const deleteFacilityHandle = async (item: any) => {
  console.log('删除分类', item)
  try {
    await deleteGoodsTypeByIdApi(item.id)
    await getTypeListHandle()
    ElMessage.success('操作成功')
  } catch (error) {
    console.log(error)
  }
}
// 编辑分类
const editTypeHandle = (item: typeFromData) => {
  console.log('编辑分类', item)
  supportTypeDialog.value?.show(item)
}
// 添加分类
const addTypeDialog = (item: any) => {
  console.log('添加分类', item)
  supportTypeDialog.value?.show({ type: item.id })
}

// 新增或更新商品分类信息
async function addOrUpdateTypeHandle() {
  try {
    console.log(formData.value);
    let res = JSON.parse(JSON.stringify(formData.value));
    // 判断图片改变没有
    if (res.img?.[0]?.response) {
      res.img = res.img[0].response.data;
    } else {
      res.img = res.img[0].url;
    }
    await saveOrUpdateGoodsTypeApi(res);
    clearFormData();
    ElMessage.success('操作成功')
    router.back()
  } catch (error) {
    console.log(error)
  }
}
// 提交
function submitHandle() {
  typeFormRef.value?.validate(async (valid) => {
    if (valid) {
      await addOrUpdateTypeHandle()
    } else {
      ElMessage.error('表单填写有误,请检查')
      return false
    }
  })
}
onMounted(() => {
  if (route.query?.id) {
    getGoodsInfoList(route.query.id as string)
  }
})
</script>

<style scoped lang="scss">
::v-deep(.hide_box .el-upload.el-upload--picture-card) {
  display: none !important;
}



.card-header {
  font-size: 18px;
  font-weight: bold;
}


.text-center {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  text-align: center;
}

.container:not(:first-child) {
  margin-top: 20px;
}

.item-container {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  width: 100%;
  padding: 10px 15px;
  background-color: #efefef;
  border-radius: 20px;

  .item {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    // width: 50px;
  }
}
</style>

4.4 supportTypeDialog.Vue

<!--
 * @Date: 2024-09-29 19:45:25
 * @LastEditors: zhong
 * @LastEditTime: 2024-09-30 15:00:22
 * @FilePath: \admin\src\views\small\type\components\supportTypeDialog.vue
-->
<template>

  <el-dialog v-model="dialogFormVisible" :close-on-press-escape="true" :destroy-on-close="true" :title="title"
    style="max-width: 700px">

    <div style="display: flex;align-items: center;">
      <div style="flex: 1;">

        <el-form ref="formRef" :model="formData" :rules="rules" label-width="120px" style="max-width: 660px"
          status-icon>
          <el-form-item label="分类名称" prop="name">
            <el-input v-model="formData.name" />
          </el-form-item>
          <el-form-item label="分类简介" prop="description">
            <el-input type="textarea" v-model="formData.description" />
          </el-form-item>
          <el-form-item label="分类排序" prop="typeSort">
            <el-input v-model="formData.typeSort" />
          </el-form-item>

          <el-form-item label="是否上架" prop="status">
            <el-radio-group v-model="formData.status" class="ml-4">
              <el-radio :label="UserStatus.DISABLED">
                {{
                  getLabelByValue(
                    UserStatusMap,
                    UserStatus.DISABLED,
                  )
                }}
              </el-radio>
              <el-radio :label="UserStatus.NORMAL">
                {{
                  getLabelByValue(
                    UserStatusMap,
                    UserStatus.NORMAL,
                  )
                }}
              </el-radio>
            </el-radio-group>
          </el-form-item>
        </el-form>

      </div>

      <!-- 上传操作 -->
      <div style="width: 200px;display: flex;flex-direction: column;padding-left: 60px;padding-bottom: 70px;">
        <text label="商品主图" prop="mainImage" />
        <upload-img v-model:file-list="formData.img" :on-success="uploadSuccessHandle" :on-remove="uploadRemoveHandle"
          list-type="picture-card" :limit="1" :class="listLengthTag === 1 ? 'hide_box' : ''"></upload-img>
      </div>
    </div>

    <template #footer>
      <span class="dialog-footer">
        <el-button @click="close">取消</el-button>
        <el-button type="primary" @click="submitHandle">确定</el-button>
      </span>
    </template>


  </el-dialog>

</template>
<script setup lang="ts">
import ids from 'virtual:svg-icons-names'
import { computed, ref } from 'vue'
import { FacilityInfoInterface } from '@/api/apartmentManagement/types'
import { ElMessage, FormInstance, FormRules, UploadFiles } from 'element-plus'
import { saveOrUpdateFacilityInfo } from '@/api/apartmentManagement'
import { UploadFile } from 'element-plus/es/components/upload/src/upload'
import UploadImg from '@/components/uploadImg/uploadImg.vue'
import {
  getLabelByValue,
  UserStatus,
  UserStatusMap
} from '@/enums/constEnums'
import {
  saveOrUpdateGoodsTypeApi,
} from '@/api/goodsType'
const props = defineProps({
  updateFacility: {
    type: Function,
    default: () => ({}),
  },
})
const defaultFormData = {
  id: '',
  description: '',
  name: '',
  status: "",
  fatherId: "",
  typeSort: "",
  img: [],
}

const formRef = ref<FormInstance>()


const dialogFormVisible = ref(false)
const formData = ref<any>({
  ...defaultFormData,
})
// 清空表单数据的函数
const clearFormData = () => {
  formData.value.id = "";
  formData.value.name = "";
  formData.value.description = "";
  formData.value.typeSort = "";
  formData.value.status = "";
  formData.value.img = [];
};
// 表单验证规则
const rules = ref<FormRules>({
  name: [{ required: true, message: '请输入分类名称', trigger: 'blur' }],
  description: [{ required: true, message: '请选择分类描述', trigger: 'change' }],
  typeSort: [{ required: true, message: '请输入分类排序数值越大越靠前', trigger: 'change' }],
})

const title = computed(() => {
  return (
    (formData.value.id ? '修改' : '新增') + formData.value.name + '二级分类详情'
  )
})

// 图片上传成功
// TODO 控制上传图片数量隐藏上传按钮
const listLengthTag = computed(() => {
  return formData.value.img.length;
});
function uploadSuccessHandle(
  response: any,
  uploadFile: UploadFile,
  uploadFiles: UploadFiles,

) {
  console.log(uploadFile);

  formData.value.img = uploadFiles?.map((item) => {
    return {
      ...item,
      url: (item?.response as any)?.data.url || item.url,
    }
  })
  console.log(formData.value.img);
}
// 移除图片
const uploadRemoveHandle = (uploadFiles: UploadFiles, uploadFile: UploadFile) => {
  console.log(uploadFiles);
  console.log(uploadFile);
}
const isEdit = ref(false);
// 展示方法
const show = (data: Partial<any> = defaultFormData) => {
  console.log('show', data)
  if (data.fatherId != null) {
    formData.value = Object.assign({}, defaultFormData, data)
    formData.value.img = [{ name: data.name, url: data.img }];
  } else {
    formData.value.fatherId = data.type;
    formData.value.status = 1;
    isEdit.value = true;
  }

  dialogFormVisible.value = true
}
// 关闭方法
const close = () => {
  dialogFormVisible.value = false
}

// 提交方法
const submitHandle = () => {
  formRef.value?.validate(async (valid) => {
    if (valid) {
      let res = JSON.parse(JSON.stringify(formData.value));
      if (isEdit && res.img?.[0]?.response) {
        res.img = res.img[0].response.data;
      } else {
        res.img = res.img[0].url;
      }
      await saveOrUpdateGoodsTypeApi(res)
      clearFormData();
      await props.updateFacility()
      ElMessage.success('操作成功')
      close()
    } else {
      ElMessage.error('表单填写有误,请检查')
      return false
    }
  })
}
// 对外暴露
defineExpose({
  show,
  close,
})
</script>

<style scoped lang="scss">
::v-deep(.hide_box .el-upload.el-upload--picture-card) {
  display: none !important;
}


.icon-option {
  display: flex;
  align-items: center;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2181587.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文翻译 | LLaMA-Adapter :具有零初始化注意的语言模型的有效微调

摘要 我们提出了一种轻量级的自适应方法&#xff0c;可以有效地将LLaMA微调为指令遵循模型。lama - adapter采用52K自指导演示&#xff0c;在冻结的LLaMA 7B模型上只引入1.2M可学习参数&#xff0c;在8个A100 gpu上进行微调花费不到一个小时。具体来说&#xff0c;我们采用了一…

Vue3+Antv X6流程图基本使用

安装 antv/X6 npm i antv/x6 <template><div class"homes"><div class"Shang">上</div><div class"Zhong"><div id"container"></div></div><div class"Xia">下<…

wordpress Contact form 7发件人邮箱设置

此教程仅适用于演示站有留言的主题&#xff0c;演示站没有留言的主题&#xff0c;就别往下看了&#xff0c;免费浪费时间。 使用了Contact form 7插件的简站WordPress主题&#xff0c;在有人留言时&#xff0c;就会发邮件到网站的系统邮箱(一般与管理员邮箱为同一个)里。上面显…

Java | Leetcode Java题解之第448题找到所有数组中消失的数字

题目&#xff1a; 题解&#xff1a; class Solution {public List<Integer> findDisappearedNumbers(int[] nums) {int n nums.length;for (int num : nums) {int x (num - 1) % n;nums[x] n;}List<Integer> ret new ArrayList<Integer>();for (int i …

传奇外网架设教程带图文解说—Gee引擎

架设前准备工作&#xff1a; ①通过百度网盘下载版本、补丁、客户端和DBC2000。版本解压到D盘&#xff0c;客户端解压到D盘或是E盘&#xff0c;补丁先不解压 ②安装和配置DBC2000&#xff0c;有些版本不一定用的是DBC2000数据库&#xff0c;看引擎默认的数据库是哪个 DBC数据…

【机器学习基础】Transformer学习

Transformer学习 梯度消失FeedForward层激活函数的主要作用是在网络中加入非线性变换 梯度消失 梯度爆炸 FeedForward层 Transformer结构: Transformer结构主要分为两大部分: 一是Encoder层结构:Encoder 的输入由 Input Embedding 和 Positional Embedding 求和输入Multi…

【SpringBoot详细教程】-08-MybatisPlus详细教程以及SpringBoot整合Mybatis-plus【持续更新】

目录 🌲 MyBatis Plus 简介 🌾入门案例 🌾 MP 简介 🌲 MP 的CRUD 🌾 新增 🌾 删除 🌾 修改在进行 🌾 根据ID查询 🌾 查询所有 🌲 分页功能 🌾 设置分页参数 🌾 设置分页拦截器 🌲 优化启动 🌾 取消mbatisPlusBanner 🌾 取消Sprin…

仿真设计|基于51单片机的路口交通灯控制系统仿真

目录 具体实现功能 设计介绍 51单片机简介 资料内容 仿真实现&#xff08;protues8.7&#xff09; 程序&#xff08;Keil5&#xff09; 全部内容 资料获取 具体实现功能 &#xff08;1&#xff09;东西向右转和直行绿灯20S&#xff0c;左转红灯&#xff1b;南北向直行和…

若依从redis中获取用户列表

因为若依放入用户的时候&#xff0c;会在减值中添加随机串&#xff0c;所以用户的key会在redis中变成&#xff1a; login_tokens:6af07052-b76d-44dd-a296-1335af03b2a6 这样的样子。 如果用 Set<Object> items redisService.redisTemplate.keys("login_tokens&…

wordpress重置密码的方法

通过phpMyAdmin直接修改数据库&#xff1a; 登录到phpMyAdmin(通常在cPanel中找到)&#xff0c;找到WordPress数据库&#xff0c;进入wp_users表。 找到对应的用户ID行&#xff0c;修改user_pass字段为新的密码值&#xff0c;并保存更改。 比如&#xff0c;把值改为&#xff…

Mysql ONLY_FULL_GROUP_BY模式详解、group by非查询字段报错

文章目录 一、问题报错二、ONLY_FULL_GROUP_BY模式2.1、什么是ONLY_FULL_GROUP_BY&#xff1f;2.2、为什么要使用ONLY_FULL_GROUP_BY&#xff1f;2.3、查看sql_mode 三、解决方法3.1、关闭only_full_group_by模式3.1.1、方法一&#xff1a;关闭当前会话中的only_full_group_by3…

电商选品/分析| 亚马逊常见插件爬虫实战之-helium插件

说明 插件爬虫相当于二次爬虫,二次加工信息,因为大部分插件信息也是从正规网上去获取数据,这次列举helium插件爬虫案例,其他插件爬虫也是类似这个方式. 需求 1、⽤⾕歌浏览器&#xff0c;下载chrome extension&#xff1a;“Helium 10 2、登录helium10 3、打开 打开Amazo…

详细阐述matplotlib.pyplot中plot模块的相关用法和参数以及一些画图基础用法(解决图例不完全显示、中文不显示问题等。)

本文章类似于一篇学习笔记&#xff0c;matplotlib.pyplot是一个很实用的图像绘图模块&#xff0c;下面主要针对plot()绘图函数进行系统性的阐述。 目录 关于figure() figure() 的基本使用 plt.figure() 常用参数 figsize 和 dpi facecolor 和 edgecolor 图形的编号和重…

PHP反序列化8(phar反序列化)

考点8&#xff1a;phar反序列化 <aside> &#x1f4a1; 使用条件 </aside> 文件上传时&#xff0c;不必要.phar后缀&#xff0c;文件上传不是难点&#xff01;&#xff01;&#xff01;&#xff08;phar伪协议自动解析成.phar文件&#xff09; phar文件本质上是…

【网络安全】内部应用中的多重漏洞利用

未经许可,不得转载。 文章目录 初步发现:帐户枚举利用帐户枚举发现 IDOR 导致帐户接管拦截请求洪水攻击:注册拒绝服务目标网站:https://redacted.com 初步发现:帐户枚举 在最近的一次渗透测试中,我对一个仅供员工使用的内部应用程序进行了评估,重点关注身份验证和帐户…

LangChain进阶技巧:提高聊天机器人性能的策略[第三课]

LangChain应运而生&#xff0c;为开发者们提供了一种高效、便捷的工具&#xff0c;助力他们构建出功能强大的大型语言模型应用。本文将带您走进LangChain的世界&#xff0c;揭秘其背后的技术原理&#xff0c;探讨如何利用这一利器来拓展语言模型的无限可能。通过丰富的实例分析…

数据订阅与消费中间件Canal 服务搭建(docker)

MySQL Bin-log开启 进入mysql容器 docker exec -it mysql5.7 bash开启mysql的binlog cd /etc/mysql/mysql.conf.dvi mysqld.cnf #在文件末尾处添加如下配置&#xff08;如果没有这个文件就创建一个&#xff09; [mysqld] # 开启 binlog log-binmysql-bin #log-bin/var/lib/mys…

宿州儿童自闭症寄宿制学校:培养孩子独立能力的专业机构

在探索自闭症儿童教育的广阔领域里&#xff0c;宿州儿童自闭症寄宿制学校以其专业的教育模式和显著的成效&#xff0c;为众多家庭带来了希望。然而&#xff0c;当我们把目光投向中国南方的繁华都市——广州&#xff0c;会发现另一所同样在自闭症儿童教育领域深耕多年、成果显著…

P3397 地毯 Python题解

地毯 题目描述 在 n n n\times n nn 的格子上有 m m m 个地毯。 给出这些地毯的信息&#xff0c;问每个点被多少个地毯覆盖。 输入格式 第一行&#xff0c;两个正整数 n , m n,m n,m。意义如题所述。 接下来 m m m 行&#xff0c;每行两个坐标 ( x 1 , y 1 ) (x_1,…

在矩池云使用 Llama-3.2-11B-Vision 详细指南

Llama 3.2-Vision是Meta开发的一系列多模态大型语言模型&#xff08;LLMs&#xff09;&#xff0c;包含11B和90B两种规模的预训练和指令调整模型。 这些模型专门优化用于视觉识别、图像推理、字幕生成和回答有关图像的一般问题。Llama 3.2-Vision模型在常见行业基准测试中的表…