Avaliação da instância do Huawei Cloud Yaoyun Server L|Processo de atualização automática com base no cache do canal e casos de aplicação do projeto SpringBoot e código-fonte

Insira a descrição da imagem aqui

Prefácio

Recentemente, a instância Huawei Cloud Yaoyun Server L foi lançada e eu também construí uma para brincar. Durante o processo, encontrei vários problemas e aprendi muito sobre operação e manutenção no processo de solução dos problemas.

No blog anterior apresentei a instalação e configuração do canal, consulte o blog.

Este blog apresenta um caso de aplicação do projeto canal, detalha o processo de banco de dados e sincronização de cache baseado no canal e fornece o código-fonte do núcleo diamante.

Insira a descrição da imagem aqui

A lista de outros artigos relacionados à avaliação de instância do Huawei Cloud Yaoyun Server L é a seguinte:

Insira a descrição da imagem aqui

liderar


1. Apresentar o processo de sincronização de banco de dados e cache baseado no canal;
2. Fornecer o código fonte do núcleo diamante;

Atualizações síncronas baseadas no cache do canal

processo geral

Ao iniciar o projeto Spring, a atualização automática do cache é iniciada de forma síncrona.Se os dados relevantes da tabela do banco de dados forem alterados, o canal irá ouvi-los e então atualizar os dados correspondentes no cache redis.

Insira a descrição da imagem aqui

Quais dados são retirados do cache? ——Dados que não são atualizados com frequência: como departamentos da empresa, armazéns, etc.;

Quando o projeto começou, foi iniciado o canal, que serve para monitorar alterações no banco de dados;

Lógica de negócios: Solicite dados relevantes do front-end -> Peça ao Redis

(1) Se houver no redis, será devolvido ao front end;

(2) Se não estiver no redis, consulte-o no banco de dados, salve-o no redis e retorne-o ao front-end;

(3) Se o banco de dados for atualizado, o canal monitora a modificação e o atualiza no Redis de forma síncrona para garantir que o cache e o banco de dados sejam consistentes;

Insira a descrição da imagem aqui

Código e processos relacionados

1.Configuração do canal do canal

Insira a descrição da imagem aqui

O cache é atualizado automaticamente e o IP e o número da porta no arquivo de configuração são lidos.

Insira a descrição da imagem aqui

Se deve ativar a atualização automática do cache e ler a configuração do arquivo de configuração;

Insira a descrição da imagem aqui

2. Código comercial para consulta front-end

Insira a descrição da imagem aqui

Obtenha os dados no cache quando os dados do banco de dados não forem atualizados

Insira a descrição da imagem aqui

3. Atualização de dados do banco de dados

Se os dados do banco de dados forem atualizados, o canal os monitora e descobre que a tabela correspondente está armazenada em cache e os campos correspondentes mudam, e o cache é atualizado automaticamente.

Insira a descrição da imagem aqui

Atualização de sincronização automática de cache

Insira a descrição da imagem aqui

Os dados mais recentes armazenados no Redis

Insira a descrição da imagem aqui

4. Exibição front-end de atualização de cache

Após a atualização do cache, o front-end consulta novamente para obter os dados mais recentes.

Insira a descrição da imagem aqui

Código fonte do código principal

1. Configure classes yml e de configuração

Arquivo yml de configuração

server:
  port: 10050

## 是否启用安全框架 true为开启,false为关闭
security:
  isOpen: true

## 是否开启canal管道,true为开启,false为关闭
canal:
  isOpen: true

# canal的相关配置
canalConfig:
  host: 124.70.138.34
  port: 11111

Insira a descrição da imagem aqui

Classe de configuração para armazenar objetos Java no Redis

package com.tianju.fresh.config.redis;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisSerializeConfig {
    
    
    @Bean
    public RedisTemplate redisTemplateInit(RedisConnectionFactory redisConnectionFactory) {
    
    

        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();

        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置序列化Key的实例化对象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置序列化Value的实例化对象
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        /**
         *
         * 设置Hash类型存储时,对象序列化报错解决
         */
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }
}

2.canal atualiza automaticamente o código

O Canal atualiza automaticamente o código, usa pipeline de canal para monitorar alterações de dados MySQL e atualiza automaticamente o cache redis

