Dia 11 do Grain Mall - Melhorar o agrupamento de produtos (principalmente adicionar atributos relacionados)

Índice

1. Visão Geral

2. Parte frontal

2.1 Interface front-end aprimorada para obter lista de grupos e sua chamada

2.2 Adicione um conjunto completo de lógica para associação

3. Parte de back-end

4. Resumo


1. Visão Geral

A parte frontal é semelhante à categoria de adição de marca de produto anterior.

Também é necessário modificar a interface da paginação front-end para obter a lista e adicionar o conjunto de lógica associado, incluindo a introdução de componentes básicos, a adição de campos de dados, a modificação de métodos, etc.

A parte de back-end é quase a mesma de antes:

O agrupamento em si:

1. Interface de consulta difusa de paginação de informações de grupo ( novo método de passagem de parâmetros - dois objetos dto em um objeto grande de solicitação )

2. Exclua a interface do grupo

Os mesmos atributos estão associados aqui, portanto a associação grupo-atributo também deve ser excluída adequadamente.

Interface relacionada à associação (semelhante à classificação anterior de associação de marca):

1. Consulte a lista de associações atualmente associadas

2. Excluir associação

3. Adicione nova associação

4. Consulte a lista de atributos opcionais no grupo atual

Este quarto ponto é especial em comparação com a adição anterior de associação marca-categoria: antes não havia requisitos e todas as categorias foram fornecidas diretamente a você, para que você possa escolher como quiser. Mas agora nem todos os atributos podem ser selecionados e há muitas restrições.

2. Parte frontal

2.1 Interface front-end aprimorada para obter lista de grupos e sua chamada

1. Modifique a interface na API

// 查询属性分组列表
export function listGroup(groupParams,pageParams) {
  return request({
    url: '/product/group/pageList',
    method: 'post',
    data: {
      attrGroupDto: groupParams,
      pageParamsDto: pageParams
    }
  })
}

2. Preencha os parâmetros necessários da interface e chame a interface

/** 查询属性分组列表 */
    getList() {
      this.loading = true;
      let groupParams = {
        attrGroupName: this.queryParams.attrGroupName,
        sort: this.queryParams.sort,
        descript: this.queryParams.descript,
        icon: this.queryParams.icon,
        catelogId: this.queryParams.catelogId
      }
      let pageParams = {
        pageNum: this.queryParams.pageNum,
        pageSize: this.queryParams.pageSize
      }
      listGroup(groupParams,pageParams).then((response) => {
        this.groupList = response.rows;
        this.total = response.total;
        this.loading = false;
      });
    }

Acredito que a lógica de chamada aqui seja muito simples ( ou seja, assim que a página front-end é aberta, ela envia uma solicitação para obter os dados da lista de grupos, depois os renderiza na tabela e os vincula por meio do array. ps : é simplesmente um absurdo )

Por que escrever como postagem?

Alguns alunos seguem demais as normas, as normas da aula de treinamento e qual interface de consulta deve ser transformada em get. Na verdade, não importa. Na verdade, get só é adequado para alguns parâmetros. Quando há muitos parâmetros, o comprimento do URL é limitado e difícil de usar.

Antes de enviar get, os dois parâmetros precisam primeiro ser convertidos em strings e, em seguida, o back-end usa Gson para analisá-los em objetos. Isso ocorre porque o front-end não permite que os parâmetros tenham dois ou mais parâmetros de objeto. Um é bom e vários parâmetros de tipo de string são bons, mas dois parâmetros de tipo de objeto não.

Então agora, posso enviar uma postagem com dois parâmetros de objeto? A resposta é claro, porque post trata de passar objetos.

Mas aqui você tem que prestar atenção no backend: você não pode usar dois objetos, ou seja, dois objetos marcados com @RequestBody, para receber, isso causará um erro 400.

2.2 Adicione um conjunto completo de lógica para associação

É basicamente igual à associação marca-categoria anterior. A principal diferença aqui é a adição de um atributo opcional negócio no grupo.

1. Primeiro adicione os componentes e importe os componentes e métodos relacionados.

1.1 Componentes básicos

Isso é diferente da janela pop-up que apresentei anteriormente. Aqui a associação é completamente encapsulada em um componente:

<template>
  <div>
    <el-dialog :close-on-click-modal="false" :visible.sync="visible" @closed="dialogClose">
      <el-dialog width="40%" title="选择属性" :visible.sync="innerVisible" append-to-body>
        <div>
          <el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
            <el-form-item>
              <el-input v-model="dataForm.key" placeholder="参数名" clearable></el-input>
            </el-form-item>
            <el-form-item>
              <el-button @click="getDataList()">查询</el-button>
            </el-form-item>
          </el-form>
          <el-table
            :data="dataList"
            border
            v-loading="dataListLoading"
            @selection-change="innerSelectionChangeHandle"
            style="width: 100%;"
          >
            <el-table-column type="selection" header-align="center" align="center"></el-table-column>
            <el-table-column prop="attrId" header-align="center" align="center" label="属性id"></el-table-column>
            <el-table-column prop="attrName" header-align="center" align="center" label="属性名"></el-table-column>
            <el-table-column prop="icon" header-align="center" align="center" label="属性图标"></el-table-column>
            <el-table-column prop="valueSelect" header-align="center" align="center" label="可选值列表"></el-table-column>
          </el-table>
          <el-pagination
            @size-change="sizeChangeHandle"
            @current-change="currentChangeHandle"
            :current-page="pageIndex"
            :page-sizes="[10, 20, 50, 100]"
            :page-size="pageSize"
            :total="totalPage"
            layout="total, sizes, prev, pager, next, jumper"
          ></el-pagination>
        </div>
        <div slot="footer" class="dialog-footer">
          <el-button @click="innerVisible = false">取 消</el-button>
          <el-button type="primary" @click="submitAddRealtion">确认新增</el-button>
        </div>
      </el-dialog>
      <el-row>
        <el-col :span="24">
          <el-button type="primary" @click="addRelation">新建关联</el-button>
          <el-button
            type="danger"
            @click="batchDeleteRelation"
            :disabled="dataListSelections.length <= 0"
          >批量删除</el-button>
          <!--  -->
          <el-table
            :data="relationAttrs"
            style="width: 100%"
            @selection-change="selectionChangeHandle"
            border
          >
            <el-table-column type="selection" header-align="center" align="center" width="50"></el-table-column>
            <el-table-column prop="attrId" label="#"></el-table-column>
            <el-table-column prop="attrName" label="属性名"></el-table-column>
            <el-table-column prop="valueSelect" label="可选值">
              <template slot-scope="scope">
                <el-tooltip placement="top">
                  <div slot="content">
                    <span v-for="(i,index) in scope.row.valueSelect.split(';')" :key="index">
                      {
   
   {i}}
                      <br />
                    </span>
                  </div>
                  <el-tag>{
   
   {scope.row.valueSelect.split(";")[0]+" ..."}}</el-tag>
                </el-tooltip>
              </template>
            </el-table-column>
            <el-table-column fixed="right" header-align="center" align="center" label="操作">
              <template slot-scope="scope">
                <el-button type="text" size="small" @click="relationRemove(scope.row.attrId)">移除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-col>
      </el-row>
    </el-dialog>
  </div>
</template>

<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';

