当前位置: 首页 > news >正文

【广告投放系统】头条可视化投放平台vue3+element-plus+vite落地历程和心得体会

前言

hallo,又是许久未见,昨天也是正式把公司内部的广告投放平台暂时落地,我也即将离开待了两年多的地方。言归正传,由于头条广告后台的升级改版,因此为了满足内部投放需求,做了一个可视化的投放平台,时间大概是1个星期多,然后我会阐述我是如何在最短的时间内完成这个平台的。

需求梳理

  • 时间尽可能的短
    为了实现这一点,可能暂时不考虑非常华丽的UI设计和变化,对于后台系统来说,快速上手和简单易用是最重要的

  • 技术选型
    实际上在头条后台没有改版之前,公司内部使用的是React18那一套玩法,我也亲身参与和维护过,那么之所以选择vue3。
    一方面是:vue3发展到现在跟React的差距并不是特别大,特别在复杂的计算场景上面。
    二方面是:兼顾公司内部前端的技术栈考虑,公司主要以vue为主,那么为了之后的维护和更新,vue技术栈最合适不过
    三方面是:旧版广告系统迭代了非常多版本,既不满足新版需求,其次是数据维护极其困难,数据污染严重,规范和可靠性不强,因此二次开发比重新创作难度更大。

  • 调试简单

  • 易于维护

设计思路

借鉴于上一代广告投放系统的痛点,其实最难的就是数据的回显和数据的汇总,导致出现的各种问题。因此我给自己提出以下几点原则:

  • 不违背单向数据源原则
    数据最终的处理,应该由顶层决定,数据可以获取,但是修改必须经过顶层同意。
    在这里插入图片描述

  • 数据驱动
    为了解决回显问题,实际上迭代到后期,组件和组件之间嵌套的层级可能会比较深,那么就需要一个公共数据管理库去统一管理数据,所有的数据在初始化的时候,可以通过接口获取数据之后,存储到数据管理库去统一处理,再在各个组件中做监听,数据变化驱动视图变化。

在这里插入图片描述

方案选型

  1. 公共状态管理库(pinia)官方支持,社区活跃
  2. 请求库(axios),请求响应拦截,二次封装,自定义参数
  3. 打包构建工具(vite),本地代理,插件丰富,官方支持
  4. 组件库(element-plus),支持企业级系统搭建,适配vue3
  5. 路由管理(vue-router)
  6. 调试工具(code-inspector-plugin)支持多种前端技术框架和构建工具,ide支持,当组件嵌套深层次的时候,能通过快捷键快速定位代码位置

项目搭建

那么初次创建项目的时候,所有的资源都会在src下面去创作,结构大致如下,我也借鉴了在Flutter端和在React端的经验。
在这里插入图片描述

目录解析

  • 所有的请求都在api目录下面,不同的请求api类型区分不同的文件,比如账户相关单独一个文件,资源包相关单独一个文件
  • 静态资源都在assets下面
  • 所有的组件都放在components下面,不同的组件类型单独一个文件夹命名,子组件也是如此
  • 路由文件放在router下面,统一由index.js去对外暴露
  • 公共管理库放在store下面,统一由index.js去对外暴露
  • 所有的工具类放在utils,不同种类的工具单独文件夹分开处理
  • 主视图文件放在views下面,充当为顶层决策者
  • App.vue文件为最高决策者,如果未来规划页面布局应当在此规划

本地代理