package com.tianju.fresh.config.redis;


import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;


import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.common.utils.AddressUtils;
import com.alibaba.otter.canal.protocol.Message;
import com.alibaba.otter.canal.protocol.CanalEntry.Column;
import com.alibaba.otter.canal.protocol.CanalEntry.Entry;
import com.alibaba.otter.canal.protocol.CanalEntry.EntryType;
import com.alibaba.otter.canal.protocol.CanalEntry.EventType;
import com.alibaba.otter.canal.protocol.CanalEntry.RowChange;
import com.alibaba.otter.canal.protocol.CanalEntry.RowData;
import com.baomidou.mybatisplus.annotation.TableField;
import com.tianju.fresh.entity.common.GoodsTypeVo;
import com.tianju.fresh.entity.common.WarehouseVo;
import com.tianju.fresh.entity.goods.GoodsType;
import com.tianju.fresh.mapper.goods.GoodsTypeMapper;
import com.tianju.fresh.mapper.warehouse.StorehouseMapper;
import com.tianju.fresh.service.common.CommonStaticMethod;
import com.tianju.fresh.util.Constance;
import com.tianju.fresh.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

/**
 * 用canal管道监听MySQL数据变化,自动更新redis缓存
 */
@Slf4j
@Component
public class AutoUpdateRedis {
    
    

    @Value("${canalConfig.host}")
    private String host;

    @Value("${canalConfig.port}")
    private Integer port;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private GoodsTypeMapper typeMapper;

    @Autowired
    private StorehouseMapper storehouseMapper;

    @Autowired
    private RedisUtil redisUtil;


    public void run() {
    
    
        // 创建链接
        final InetSocketAddress HOST = new InetSocketAddress(host,port);
//        final InetSocketAddress HOST = new InetSocketAddress("192.168.111.130",11111);
        CanalConnector connector = CanalConnectors.newSingleConnector(HOST, "example", "", "");
        int batchSize = 1000;
        int emptyCount = 0;
        try {
    
    
            connector.connect();
            connector.subscribe(".*\\..*");
            connector.rollback();
            int totalEmptyCount = 120;
//            while (emptyCount < totalEmptyCount) {
    
    
            while (true) {
    
    
                Message message = connector.getWithoutAck(batchSize); // 获取指定数量的数据
                long batchId = message.getId();
                int size = message.getEntries().size();
                if (batchId == -1 || size == 0) {
    
    
                    emptyCount++;
                    if(emptyCount % 100==0 || emptyCount==1){
    
    
                        System.out.println("empty count : " + emptyCount);
                    }
                    try {
    
    
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
    
    
                    }
                } else {
    
    
                    emptyCount = 0;
                    // System.out.printf("message[batchId=%s,size=%s] \n", batchId, size);
                    printEntry(message.getEntries());
                }

                connector.ack(batchId); // 提交确认
                // connector.rollback(batchId); // 处理失败, 回滚数据
            }

//            System.out.println("empty too many times, exit");
        } finally {
    
    
            connector.disconnect();
        }
    }

    private void printEntry(List<Entry> entrys) {
    
    
        for (Entry entry : entrys) {
    
    
            if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) {
    
    
                continue;
            }

            RowChange rowChage = null;
            try {
    
    
                rowChage = RowChange.parseFrom(entry.getStoreValue());
            } catch (Exception e) {
    
    
                throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(),
                        e);
            }

            EventType eventType = rowChage.getEventType();
            System.out.println(String.format("================&gt; binlog[%s:%s] , name[%s,%s] , eventType : %s",
                    entry.getHeader().getLogfileName(), entry.getHeader().getLogfileOffset(),
                    entry.getHeader().getSchemaName(), entry.getHeader().getTableName(),
                    eventType));