export default {
  //import引入的组件需要注入到对象中才能使用
  components: {},
  props: {},
  data() {
    //这里存放数据
    return {
      attrGroupId: 0,
      visible: false,
      innerVisible: false,
      relationAttrs: [],
      dataListSelections: [],
      dataForm: {
        key: ""
      },
      dataList: [],
      pageIndex: 1,
      pageSize: 10,
      totalPage: 0,
      dataListLoading: false,
      innerdataListSelections: []
    };
  },
  //计算属性 类似于data概念
  computed: {},
  //监控data中的数据变化
  watch: {},
  //方法集合
  methods: {
    selectionChangeHandle(val) {
      this.dataListSelections = val;
    },
    innerSelectionChangeHandle(val) {
      this.innerdataListSelections = val;
    },
    addRelation() {
      this.getDataList();
      this.innerVisible = true;
    },
    batchDeleteRelation(val) {
      let postData = [];
      this.dataListSelections.forEach(item => {
        postData.push({ attrId: item.attrId, attrGroupId: this.attrGroupId });
      });
      this.$http({
        url: this.$http.adornUrl("/product/attrgroup/attr/relation/delete"),
        method: "post",
        data: this.$http.adornData(postData, false)
      }).then(({ data }) => {
        if (data.code == 0) {
          this.$message({ type: "success", message: "删除成功" });
          this.init(this.attrGroupId);
        } else {
          this.$message({ type: "error", message: data.msg });
        }
      });
    },
    //移除关联
    relationRemove(attrId) {
      let data = [];
      data.push({ attrId, attrGroupId: this.attrGroupId });
      this.$http({
        url: this.$http.adornUrl("/product/attrgroup/attr/relation/delete"),
        method: "post",
        data: this.$http.adornData(data, false)
      }).then(({ data }) => {
        if (data.code == 0) {
          this.$message({ type: "success", message: "删除成功" });
          this.init(this.attrGroupId);
        } else {
          this.$message({ type: "error", message: data.msg });
        }
      });
    },
    submitAddRealtion() {
      this.innerVisible = false;
      //准备数据
      console.log("准备新增的数据", this.innerdataListSelections);
      if (this.innerdataListSelections.length > 0) {
        let postData = [];
        this.innerdataListSelections.forEach(item => {
          postData.push({ attrId: item.attrId, attrGroupId: this.attrGroupId });
        });
        this.$http({
          url: this.$http.adornUrl("/product/attrgroup/attr/relation"),
          method: "post",
          data: this.$http.adornData(postData, false)
        }).then(({ data }) => {
          if (data.code == 0) {
            this.$message({ type: "success", message: "新增关联成功" });
          }
          this.$emit("refreshData");
          this.init(this.attrGroupId);
        });
      } else {
      }
    },
    init(id) {
      this.attrGroupId = id || 0;
      this.visible = true;
      this.$http({
        url: this.$http.adornUrl(
          "/product/attrgroup/" + this.attrGroupId + "/attr/relation"
        ),
        method: "get",
        params: this.$http.adornParams({})
      }).then(({ data }) => {
        this.relationAttrs = data.data;
      });
    },
    dialogClose() {},

    //========
    // 获取数据列表
    getDataList() {
      this.dataListLoading = true;
      this.$http({
        url: this.$http.adornUrl(
          "/product/attrgroup/" + this.attrGroupId + "/noattr/relation"
        ),
        method: "get",
        params: this.$http.adornParams({
          page: this.pageIndex,
          limit: this.pageSize,
          key: this.dataForm.key
        })
      }).then(({ data }) => {
        if (data && data.code === 0) {
          this.dataList = data.page.list;
          this.totalPage = data.page.totalCount;
        } else {
          this.dataList = [];
          this.totalPage = 0;
        }
        this.dataListLoading = false;
      });
    },
    // 每页数
    sizeChangeHandle(val) {
      this.pageSize = val;
      this.pageIndex = 1;
      this.getDataList();
    },
    // 当前页
    currentChangeHandle(val) {
      this.pageIndex = val;
      this.getDataList();
    }
  }
};
</script>
<style scoped>
</style>

 Este é o código fornecido pelo professor, principalmente modificarei os métodos internos mais tarde.

1.2 Adicionar botões e usar componentes

Como na verdade eu uso o código vue reverso de Ruoyi, incluindo a marca anterior, ainda preciso adicionar esses componentes funcionais adicionais manualmente. De agora em diante, não usarei o dado pelo Ruoyi, mas sim diretamente o dado pelo professor, que é prático e simples. Na verdade, desde que você entenda a lógica geral, front-end.

Primeiro adicione o botão associado:

<el-button type="text" size="mini" @click="relationHandle(scope.row.attrGroupId)">关联</el-button>

Então use o componente, só assim será eficaz

Continuam os mesmos três passos ( esta é uma operação muito básica, mas tendo em conta que ainda há alunos que não são rigorosos ):

1. Extraia componentes

Já disse acima

2. Importar componentes

import RelationUpdate from "./attr-group-relation";

3. Use componentes 

Registre-se primeiro:

components: { Category,RelationUpdate }

 Então use:

<!-- 修改关联关系 -->
          <relation-update v-if="relationVisible" ref="relationUpdate" @refreshData="getDataList"></relation-update>

2. Visualize seus campos de dados

