<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://purl.org/rss/1.0/"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel rdf:about="https://blog.anlucky.cn/index.php/feed/rss/author/1/">
<title>LuckyDu - 都依凡</title>
<link>https://blog.anlucky.cn/index.php/author/1/</link>
<description>都依凡</description>
<items>
<rdf:Seq>
<rdf:li resource="https://blog.anlucky.cn/index.php/WebProject/242"/>
<rdf:li resource="https://blog.anlucky.cn/index.php/WebProject/240"/>
<rdf:li resource="https://blog.anlucky.cn/index.php/programming/239"/>
<rdf:li resource="https://blog.anlucky.cn/index.php/programming/web/236"/>
<rdf:li resource="https://blog.anlucky.cn/index.php/WebProject/235"/>
<rdf:li resource="https://blog.anlucky.cn/index.php/mes/cell/234"/>
<rdf:li resource="https://blog.anlucky.cn/index.php/programming/tools/223"/>
<rdf:li resource="https://blog.anlucky.cn/index.php/programming/java/215"/>
<rdf:li resource="https://blog.anlucky.cn/index.php/programming/java/213"/>
<rdf:li resource="https://blog.anlucky.cn/index.php/mes/Apriso/208"/>
</rdf:Seq>
</items>
</channel>
<item rdf:about="https://blog.anlucky.cn/index.php/WebProject/242">
<title>宝塔 - Vue Press 部署</title>
<link>https://blog.anlucky.cn/index.php/WebProject/242</link>
<dc:date>2025-05-13T10:22:34+08:00</dc:date>
<description>Vue Press 官网：首页 | VuePress这里我使用了Vue Press 主题：Plume 主题 进行编写文档对应的其他主体可以去官网：主题 | VuePress 获取宝塔-添加静态网站添加完网站之后会生成对应的网站目录，进入目录，点击 终端宝塔-命令行安装# pnpm 命令
pnpm create vuepress-theme-plume@latest
# yarn 命令
yarn create vuepress-theme-plume@latest
# npm 命令
npm create vuepress-theme-plume@latest安装时回答问题┌  Welcome to VuePress and vuepress-theme-plume !
│
◇  Select a language to display / 选择显示语言
│  简体中文
│
◇  您想在哪里初始化 VuePress？
│  ./my-project
│
◇  站点名称：
│  My Vuepress Site
│
◇  站点描述信息：
│  My Vuepress Site Description
│
◇  是否使用多语言？
│  No
│
◇  请选择站点默认语言
│  简体中文
│
◇  是否使用 TypeScript？
│  Yes
│
◇  请选择打包工具
│  Vite
│
◇  部署方式：
│  Custom
│
◇  是否初始化 git 仓库？
│  Yes
│
◇  是否安装依赖？
│  Yes
│
◇   🎉 创建成功!
│
└  🔨 执行以下命令即可启动：
      cd ./my-project
      pnpm run docs:dev手动安装参考官网：安装/使用 | Plume 主题运行构建对应安装目录：package.json 查看构建指令pnpm run docs:build构建完成后的代码在：/my-project/docs/.vuepress/dist设置运行目录打开域名打开网站即可看到效果</description>
</item>
<item rdf:about="https://blog.anlucky.cn/index.php/WebProject/240">
<title>阿里云CDN配置问题-忽略参数</title>
<link>https://blog.anlucky.cn/index.php/WebProject/240</link>
<dc:date>2025-05-13T10:13:29+08:00</dc:date>
<description>问题描述场景：图片链接中携带了用户登录的token，不同用户的token是不一样的，在不同用户时，因Token不一样，缓存的链接Key就不一致，CDN缓存将不会被命中解决方式阿里云CDN控制台 -&gt; 域名管理 -&gt; 选择要配置的域名 -&gt; 性能优化 -&gt; 忽略参数如此这样配置就可以实现了大概意思就是在缓存时不会携带  ？ 之后的的所有参数，使用 uri 进行做为缓存key但是在回源的时候，会完整的保留原始链接进行回源，就是你的URL是什么样子就是什么样子，然后再使用uri进行设置缓存</description>
</item>
<item rdf:about="https://blog.anlucky.cn/index.php/programming/239">
<title>微信小程序检查更新</title>
<link>https://blog.anlucky.cn/index.php/programming/239</link>
<dc:date>2025-04-29T11:07:44+08:00</dc:date>
<description>官方文档：小程序运行时 / 更新机制小程序运行时 /更新机制小程序更新机制开发者在管理后台发布新版本的小程序之后，微信客户端会有若干个时机去检查本地缓存的小程序有没有新版本，并进行小程序的代码包更新。但如果用户本地有小程序的历史版本，此时打开的可能还是旧版本。1. 启动时同步更新在以下情况下，小程序启动时会同步更新代码包。同步更新会阻塞小程序的启动流程，影响小程序的启动耗时。如果更新失败或超时，为了保障小程序的可用性，还是会使用本地版本打开。定期检查发现版本更新微信运行时，会定期检查最近使用的小程序是否有更新。如果有更新，下次小程序启动时会同步进行更新，更新到最新版本后再打开小程序，尽可能保证用户能够尽快使用小程序的最新版本。用户长时间未使用小程序用户长时间未使用小程序时，为保障小程序版本的实时性，会强制同步检查版本更新，更新到最新版本后再打开小程序。若用户处于弱网环境、下载最新版本失败等情况下，仍会启动本地的较低版本。2. 启动时异步更新即使启动前未发现更新，小程序每次冷启动时，都会异步检查是否有更新版本。如果发现有新版本，将会异步下载新版本的代码包。但当次启动仍会使用客户端本地的旧版本代码，即新版本的小程序需要等下一次冷启动才会使用。开发者手动触发更新在启动时异步更新的情况下，如果开发者希望立刻进行版本更新，可以使用 wx.getUpdateManager API 进行处理。在有新版本时提示用户重启小程序更新新版本。const updateManager = wx.getUpdateManager()

updateManager.onCheckForUpdate(function (res) {
  // 请求完新版本信息的回调
  console.log(res.hasUpdate)
})

updateManager.onUpdateReady(function () {
  wx.showModal({
    title: &#039;更新提示&#039;,
    content: &#039;新版本已经准备好，是否重启应用？&#039;,
    success(res) {
      if (res.confirm) {
        // 新的版本已经下载好，调用 applyUpdate 应用新版本并重启
        updateManager.applyUpdate()
      }
    }
  })
})