            String tableName = entry.getHeader().getTableName();
            if (Constance.LISTEN_TAB_NAMES.contains(tableName)){
    
    
                for (RowData rowData : rowChage.getRowDatasList()) {
    
    
                    if (eventType == EventType.DELETE){
    
    
                        // 删除之前
                        log.debug("-------删除之前before");
                        changeBefore(rowData.getBeforeColumnsList());

                        log.debug("-------删除之后after");
                        // 传修改的表名,和常量中的map对比,从而对应的redis里的key
//                        changeAfter(rowData.getAfterColumnsList(),tableName);

                    }else if (eventType == EventType.INSERT){
    
    
                        // 插入之前
                        log.debug("-------插入之前before");
                        changeBefore(rowData.getBeforeColumnsList());

                        log.debug("-------插入之后after");
                        // 传修改的表名,和常量中的map对比,从而对应的redis里的key
//                        changeAfter(rowData.getAfterColumnsList(),tableName);

                    }else {
    
    
                        // 修改之前
                        log.debug("-------修改之前before");
                        changeBefore(rowData.getBeforeColumnsList());

                        log.debug("-------修改之后after");
                        // 传修改的表名,和常量中的map对比,从而对应的redis里的key
                        changeAfter(rowData.getAfterColumnsList(),tableName);
                    }
                }
            }
        }
    }


    /**
     * 数据库更新之前
     * @param columns
     */

    private  void changeBefore(List<Column> columns) {
    
    
        for (Column column : columns) {
    
    
            System.out.println(column.getName() + " : " + column.getValue() + "    update=" + column.getUpdated());
        }
    }

    private  void changeAfter(List<Column> columns, String tableName) {
    
    
        for (Column column : columns) {
    
    
            System.out.println(column.getName() + " : " + column.getValue() + "    update=" + column.getUpdated());

            // 如果是商品类别表变化

            if ("name".equals(column.getName()) && Constance.GOODS_TYPE_TAB_NAME.equals(tableName)){
    
     // 默认是名称那一列变化才更新缓存
                // 先删除key,再设置好新的key
                Map tabNameToRedisKey = Constance.getTabNameToRedisKey();
                String redisKey = (String) tabNameToRedisKey.get(tableName);
                redisTemplate.delete(redisKey);
                // TODO:设置新的key
                List<GoodsTypeVo> list = CommonStaticMethod.getGoodsTypeVos(typeMapper);
                redisUtil.saveObjectToRedis(Constance.GOODS_TYPE_REDIS_KEY, list);
                break;
            }

            // 如果是仓库那张表变化 storehouse
            if ("name".equals(column.getName()) && Constance.STOREHOUSE_TAB_NAME.equals(tableName)){
    
     // 默认是名称那一列变化才更新缓存
                // 先删除key,再设置好新的key
                Map tabNameToRedisKey = Constance.getTabNameToRedisKey();
                String redisKey = (String) tabNameToRedisKey.get(tableName);
                redisTemplate.delete(redisKey);

                // 设置新的key,存到redis里面
                List<WarehouseVo> list = CommonStaticMethod.getStorehouseVos(storehouseMapper);

                redisUtil.saveObjectToRedis(Constance.STOREHOUSE_REDIS_KEY,list);

                break;
            }
        }
    }
}

Insira a descrição da imagem aqui

classe de ferramenta redis

package com.tianju.fresh.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@Component
public class RedisUtil {
    
    

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    public void  saveObjectToRedis(String key,Object json){
    
    
        redisTemplate.opsForValue().set(key,json);
    }

    /**
     * 从redis里面获取json对象,如果没有,返回null
     * @param key
     * @return
     */
    public Object getJsonFromRedis(String key){
    
    
        return redisTemplate.opsForValue().get(key);
    }

}

Classe constante para monitorar tabelas de banco de dados e nomes de colunas

package com.tianju.fresh.util;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 专门放各种常量
 */
public interface Constance {
    
    
    // 设置哪些数据库表需要监听,比如单位unit,仓库warehouse,商品类型等
    List<String> LISTEN_TAB_NAMES = Arrays.asList("goods_type","unit_commodity","warehouse_center","warehouse_tab");

    String GOODS_TYPE_TAB_NAME = "goods_type";
    String GOODS_TYPE_REDIS_KEY = "goodsTypeVo";
    String UNIT_TAB_NAME = "unit_commodity";
    String UNIT_REDIS_KEY = "unitVo";
    String WAREHOUSE_TAB_NAME = "warehouse_center";
    String WAREHOUSE_REDIS_KEY = "warehouseCenterVo";
    String STOREHOUSE_TAB_NAME = "warehouse_tab";
    String STOREHOUSE_REDIS_KEY = "storehouseVo";