Nada mais é do que logotipos pop-up e atributos de dados.

Aqui, foram fornecidos os dados básicos para os componentes do agrupamento reverso de Ruoyi.

Mas como um componente pop-up é introduzido aqui, deve-se determinar se ele deve ser exibido por meio de um sinalizador booleano, portanto, isso deve ser colocado:

O nome do atributo está no v-if do componente fornecido pelo professor: RelationshipVisible

Quanto ao componente de janela pop-up associado, o professor escreveu todos os dados necessários e não precisamos mais nos mover. 

3. Modifique o método (principalmente para alterar a solicitação, a lógica basicamente não precisa ser alterada)

 Em componentes agrupados:

No componente de grupo, clique no evento acionado pela associação:

<el-button type="text" size="mini" @click="relationHandle(scope.row.attrGroupId)">关联</el-button>

Não há muito a dizer sobre esse método relacionamentoHandle, basta usar o método do professor, pois ele apenas abre a janela. Chame o método de inicialização do componente associado.

//处理分组与属性的关联
    relationHandle(groupId) {
      this.relationVisible = true;
      this.$nextTick(() => {
        this.$refs.relationUpdate.init(groupId);
      });
    }

 Claro, o método fuzzy de paginação anterior foi escrito, então não entrarei em detalhes.

Na verdade, aqui está apenas uma nova função relacionada, então basicamente basta adicionar este método de evento de botão de clique.

Caso contrário, os gerados por Zoey foram modificados nos últimos dias...

Em componentes relacionados:

Na verdade o ponto está aqui

Na verdade, depois que a função anterior de associação marca-categoria foi implementada, você sabe como escrevê-la aqui, porque são todas associações e a lógica geral é a mesma.

Nada mais que:

1. Consulte o método da lista de associações atual

Vamos primeiro dar uma olhada nas propriedades do componente vinculado ao valor de retorno desse método, para que possamos entender onde os dados são obtidos por esse método.

É óbvio saber que esta é a lista de propriedades associadas. 

Então, qual é a lógica de aquisição?

Na verdade, quando clicamos no botão associado no componente de grupo, o método init no componente associado será chamado para obter os dados para a lista de atributos.

Chamando init em componentes agrupados:

 

Primeiro, análise do método init

init(id) {
      this.attrGroupId = id || 0;
      this.visible = true;
      listRelation({attrGroupId: this.attrGroupId}).then((response)=>{
        this.relationAttrs = response.rows;
        this.total = response.total;
        this.loading = false;
      })
    }

Basicamente não mude a lógica, apenas mude esta solicitação

Interface frontal:

// 查询属性&属性分组关联列表
export function listRelation(query) {
  return request({
    url: '/product/attrAttrGroupRelation/list',
    method: 'get',
    params: query
  })
}

2. Adicione novo método de associação

Para criar uma nova associação, devemos primeiro ter uma lista para vermos, e depois podemos escolher a associação marca-categoria anterior, porque uma marca pode ser associada a qualquer categoria, e não há necessidade de considerar se esta categoria tem sido associada a outras marcas. Como uma marca pode corresponder a várias categorias, todas as categorias são exibidas diretamente sem pensar, e então escolhemos.

Mas aqui é diferente. Deixe-me falar sobre o negócio aqui. Na verdade, é muito simples:

1. Os atributos devem ser atributos básicos, claro que isso é óbvio

2. Em segundo lugar, os atributos selecionados devem ser atributos da categoria correspondente ao grupo atual. Não faz sentido usar atributos de categorias que não estejam neste grupo.

3. Então você não pode selecionar atributos que foram selecionados para o grupo atual, ou atributos que foram selecionados para outros grupos na categoria à qual o grupo atual pertence, porque um atributo básico só pode corresponder a um grupo, e o relacionamento entre grupos e atributos são um para muitos. Relacionamento, existem vários atributos em um grupo, mas um atributo só pode pertencer a um grupo

Claro, eu disse isso no front-end, na verdade, a lógica de consulta desse negócio é implementada no back-end, mas ainda quero avisar com antecedência e saber primeiro...

Hahaha, agora ainda existe um novo método. Como a nova adição envolve essa consulta, acabei de dizer isso.

Abaixo postarei diretamente o código do novo método:

A partir deste evento, clique no novo evento:

Novo método:

 

submitAddRealtion() {
      this.innerVisible = false;
      //准备数据
      console.log("准备新增的数据", this.innerdataListSelections);
      if (this.innerdataListSelections.length > 0) {
        let postData = [];
        this.innerdataListSelections.forEach(item => {
          postData.push({ attrId: item.attrId, attrGroupId: this.attrGroupId });
        });
        batchAddRelation(postData).then((response) => {
          this.$modal.msgSuccess("新增关联成功");
          this.$emit("refreshData");
          this.init(this.attrGroupId);
        });
      }else{
        this.$modal.confirm("未选择属性")
      }
    }

 Vamos falar sobre isso.$emit("refreshData"):

Basta atualizar a lista de atributos opcionais:

.emit é um evento chamado: refreshData passado para o componente pai, que acionará o método vinculado a este evento no componente pai.

 

Retorne à adição original, a seguir está a nova interface

// 新增属性&属性分组关联
export function addRelation(data) {
  return request({
    url: '/product/attrAttrGroupRelation',
    method: 'post',
    data: data
  })
}

 Então vá para o novo método

3. Exclua métodos associados

Eventos do botão Remover e excluir em lote:

Método de remoção:

//移除关联
    relationRemove(id) {
      delRelation(id).then((response)=>{
        this.$modal.msgSuccess("删除关联成功");
        this.init(this.attrGroupId);
      })
    }

 Método de exclusão em lote:

batchDeleteRelation() {
      let postData = [];
      this.dataListSelections.forEach(item => {
        postData.push(item.id);
      });
      delRelation(postData).then((response)=>{
        this.$modal.msgSuccess("批量删除关联成功");
        this.init(this.attrGroupId);
      })
    }

Ainda é o mesmo, lembre-se de atualizá-lo após excluí-lo;

interface:

A remoção e a exclusão em lote compartilham a mesma interface:

// 删除属性&属性分组关联
export function delRelation(id) {
  return request({
    url: '/product/attrAttrGroupRelation/' + id,
    method: 'delete'
  })
}

Independentemente de ser um ID, você também pode passar uma matriz de IDs 


Obviamente, o ponto especial aqui é adicionar um método para consultar a lista de atributos opcionais no grupo atual, devido às necessidades do negócio.

4. Consulte o método de lista de atributos opcionais no grupo atual

A razão pela qual isto é necessário já foi mencionada na nova adição.

Dados vinculados ou botão de consulta:

método:

// 获取可选属性列表
    getDataList() {
      this.dataListLoading = true;
      let pageParams =  {
          page: this.pageIndex,
          limit: this.pageSize,
          key: this.dataForm.key
      };
      attrList(this.attrGroupId,pageParams).then((tableDataInfo) => {
        if (tableDataInfo) {
          this.dataList = tableDataInfo.rows;
          this.totalPage = tableDataInfo.total;
        } else {
          this.dataList = [];
          this.totalPage = 0;
        }
        this.dataListLoading = false;
      });
    }

 interface:

Dentro de attr.js:

// 查询某个分组下可选的商品属性列表
export function attrList(groupId,params) {
  return request({
    url: `/product/attr/attrList?groupId=${groupId}`,
    method: 'post',
    data: params
  })
}

3. Parte de back-end

Aqui são mencionadas apenas aquelas que precisam ser modificadas, para outras interfaces basta utilizar as geradas por engenharia reversa.

1. O agrupamento em si

1. Interface de lista de consulta difusa de paginação

Não há muito a dizer sobre isso, já escrevi sobre isso antes.

interface:

/**
     * 查询属性分组列表
     */
    @ApiOperation("查询属性分组列表")
    //@PreAuthorize("@ss.hasPermi('product:group:list')")
    @PostMapping("/pageList")
    public TableDataInfo list(@RequestBody GroupPageRequest groupPageRequest){
        TableDataInfo tableDataInfo = attrGroupService.pageList(groupPageRequest.getAttrGroupDto(),groupPageRequest.getPageParamsDto());
        return tableDataInfo;
    }

concluir:

/**
     * 分页查询分组列表
     *
     * @param attrGroupDto
     * @param pageParamsDto
     * @return
     */
    @Override
    public TableDataInfo pageList(AttrGroupDto attrGroupDto, PageParamsDto pageParamsDto) {
        LambdaQueryWrapper<AttrGroup> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.hasText(attrGroupDto.getAttrGroupName()),AttrGroup::getAttrGroupName,attrGroupDto.getAttrGroupName());
        wrapper.eq(attrGroupDto.getSort()!=null,AttrGroup::getSort,attrGroupDto.getSort());
        wrapper.like(StringUtils.hasText(attrGroupDto.getDescript()),AttrGroup::getDescript,attrGroupDto.getDescript());
        wrapper.like(StringUtils.hasText(attrGroupDto.getIcon()),AttrGroup::getIcon,attrGroupDto.getIcon());
        wrapper.eq(attrGroupDto.getCatelogId()!=null,AttrGroup::getCatelogId,attrGroupDto.getCatelogId());
        Page<AttrGroup> page = new Page<>(pageParamsDto.getPageNum(), pageParamsDto.getPageSize());
        page(page,wrapper);
        return new TableDataInfo(page.getRecords(),(int)page.getTotal());
    }

Ou seja, use o método de paginação pronto do MP e, em seguida, encapsule os dados da consulta de acordo com as especificações de Ruoyi. 

2. Excluir interface

Como existe uma associação aqui, a associação também deve ser excluída.

interface:

/**
     * 删除属性分组
     */
    @ApiOperation("删除属性分组")
    //@PreAuthorize("@ss.hasPermi('product:group:remove')")
    @Log(title = "属性分组", businessType = BusinessType.DELETE)
    @DeleteMapping("/{attrGroupIds}")
    public AjaxResult remove(@PathVariable Long[] attrGroupIds) {
        return toAjax(attrGroupService.removeMore(Arrays.asList(attrGroupIds)));
    }

concluir:

/**
     * 删除分组本身以及删除分组所关联的 分组-属性关联
     * @param list
     * @return
     */
    @Override
    @Transactional
    public boolean removeMore(List<Long> list) {
        //1. 删除分组本身
        boolean remove = removeByIds(list);
        AtomicBoolean flag = new AtomicBoolean(true);
        //2. 删除 分组-属性关联
        list.stream().forEach(item->{
            List<AttrAttrgroupRelation> relations = attrAttrgroupRelationService.list(new LambdaQueryWrapper<AttrAttrgroupRelation>().eq(AttrAttrgroupRelation::getAttrGroupId, item));
            relations.stream().forEach(item1->{
                boolean remove1 = attrAttrgroupRelationService.removeById(item1.getId());
                if (!remove1) {
                    flag.set(false);
                }
            });
        });
        return remove&& flag.get();
    }

 Apenas me dê os resultados. Como esta é uma operação de adição, exclusão e modificação que envolve diversas tabelas, lembre-se de adicionar a anotação @Transactional para garantir as transações.

2. Associar interfaces relacionadas

1. Consulte a lista de atributos associados (sem paginação difusa)

Por se tratar de uma associação, pense em quantos atributos pode haver em um grupo? Só pode haver um determinado número, portanto não há necessidade de paginação e, como são poucos, não há necessidade de desfocar.

interface:

/**
     * 查询属性&属性分组关联列表
     */
    @ApiOperation("查询属性&属性分组关联列表")
    //@PreAuthorize("@ss.hasPermi('product:relation:list')")
    @GetMapping("/list")
    public TableDataInfo list(AttrAttrgroupRelation attrAttrgroupRelation) {
        startPage();
        List<AttrAttrGroupRelationVo> list = attrAttrgroupRelationService.detailList(new QueryWrapper<AttrAttrgroupRelation>(attrAttrgroupRelation));
        return getDataTable(list);
    }

2. Consulte a lista de atributos opcionais do grupo atual

A lógica é explicada no front end e há comentários no código. Na verdade, é muito simples.

interface:

Esta interface está no controlador de atributos porque é o atributo a ser verificado.

/**
     * 获取分组下可选的属性
     */
    @ApiOperation("查询分组下可选的属性列表")
    @PostMapping("/attrList")
    public TableDataInfo attrList(Long groupId,@RequestBody Map<String,Object> params){
        return attrService.attrList(groupId,params);
    }