updateManager.onUpdateFailed(function () {
  // 新版本下载失败
})3. 小程序管理后台的相关设置小程序开发者可以通过在小程序管理后台进行设置，影响更新逻辑。优先使用本地版本设置若开发者判断某些较新的小程序版本无需强制用户同步更新到最新版本，可以在小程序管理后台「设置」-「版本设置」-「优先使用本地版本设置」中进行设置，设置后若同步更新时检查本地版本不低于该版本，则优先使用本地版本，同时将会异步下载最新版本的代码包。小程序最低可用版本设置若开发者判断某些较旧的小程序版本服务不再可用，可以在小程序管理后台「设置」-「版本设置」-「小程序最低可用版本设置」中进行设置。设置后若同步更新时检查本地版本低于该版本，则无法打开，并继续尝试下载最新版本、若异步更新，则会在检查到更新后提示用户重启小程序更新新版本。注意开发者在后台发布新版本之后，无法立刻影响到所有现网用户，正常情况下，在全量发布 24 小时之后，新版本可以覆盖 99% 以上的用户。小程序管理后台的「优先使用本地版本设置」和「小程序最低可用版本设置」不会影响同步更新与异步更新的选择。</description>
</item>
<item rdf:about="https://blog.anlucky.cn/index.php/programming/web/236">
<title>Uni-APP 组件-抽奖轮盘</title>
<link>https://blog.anlucky.cn/index.php/programming/web/236</link>
<dc:date>2025-04-15T17:57:59+08:00</dc:date>
<description>组件预览创建commponents/lottery/index.vue 文件输入如下代码轮盘抽检组件&lt;template&gt;
    &lt;view class=&quot;main&quot;&gt;
        &lt;view v-if=&quot;options.length &gt; 0&quot; class=&quot;canvas-container&quot;&gt;
            &lt;canvas canvas-id=&quot;canvas&quot; id=&quot;canvas&quot; :style=&quot;canvasStyle&quot; /&gt;

            &lt;canvas canvas-id=&quot;canvasBtn&quot; id=&quot;canvasBtn&quot; class=&quot;canvasBtn&quot; :style=&quot;canvasStyle&quot; /&gt;

            &lt;cover-view @tap=&quot;playReward&quot; :class=&quot;[&#039;canvas-btn&#039;, { &#039;isLottery&#039;: isLottery }]&quot;
                :style=&quot;{ backgroundColor: centerBtnColor }&quot;&gt;
                {{ centerBtnText }}
            &lt;/cover-view&gt;
        &lt;/view&gt;
        &lt;view v-else class=&quot;empty-tip&quot;&gt;
            &lt;text&gt;暂无抽奖选项&lt;/text&gt;
        &lt;/view&gt;
        &lt;view v-if=&quot;showBtn&quot; class=&quot;btn-container&quot;&gt;
            &lt;button type=&quot;primary&quot; :disabled=&quot;isLottery&quot; @click=&quot;playReward&quot;&gt;{{ btnTitle }}&lt;/button&gt;
        &lt;/view&gt;
    &lt;/view&gt;
&lt;/template&gt;
&lt;script&gt;
var ctx = null;
export default {

    props: {
        // 弹窗内容 ，当 turnModalContent=【】时，默认弹窗内容为抽奖结果，并且不展示标题
        turnModalContent: {
            type: Array,
            default: () =&gt; []
        },
        // 减速，值越小，减速效果越明显 turnReduceSpeed
        turnReduceSpeed: {
            type: Number,
            default: 50
        },
        // 表示转速：表示再转多少圈再进行抽奖
        turnCircle: {
            type: Number,
            default: 0
        },
        // 画布宽度
        width: {
            type: Number,
            default: 100,
        },
        // 画布高度
        height: {
            type: Number,
            default: 100
        },
        // 画布内字体大小
        fontSize: {
            type: Number,
            default: 18
        },
        // 钩子函数，抽奖开始前执行，返回值为选项列表下标，若返回值为-1，则进行随机抽奖
        setWinnerFn: {
            type: Function,
            default: null,
        },
        // // 钩子函数，抽奖开始前执行
        beforePlay: {
            type: Function,
            default: null,
        },
        // // 钩子函数，抽奖结束后执行
        afterPlay: {
            type: Function,
            default: null,
        },
        // 如果 true，则 使用组件默认的选项数据
        isUseDefaultOptions: {
            type: Boolean,
            default: false
        },
        // 选项列表
        data: {
            type: Array,
            default: () =&gt; []
        },
        // 是否要展示开始按钮
        showBtn: {
            type: Boolean,
            default: false,
        },
        // 按钮文本
        btnTitle: {
            type: String,
            default: &quot;开始&quot;
        },
        // 是否显示结果弹窗
        showResultModal: {
            type: Boolean,
            default: true
        },
        // 中心按钮文本
        centerBtnText: {
            type: String,
            default: &quot;GO&quot;
        },
        // 中心按钮颜色
        centerBtnColor: {
            type: String,
            default: &quot;#ffffff&quot;
        }
    },
    data() {
        return {
            options: [{
                id: 1, // 唯一id
                name: &#039;水饺&#039;, // 名称
                // &quot;weight&quot;: 50, //  中奖权重，0-100
                img: &#039;&#039;, // 展示图片
                color: &quot;#f6e174&quot; // 轮盘区域底色
            },
            {
                id: 2,
                name: &#039;火锅&#039;,
                img: &#039;&#039;,
                color: &quot;#94494d&quot;
            },
            {
                id: 3,
                name: &#039;川菜&#039;,
                img: &#039;&#039;,
                color: &quot;#ffaa7f&quot;
            },
            {
                id: 4,
                name: &#039;麻辣烫&#039;,
                img: &#039;&#039;,
                color: &quot;#a48342&quot;
            },
            {
                id: 5,
                name: &#039;炸鸡汉堡&#039;,
                img: &#039;&#039;,
                color: &quot;#a25f81&quot;
            },
            {
                id: 6,
                name: &#039;重庆小面&#039;,
                img: &#039;&#039;,
                color: &quot;#98e2e2&quot;
            },
            {
                id: 7,
                name: &#039;酸辣粉&#039;,
                img: &#039;&#039;,
                color: &quot;#aaaa00&quot;
            },
            {
                id: 8,
                name: &#039;面条&#039;,
                img: &#039;&#039;,
                color: &quot;#648f76&quot;
            },
            {
                id: 9,
                name: &#039;汤河粉&#039;,
                img: &#039;&#039;,
                color: &quot;#40b3ff&quot;
            },
            {
                id: 10,
                name: &#039;猪脚饭&#039;,
                img: &#039;&#039;,
                color: &quot;#ffaaff&quot;
            },
            {
                id: 11,
                name: &#039;烧鸭饭&#039;,
                img: &#039;&#039;,
                color: &quot;#5555ff&quot;
            },
            {
                id: 12,
                name: &#039;白切鸡&#039;,
                img: &#039;&#039;,
                color: &quot;#ff90cf&quot;
            },
            {
                id: 13,
                name: &#039;烧鸡饭&#039;,
                img: &#039;&#039;,
                color: &quot;#55aa7f&quot;
            },
            {
                id: 14,
                name: &#039;肥肠面&#039;,
                img: &#039;&#039;,
                color: &quot;#4f95ff&quot;
            },
            {
                id: 15,
                name: &#039;炒饭&#039;,
                img: &#039;&#039;,
                color: &quot;#a509aa&quot;
            },
            {
                id: 16,
                name: &#039;黄焖鸡米饭&#039;,
                img: &#039;&#039;,
                color: &quot;#aaaa00&quot;
            },
            {
                id: 17,
                name: &#039;皮蛋瘦肉粥&#039;,
                img: &#039;&#039;,
                color: &quot;#ff52d1&quot;
            },
            {
                id: 18,
                name: &#039;沙县小吃&#039;,
                img: &#039;&#039;,
                color: &quot;#944ade&quot;
            },
            {
                id: 19,
                name: &#039;焖锅&#039;,
                img: &#039;&#039;,
                color: &quot;#43c900&quot;
            },
            {
                id: 20,
                name: &#039;披萨&#039;,
                img: &#039;&#039;,
                color: &quot;#7cbaba&quot;
            }
            ],
            isLottery: false, // 是否正在抽奖
            winnerIndex: -1, // 中奖索引
            isInitialized: false // 是否已初始化
        };
    },
    computed: {
        canvasStyle() {
            return &quot;width:&quot; + this.width + &quot;px;; height:&quot; + this.height + &quot;px;&quot;;
        },
    },
    watch: {
        // 监听数据变化，重新初始化
        data: {
            handler(newVal) {
                if (newVal &amp;&amp; newVal.length &gt; 0 &amp;&amp; !this.isUseDefaultOptions) {
                    this.init();
                }
            },
            deep: true
        }
    },
    methods: {
        // 处理文本，根据长度进行截断或调整
        processText(text, maxLength) {
            if (!text) return &#039;&#039;;

            // 如果文本长度超过最大长度，截断并添加省略号
            if (text.length &gt; maxLength) {
                return text.substring(0, maxLength - 2) + &#039;..&#039;;
            }
            return text;
        },
        // 获取文本显示的字体大小
        getTextFontSize(text, baseSize) {
            // 根据文本长度动态调整字体大小
            if (!text) return baseSize;

            if (text.length &gt; 6) {
                // 文本较长时，逐步减小字体
                const reduction = Math.min(Math.floor(text.length / 2), 8);
                return Math.max(baseSize - reduction, 10); // 最小字体为10
            }
            return baseSize;
        },


        async playReward() {
            if (this.isLottery) {
                return
            }
            let len = this.options.length
            if (len == 0) {
                console.error(&quot;抽奖选项为空，无法开始抽奖&quot;);
                return;
            }
            this.isLottery = true
            console.log(&quot;开始抽奖&quot;)
            // 触发beforePlay事件
            if (this.beforePlay) {
                this.beforePlay();
            }
            this.$emit(&quot;beforePlay&quot;);
            // 获取中奖索引
            let num = -1;
            // 使用setWinnerFn获取中奖索引
            if (this.setWinnerFn &amp;&amp; typeof this.setWinnerFn === &#039;function&#039;) {
                try {
                    // 修复调用方式
                    num = this.setWinnerFn(this.options);
                    if (num === undefined || num &lt; 0 || num &gt;= len) {
                        console.warn(&quot;setWinnerFn返回的索引无效，将使用随机抽奖&quot;);
                        num = -1;
                    }
                } catch (error) {
                    console.error(&quot;调用setWinnerFn出错:&quot;, error);
                    num = -1;
                }
            }
            if (num &lt; 0) {
                // 进行权重抽奖
                let optionIndex = this.lotteryWeight(this.options)
                if (optionIndex !== undefined &amp;&amp; optionIndex &gt;= 0) {
                    num = optionIndex
                } else {
                    // 没有自动抽奖结果 &amp;&amp; 没有定义选项权重，则进行随机数抽奖
                    num = Math.floor(Math.random() * len)
                }
            }
            this.winnerIndex = num;
            try {
                const result = await this.roateCanvas(num)
                console.log(&quot;抽奖结果：&quot;, result.name)
                this.isLottery = false
                // 是否显示结果弹窗
                if (this.showResultModal) {
                    let title = &quot;&quot;
                    let content = result.name
                    if (this.turnModalContent.length &gt; 0) {
                        // 若设置了 content ，则随机取一个 content 内容，并且 title 将展示为抽奖结果 
                        title = result.name
                        content = this.turnModalContent[Math.floor(Math.random() * this.turnModalContent.length)]
                    }
                    uni.showModal({
                        confirmText: &quot;确定&quot;,
                        showCancel: false,
                        title: title,
                        content: content,
                        success: (res) =&gt; {
                            if (res.confirm) {
                                console.log(&#039;用户点击确定&#039;);
                                // 调用钩子函数
                                if (this.afterPlay) {
                                    this.afterPlay(result);
                                }
                                this.$emit(&quot;afterPlay&quot;, result)
                            }
                        }
                    })
                } else {
                    // 直接触发afterPlay事件
                    if (this.afterPlay) {
                        this.afterPlay(result);
                    }
                    this.$emit(&quot;afterPlay&quot;, result)
                }
            } catch (error) {
                console.error(&quot;抽奖过程出错:&quot;, error);
                this.isLottery = false;
                uni.showToast({
                    title: &#039;抽奖失败，请重试&#039;,
                    icon: &#039;none&#039;
                });
            }

        },

        initBtnCanvas() {
            try {
                let angleTo = 0
                let ctx = uni.createCanvasContext(&quot;canvasBtn&quot;, this);
                // 圆中心点的坐标 x： 宽度的一半
                let center_x = this.width / 2;
                // 圆中心点的坐标 y： 高度的一半
                let center_y = this.height / 2;

                // 先清除画布上在该矩形区域内的内容
                ctx.clearRect(0, 0, this.width, this.height);

                ctx.translate(center_x, center_y);

                // 画中心点圆
                ctx.beginPath();
                ctx.moveTo(0, -50); // 三角形顶点坐标
                ctx.lineTo(-20, 10); // 左下角坐标
                ctx.lineTo(20, 10); // 右下角坐标
                ctx.setFillStyle(&quot;#ff0000&quot;);
                ctx.fill();
                ctx.draw();
            } catch (error) {
                console.error(&quot;初始化按钮画布失败:&quot;, error);
            }
        },
        initCanvas: function (ctx, angleTo) {
            try {
                const len = this.options.length; //数组长度
                if (len == 0) {
                    console.warn(&quot;options len == 0&quot;);
                    return;
                }

                if (!angleTo) {
                    angleTo = 0
                }

                // 圆中心点的坐标 x： 宽度的一半
                let center_x = this.width / 2;
                // 圆中心点的坐标 y： 高度的一半
                let center_y = this.height / 2;
                // 圆的弧度的总度数，2π表示画圆
                let totalAngle = 2 * Math.PI;
                // 平均一个选项占用的孤度数
                let avgAngle = totalAngle / len;

                let radius = center_x - 14;
                let baseFontSize = this.getFontSize();

                // 先清除画布上在该矩形区域内的内容
                ctx.clearRect(0, 0, this.width, this.height);

                ctx.translate(center_x, center_y);
                ctx.setLineWidth(14);
                ctx.save();

                // 画外圆
                ctx.rotate(angleTo * Math.PI / 180);
                var beginAngle = 2 * Math.PI / 360 * (-90);
                ctx.setStrokeStyle(&quot;#ffffff&quot;);
                ctx.arc(0, 0, radius - 3, 0, Math.PI * 2);
                ctx.stroke();

                // 划分区域，并且填充颜色
                ctx.setLineWidth(0.1);
                beginAngle = 2 * Math.PI / 360 * (-90);
                //绘制填充形状
                for (var i = 0; i &lt; len; i++) {
                    ctx.save();
                    ctx.beginPath();
                    ctx.moveTo(0, 0);
                    ctx.setStrokeStyle(this.options[i].color);
                    ctx.setFillStyle(this.options[i].color);

                    ctx.arc(0, 0, radius, beginAngle, beginAngle + avgAngle, false);
                    ctx.fill();
                    ctx.save();
                    beginAngle = beginAngle + avgAngle;
                }

                // 绘制选项文字
                beginAngle = 0;
                for (var i = 0; i &lt; len; i++) {
                    // 根据奖项数量和文本长度调整文本位置和大小
                    let textDistance = -(center_x / 2) - 25;

                    // 奖项过多时，文本更靠近中心
                    if (len &gt; 10) {
                        textDistance = -(center_x / 2) - 15;
                    }
                    if (len &gt; 15) {
                        textDistance = -(center_x / 2) - 5;
                    }

                    // 处理文本，根据奖项数量决定最大长度
                    let maxTextLength = len &gt; 12 ? 4 : (len &gt; 8 ? 6 : 8);
                    let processedText = this.processText(this.options[i].name, maxTextLength);

                    // 根据文本长度调整字体大小
                    let fontSize = this.getTextFontSize(processedText, baseFontSize);

                    //绘制旋转文字
                    ctx.rotate((beginAngle + (avgAngle * 0.5))); //顺时针旋转
                    ctx.setTextAlign(&quot;center&quot;);
                    ctx.setFillStyle(&quot;#FFFFFF&quot;);
                    ctx.setFontSize(fontSize);
                    ctx.fillText(processedText, 0, textDistance);

                    ctx.restore();
                    beginAngle = beginAngle + avgAngle;
                }
                ctx.save();
                // 画中心点圆
                ctx.beginPath();
                ctx.arc(0, 0, 15, 0, Math.PI * 2); // 15 为中心点圆的半径
                ctx.setFillStyle(&quot;#FFFFFF&quot;);
                ctx.fill();
                ctx.draw();

                this.isInitialized = true;
            } catch (error) {
                console.error(&quot;初始化画布失败:&quot;, error);
                this.isInitialized = false;
            }
        },
        // 根据设置的权重进行抽奖
        lotteryWeight(prizes) {
            console.log(&quot;进行权重抽奖&quot;)
            if (!prizes || prizes.length === 0) {
                console.log(&quot;奖品列表为空&quot;)
                return -1
            }

            // 计算总权重和有效奖品
            let totalWeight = 0
            const validPrizes = []

            // 筛选有效奖品并计算总权重
            for (let index = 0; index &lt; prizes.length; index++) {
                const prize = prizes[index]
                const weight = Number(prize.weight)

                // 只有权重大于0的奖品才参与抽奖
                if (weight &amp;&amp; weight &gt; 0) {
                    totalWeight += weight
                    validPrizes.push({
                        index,
                        weight,
                        name: prize.name
                    })
                }
            }

            // 如果没有有效奖品，返回-1表示随机抽奖
            if (validPrizes.length === 0 || totalWeight === 0) {
                console.log(&quot;没有设置有效权重的奖品，将进行随机抽奖&quot;)
                return -1
            }

            // 生成0到总权重之间的随机数
            const random = Math.random() * totalWeight
            console.log(&quot;权重抽奖随机数:&quot;, random, &quot;总权重:&quot;, totalWeight)

            // 根据权重区间确定中奖奖品
            let accumulatedWeight = 0
            for (const prize of validPrizes) {
                accumulatedWeight += prize.weight
                if (random &lt; accumulatedWeight) {
                    console.log(&quot;权重抽奖奖品 &quot;, prizes[prize.index].name, &quot; 中奖，权重:&quot;, prize.weight)
                    return prize.index
                }
            }
            // 保底返回最后一个有效奖品
            console.log(&quot;未找到匹配奖品，进行随机抽奖&quot;)
            return -1
        },
        // 旋转画布，num 表示选项 options 的下标
        roateCanvas(num) {
            let len = this.options.length
            let angle = 360 / len;
            angle = num * angle + angle / 2;
            angle = angle || 0;
            angle = 360 - angle;
            angle += 360 * 5;
            if (this.turnCircle &gt; 0) {
                let turnCircle = this.turnCircle
                // 最多只能转 10 圈
                if (turnCircle &gt; 10) {
                    turnCircle = 10
                }
                angle += 360 * turnCircle;
            }
            let that = this;
            let count = 1;
            // 减速，值越小，减速效果越明显 
            let turnReduceSpeed = this.turnReduceSpeed
            if (turnReduceSpeed == 0) {
                turnReduceSpeed = 1
            }
            let baseStep = turnReduceSpeed;
            // 起始滚动速度
            let baseSpeed = 1;
            let result = {}
            return new Promise((resolve, reject) =&gt; {
                let timer = setInterval(function () {
                    // console.log(&quot;count = &quot;， count);
                    that.initCanvas(that.ctx, count);
                    if (count == angle) {
                        clearInterval(timer);
                        result = that.options[num];
                        resolve(result)
                    }
                    count = count + baseStep * (((angle - count) / angle) &gt; baseSpeed ? baseSpeed :
                        ((angle -
                            count) / angle)) + 0.1;

                    if (angle - count &lt; 0.5) {
                        count = angle;
                    }
                }, 25);
            });
        },
        getFontSize() {
            let fontSize = this.fontSize
            if (this.options.length &gt; 10) {
                if (this.fontSize &gt;= 18) {
                    fontSize = this.fontSize - (this.options.length - 10)
                }
            }

            return fontSize
        },
        // 生成随机颜色
        genRandColor() {
            // 生成随机的 RGB 值
            var r = Math.floor(Math.random() * 256); // 0 到 255 之间的随机数
            var g = Math.floor(Math.random() * 256);
            var b = Math.floor(Math.random() * 256);

            // 将 RGB 值转换为 Hex 颜色表示
            var hexColor = &quot;#&quot; + this.componentToHex(r) + this.componentToHex(g) + this.componentToHex(b);

            return hexColor;
        },
        componentToHex(c) {
            var hex = c.toString(16);
            return hex.length === 1 ? &quot;0&quot; + hex : hex;
        },
        initOptions: function () {
            try {
                let defaultOptions = JSON.parse(JSON.stringify(this.options)); // 深拷贝默认选项

                if (this.isUseDefaultOptions) {
                    // 使用默认数据
                    console.log(&quot;使用默认选项数据&quot;);
                } else if (this.data &amp;&amp; this.data.length &gt; 0) {
                    console.log(&quot;使用传入的选项数据, 长度:&quot;, this.data.length);
                    this.options = JSON.parse(JSON.stringify(this.data)); // 深拷贝传入数据
                } else {
                    console.warn(&quot;未提供有效的选项数据，将使用默认选项&quot;);
                }

                // 所有默认的颜色
                let allDefColorArr = defaultOptions.map(item =&gt; item.color);

                // 找到最大的 id
                let maxId = 0;
                this.options.forEach(item =&gt; {
                    if (item.id &amp;&amp; item.id &gt; maxId) {
                        maxId = item.id;
                    }
                });

                // 填充 id，确保 id 唯一
                var existIds = []
                for (var i = 0; i &lt; this.options.length; i++) {
                    let item = this.options[i]
                    if (item[&#039;id&#039;] == undefined || item.id == 0 || existIds.includes(item.id)) {
                        // id 不存在，或者 id 重复了
                        maxId++;
                        this.options[i][&#039;id&#039;] = maxId;
                    }
                    existIds.push(this.options[i].id)
                }

                // 填充颜色，确保颜色唯一
                let availableColor = JSON.parse(JSON.stringify(allDefColorArr)) // 可用颜色
                let existColor = [] // 存在颜色

                // 先收集已有颜色
                for (var i = 0; i &lt; this.options.length; i++) {
                    let item = this.options[i]
                    if (item[&#039;color&#039;] &amp;&amp; item.color !== &quot;&quot;) {
                        let color = item.color
                        existColor.push(color)
                        // 过滤掉已经用了的 color
                        availableColor = availableColor.filter(c =&gt; c !== color);
                    }
                }

                // 为没有颜色的选项分配颜色
                for (var i = 0; i &lt; this.options.length; i++) {
                    let item = this.options[i]
                    if (!item[&#039;color&#039;] || item.color === &quot;&quot;) {
                        if (availableColor.length == 0) {
                            // 没有可用颜色了，则随机生成一个
                            let color = &#039;&#039;;
                            for (var j = 0; j &lt; 100; j++) {
                                if (color !== &#039;&#039;) break;
                                let genColor = this.genRandColor()
                                if (!existColor.includes(genColor)) {
                                    existColor.push(genColor)
                                    color = genColor
                                }
                            }
                            this.options[i][&#039;color&#039;] = color
                        } else {
                            const color = availableColor.shift();
                            existColor.push(color)
                            this.options[i].color = color
                        }
                    }
                }

                console.log(&quot;选项初始化完成，数量:&quot;, this.options.length);
            } catch (error) {
                console.error(&quot;初始化选项失败:&quot;, error);
                // 确保至少有默认选项
                if (!this.options || this.options.length === 0) {
                    this.options = [{
                        id: 1,
                        name: &#039;默认选项&#039;,
                        color: &quot;#f6e174&quot;
                    }];
                }
            }
        },
        init() {
            try {
                this.initOptions();
                this.ctx = uni.createCanvasContext(&quot;canvas&quot;, this);
                this.initCanvas(this.ctx, 0);
                this.initBtnCanvas();
            } catch (error) {
                console.error(&quot;初始化组件失败:&quot;, error);
                uni.showToast({
                    title: &#039;初始化抽奖组件失败&#039;,
                    icon: &#039;none&#039;
                });
            }
        }
    },
    // 初始化画布
    mounted: function () {
        console.log(&quot;lottery mounted init......&quot;)
        this.init()
    }
}
&lt;/script&gt;
&lt;style scoped&gt;
.main {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

.title-container {
    font-size: 25px;
    margin-top: 120rpx;
    margin-bottom: 40rpx;
    z-index: 100;
}

.canvas-container {
    position: relative;
    width: fit-content;
    height: fit-content;
}

.canvasBtn {
    position: absolute;
    top: 0%;
}

.canvas-btn {
    position: absolute;
    top: 50%;
    left: 50%;
    background-color: #ffffff;
    transform: translate(-50%, -50%);
    width: 110rpx;
    height: 110rpx;
    border-radius: 50%;
    line-height: 110rpx;
    text-align: center;
    font-size: 45rpx;
    text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.6);
    box-shadow: 0 3px 5px rgba(0, 0, 0, 0.6);
    text-decoration: none;
}

.canvas-btn.isLottery {
    background-color: #CCCCCC;
    pointer-events: none;
}

.empty-tip {
    padding: 30rpx;
    text-align: center;
    color: #999;
    font-size: 28rpx;
}

.btn-container {
    margin-top: 30rpx;
}
&lt;/style&gt;测试Demo&lt;template&gt;
    &lt;view class=&quot;container&quot;&gt;
        &lt;view class=&quot;title&quot;&gt;转盘抽奖组件演示&lt;/view&gt;

        &lt;!-- 转盘抽奖组件 --&gt;
        &lt;lottery ref=&quot;lotteryRef&quot; :width=&quot;300&quot; :height=&quot;300&quot; :fontSize=&quot;16&quot; :data=&quot;lotteryOptions&quot;
            :isUseDefaultOptions=&quot;useDefaultOptions&quot; :turnReduceSpeed=&quot;reduceSpeed&quot; :turnCircle=&quot;circleCount&quot;
            :showBtn=&quot;true&quot; :btnTitle=&quot;&#039;开始抽奖&#039;&quot; :centerBtnText=&quot;&#039;GO&#039;&quot; :centerBtnColor=&quot;&#039;#ff5252&#039;&quot;
            :showResultModal=&quot;showModal&quot; :turnModalContent=&quot;modalContents&quot; :setWinnerFn=&quot;setWinner&quot;
            :beforePlay=&quot;onBeforePlay&quot; :afterPlay=&quot;onAfterPlay&quot; /&gt;

        &lt;!-- 配置面板 --&gt;
        &lt;view class=&quot;config-panel&quot;&gt;
            &lt;view class=&quot;panel-title&quot;&gt;配置选项&lt;/view&gt;

            &lt;view class=&quot;config-item&quot;&gt;
                &lt;text&gt;使用默认选项:&lt;/text&gt;
                &lt;switch :checked=&quot;useDefaultOptions&quot; @change=&quot;(e) =&gt; useDefaultOptions = e.detail.value&quot; /&gt;
            &lt;/view&gt;

            &lt;view class=&quot;config-item&quot;&gt;
                &lt;text&gt;减速效果({{ reduceSpeed }}):&lt;/text&gt;
                &lt;slider :value=&quot;reduceSpeed&quot; :min=&quot;1&quot; :max=&quot;100&quot; :step=&quot;1&quot; show-value
                    @change=&quot;(e) =&gt; reduceSpeed = e.detail.value&quot; /&gt;
            &lt;/view&gt;

            &lt;view class=&quot;config-item&quot;&gt;
                &lt;text&gt;额外旋转圈数({{ circleCount }}):&lt;/text&gt;
                &lt;slider :value=&quot;circleCount&quot; :min=&quot;0&quot; :max=&quot;10&quot; :step=&quot;1&quot; show-value
                    @change=&quot;(e) =&gt; circleCount = e.detail.value&quot; /&gt;
            &lt;/view&gt;

            &lt;view class=&quot;config-item&quot;&gt;
                &lt;text&gt;显示结果弹窗:&lt;/text&gt;
                &lt;switch :checked=&quot;showModal&quot; @change=&quot;(e) =&gt; showModal = e.detail.value&quot; /&gt;
            &lt;/view&gt;

            &lt;view class=&quot;config-item&quot;&gt;
                &lt;text&gt;指定中奖项:&lt;/text&gt;
                &lt;picker :value=&quot;winnerIndex&quot; :range=&quot;winnerOptions&quot; range-key=&quot;name&quot; @change=&quot;onWinnerChange&quot;&gt;
                    &lt;view class=&quot;picker-value&quot;&gt;{{ winnerOptions[winnerIndex].name || &#039;随机&#039; }}&lt;/view&gt;
                &lt;/picker&gt;
            &lt;/view&gt;

            &lt;button class=&quot;reset-btn&quot; type=&quot;default&quot; @click=&quot;resetLottery&quot;&gt;重置转盘&lt;/button&gt;
        &lt;/view&gt;

        &lt;!-- 事件日志 --&gt;
        &lt;view class=&quot;event-log&quot;&gt;
            &lt;view class=&quot;log-title&quot;&gt;事件日志&lt;/view&gt;
            &lt;scroll-view scroll-y class=&quot;log-content&quot;&gt;
                &lt;view v-for=&quot;(log, index) in eventLogs&quot; :key=&quot;index&quot; class=&quot;log-item&quot;&gt;
                    {{ log }}
                &lt;/view&gt;
            &lt;/scroll-view&gt;
            &lt;button size=&quot;mini&quot; type=&quot;default&quot; @click=&quot;clearLogs&quot;&gt;清空日志&lt;/button&gt;
        &lt;/view&gt;
    &lt;/view&gt;
&lt;/template&gt;

&lt;script&gt;
import Lottery from &#039;@/components/lottery/index.vue&#039;

export default {
    // 注册组件
    components: {
        Lottery
    },
    data() {
        return {
            // 转盘选项数据
            lotteryOptions: [
                { id: 1, name: &#039;一等奖&#039;, weight: 5, color: &#039;#ff4444&#039; },
                { id: 2, name: &#039;二等奖&#039;, weight: 10, color: &#039;#ff8800&#039; },
                { id: 3, name: &#039;三等奖&#039;, weight: 15, color: &#039;#ffcc00&#039; },
                { id: 4, name: &#039;四等奖&#039;, weight: 20, color: &#039;#33cc33&#039; },
                { id: 5, name: &#039;五等奖&#039;, weight: 25, color: &#039;#3399ff&#039; },
                { id: 6, name: &#039;谢谢参与&#039;, weight: 25, color: &#039;#9966ff&#039; }
            ],

            // 配置选项
            useDefaultOptions: false, // 是否使用组件默认选项
            reduceSpeed: 50, // 减速效果，值越小减速效果越明显
            circleCount: 3, // 额外旋转圈数
            showModal: true, // 是否显示结果弹窗

            // 弹窗内容配置
            modalContents: [
                &#039;恭喜您获得了奖品！&#039;,
                &#039;太棒了！您中奖了！&#039;,
                &#039;好运连连！&#039;
            ],

            // 指定中奖项配置
            forceWinner: false, // 是否强制指定中奖项
            winnerIndex: 0, // 指定的中奖项索引

            // 事件日志
            eventLogs: [],

            // 中奖选项列表（用于选择器）
            winnerOptions: [
                { index: -1, name: &#039;随机抽取&#039; }
            ]
        };
    },

    created() {
        // 初始化中奖选项列表
        this.initWinnerOptions();
    },

    methods: {
        /**
         * 初始化中奖选项列表
         */
        initWinnerOptions() {
            // 先添加随机选项
            this.winnerOptions = [{ index: -1, name: &#039;随机抽取&#039; }];

            // 添加所有奖品选项
            this.lotteryOptions.forEach((item, index) =&gt; {
                this.winnerOptions.push({
                    index: index,
                    name: item.name
                });
            });
        },

        /**
         * 设置中奖者的钩子函数
         * @param {Array} options - 当前抽奖选项列表
         * @returns {Number} - 返回中奖索引，-1表示随机抽取
         */
        setWinner(options) {
            // 记录日志
            this.addLog(&#039;调用 setWinnerFn 钩子函数&#039;);

            // 如果强制指定中奖项且索引有效，则返回指定索引
            if (this.forceWinner &amp;&amp; this.winnerIndex &gt; 0) {
                const selectedIndex = this.winnerOptions[this.winnerIndex].index;
                this.addLog(`指定中奖项: ${options[selectedIndex].name}`);
                return selectedIndex;
            }

            // 返回-1表示随机抽取
            this.addLog(&#039;未指定中奖项，将随机抽取&#039;);
            return -1;
        },

        /**
         * 抽奖开始前的钩子函数
         */
        onBeforePlay() {
            this.addLog(&#039;抽奖开始&#039;);
        },

        /**
         * 抽奖结束后的钩子函数
         * @param {Object} result - 抽奖结果
         */
        onAfterPlay(result) {
            this.addLog(`抽奖结束，结果: ${result.name}`);
        },

        /**
         * 重置转盘
         */
        resetLottery() {
            // 重新初始化转盘
            this.$refs.lotteryRef.init();
            this.addLog(&#039;转盘已重置&#039;);
        },

        /**
         * 添加日志
         * @param {String} message - 日志消息
         */
        addLog(message) {
            const now = new Date();
            const timeStr = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
            this.eventLogs.unshift(`[${timeStr}] ${message}`);
        },

        /**
         * 清空日志
         */
        clearLogs() {
            this.eventLogs = [];
        },

        /**
         * 中奖项选择变更
         */
        onWinnerChange(e) {
            this.winnerIndex = e.detail.value;
            this.forceWinner = this.winnerIndex &gt; 0;

            if (this.forceWinner) {
                const selectedIndex = this.winnerOptions[this.winnerIndex].index;
                this.addLog(`已设置指定中奖项: ${this.lotteryOptions[selectedIndex].name}`);
            } else {
                this.addLog(&#039;已设置为随机抽取&#039;);
            }
        }
    }
}
&lt;/script&gt;

&lt;style&gt;
.container {
    padding: 20rpx;
}

.title {
    font-size: 36rpx;
    font-weight: bold;
    text-align: center;
    margin-bottom: 30rpx;
}

.config-panel {
    margin-top: 40rpx;
    padding: 20rpx;
    border-radius: 10rpx;
    background-color: #f8f8f8;
}

.panel-title,
.log-title {
    font-size: 30rpx;
    font-weight: bold;
    margin-bottom: 20rpx;
    border-bottom: 1px solid #eee;
    padding-bottom: 10rpx;
}

.config-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20rpx;
}

.picker-value {
    padding: 10rpx 20rpx;
    background-color: #fff;
    border-radius: 6rpx;
    min-width: 200rpx;
    text-align: center;
}

.reset-btn {
    margin: 20rpx 0;
}

.event-log {
    margin-top: 40rpx;
    padding: 20rpx;
    border-radius: 10rpx;
    background-color: #f8f8f8;
}

.log-content {
    height: 300rpx;
    background-color: #fff;
    padding: 10rpx;
    border-radius: 6rpx;
    margin-bottom: 20rpx;
}

.log-item {
    font-size: 24rpx;
    padding: 6rpx 0;
    border-bottom: 1px dashed #eee;
}
&lt;/style&gt;</description>
</item>
<item rdf:about="https://blog.anlucky.cn/index.php/WebProject/235">
<title>Shell 脚本恢复数据</title>
<link>https://blog.anlucky.cn/index.php/WebProject/235</link>
<dc:date>2025-04-15T15:49:44+08:00</dc:date>
<description>使用场景当搭建了一个测试站时，开放给广大用户进行使用，但部分用户会对其角色，权限进行修改，或账号密码进行修改，修改之后影响其他网友进行查阅系统，以及翻看系统信息，若不对系统进行控制，可对数据库进行直接恢复数据MySQL#!/bin/bash

# 数据库连接信息
DB_USER=&quot;数据库用户名&quot;
DB_PASSWORD=&quot;数据库密码&quot;
DB_HOST=&quot;localhost&quot;
DB_NAME=&quot;数据库名称&quot;

# SQL 文件路径
SQL_FILE=&quot;/www/backup/database/back.sql&quot;

# 检查 SQL 文件是否存在
if [ ! -f &quot;$SQL_FILE&quot; ]; then
    echo &quot;错误: SQL 文件 $SQL_FILE 不存在。&quot;
    exit 1
fi

# 执行 SQL 文件
mysql -h &quot;$DB_HOST&quot; -u &quot;$DB_USER&quot; -p&quot;$DB_PASSWORD&quot; &quot;$DB_NAME&quot; &lt; &quot;$SQL_FILE&quot;

# 检查执行结果
if [ $? -eq 0 ]; then
    echo &quot;SQL 文件执行成功。&quot;
else
    echo &quot;SQL 文件执行失败。&quot;
fi    
Redis#!/bin/bash

# Redis 服务器地址
REDIS_HOST=&quot;localhost&quot;
# Redis 服务器端口
REDIS_PORT=&quot;6379&quot;
# Redis 服务器密码，如果没有则为空
REDIS_PASSWORD=&quot;123456&quot;
# 要操作的 Redis 数据库编号
REDIS_DB=0

# 检查 redis-cli 是否可用
if ! command -v redis-cli &amp;&gt; /dev/null; then
    echo &quot;错误: redis-cli 未安装，请先安装 Redis 客户端。&quot;
    exit 1
fi

# 构建 redis-cli 命令
if [ -z &quot;$REDIS_PASSWORD&quot; ]; then
    REDIS_COMMAND=&quot;redis-cli -h $REDIS_HOST -p $REDIS_PORT -n $REDIS_DB FLUSHDB&quot;
else
    REDIS_COMMAND=&quot;redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD -n $REDIS_DB FLUSHDB&quot;
fi

# 执行命令
echo &quot;正在删除 Redis 数据库 $REDIS_DB 中的所有数据...&quot;
$REDIS_COMMAND

# 检查执行结果
if [ $? -eq 0 ]; then
    echo &quot;Redis 数据库 $REDIS_DB 中的数据已成功删除。&quot;
else
    echo &quot;删除 Redis 数据库 $REDIS_DB 中的数据时出错。&quot;
fi    可对两个进行合并执行#!/bin/bash

# 数据库连接信息
DB_USER=&quot;数据库用户名&quot;
DB_PASSWORD=&quot;数据库密码&quot;
DB_HOST=&quot;localhost&quot;
DB_NAME=&quot;数据库名称&quot;

# SQL 文件路径
SQL_FILE=&quot;/www/backup/database/back.sql&quot;

# 检查 SQL 文件是否存在
if [ ! -f &quot;$SQL_FILE&quot; ]; then
    echo &quot;错误: SQL 文件 $SQL_FILE 不存在。&quot;
    exit 1
fi

# 执行 SQL 文件
mysql -h &quot;$DB_HOST&quot; -u &quot;$DB_USER&quot; -p&quot;$DB_PASSWORD&quot; &quot;$DB_NAME&quot; &lt; &quot;$SQL_FILE&quot;

# 检查执行结果
if [ $? -eq 0 ]; then
    echo &quot;SQL 文件执行成功。&quot;
else
    echo &quot;SQL 文件执行失败。&quot;
fi  


# Redis 服务器地址
REDIS_HOST=&quot;localhost&quot;
# Redis 服务器端口
REDIS_PORT=&quot;6379&quot;
# Redis 服务器密码，如果没有则为空
REDIS_PASSWORD=&quot;123456&quot;
# 要操作的 Redis 数据库编号
REDIS_DB=0

# 检查 redis-cli 是否可用
if ! command -v redis-cli &amp;&gt; /dev/null; then
    echo &quot;错误: redis-cli 未安装，请先安装 Redis 客户端。&quot;
    exit 1
fi

# 构建 redis-cli 命令
if [ -z &quot;$REDIS_PASSWORD&quot; ]; then
    REDIS_COMMAND=&quot;redis-cli -h $REDIS_HOST -p $REDIS_PORT -n $REDIS_DB FLUSHDB&quot;
else
    REDIS_COMMAND=&quot;redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD -n $REDIS_DB FLUSHDB&quot;
fi

# 执行命令
echo &quot;正在删除 Redis 数据库 $REDIS_DB 中的所有数据...&quot;
$REDIS_COMMAND

# 检查执行结果
if [ $? -eq 0 ]; then
    echo &quot;Redis 数据库 $REDIS_DB 中的数据已成功删除。&quot;
else
    echo &quot;删除 Redis 数据库 $REDIS_DB 中的数据时出错。&quot;
fi    使用宝塔计划任务计划任务 =&gt; 添加任务 =&gt; 选择Shell脚本 =&gt; 设置任务名称 =&gt; 设置执行周期 =&gt; 设置执行用户(必须要有执行权限的用户) =&gt; 脚本内容(填写上方脚本)注意要将数据库名称，以及数据库的密码进行修改指定为自己的点击执行查看日志是否执行成功</description>
</item>
<item rdf:about="https://blog.anlucky.cn/index.php/mes/cell/234">
<title>新能源电池工序工艺</title>
<link>https://blog.anlucky.cn/index.php/mes/cell/234</link>
<dc:date>2024-12-13T10:30:11+08:00</dc:date>
<description>新能源电池智造工序工艺分类按照外观形态不同，锂离子电池可以分为圆柱电池、方形电池以及软包电池等。圆柱形电池以圆柱形锂离子电池为例，从整体来看，电池生产工序可以概括为3大工段，21道工序。3大工段分别是前段工序（极片制备）、中段工序（电芯装配）、后段工序（化成封装）。21道工序分别是负极匀浆、正极匀浆、涂布、辊压、分切、制片、卷绕、入壳、底焊、滚槽、烘烤、注液、焊接、封口、清洗、套膜、活化、化成、陈化、分选、分容。1. 前段工序(极片制备)前段工序主要是极片制备阶段，包括正（负）极匀浆、涂布、辊压、分切、制片。正（负）极匀浆将正（负）极活性物质、导电剂、粘结剂等正（负）极物质混合在一起的混料过程，混料是把电池活性物质材料和辅料，在溶剂中进行高度分散形成牛顿型高粘度流体，达到将活性物质、导电剂、粘结剂及其它添加剂充分混合，均匀分散的目的。涂布将浆料通过涂布机在集流体表面涂覆一层厚度均匀的涂层，再经过烘道加热将溶剂除去，得到极片。辊压涂布完成后，极片需通过辊压机调整轧辊间隙、收放卷位置、张力等，并用试片试压，确保试压后的试片厚度符合工艺参数要求。分切将较宽的极片用分切机分切成单颗电芯所需要的宽度。制片在制片机上焊接极耳并在极耳位置贴上绝缘胶包覆裸露的集流体和极耳。2. 中段工序(电芯装配)中段工序主要是完成电芯的制备，包括卷绕、入壳、底焊、辊槽、烘烤、注液、焊接、封口、清洗、套膜。卷绕是由条状正负极极片和隔膜通过卷绕机卷成圆柱形卷芯，这一工序管控要点在于负极极片必须完全包覆正极极片，而隔膜必须完全包覆负极极片，对工艺精度的要求非常高。入壳、底焊、辊槽卷芯完成后需放入钢壳并通过底焊使得负极耳与钢壳连接，这时整个钢壳就是电池的负极，再通过辊槽固定钢壳内的卷芯。烘烤将已入壳的卷芯置于烘烤箱中烘烤，直至卷芯的水分含量达到标准后才能转入下一工序。注液通过注液机将电解液注入烘烤后水分要求合格的卷芯。注液完成后，锂电池的四大主材均被应用到电芯之中。焊接将盖板与正极耳焊接在一起，这时整个盖板就是电池的正极，焊接的管控点在于防止虚焊、偏焊及盖帽外观不良。封口将钢壳与盖板密封，使壳体内的电芯体处于完全密封的状态，与外界环境隔离，避免物质交换。清洗清洗工序的目的是清除电池钢壳表面残留的电解液，防止电解液腐蚀钢壳。套膜套膜工序是保证电芯正负极端分开，防止外部电路发生短路，同时使电池有一定的美观度。3.后段(化成封装)完成中段工序意味着一颗外形完整的电芯制造已经结束。之后就是后段工序，此工序主要目的是将电芯激活，经过检测、分选、组装，形成锂离子电池成品。主要包括活化、化成、陈化、分选、分容。活化电芯套膜之后在恒温环境搁置一段时间，使电解液充分浸润极片和隔膜，防止因电解液浸润不均匀而导致析锂。化成通过第一次充电，使得电芯激活，此过程中负极表面会形成一层稳定的固体电解质相界面（SEI）膜。电池在化成后，才能体现真实的电性能；没有经过化成的电池，无法进行正常充放电。陈化将化成后某一荷电状态的电芯在一定温度环境下搁置一段时间，并测试搁置前后电池的电压，根据电压下降情况筛选、分类，排除外界因素的影响，剔除压降大或压降异常的电芯。  分选  根据电芯交流内阻大小分选出不同内阻档位电芯，剔除内阻异常电芯。分容分容即分析容量。电池在制造过程中，因工艺原因使电池的实际容量不可能完全一致，通过一定的充放电检测，将电池按容量分类的过程称为分容。</description>
</item>
<item rdf:about="https://blog.anlucky.cn/index.php/programming/tools/223">
<title>Git如何更换远程仓库</title>
<link>https://blog.anlucky.cn/index.php/programming/tools/223</link>
<dc:date>2024-12-02T17:18:04+08:00</dc:date>
<description></description>
</item>
<item rdf:about="https://blog.anlucky.cn/index.php/programming/java/215">
<title>SpringBoot解决全局跨域问题</title>
<link>https://blog.anlucky.cn/index.php/programming/java/215</link>
<dc:date>2024-04-28T11:09:22+08:00</dc:date>
<description>SpringBoot解决全局跨域问题什么是跨域跨域：指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的，是浏览器对javascript施加的安全限制。例如：a页面想获取b页面资源，如果a、b页面的协议、域名、端口、子域名不同，所进行的访问行动都是跨域的，而浏览器为了安全问题一般都限制了跨域访问，也就是不允许跨域请求资源。注意：跨域限制访问，其实是浏览器的限制。理解这一点很重要！！！同源策略：是指协议，域名，端口都要相同，其中有一个不同都会产生跨域；同源策略同源，就是咱们域名、端口号、ip、采用的协议都相同，那么我们就是同源的反之就是不同源的！！！出于浏览器的同源策略限制。同源策略（Sameoriginpolicy）是一种约定，它是浏览器最核心也最基本的安全功能，如果缺少了同源策略，则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的，浏览器只是针对同源策略的一种实现。所以，用最简单的话来说，就是前端可以发请求给服务器，服务器也可以进行响应，只是因为浏览器会对请求头进行判断，所以要么前端设置请求头，要么后端设置请求头JAVA解决CORS跨域请求的方式返回新的CorsFilter重写 WebMvcConfigurer使用注解 @CrossOrigin手动设置响应头 (HttpServletResponse)自定web filter 实现跨域注意:CorFilter / WebMvConfigurer / @CrossOrigin 需要 SpringMVC 4.2以上版本才支持，对应springBoot 1.3版本以上上面前两种方式属于全局 CORS 配置，后两种属于局部 CORS配置。如果使用了局部跨域是会覆盖全局跨域的规则，所以可以通过 @CrossOrigin 注解来进行细粒度更高的跨域资源控制。其实无论哪种方案，最终目的都是修改响应头，向响应头中添加浏览器所要求的数据，进而实现跨域这里只介绍全局解决SpringBoot跨域问题，使用返回新的CorsFilter方式1. 编写CorsConfig.java 类/**
 * 解决全局跨域问题
 */
@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        // 配置跨域
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        // 允许哪个请求头
        corsConfiguration.addAllowedHeader(&quot;*&quot;);
        // 允许哪个方法进行跨域
        corsConfiguration.addAllowedMethod(&quot;*&quot;);
        // 允许哪个请求来源进行跨域
        // corsConfiguration.addAllowedOrigin(&quot;*&quot;);
        corsConfiguration.addAllowedOriginPattern(&quot;*&quot;);
        // 是否允许携带cookie进行跨域
        corsConfiguration.setAllowCredentials(true);

        source.registerCorsConfiguration(&quot;/**&quot;,corsConfiguration);

        return new CorsFilter(source);
    }
}2. 全局拦截器配置/**
 * 拦截器
 */
@Configuration
public class WebConfigure implements WebMvcConfigurer {
    /**
     * 全局解决跨域问题
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping(&quot;/**&quot;)
                .allowedOriginPatterns(&quot;*&quot;)
                .allowedMethods(&quot;GET&quot;, &quot;HEAD&quot;, &quot;POST&quot;, &quot;PUT&quot;, &quot;DELETE&quot;, &quot;OPTIONS&quot;)
                .allowCredentials(true)
                .maxAge(3600)
                .allowedHeaders(&quot;*&quot;);
    }
}
如此，这样，即解决所有解决跨域问题，不外乎就是解决浏览器拦截问题，要么前端设置请求头，要么后端设置请求头，无论谁设置请求头，浏览器只要放行即可</description>
</item>
<item rdf:about="https://blog.anlucky.cn/index.php/programming/java/213">
<title>Java工具类-通用对象转换为Json字符</title>
<link>https://blog.anlucky.cn/index.php/programming/java/213</link>
<dc:date>2024-04-01T09:41:34+08:00</dc:date>
<description>Java工具类-通用对象转换为Json字符import com.alibaba.fastjson2.JSONObject;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;

public class JsonObjectUtlis {

    public static &lt;U&gt; JSONObject processEntityToJson(Class&lt;U&gt; clazz, U cla) {
        //将传过来的对象进行赋值处理，
        //此时u可用来代表传过来的对象（本示意中是Users）,
        //此时可以用u调用传过来对象的方法
        U u = clazz.cast(cla);
        //以下是验证此示意中实体类可被操作了
        //getDeclaredFields()：获得某个类的所有声明的字段，即包括public、private和proteced，但是不包括父类的申明字段。
        //.getClass()是一个对象实例的方法，只有对象实例才有这个方法，具体的类是没有的
        JSONObject jsonObject = new JSONObject();
        for (Field field : u.getClass().getDeclaredFields()) {
            //允许获取实体类private的参数信息 field.setAccessible(true);
            field.setAccessible(true);
            try {
                String name = field.getType().getName();
                if (&quot;java.util.Date&quot;.equals(name) &amp;&amp; field.get(u) != null) {
                    String dateStr = new SimpleDateFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;).format(field.get(u));
                    if (dateStr.indexOf(&quot;00:00:00&quot;) &gt; 0){
                        dateStr = dateStr.substring(0,10) ;
                    }
                    jsonObject.put(field.getName(), dateStr);
                }else {
                    jsonObject.put(field.getName(), field.get(u));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                jsonObject.put(&quot;convertJsonStatus&quot;,500);
                return jsonObject;
            }
        }
        return jsonObject;
    }
}使用例子        JSONObject jsonObject = JsonObjectUtlis.processEntityToJson(JudgeResultSynchronizationMatVO.class, synchronizationVO);
        // 第一个参数为对象的Clss类    第二个入参为实际对象Json判断判断当前字符串是不是Json字符串，是JSON返回True 否则返回falsepublic static boolean isjson(String str) {
        try {
            JSONObject jsonStr = JSONObject.parseObject(str);
            return  true;
        } catch (Exception e) {
            return false;
        }
}</description>
</item>
<item rdf:about="https://blog.anlucky.cn/index.php/mes/Apriso/208">
<title>Apriso 代码状态修改&amp;amp;&amp;amp;GPM打包报错问题查找</title>
<link>https://blog.anlucky.cn/index.php/mes/Apriso/208</link>
<dc:date>2024-01-17T11:17:00+08:00</dc:date>
<description>Apriso 代码状态修改使用场景例如：​    我们实际开发中，不免得有一些紧急情况需要直接在生产环境中直接修改代码，而我们在实际开发当中并不会使用一个环境进行开发，一般情况下会使用多个环境，而我们的代码一般会使用  Apriso 中的 GPM(GlobalProcessManager) 工具 进行将开发环境的代码进行打包发送至生产环境在一般情况下，因代码是GPM打包发送，无法对代码进行直接修改，需要修改其状态才可修改代码，如下的SQL语句就实现了修改数据库中存储状态的字段而进行改变我们的代码状态--LAYOUT状态修改  布局
SELECT SL.*  FROM SF_LAYOUT SL
WHERE SL.NAME = &#039;IL_QMS_CPKMonitor&#039;;

--SCREEN状态修改  画面
SELECT SSR.* FROM SF_SCREEN SS
LEFT JOIN SF_SCREEN_REVISION SSR ON SS.ID = SSR.SCREENID
WHERE SS.NAME = &#039;ScreenName&#039;;
-- 根据上方查询的ID进行修改Screen的状态
UPDATE SF_SCREEN_REVISION SSR SET REVISIONSTATUSID = 4  WHERE ID = ScreenID;

--VIEW状态修改  视图
SELECT SVR.* FROM SF_VIEW SV
LEFT JOIN SF_VIEW_REVISION SVR ON SV.ID = SVR.VIEWID 
WHERE SV.NAME = &#039;ViewName&#039;;
-- 根据上方查询的View的ID进行修改View的状态
UPDATE SF_VIEW_REVISION SET REVISIONSTATUSID = 4  WHERE ID = ViewID;

--Operation状态修改  操作
SELECT O.REVISIONSTATUSID,O.* FROM OPERATION O
WHERE OPERATIONCODE = &#039;OperationName&#039;;
-- 根据操作的名字进行修改操作的状态
UPDATE OPERATION SET REVISIONSTATUSID = 4 WHERE OPERATIONCODE = &#039;OperationName&#039;;

-- 字典项表名称
SELECT * FROM LITERAL_DICTIONARY LD WHERE LD.DESCRIPTION = &#039;字典名&#039;;

-- 系统参数查询
SELECT * FROM SYSTEM_PARAMETER SP WHERE SP.FUID = &#039;&#039;;GPM (GlobalProcessManager) 在打包发布过程中会有一个FUID报错，亦可以使用这些SQL进行查询是哪些代码未正确打包注意为了我们的代码统一性，若直接修改了正式环境的代码要将代码同步至开环境和测试环境，以免影响后续功能的修改和优化</description>
</item>
</rdf:RDF>