    static Map getTabNameToRedisKey(){
    
    
        Map<String,String> map = new HashMap<>();
        map.put(GOODS_TYPE_TAB_NAME,"goodsTypeVo");
        map.put("unit_commodity","unitVo");
        map.put("warehouse_center","warehouseCenterVo");
        map.put("warehouse_tab","storehouseVo");
        return map;
    }
}

3. Consulte o código de serviço da camada de negócios

Insira a descrição da imagem aqui

    @Override
    public List<WarehouseVo> findStorehouse() {
    
    
//        List<Storehouse> storehouses = storehouseMapper.selectList(null);
//        List<WarehouseVo> list = new ArrayList<>(storehouses.size());
//        storehouses.forEach(s->{
    
    
//            list.add(new WarehouseVo(s.getId()+"", s.getName()));
//        });

        // 是否有小仓库的redis的key
        Boolean hasKey = redisTemplate.hasKey(Constance.STOREHOUSE_REDIS_KEY);
        if (hasKey){
    
     // 如果有,走缓存
            List<WarehouseVo> list = (List<WarehouseVo>) redisTemplate.opsForValue()
                    .get(Constance.STOREHOUSE_REDIS_KEY);
            log.debug("get storehouseVo from redis: "+list);
            return list;
        }
        // 如果没有从数据库查询,存到redis里面
        List<WarehouseVo> list = CommonStaticMethod.getStorehouseVos(storehouseMapper);
        log.debug("get storehouseVo from mysql: "+list);
        redisUtil.saveObjectToRedis(Constance.STOREHOUSE_REDIS_KEY, list);
        return list;
    }

4. Aula principal de startups

A classe de inicialização principal implementa o método CommandLineRunner, inicia o canal do canal, monitora alterações no banco de dados e implementa atualizações de sincronização de cache.

package com.woniu.fresh;


import com.woniu.fresh.config.redis.AutoUpdateRedis;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableScheduling;


@SpringBootApplication
@Slf4j
@EnableAspectJAutoProxy // 让动态代理生效
@EnableScheduling // 让定时任务生效
public class FreshApp implements CommandLineRunner {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(FreshApp.class);
    }

    @Autowired
    private AutoUpdateRedis autoUpdateRedis;

    @Value("${canal.isOpen}")
    private Boolean isCanal;

    @Override
    public void run(String... args) throws Exception {
    
    

        if (isCanal){
    
    
            log.debug(">>>>>启动缓存自动更新");
            autoUpdateRedis.run();
        }
    }
}

5. Código vue de front-end