Diferente da interface de lista de grupos anterior, Map é usado aqui para receber parâmetros de paginação. 

concluir:

/**
     * 获取分组下可选的属性
     * @param groupId
     * @param params
     * @return
     */
    @Override
    public TableDataInfo attrList(Long groupId, Map<String, Object> params) {
        //1. 只需要这个分组同分类下的属性
        AttrGroup group = groupService.getById(groupId);
        Long catId = group.getCatelogId();
        //2. 不能是这个分类下其他分组已经选过的属性
        //2.1 当前分类下的其他分组
        List<AttrGroup> list = groupService.list(new LambdaQueryWrapper<AttrGroup>().eq(AttrGroup::getCatelogId, catId));

        //2.2 这些分组所关联的属性
        List<Long> listIds = new ArrayList<>();
        list.stream().forEach(item->{
            List<AttrAttrgroupRelation> list1 = attrAttrgroupRelationService.list(new LambdaQueryWrapper<AttrAttrgroupRelation>().eq(AttrAttrgroupRelation::getAttrGroupId, item.getAttrGroupId()));
            list1.stream().forEach(item1 -> listIds.add(item1.getAttrId()));
        });
        LambdaQueryWrapper<Attr> wrapper = new LambdaQueryWrapper<Attr>().eq(Attr::getCatelogId, catId).like(StringUtils.hasText((String) params.get("key")), Attr::getAttrName, (String) params.get("key"));
        if(listIds.size()!=0){
            wrapper.notIn(Attr::getAttrId, listIds);
        }
        //2.3 从当前分类下的属性排除
        List<Attr> attrList = list(wrapper);
        //封装分页数据
        Integer page = (Integer) params.get("page");
        Integer limit = (Integer) params.get("limit");
        List<Attr> records = PageUtils.page(attrList, page, limit);
        return new TableDataInfo(records, attrList.size());
    }

3. Adicione nova interface associada

Não há nada a dizer, não envolve tabelas ou outros campos, basta adicioná-los diretamente.

interface:

/**
     * 新增属性&属性分组关联
     */
    @ApiOperation("新增属性&属性分组关联")
    //@PreAuthorize("@ss.hasPermi('product:relation:add')")
    @Log(title = "属性&属性分组关联", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody AttrAttrgroupRelation attrAttrgroupRelation) {
        return toAjax(attrAttrgroupRelationService.save(attrAttrgroupRelation));
    }

4. Exclua a interface associada

Também não envolve outras tabelas, apenas exclua-as diretamente.

interface:

/**
     * 删除属性&属性分组关联
     */
    @ApiOperation("删除属性&属性分组关联")
    //@PreAuthorize("@ss.hasPermi('product:relation:remove')")
    @Log(title = "属性&属性分组关联", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(attrAttrgroupRelationService.removeByIds(Arrays.asList(ids)));
    }

4. Resumo

De um modo geral, a parte frontal ainda é relativamente complicada, na verdade não é difícil, mas complicada.

Por que introduzir esses componentes e alcançar o estilo básico?

Existem também componentes e métodos importados.

Faça um bom trabalho no domínio de dados.

Faça isso no bom sentido.

Quanto ao backend, também não é difícil: ainda é uma interface comum para adicionar, excluir, modificar e verificar.

Consulta de paginação, consulta difusa, adição, exclusão e modificação precisam ter consciência global se será projetada para outros campos ou outras tabelas.A chamada consciência global é, na verdade, baseada no negócio.

Como aqui, o negócio de consulta da lista de atributos opcionais no grupo atual é um pouco mais complicado.

Além disso, existem diversas maneiras de passar parâmetros no front-end e receber parâmetros no back-end que você precisa dominar:

1. Obtenção pura, quando há dois parâmetros de objeto, o front-end precisa prestar atenção. O que é passado é uma string e o back-end precisa analisá-la.

2. Uma obtenção, um dado. O front-end não tem nada a dizer aqui, e o mesmo vale para o back-end.

3. Postagem pura, o front-end ainda transmite, mas o back-end não permite o recebimento de dois objetos, então um objeto deve ser usado, um @RequestBody

Acho que você gosta

Origin blog.csdn.net/m0_63445035/article/details/132224084
Recomendado
Clasificación