vite本身就支持本地代理操作,所有的配置都在vite.config.js文件中去配置,假如是公司内部使用,那么公司内部系统会在请求上带上特殊参数,那么可以通过代理的手段去设置。

 server: {// port: 8080, // 设置端口号// host: '192.168.11.5',proxy: {'/static': {target: 'http://xxxxxx.com',ws: false,changeOrigin: true,rewrite: (path) => path.replace(/^\/static/, ''),configure: (proxy) => {proxy.on('proxyReq', function (proxyReq) {proxyReq.setHeader('Cookie', 'my_dev=a221cc9410bae508aa3c1106af467db5; ly_my_user=Ikft5xHzizNCSKdfddTxTVyj9wZ3pdhh; ly_my_refer=1380.8.74.2; PHPSESSID=fufvppacre3nor48aos834dtei; SERVERID=6c7b09313256c7aae1d2b6b27bf60e38|1732675765|1732675765');});}},

请求配置

本地代理是需要和请求配置相对应的,当处理本地环境时,请求链接为配置好的代理头,触发本地代理,完成本地请求。

const service = axios.create({timeout: 5000,timeoutRetry: true,// 请求头信息headers: {'Content-Type': 'application/x-www-form-urlencoded'},// 携带凭证withCredentials: true,// 返回数据类型// responseType: 'json'
})service.interceptors.request.use(config => {// 根据custom参数中配置的是否需要baseURL,添加对应的请求头if (config?.custom?.baseUrlType) {if (process.env.NODE_ENV === 'development') {config.baseURL = `/${config.custom.baseUrlType}`} else {config.baseURL = `//${config.custom.baseUrlType}.${window.location.host.split('.')[1]}.com`}}

我在请求拦截中就是这么做的。

打包配置

打包注意要在vite.config.js中进行配置,否则可能出现找不到资源的问题

  base: process.env.NODE_ENV === 'production' ? './' : '/',

资源访问配置

这里我为了方便资源的获取,将src目录设置别名

  resolve: {alias: {'@': path.resolve(__dirname, 'src')}},

难点和解析

数据传递

前面说过了,我希望做到的就是不违背单一数据源的原则,因此在数据的处理上,我希望最终都交给顶层去决策,那么是这么处理的:

对于子级组件,我在父级中给予一个ref,为了能够操作子组件

  <CustomTemplate name="选择账户"><Account ref="AccountRef" /></CustomTemplate>const AccountRef = ref();

子组件对外暴露一个handleSubmit方法,用于对外抛出数据

const account = await AccountRef.value.handleSubmit() 

这样有几个好处:

  1. 组件和组件之前是解耦的。
    不会说一个组件影响到了其他组件,组件的事情组件自己处理,我要的只是处理完之后的数据,在多人开发中,可以把页面组件化,这一块组件只做自己的事情,最终要的只是通过你暴露出来的方法拿到最终处理好的数据即可。
  2. 单一数据源原则

地域数据树级处理

从接口拿到中国地域数据的时候,首先要考虑以下问题:

  • 数据量大
    地域数据通常数据量都会比较大,反复的调用接口去拿显然是不合适的,因为地域数据通常是不会改变的,因此在首次调用接口成功拿到数据之后,就应该存储本地了,之后都看本地有就本地拿,没有就调用接口,接口需要更新再重新调用重新执行流程
  • 怎么存
    对于浏览器来说,存储的方式有很多种:
    例如cookie、LocalStorage、SessionStorage、浏览器数据库。
    但是我们的数据量比较大,可能需要反复读写,那么就要求:
    一是能够存储比较大的数据
    二是读写得快,不能阻塞渲染进程
    那么数据库IndexedDB就非常合适了,存储容量大,异步操作不阻塞线程,数据结构也足够灵活
  • 怎么展示
    展示当然就选中了element-plus的树级选择器了,但是需要注意的是,由于地域在嵌套方面比较深的时候,渲染会慢,因此我们需要做懒加载(render-after-expand),并且选中的时候,不能选中父子级联(check-strictly),否则严重阻塞渲染。
  <el-tree-select v-model="ACForm.city" :data="cityOptions" multiple :render-after-expand="true"show-checkbox style="width: 240px" placeholder="请选择区域" node-key="id" check-strictly />

并且大概率从头条获取的数据并不是一个标准的树级结构,因此需要修改为标准的树级结构

const addAdminSelectorsCity = (data) => {let arr = [];data.map(item => {let newData = {};//这一块根据选用的组件来newData.label = item.name; newData.id = item.geoname_id;newData.value = item.code;if (item.name === "台湾省" ||item.name === "香港特别行政区" ||item.name === "澳门特别行政区") {newData.value = item.geoname_id;}if (item.sub_districts) {newData.children = addAdminSelectorsCity(item.sub_districts);if (newData.label === newData.children[0].label) {newData = newData.children[0];}}return arr.push(newData);});return arr;
};

可动态增删数据的数据校验

本身其实el-form 配合el-form-item是有一套标准的校验规范的,在非动态的数据校验不会有任何问题。

 <el-form :model="AdBudgetForm" :rules="rules" style="max-width: 600px" label-width="auto" label-position="left"size="default" ref="AdBudgetRef"><div class="form-container"><el-form-item label="广告预算" prop="budget"><el-input v-model="AdBudgetForm.budget" style="width: 240px" placeholder="请输入广告预算"><template #suffix>元</template></el-input></el-form-item></div></el-form>

表单定义一个AdBudgetForm负责获取所有数据,定义一个rules负责处理规则,每一项都使用el-form-item进行包裹,通过设置prop去匹配rules中的校验,去完成校验。

但是有一种场景:
在这里插入图片描述
点击能够不断添加,删除又可以批量删除和添加,当条数比较多的时候,肯定不能去手动定义非常多的rules去处理,因为他们实际上校验规则都是同一个。

只需要这么处理即可:

            <div style="margin-bottom: 10px;" v-for="(item, index) in textSourceForm.textSourceList" :key="index"><el-form-item :prop="'textSourceList.' + index + '.title'" :rules="rules.title">const rules = reactive({title: [{validator: textRules,trigger: 'blur'}]
});

头条自定义日期选择组件

这个组件是在这一位开源的基础上进行二次改造成vue3版本的,完整实例如下,开箱即用:
开源作者地址:https://github.com/xiejunping/andt-components
在这里插入图片描述

        <TimeRangePicker ref="TimeRangePickerRef" :value="mult_timeRange" :data="weektimeDataArr"@clearSelection="clearSelection" />const weektimeDataArr = ref(weektimeData)
const mult_timeRange = computed(() => {  //时间范围return weektimeDataArr.value.map((item) => {return {id: item.row,week: item.value,value: splicing(item.child),};});
});const clearSelection = () => {weektimeDataArr.value.forEach((item) => {item.child.forEach((t) => {t.check = false; // 直接修改属性即可});});
}

weektimeData

const formatDate = (date, fmt) => {const o = {'M+': date.getMonth() + 1,'d+': date.getDate(),'h+': date.getHours(),'m+': date.getMinutes(),'s+': date.getSeconds(),'q+': Math.floor((date.getMonth() + 3) / 3),S: date.getMilliseconds()}if (/(y+)/.test(fmt)) {fmt = fmt.replace(RegExp.$1,(date.getFullYear() + '').substr(4 - RegExp.$1.length))}for (const k in o) {if (new RegExp('(' + k + ')').test(fmt)) {fmt = fmt.replace(RegExp.$1,RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length))}}return fmt
}const createArr = (len) => {return Array.from(Array(len)).map((ret, id) => id)
}const formatWeektime = (col) => {const timestamp = 1542384000000 // '2018-11-17 00:00:00'const beginstamp = timestamp + col * 1800000 // col * 30 * 60 * 1000const endstamp = beginstamp + 1800000const begin = formatDate(new Date(beginstamp), 'hh:mm')const end = formatDate(new Date(endstamp), 'hh:mm')return `${begin}~${end}`
}const data = ['星期一','星期二','星期三','星期四','星期五','星期六','星期日'
].map((ret, index) => {const children = (ret, row, max) => {return createArr(max).map((t, col) => {return {week: ret,value: formatWeektime(col),begin: formatWeektime(col).split('~')[0],end: formatWeektime(col).split('~')[1],row,col}})}return {value: ret,row: index,child: children(ret, index, 48)}
})export default data
<template><div class="c-weektime"><div class="c-schedue"></div><div :class="{ 'c-schedue': true, 'c-schedue-notransi': mode }" :style="styleValue"></div><table :class="{ 'c-min-table': colspan < 2 }" class="c-weektime-table"><thead class="c-weektime-head"><tr><th rowspan="8" class="week-td">星期/时间</th><th :colspan="12 * colspan">00:00 - 12:00</th><th :colspan="12 * colspan">12:00 - 24:00</th></tr><tr><td v-for="t in theadArr" :key="t" :colspan="colspan">{{ t }}</td></tr></thead><tbody class="c-weektime-body"><tr v-for="t in data" :key="t.row"><td>{{ t.value }}</td><td v-for="n in t.child" :key="`${n.row}-${n.col}`" :data-week="n.row" :data-time="n.col":class="selectClasses(n)" @mouseenter="cellEnter(n)" @mousedown="cellDown(n)"@mouseup="cellUp(n)" class="weektime-atom-item"></td></tr><tr><td colspan="49" class="c-weektime-preview"><div class="g-clearfix c-weektime-con"><span class="g-pull-left">{{selectState ? '已选择时间段' : '可拖动鼠标选择时间段'}}</span><a @click.prevent="clearSelection" class="g-pull-right">清空选择</a></div><div v-if="selectState" class="c-weektime-time"><div v-for="t in selectValue" :key="t.id"><p v-if="t.value"><span class="g-tip-text">{{ t.week }}</span><span>{{ t.value }}</span></p></div></div></td></tr></tbody></table></div>
</template><script setup>
import { computed, defineEmits, defineExpose, defineProps, ref } from "vue";const emit = defineEmits(['clearSelection']);// Props
const props = defineProps({value: { type: Array, required: true },data: { type: Array, required: true },colspan: { type: Number, default: 2 },
});// Reactive State
const width = ref(0);
const height = ref(0);
const left = ref(0);
const top = ref(0);
const mode = ref(0);
const row = ref(0);
const col = ref(0);
const theadArr = ref([]);// Helper Function
const createArr = (len) => Array.from({ length: len }, (_, id) => id);// Computed Properties
const styleValue = computed(() => ({width: `${width.value}px`,height: `${height.value}px`,left: `${left.value}px`,top: `${top.value}px`,
}));const selectValue = computed(() => props.value);const selectState = computed(() => props.value.some((ret) => ret.value));const selectClasses = (n) => (n.check ? "ui-selected" : "");// Initialization (created hook)
theadArr.value = createArr(24);// Methods
const cellEnter = (item) => {const ele = document.querySelector(`td[data-week='${item.row}'][data-time='${item.col}']`);if (!ele) return;if (!mode.value) {left.value = ele.offsetLeft;top.value = ele.offsetTop;} else if (item.col <= col.value && item.row <= row.value) {width.value = (col.value - item.col + 1) * ele.offsetWidth;height.value = (row.value - item.row + 1) * ele.offsetHeight;left.value = ele.offsetLeft;top.value = ele.offsetTop;} else if (item.col >= col.value && item.row >= row.value) {width.value = (item.col - col.value + 1) * ele.offsetWidth;height.value = (item.row - row.value + 1) * ele.offsetHeight;if (item.col > col.value && item.row === row.value) top.value = ele.offsetTop;if (item.col === col.value && item.row > row.value) left.value = ele.offsetLeft;} else if (item.col > col.value && item.row < row.value) {width.value = (item.col - col.value + 1) * ele.offsetWidth;height.value = (row.value - item.row + 1) * ele.offsetHeight;top.value = ele.offsetTop;} else if (item.col < col.value && item.row > row.value) {width.value = (col.value - item.col + 1) * ele.offsetWidth;height.value = (item.row - row.value + 1) * ele.offsetHeight;left.value = ele.offsetLeft;}
};const cellDown = (item) => {const ele = document.querySelector(`td[data-week='${item.row}'][data-time='${item.col}']`);if (!ele) return;mode.value = 1;width.value = ele.offsetWidth;height.value = ele.offsetHeight;row.value = item.row;col.value = item.col;
};const cellUp = (item) => {if (item.col <= col.value && item.row <= row.value) {selectWeek([item.row, row.value], [item.col, col.value], !item.check);} else if (item.col >= col.value && item.row >= row.value) {selectWeek([row.value, item.row], [col.value, item.col], !item.check);} else if (item.col > col.value && item.row < row.value) {selectWeek([item.row, row.value], [col.value, item.col], !item.check);} else if (item.col < col.value && item.row > row.value) {selectWeek([row.value, item.row], [item.col, col.value], !item.check);}width.value = 0;height.value = 0;mode.value = 0;
};const selectWeek = (rowRange, colRange, check) => {const [minRow, maxRow] = rowRange;const [minCol, maxCol] = colRange;props.data.forEach((item) => {item.child.forEach((t) => {if (t.row >= minRow &&t.row <= maxRow &&t.col >= minCol &&t.col <= maxCol) {t.check = check;}});});
};const clearSelection = () => {emit('clearSelection')
};defineExpose({selectValue
})
</script><style lang="scss" scoped>
.c-weektime {min-width: 640px;position: relative;display: inline-block;
}.c-schedue {background: #598fe6;position: absolute;width: 0;height: 0;opacity: 0.6;pointer-events: none;&-notransi {transition: width 0.12s ease, height 0.12s ease, top 0.12s ease,left 0.12s ease;}
}.c-weektime-table {border-collapse: collapse;th {vertical-align: inherit;font-weight: bold;}tr {height: 30px;}tr,td,th {user-select: none;border: 1px solid #dee4f5;text-align: center;line-height: 1.0em;transition: background 0.2s ease;}.c-weektime-head {font-size: 12px;.week-td {width: 9.2em !important;}}.c-weektime-body {font-size: 12px;td {&.weektime-atom-item {user-select: unset;background-color: #f5f5f5;width: 1.4em;}&.ui-selected {background-color: #598fe6;}}}.c-weektime-preview {line-height: 2.4em;padding: 0 10px;font-size: 14px;.c-weektime-con {line-height: 46px;user-select: none;}.c-weektime-time {text-align: left;line-height: 2.4em;p {max-width: 625px;line-height: 1.4em;word-break: break-all;margin-bottom: 8px;}}}
}.c-min-table {tr,td,th {min-width: 24px;}
}.g-clearfix {&:after,&:before {clear: both;content: ' ';display: table;}
}.g-pull-left {float: left;
}.g-pull-right {float: right;
}.g-tip-text {color: #999;
}
</style>

性能优化和迭代

  • 在点击不同操作的时候,注意浏览器的性能指标,及时发现究竟哪些操作会阻塞到渲染进程
  • 目前仅是单账户和单广告,实际上做成多账户和多广告只需要补充一些匹配规则,然后做不同的分配即可。

总结

本文简单阐述使用vue3去实现简易版的广告投放系统中遇到的问题和解决思路,希望能给到一些设计思路,同时如果有更好的建议,欢迎提出!

相关文章:

【广告投放系统】头条可视化投放平台vue3+element-plus+vite落地历程和心得体会

前言 hallo&#xff0c;又是许久未见&#xff0c;昨天也是正式把公司内部的广告投放平台暂时落地&#xff0c;我也即将离开待了两年多的地方。言归正传&#xff0c;由于头条广告后台的升级改版&#xff0c;因此为了满足内部投放需求&#xff0c;做了一个可视化的投放平台&…...

Gazebo插件相机传感器(可订阅/camera/image_raw话题)

在仿真环境中使用相机传感器&#xff0c;通常需要结合Gazebo插件来实现。Gazebo是一个功能强大的机器人仿真工具&#xff0c;支持多种传感器模型&#xff0c;包括相机。下面是如何在Gazebo中使用相机传感器的详细步骤。 1. 修改Xacro文件以包含Gazebo插件 首先&#xff0c;修…...

华三(HCL)和华为(eNSP)模拟器共存安装手册

接上章叙述&#xff0c;解决同一台PC上同时部署华三(HCL)和华为(eNSP&#xff09;模拟器。原因就是华三HCL 的老版本如v2及以下使用VirtualBox v5版本&#xff0c;可以直接和eNSP兼容Oracle VirtualBox&#xff0c;而其他版本均使用Oracle VirtualBox v6以上的版本&#xff0c;…...

信息学奥赛一本通 1448:【例题1】电路维修 | 洛谷 P4667 [BalticOI 2011 Day1] Switch the Lamp On 电路维修

【题目链接】 ybt 1448&#xff1a;【例题1】电路维修 洛谷 P4667 [BalticOI 2011 Day1] Switch the Lamp On 电路维修 【题目考点】 1. 双端队列广搜&#xff08;0-1BFS&#xff09; 【解题思路】 整个电路是由一个个的正方形的电路元件组成&#xff0c;每个正方形有四个…...

k8s删除网络组件错误

k8s集群删除calico网络组件重新部署flannel网络组件&#xff0c;再部署pod后出现报错不能分配ip地址 plugin type"calico" failed (add): error getting ClusterInformation: connection is unauthorized: Unauthorized 出现该问题是因为删除网络组件后&#xff0c;网…...

MySQL之JDBC

我们在学习完了数据库的基本操作后&#xff0c;希望和我们的Java程序建立连接&#xff0c;那么我们今天就来一探究竟JDBC是如何让Java程序与数据库建立连接的 1. 什么是JDBC JDBC&#xff08;Java Data Base Connectivity, Java数据库连接&#xff09; 是Java程序和数据库之间…...

音视频入门基础:MPEG2-TS专题(10)——PAT简介

一、引言 当某个transport packet的TS Header中的PID属性的值为0x0000时&#xff0c;该transport packet的payload为Program association table &#xff0c;即 PAT表。PAT表包含所有PMT表的目录列表&#xff0c;将program_number和PMT表的PID相关联&#xff0c;获取数据的起始…...

ElementUI:el-drawer实现在父组件区域内打开抽屉组件非全屏

我们在开发ElementUI的时候遇到抽屉组件全屏的问题&#xff0c;但是我们需要在指定div中展示出来&#xff0c;上代码&#xff1a; 1、在el-drawer中增加属性 el-drawerstyle"position: absolute"z-index"-1":append-to-body"false">// do s…...

Vue教程|搭建vue项目|Vue-CLI2.x 模板脚手架

一、项目构建环境准备 在构建Vue项目之前&#xff0c;需要搭建Node环境以及Vue-CLI脚手架&#xff0c;由于本篇文章为上一篇文章的补充&#xff0c;也是为了给大家分享更为完整的搭建vue项目方式&#xff0c;所以环境准备部分采用Vue教程&#xff5c;搭建vue项目&#xff5c;V…...

jmeter学习(7)命令行控制

jmeter -n -t E:\IOT\test2.jmx -l E:\IOT\output\output.jtl -j E:\IOT\output\jmeter.log -e -o E:\IOT\output\report IOT下创建output 文件夹&#xff0c;jmx文件名避免中文&#xff0c;再次执行output.jtl不能有数据要删除...

BGP协议路由黑洞

一、实验环境 1、分公司与运营商AS自治系统内运行IGP路由协议OSPF、RIP或静态路由&#xff0c;AS自治系统内通过IBGP路由协议建立BGP邻居关系。 2、公司AS自治系统与运营商AS自治系统间运行EBGP路由协议。 3、通过loopback建立IBGP与EBGP邻居关系&#xff0c;发挥loopback建立…...

存储结构及关系(一)

学习目标 描述数据库的逻辑结构列出段类型及其用途列出控制块空间使用的关键字获取存储结构信息 段的类型 段是数据库中占用空间的对象。它们使用数据库数据文件中的空间。介绍不同类型的段。 表 表是在数据库中存储数据的最常用方法。表段用于存储既没有集群也没有分区的表…...

玄机应急:linux入侵排查webshell查杀日志分析

目录 第一章linux:入侵排查 1.web目录存在木马&#xff0c;请找到木马的密码提交 2.服务器疑似存在不死马&#xff0c;请找到不死马的密码提交 3.不死马是通过哪个文件生成的&#xff0c;请提交文件名 4.黑客留下了木马文件&#xff0c;请找出黑客的服务器ip提交 5.黑客留…...

python爬虫安装教程

Python爬虫是用于从网站上自动抓取信息的程序。在开始之前&#xff0c;请确保您了解并遵守目标网站的服务条款&#xff0c;尊重版权法&#xff0c;并且在合理合法的范围内使用爬虫技术。 安装环境 安装Python&#xff1a;首先确保您的计算机上已经安装了Python。推荐版本为3.…...

田忌赛马五局三胜问题matlab代码

问题描述&#xff1a;在可以随机选择出场顺序的情况下&#xff0c;如果把比赛规则从三局两胜制改为五局三胜制&#xff0c;齐王胜出的概率是上升了还是下降了&#xff1f;五局三胜的赛制下&#xff0c;大家的马重新分为5个等级。前提条件仍然是齐王每种等级的马都优于田忌同等级…...

Spring循环依赖问题的解决

项目启动提示如下异常&#xff1a; The dependencies of some of the beans in the application context form a cycle 这表明在我们的应用中存在了循环依赖&#xff0c;示例&#xff1a; Bean A 中注入了Bean B依赖&#xff0c;然后 Bean B 中注入了Bean A依赖。也就是说&…...

KAN-Transfomer——基于新型神经网络KAN的时间序列预测

1.数据集介绍 ETT(电变压器温度)&#xff1a;由两个小时级数据集&#xff08;ETTh&#xff09;和两个 15 分钟级数据集&#xff08;ETTm&#xff09;组成。它们中的每一个都包含 2016 年 7 月至 2018 年 7 月的七种石油和电力变压器的负载特征。 traffic(交通) &#xff1a;描…...

鸿蒙学习自由流转与分布式运行环境-价值与架构定义(1)

文章目录 价值与架构定义1、价值2、架构定义 随着个人设备数量越来越多&#xff0c;跨多个设备间的交互将成为常态。基于传统 OS 开发跨设备交互的应用程序时&#xff0c;需要解决设备发现、设备认证、设备连接、数据同步等技术难题&#xff0c;不但开发成本高&#xff0c;还存…...

【k8s深入理解之 Scheme 补充-2】理解 register.go 暴露的 AddToScheme 函数

AddToScheme 函数 AddToScheme 就是为了对外暴露&#xff0c;方便别人调用&#xff0c;将当前Group组的信息注册到其 Scheme 中&#xff0c;以便了解该 Group 组的数据结构&#xff0c;用于后续处理 项目版本用途使用场景k8s.io/apiV1注册资源某一外部版本数据结构&#xff0…...

uni-app写的微信小程序每次换账号登录时出现缓存上一个账号数据的问题

uni-app写的微信小程序每次更换另外账号登录时出现缓存上一个账号数据的问题&#xff1f; 清除缓存数据&#xff1a;在 onShow 钩子中&#xff0c;我们将 powerStations、list 和 responseRoles 的值重置为初始状态&#xff0c;以清除之前的缓存数据。重新获取数据&#xff1a…...

数据分析流程中的Lambda架构,以及数据湖基于Hadoop、Spark的实现

文章目录 一、Lambda架构1、Lambda的三层架构2、简单解释&#xff1a;3、Lambda架构的优缺点 二、数据湖基于Hadoop、Spark的实现1、架构2、数据管理&#xff08;存储层的辅助功能&#xff09; 一、Lambda架构 1、Lambda的三层架构 Batch View&#xff08;批处理视图层&#…...

Android 原生解析 Json 字符串

Android 原生解析 JSON 字符串 1. JSON 基础2. Android 原生 JSON 解析方法2.1 解析 JSON 字符串到 JSONObject关键方法 2.2 解析 JSON 数组到 JSONArray关键方法 2.3 解析嵌套的 JSON 对象 3. 处理异常4. 总结 在 Android 开发中&#xff0c;我们经常需要从服务器获取 JSON 格…...

Windsurf可以上传图片开发UI了

背景 曾经羡慕Cursor的“画图”开发功能&#xff0c;这不Windsurf安排上了。 Upload Images to Cascade Cascade now supports uploading images on premium models Ask Cascade to build or tweak UI from on image upload New keybindings Keybindings to navigate betwe…...

Qt UI设计 菜单栏无法输入名字

在UI界面“在这里输入”&#xff0c;直接双击填写名称&#xff0c;无论是中文还是英文都没有反应。解决方案 2个&#xff1a; 1.双击“在这里输入之后”&#xff0c;在可编辑状态下&#xff0c;空格→enter键&#xff0c;然后在右下角属性框的title中直接填写中文或英文名&…...

blender 视频背景

准备视频文件 首先&#xff0c;确保你有想要用作背景的视频文件。视频格式最好是 Blender 能够很好兼容的&#xff0c;如 MP4 等常见格式。 创建一个新的 Blender 场景或打开现有场景 打开 Blender 软件后&#xff0c;你可以新建一个场景&#xff08;通过点击 “文件” - “新建…...

【python】OpenCV—Tracking(10.5)—dlib

文章目录 1、功能描述2、代码实现3、效果展示4、完整代码5、涉及到的库函数dlib.correlation_tracker() 6、参考 1、功能描述 基于 dlib 库&#xff0c;实现指定类别的目标检测和单目标跟踪 2、代码实现 caffe 模型 https://github.com/MediosZ/MobileNet-SSD/tree/master/…...

音视频入门基础:MPEG2-TS专题(9)——FFmpeg源码中,解码TS Header的实现

一、引言 FFmpeg源码对MPEG2-TS传输流/TS文件解复用时&#xff0c;在通过read_packet函数读取出一个transport packet后&#xff0c;会调用handle_packet函数来处理该transport packet&#xff1a; static int handle_packets(MpegTSContext *ts, int64_t nb_packets) { //..…...

解决“磁盘已插上,但Windows系统无法识别“问题

电脑上有2块硬盘&#xff0c;一块是500GB的固态硬盘&#xff0c;另一块是1000GB的机械硬盘&#xff0c;按下开机键&#xff0c;发现500G的固态硬盘识别了&#xff0c;但1000GB的机械硬盘却无法识别。后面为了描述方便&#xff0c;将"500GB的固态硬盘"称为X盘&#xf…...

论文笔记-WWW2024-ClickPrompt

论文笔记-WWW2024-ClickPrompt: CTR Models are Strong Prompt Generators for Adapting Language Models to CTR Prediction ClickPrompt: CTR模型是大模型适配CTR预测任务的强大提示生成器摘要1.引言2.预备知识2.1传统CTR预测2.2基于PLM的CTR预测 3.方法3.1概述3.2模态转换3.…...

53 基于单片机的8路抢答器加记分

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 首先有三个按键 分别为开始 暂停 复位&#xff0c;然后八个选手按键&#xff0c;开机显示四条杠&#xff0c;然后按一号选手按键&#xff0c;数码管显示&#xff13;&#xff10;&#xff0c;这…...

wordpress伪静态路径写法/大数据精准营销获客

本文首先简单介绍了垃圾收集的常见方式&#xff0c;然后再分析了G1收集器的收集原理&#xff0c;相比其他垃圾收集器的优势&#xff0c;最后给出了一些调优实践。 一&#xff0c;什么是垃圾回收 首先&#xff0c;在了解G1之前&#xff0c;我们需要清楚的知道&#xff0c;垃圾回…...

wordpress站群 会员/站长统计

centos7没有这个文件 /etc/sysconfig/i18n 一、永久修改编码格式 永久修改服务器编码格式需要root权限。 1. 查看系统版本 2.查看当前编码格式 [rootlocalhost ~]$ locale LANGzh_CN.UTF-8 LC_CTYPE"zh_CN.UTF-8" LC_NUMERIC"zh_CN.UTF-8" LC_TIME"…...

长春网站建设找源晟/seo百科

Win7系统安装USB-Blaster驱动程序的方法 原来一直在xp下使用USB-Blaster&#xff0c;最近在笔记本上突然发现win7系统不能安装USB-Blaster驱动程序&#xff0c;摸索了很久终于成功了。 1&#xff0e;将USB-Blaster插入USB口&#xff0c;系统会提示设备安装不成功&#xff0c;没…...

中国工程建设招标网官方网站/网站页面禁止访问

https://www.cnblogs.com/zhangxiaoguang/p/5855113.html AntPathMatcher是什么&#xff1f;主要用来解决什么问题&#xff1f; 背景&#xff1a;在做uri匹配规则发现这个类&#xff0c;根据源码对该类进行分析&#xff0c;它主要用来做类URLs字符串匹配&#xff1b; 效果 …...

丹东建设工程信息网站/电话投放小网站

这是一个及其常见的问题&#xff0c;网上已经有关于这个问题的很多讨论。但是我觉得都是不求甚解&#xff0c;有一些还是在误导别人。下面我来说下我对这三者的理解&#xff0c;如有错误的地方请大家及时指正。 一&#xff1a;""与string.Empty我认为是一样的。网上有…...

网站转备案/广州百度关键词排名

网址copy过来... 命名规范: http://opensource.adobe.com/wiki/display/flexsdk/CodingConventions转载于:https://www.cnblogs.com/sun11086/archive/2010/03/29/1699996.html...