<template>
    <div>
        <el-row>
            <el-col :span="24">
                <el-form :inline="true" label-width="80px">
                    <el-form-item label="领料单号">
                        <el-input v-model="findGoodsParams.shoppingNo"></el-input>
                    </el-form-item>

                    <el-form-item label="领料数量≥">
                        <el-input v-model="findGoodsParams.nums"></el-input>
                    </el-form-item>

                    <el-form-item label="原料名称">
                        <el-input v-model="findGoodsParams.rawName"></el-input>
                    </el-form-item>

                    <el-form-item label="领料仓库">
                        <el-select v-model="findGoodsParams.warehouseId" placeholder="请选择">
                            <el-option v-for="item in commondata.storehouse" :key="item.value" :label="item.label"
                                :value="item.value">
                            </el-option>
                        </el-select>
                    </el-form-item>

                    <el-form-item label="状态">
                        <el-select v-model="findGoodsParams.status" placeholder="请选择">
                            <el-option v-for="item in commondata.status" :key="item.value" :label="item.label"
                                :value="item.value">
                            </el-option>
                        </el-select>
                    </el-form-item>

                    <el-form-item>
                        <el-button type="primary" @click="findGoods">查询</el-button>
                        <el-button type="success" @click="reFindGoods">重置</el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>

        <el-row>
            <el-col :span="24">
                <el-button type="success" @click="addGoodsBtn">新增</el-button>
                <el-button type="warning" icon="el-icon-edit" @click="batchDelete">批量审批</el-button>
                <el-button type="primary" icon="el-icon-magic-stick" @click="batchPickDoing">批量领取中</el-button>
                <el-button type="primary" icon="el-icon-shopping-cart-full" @click="batchPickDown">批量已领完</el-button>

            </el-col>
        </el-row>

        <el-row>
            <el-col :span="24">
                <el-table :data="tableData" style="width: 100%" @selection-change="handleSelectionChange">
                    <el-table-column type="selection" width="55">
                    </el-table-column>
                    <el-table-column prop="pickNo" label="领料单号" width="240">
                    </el-table-column>
                    <el-table-column prop="name" label="原材料名" width="100">
                    </el-table-column>
                    <el-table-column prop="nums" label="领料数量" width="80">
                    </el-table-column>
                    <el-table-column prop="unit" label="单位" width="80">
                    </el-table-column>
                    <el-table-column prop="warehouse" label="领料仓库" width="180">
                    </el-table-column>
                    <el-table-column prop="emp" label="仓管员" width="150">
                    </el-table-column>

                    <el-table-column prop="status" label="状态" width="80">

                        <template slot-scope="scope">
                            <span v-if="scope.row.status == '0'" style="color: red;">未审批</span>
                            <span v-if="scope.row.status == '1'" style="color: rgb(9, 209, 109);">已审批</span>
                            <span v-if="scope.row.status == '2'" style="color: rgb(44, 39, 205);">已领取</span>
                            <span v-if="scope.row.status == '3'" style="color: rgb(173, 16, 157);">已领完</span>
                            <!-- {
    
    {
    
     scope.row.status == 1 ? '已上架' : '下架' }} -->
                        </template>
                    </el-table-column>
                    <el-table-column label="操作">
                        <template slot-scope="scope">
                            <el-button type="primary" icon="el-icon-edit" circle
                                @click="loadBtn(scope.row.id)">审批</el-button>
                        </template>
                    </el-table-column>
                </el-table>

            </el-col>
        </el-row>
        <el-row>
            <el-col :span="24">
                <div class="block">
                    <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
                        :current-page.sync="currentPage" :page-sizes="[3, 5, 10]" :page-size="3"
                        layout="total,sizes, prev, pager, next" :total=total>
                    </el-pagination>
                </div>
            </el-col>
        </el-row>


        <!-- 新增原材料入库弹窗 ******* -->
        <el-dialog title="添加原材料单" :visible.sync="b">
            <el-form>
                <el-row>
                    <el-col :span="12">

                        <el-form-item label="原料名称" clearable>
                            <el-select v-model="shoppingNoId" placeholder="请选择"
                                style="width: 355px;margin-right:px;margin-left:px" @change="selectBuyNo">
                                <el-option v-for="item in shoppingIdToNo" :key="item.label" :label="item.label"
                                    :value="item.label">
                                </el-option>
                            </el-select>
                        </el-form-item>

                        <el-form-item label="数量" :label-width="formLabelWidth">
                            <el-input v-model="goods.nums" autocomplete="off"></el-input>
                        </el-form-item>



                        <el-form-item label="单位" clearable>
                            <el-select v-model="goods.unit" placeholder="请选择商品单位"
                                style="width: 355px;margin-right:px;margin-left:px">
                                <el-option v-for="item in commondata.unit" :key="item.value" :label="item.label"
                                    :value="item.value">
                                </el-option>
                            </el-select>
                        </el-form-item>

                        <el-form-item label="中心仓库" clearable>
                            <el-select v-model="goods.warehouse" placeholder="请选择" disabled
                                style="width: 355px;margin-right:px;margin-left:px">
                                <el-option v-for="item in commondata.warehouse" :key="item.value" :label="item.label"
                                    :value="item.value">
                                </el-option>
                            </el-select>
                        </el-form-item>

                        <el-form-item label="领料仓库" clearable>
                            <el-select v-model="goods.storehouse" placeholder="请选择"
                                style="width: 355px;margin-right:px;margin-left:px">
                                <el-option v-for="item in commondata.storehouse" :key="item.value" :label="item.label"
                                    :value="item.value">
                                </el-option>
                            </el-select>
                        </el-form-item>


                    </el-col>
                </el-row>

            </el-form>

            <div slot="footer" class="dialog-footer">
                <el-button @click="b = false">取 消</el-button>
                <el-button type="primary" @click="addGoods()">确 定</el-button>
            </div>
        </el-dialog>



    </div>
</template>

<script>
export default {
    
    
    data() {
    
    
        return {
    
    
            findGoodsParams: {
    
    
                "pickNo": ""
                , "name": ""
                , "nums": ""
                , "storehouseId": ""
                , "status": ""
            },
            // 批量删除的id
            deleteIds: [],


            tableData: [
                {
    
    
                    "id": 1,
                    "pickNo": "PICK2023090818003927",
                    "name": "富士苹果",
                    "nums": "350.00",
                    "unit": "千克",
                    "warehouse": "南京江宁生鲜1号仓库",
                    "storehouseId": 2,
                    "emp": "领料操作员1李四",
                    "status": "0"
                }
            ],

            // 分页相关的参数
            total: 10,
            currentPage: 1,
            pageSize: 3,

            options: [
                {
    
     value: '0', label: '未审批' },
                {
    
     value: '1', label: '审批通过' },
                {
    
     value: '2', label: '已领取' },
                {
    
     value: '3', label: '已领完' },
            ],

            commondata: {
    
    
                "storehouse": [
                    {
    
    
                        "value": 1, "label": "南京中心仓库南京总统府"
                    },],
                "status": [
                    {
    
     "value": 0, "label": "未审批" },
                    {
    
     "value": 1, "label": "审批通过" }]
            },


            // 新增商品弹窗控制变量
            b: false,



            // 新增的入库信息 goods shoppingNoId
            goods: {
    
    
                "name":"富士苹果",
                "nums":"200.56",
                "unit":"1",
                // 中心仓库
                "warehouse":"1", 
                // 目标仓库
                "storehouse":"2"
            },

            formLabelWidth: '100px',

            
            // 新增原材料入库清单
            addRawTab:[{
    
    
                "name": {
    
    
                    "unit": "",
                    "warehouse": {
    
    
                        "1": 1000.20
                    }
                }},
            ],

            // 和上面进行比对
            shoppingNoId:"",

            // 选择采购清单的下拉框
            shoppingIdToNo: [
                    {
    
    "label": "BUY2023091317093927"},],
        }

    },
    methods: {
    
    
        handleSizeChange(val) {
    
    
            console.log(`每页 ${
    
    val} 条`);
            this.pageSize = val
            this.findGoods()
        },
        handleCurrentChange(val) {
    
    
            console.log(`当前页: ${
    
    val}`);
            this.pageNum = val
            this.findGoods()
        },
        findGoods() {
    
    
            let params = {
    
    }
            params.pageNum = this.currentPage
            params.pageSize = this.pageSize
            params.param = this.findGoodsParams
            console.log(params)
            this.$axios.post("/api/warehouse/findPagePickRaw", params)
                .then(response => {
    
    
                    let resp = response.data
                    console.log(resp)
                    if (resp.resultCode.code == 20000) {
    
    
                        this.tableData = resp.results.list
                        this.total = resp.results.total
                        this.currentPage = resp.results.pageNum
                        this.pageSize = resp.results.pageSize
                    }
                })
        },

        reFindGoods() {
    
    
            let params = {
    
    }

            this.findGoodsParams = {
    
    
                "pickNo": ""
                , "name": ""
                , "nums": ""
                , "storehouseId": ""
                , "status": ""
            },

            params.pageNum = this.currentPage
            params.pageSize = this.pageSize
            params.param = this.findGoodsParams

            console.log(params)
            this.$axios.post("/api/warehouse/findPagePickRaw", params)
                .then(response => {
    
    
                    let resp = response.data
                    console.log(resp)
                    if (resp.resultCode.code == 20000) {
    
    
                        this.tableData = resp.results.list
                        this.total = resp.results.total
                        this.currentPage = resp.results.pageNum
                        this.pageSize = resp.results.pageSize
                    }
                })
        },

        handleSelectionChange(val) {
    
    
            this.deleteIds = []
            console.log(val);
            val.forEach(e => this.deleteIds.push(e.id))
        },

        // 批量修改领取中
        batchPickDoing() {
    
    
            console.log(this.deleteIds)
            this.$axios.put("/api/warehouse/batchDoingPickMaterial", this.deleteIds)
                .then(response => {
    
    
                    let resp = response.data
                    console.log(resp)
                    if (resp.resultCode.code == 20000) {
    
    
                        this.findGoods()
                    } else {
    
    
                        alert(resp.results)
                    }
                })
        },

        // 批量修改已领完
        batchPickDown() {
    
    
            console.log(this.deleteIds)
            this.$axios.put("/api/warehouse/batchDownPickMaterial", this.deleteIds)
                .then(response => {
    
    
                    let resp = response.data
                    console.log(resp)
                    if (resp.resultCode.code == 20000) {
    
    
                        this.findGoods()
                    } else {
    
    
                        alert(resp.results)
                    }
                })
        },

        // 批量审批通过
        batchDelete() {
    
    
            console.log(this.deleteIds)
            this.$axios.put("/api/warehouse/batchPassPickMaterial", this.deleteIds)
                .then(response => {
    
    
                    let resp = response.data
                    console.log(resp)
                    if (resp.resultCode.code == 20000) {
    
    
                        this.findGoods()
                    } else {
    
    
                        alert(resp.results)
                    }
                })
        },

        // 逐一审批通过
        loadBtn(val) {
    
    
            console.log(val)
            const deleteIds = []
            deleteIds.push(val)
            console.log(deleteIds)
            this.$axios.put("/api/warehouse/batchPassPickMaterial", deleteIds)
                .then(response => {
    
    
                    let resp = response.data
                    console.log(resp)
                    if (resp.resultCode.code == 20000) {
    
    
                        this.findGoods()
                    } else {
    
    
                        alert(resp.results)
                    }
                })
        },

        // 获取公共数据
        getCommonData() {
    
    
            this.$axios.get("/api/common/pickCommon")
                .then(response => {
    
    
                    let resp = response.data
                    
                    if (resp.resultCode.code == 20000) {
    
    
                        this.commondata = resp.results
                        console.log("#############")
                        console.log(this.commondata)
                    }
                })
        },

        addGoodsBtn() {
    
    
            this.b = true
            this.goods = {
    
    } 
            this.shoppingIdToNo = []
            this.$axios.get('/api/warehouse/findRawNames')
                .then(res => {
    
    
                if (res.data.resultCode.code == 20000) {
    
    
                    this.addRawTab = res.data.results
                    console.log(this.addRawTab)
                    this.addRawTab.forEach(r=>{
    
    
                        this.shoppingIdToNo.push(
                            {
    
    "label": Object.keys(r)[0]}
                        )
                    })
                    console.log(this.shoppingIdToNo)
                }
            })

        },
        // 弹出的新增窗口的添加
        addGoods() {
    
    
            console.log("#############")
            console.log(this.goods)
            this.$axios.post('/api/warehouse/addPickRaw', this.goods)
                .then(res => {
    
    
                    console.log("&&&&&")
                    console.log(res.data)
                    if (res.data.resultCode.code == 20000) {
    
    
                        alert('添加成功')
                        this.findGoods()
                    }else{
    
    
                        alert('添加失败')
                    }
                }),
                this.b = false
        },

        // 绑定下拉框的选择事件
        selectBuyNo(){
    
    
            console.log("change")
            const goodsTemp = this.addRawTab.filter(r=> Object.keys(r)[0] == this.shoppingNoId)[0]
            console.log(goodsTemp)
            const nameTmp = Object.keys(goodsTemp)[0]
            const nextTmp = Object.values(goodsTemp)[0].warehouse
            const keyTmp = Object.keys(nextTmp)[0]
            console.log(nextTmp)
            this.goods={
    
    
                name:nameTmp,
                nums:nextTmp[keyTmp],
                unit:Object.values(goodsTemp)[0].unit+"",
                warehouse:Object.keys(nextTmp)[0]
            }
            console.log(this.goods)
        },
    },
    created() {
    
    
        this.findGoods()
        this.getCommonData()
    }

}

</script>

Resumir

1. Apresentar o processo de sincronização de banco de dados e cache baseado no canal;
2. Fornecer o código fonte do núcleo diamante;

Acho que você gosta

Origin blog.csdn.net/Pireley/article/details/133548639
Recomendado
Clasificación