202411 月29
以下以Nutz代码为例:
Header header = Header.create();
header.addv("Content-Type", "application/json");
header.addv("AppCode", appcode);
Request request = Request.create(url, Request.METHOD.POST);
NutMap body = NutMap.NEW();
body.put("kssj", kssj);
body.put("jssj", jssj);
request.setHeader(header);
request.setData(Json.toJson(body));
Sender sender = Sender.create(request).setTimeout(30 * 1000);
if (url.startsWith("https")) {
try {
SSLContext sslcontext = this.createIgnoreVerifySSL();
sender.setSSLSocketFactory(sslcontext.getSocketFactory());
sender.setHostnameVerifier((urlHostName, session) -> true);
} catch (Exception e) {
e.printStackTrace();
}
}
Response response = sender.send();
if (response.isOK()) {
//todo
}
private static class TrustAllManager
implements X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
}
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
}
}
public SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new CityLifelineServer.TrustAllManager()}, null);
return sc;
}
202410 月24
ALTER USER 'root'@'%' IDENTIFIED BY 'pwd' PASSWORD EXPIRE NEVER;
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd';
FLUSH PRIVILEGES;
20249 月8
http://10.10.10.3:5244/dav/usb
`sudo chown -R alist3 SSK`
20247 月23
BUDIOT 是一个开源的、企业级的物联网平台,它集成了设备管理、协议解析、消息订阅、场景联动等一系列物联网核心能力,支持以平台适配设备的方式连接海量设备,支持在线下发指令实现远程控制,支持扩展水电气等各类计费业务场景。
本平台是在千万级设备实时计费物联网平台经验基础上,在不损失性能的前提下进行功能删减、结构优化而来,小而美,同时又具备灵活的扩展性。
在线演示地址: https://demo.budiot.com 用户名: superadmin 密码: 1
官网: https://budiot.com
开发框架
基于自研 Java 微服务框架 https://budwk.com
简单说明
Jar 运行模块
budiot-access/budiot-access-gateway
设备网关,用于设备协议和 network 组件
budiot-access/budiot-access-processor
设备数据上报业务处理模块
budiot-server
WEB 服务 API ,定时任务等
其他模块说明
budiot-access/budiot-access-network
网络组件,支持 TCP/MQTT/UDP/HTTP 等
budiot-access/budiot-access-protocol
设备协议开发包,内含 demo 示例
budiot-access/budiot-access-storage
设备数据存储,可扩展时序数据库等
前端模块
budiot-vue-admin
Vue3 + Element-Plus
开发环境
- OpenJDK 11
- Redis 6.x
- MariaDB 10.x
- MongoDB 7.0.x
- RocketMQ 5.2.x
设备上报有效数据存储
默认采用 MongoDB 7 的时序集合,可根据项目规模需要,扩展为 TDEngine 等时序数据库
20247 月9
java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: Comparison method violates its general contract!
错误代码:
children.sort((o1, o2) -> (int) (o2.getLong("createdAt", 0) - o1.getLong("createdAt", 0)));
修复后:
children.sort((o1, o2) -> Long.compare(o2.getLong("createdAt", 0), o1.getLong("createdAt", 0)));
排序器 children.sort((o1, o2) -> (int) (o2.getLong("createdAt", 0) - o1.getLong("createdAt", 0)));
存在一个潜在的问题,即当时间戳的差值超出 int
的范围时,强制转换为 int
会导致数据溢出,从而导致比较结果不正确。
一个解决方法是使用 Long.compare
方法进行比较,而不是手动进行减法运算。Long.compare
方法确保了比较的对称性和一致性。
20247 月5
Mongod 的服务模型是每个网络连接由一个单独的线程来处理,每个线程配置了1MB 的栈空间,当网络连接数太多时,过多的线程会导致上下文切换开销变大,同时内存开销也会上涨。
- 连接是要消耗资源的,而且消耗的并不少。
- 内存:MongoDB为例,每个线程都要分配1MB的栈内存出来。1000个连接,1G内存就这么没了,甭管是否是活跃连接
- 文件句柄:每个连接都要打开一个文件句柄,当然从成本上讲,这个消耗相对内存是小了很多。但换个角度,文件句柄也被其他模块消耗着,比如WT存储引擎,就需要消耗大量的文件句柄
- 是否真的需要这么多的链接,一般的业务场景下请求压力在1000QPS左右,按照每个请求50ms计算,最多也就需要1000/(1000/50)==50个链接即可满足需求,并且是整个系统50个链接即可。
- 很多人平时没有怎么注意过链接数概念,上云后发现居然有这样的限制,心里很不舒服,可能非常不理解。这里说下常见的两种情况:
- 短链接:一般都是PHP环境,因为PHP的框架决定了PHP短链接的特性,并且链接数的需求一般是在1000-3000左右,具体多少还要根据业务部署的PHP数量来计算。并且MongoDB开源版本在短链接Auth处理上并不优雅,会消耗非常多的CPU资源,3000链接即可跑满24Core的CPU。PHP大拿Facebook也有同样的问题,所以他们用go语言自行开发了一套Proxy代理,来解决对MongoDB的短链接请求问题,但这毕竟带来部署成本和兼容性问题。
- 长链接:比较健康合理的使用方式,但是也要正确的配置客户端,相关的参数为
&maxPoolSize=xx
在ConnectionURI上追加上去即可,否则默认每个客户端就是高处100来个,平白的浪费资源
- 链接数的上限需要综合考虑性能,稳定性,业务需求。多方面去考虑,缺一不可。超低的内存,配置超高的链接数,得到的只能是OOM。
20246 月20
启动需指定配置文件(配置数据库用户和密码,用户不可为默认用户)
python3 odoo-bin -c debian/odoo.conf -i base -d odoo
配置文件
[options]
; This is the password that allows database operations:
; admin_passwd = admin
db_host = 127.0.0.1
db_port = 5432
db_user = odoo
db_password = 1234567890
addons_path = /data/odoo/addons
default_productivity_apps = True
需安装依赖
pip3 install -r requirements.txt
20246 月20
su postgres
pgsql
\l 列出数据库
\du 列出用户
\q 退出窗口
su – postgres
pgsql
select usename,passwd from pg_shadow;
ALTER USER demo with password ‘demo12345678’;
或创建用户
CREATE USER demo WITH PASSWORD ‘demo12345678’;
赋予权限
ALTER USER demo WITH SUPERUSER;
ALTER USER demo WITH CreateDB;
创建数据库
CREATE DATABASE demo
OWNER demo
;
20246 月19
1、文档说明要求 python 3版本,但没有说必须是 3.6 版本,其他版本报错找不到 libpython3.6m.so.1.0;
2、使用 python 3.6 得安装 requests 组件,文档没有说明;
3、部署时必须指定执行的 sh 脚本文件;
Dcokerfile 文件内容如下:
FROM python:3.6-slim
WROKDIR /app
COPY . /app
RUN python -m pip install --upgrade pip
RUN pip install requests
RUN pip install pycryptodome
EXPOSE 8080
ps:搞过微信开发的都知道,微信的开发文档到底是多么多么的……
20246 月12
前端开发工程师
职位描述:
1、负责与开发组长沟通业务需求,与后端开发人员对接后端API、开发前端页面;
2、负责修改公司现有软件项目BUG,并对前端功能的持续优化改进;
3、负责公司现有前端框架和组件的维护、改进;
职位要求:
1、2年以上前端开发经验;
2、熟悉Web前端开发基础技能(HTML/CSS/JavaScript);
3、熟悉Vue2、Vue3、ElementUI、Element-Plus等前端开发框架;
4、对前端工程化与模块化开发有一定了解,有webpack/vite/npm实践经验;
5、有GIS开发经验(电子围栏、轨迹、图层等)、数据大屏开发经验者优先;
6、对前端开发有浓厚兴趣,能主动学习;
7、有良好的编码习惯,重视代码质量;
8、善于沟通,工作积极,有责任心,善于协作与分享;
测试运维工程师
岗位职责:
1、负责Java软件项目的全流程测试,包括制定测试计划、编写测试方案和测试用例等;
2、负责Java软件项目的功能、性能等方面的测试工作,执行测试用例,提交BUG,并进行BUG跟踪和回归测试,直到BUG解决;
3、负责Java软件项目的日常更新维护,包括Docker容器化部署等环境;
4、负责收集、跟进客户的使用问题,直到问题被有效解决;
任职资格:
1、本科及以上学历,计算机或相关专业,3年以上软件测试经验;
2、熟悉软件研发、测试流程,了解过程标准和规范,能主动在关键过程节点推动任务执行;
3、熟悉软件测试方法和软件工程知识,流程意识强,具备有效发现问题和解决问题的能力;
4、熟悉Docker部署,熟练掌握Linux服务器的配置和管理;
5、了解常见开源软件的集群化部署、维护和使用,例如RabbitMQ,MongoDB,Redis,MySQL/MariaDB、ElasticSearch等
6、具有一定的文档编写能力,如部署文档、测试方案、测试用例等;
20241 月25
调用页面添加样式
<style scoped>
::v-deep .el-table {
display: flex;
flex-direction: column;
}
::v-deep .el-table__body-wrapper {
order: 1;
}
::v-deep .el-table__fixed-body-wrapper {
top: 92px !important;
}
::v-deep .el-table__fixed-footer-wrapper {
z-index: 0;
top: 45px;
}
</style>
分页组件完整代码
<template>
<div class="data-list">
<transition name="el-fade-in">
<div v-show="selectRows.length > 0" class="el-selection-bar">
选择了<span class="el-selection-bar__text">{{ selectRows.length }}</span
>条数据
<a class="el-selection-bar__clear" @click="clearSelection">清空</a>
</div>
</transition>
<div v-loading="isRequestIng" class="data-list__table" :element-loading-text="loadingTxt">
<span v-if="summary">总条数:{{ rows.length }}</span>
<el-table
v-bind="$attrs"
ref="tabList"
:data="rows"
v-on="$listeners"
:border="true"
:span-method="handleRowSpanMethod"
:show-summary="summary"
sum-text=" 汇 总 "
>
<slot />
<pro-empty slot="empty" />
</el-table>
</div>
<div v-if="!summary && (pageData.totalCount > pageData.pageSize || pageData.pageSize > 10)" class="data-list__pager">
<el-pagination
:current-page="pageData.pageNo"
:page-size="pageData.pageSize"
:total="pageData.totalCount"
background
:page-sizes="pageSizes"
layout="total, ->, prev, pager, next, sizes, jumper"
@current-change="doChangePage"
@size-change="doSizeChange"
/>
</div>
</div>
</template>
<script>
import { forIn, findIndex, cloneDeep, remove, uniqBy, concat, isArray, first } from "lodash-es"
import { f } from 'vue-marquee-component'
export default {
name: "PlusTableList",
props: {
server: {
type: String,
require: true,
default: ""
},
methods: {
type: String,
default: "post"
},
lazy: {
type: Boolean,
default: false
},
data: {
type: Object,
default: () => {}
},
dataFilter: {
type: Function,
default: data => data
},
loadingTxt: {
type: String,
default: "数据加载中..."
},
paramClear: {
type: Boolean,
default: false
},
selectRows: {
type: Array,
default: () => []
},
selectable: {
type: Function,
default: () => true
},
rowKey: {
type: String,
default: "id"
},
selection: {
type: Boolean,
default: true
},
pageSizes: {
type: Array,
default: () => [10, 20, 30, 50]
},
// 合并行(第一列)
spanName0: {
type: String,
default: null
},
// 合并行(第二列)
spanName1: {
type: String,
default: null
},
// 是否汇总数据
summary: {
type: Boolean,
default: false
}
},
data() {
return {
pageData: {
pageNo: 1,
pageSize: 10,
totalCount: 0
},
rows: [],
isRequestIng: false
}
},
watch: {
pageSizes: {
handler: function (val) {
if (isArray(val)) {
this.pageData.pageSize = first(val)
}
},
immediate: true
}
},
mounted() {
if (!this.lazy) {
this.getList()
}
},
methods: {
// 合并相同值的行
handleRowSpanMethod({ row, column, rowIndex, columnIndex }) {
if (columnIndex === 0) {
if (!this.spanName0) return
if (rowIndex > 0 && row[this.spanName0] === this.rows[rowIndex - 1][this.spanName0]) {
return {
rowspan: 0,
colspan: 0
}
} else {
let count = 1
for (let i = rowIndex + 1; i < this.rows.length; i++) {
if (row[this.spanName0] === this.rows[i][this.spanName0]) {
count++
} else {
break
}
}
if(count>1){
return {
rowspan: count,
colspan: 1
}
}
}
}
if (columnIndex === 1) {
if (!this.spanName1) return
// 第一列值相同,且第二列值相同的的情况下合并
if (rowIndex > 0 && row[this.spanName0] === this.rows[rowIndex-1][this.spanName0] && row[this.spanName1] === this.rows[rowIndex - 1][this.spanName1]) {
return {
rowspan: 0,
colspan: 0
}
} else {
let count = 1
for (let i = rowIndex + 1; i < this.rows.length; i++) {
// 第一列值相同,且第二列值相同的的情况下合并
if (row[this.spanName0] === this.rows[i][this.spanName0] && row[this.spanName1] === this.rows[i][this.spanName1]) {
count++
} else {
break
}
}
if(count>1){
return {
rowspan: count,
colspan: 1
}
}
}
}
},
// 页码变动事件
doChangePage(val) {
this.pageData.pageNo = val
this.getList()
},
// 页大小变动事件
doSizeChange(val) {
this.pageData.pageSize = val
this.pageData.pageNo = 1
this.getList()
},
getList() {
const { totalCount, ...pager } = this.pageData
const params = Object.assign({}, this.data, pager)
if (this.paramClear) {
forIn(params, (value, key) => {
if (value === "") delete params[key]
})
}
this.isRequestIng = true
this.$get(params)
.then(({ data }) => {
this.rows = this.dataFilter(data.list || [])
this.pageData.totalCount = data.totalCount
this.$emit("updateTotal", data.totalCount)
this.isRequestIng = false
this.$nextTick(() => {
this.handlePageUpdate()
})
})
.catch(error => {
this.isRequestIng = false
})
},
handlePageUpdate() {
const list = this.rows
list.forEach(row => {
if (
findIndex(this.selectRows, el => {
return el[this.rowKey] === row[this.rowKey]
}) !== -1
) {
this.$refs.tabList.toggleRowSelection(row, true)
}
})
},
handleSelectionChange(val) {
const selectRows = cloneDeep(this.selectRows)
this.$nextTick(() => {
const list = this.rows.map(el => el[this.rowKey])
remove(selectRows, el => {
return list.includes(el[this.rowKey])
})
this.$emit(
"update:selectRows",
uniqBy(concat(selectRows, val), el => el[this.rowKey])
)
})
},
$get(data) {
if (this.methods === "get") {
return this.$axios.get(this.server, {
params: data
})
} else {
return this.$axios.post(this.server, data)
}
},
reset() {
this.pageData.pageNo = 1
this.pageData.totalCount = 0
this.rows = []
this.clearSelection()
},
async clearSelection() {
this.$refs.tabList.clearSelection()
await this.$nextTick()
this.$emit("update:selectRows", [])
},
query() {
this.reset()
this.getList()
}
}
}
</script>
20241 月24
<template>
<div class="data-list">
<transition name="el-fade-in">
<div v-show="selectRows.length > 0" class="el-selection-bar">
选择了<span class="el-selection-bar__text">{{ selectRows.length }}</span
>条数据
<a class="el-selection-bar__clear" @click="clearSelection">清空</a>
</div>
</transition>
<div v-loading="isRequestIng" class="data-list__table" :element-loading-text="loadingTxt">
<el-table
v-bind="$attrs"
ref="tabList"
:data="rows"
v-on="$listeners"
:border="true"
:span-method="handleRowSpanMethod"
>
<slot />
<pro-empty slot="empty" />
</el-table>
</div>
<div v-if="pageData.totalCount > pageData.pageSize || pageData.pageSize > 10" class="data-list__pager">
<el-pagination
:current-page="pageData.pageNo"
:page-size="pageData.pageSize"
:total="pageData.totalCount"
background
:page-sizes="pageSizes"
layout="total, ->, prev, pager, next, sizes, jumper"
@current-change="doChangePage"
@size-change="doSizeChange"
/>
</div>
</div>
</template>
<script>
import { forIn, findIndex, cloneDeep, remove, uniqBy, concat, isArray, first } from "lodash-es"
export default {
name: "PlusTableList",
props: {
server: {
type: String,
require: true,
default: ""
},
methods: {
type: String,
default: "post"
},
lazy: {
type: Boolean,
default: false
},
data: {
type: Object,
default: () => {}
},
dataFilter: {
type: Function,
default: data => data
},
loadingTxt: {
type: String,
default: "数据加载中..."
},
paramClear: {
type: Boolean,
default: false
},
selectRows: {
type: Array,
default: () => []
},
selectable: {
type: Function,
default: () => true
},
rowKey: {
type: String,
default: "id"
},
selection: {
type: Boolean,
default: true
},
pageSizes: {
type: Array,
default: () => [10, 20, 30, 50]
},
spanName0: {
type: String,
default: null
},
spanName1: {
type: String,
default: null
}
},
data() {
return {
pageData: {
pageNo: 1,
pageSize: 10,
totalCount: 0
},
rows: [],
isRequestIng: false
}
},
watch: {
pageSizes: {
handler: function (val) {
if (isArray(val)) {
this.pageData.pageSize = first(val)
}
},
immediate: true
}
},
mounted() {
if (!this.lazy) {
this.getList()
}
},
methods: {
// 合并相同值的行
handleRowSpanMethod({ row, column, rowIndex, columnIndex }) {
if (columnIndex === 0) {
if (!this.spanName0) return
if (rowIndex > 0 && row[this.spanName0] === this.rows[rowIndex - 1][this.spanName0]) {
return {
rowspan: 0,
colspan: 0
}
} else {
let count = 1
for (let i = rowIndex + 1; i < this.rows.length; i++) {
if (row[this.spanName0] === this.rows[i][this.spanName0]) {
count++
} else {
break
}
}
if(count>1){
return {
rowspan: count,
colspan: 1
}
}
}
}
if (columnIndex === 1) {
if (!this.spanName1) return
// 第一列值相同,且第二列值相同的的情况下合并
if (rowIndex > 0 && row[this.spanName0] === this.rows[rowIndex-1][this.spanName0] && row[this.spanName1] === this.rows[rowIndex - 1][this.spanName1]) {
return {
rowspan: 0,
colspan: 0
}
} else {
let count = 1
for (let i = rowIndex + 1; i < this.rows.length; i++) {
// 第一列值相同,且第二列值相同的的情况下合并
if (row[this.spanName0] === this.rows[i][this.spanName0] && row[this.spanName1] === this.rows[i][this.spanName1]) {
count++
} else {
break
}
}
if(count>1){
return {
rowspan: count,
colspan: 1
}
}
}
}
},
// 页码变动事件
doChangePage(val) {
this.pageData.pageNo = val
this.getList()
},
// 页大小变动事件
doSizeChange(val) {
this.pageData.pageSize = val
this.pageData.pageNo = 1
this.getList()
},
getList() {
const { totalCount, ...pager } = this.pageData
const params = Object.assign({}, this.data, pager)
if (this.paramClear) {
forIn(params, (value, key) => {
if (value === "") delete params[key]
})
}
this.isRequestIng = true
this.$get(params)
.then(({ data }) => {
this.rows = this.dataFilter(data.list || [])
this.pageData.totalCount = data.totalCount
this.$emit("updateTotal", data.totalCount)
this.isRequestIng = false
this.$nextTick(() => {
this.handlePageUpdate()
})
})
.catch(error => {
this.isRequestIng = false
})
},
handlePageUpdate() {
const list = this.rows
list.forEach(row => {
if (
findIndex(this.selectRows, el => {
return el[this.rowKey] === row[this.rowKey]
}) !== -1
) {
this.$refs.tabList.toggleRowSelection(row, true)
}
})
},
handleSelectionChange(val) {
const selectRows = cloneDeep(this.selectRows)
this.$nextTick(() => {
const list = this.rows.map(el => el[this.rowKey])
remove(selectRows, el => {
return list.includes(el[this.rowKey])
})
this.$emit(
"update:selectRows",
uniqBy(concat(selectRows, val), el => el[this.rowKey])
)
})
},
$get(data) {
if (this.methods === "get") {
return this.$axios.get(this.server, {
params: data
})
} else {
return this.$axios.post(this.server, data)
}
},
reset() {
this.pageData.pageNo = 1
this.pageData.totalCount = 0
this.rows = []
this.clearSelection()
},
async clearSelection() {
this.$refs.tabList.clearSelection()
await this.$nextTick()
this.$emit("update:selectRows", [])
},
query() {
this.reset()
this.getList()
}
}
}
</script>
20238 月10
@IocBean
@Slf4j
public class CimApiServer {
@Inject
private RedisService redisService;
private String redis_key = "cim:accessToken";
@Inject
@Reference(check = false)
private ISysConfigProvider sysConfigProvider;
public String getAccessToken() {
String token = redisService.get(redis_key);
if (Strings.isBlank(token)) {
token = this.getHttpToken();
redisService.setex(redis_key, 3600 * 24 - 100, token);
}
return token;
}
private String getHttpToken() {
String CIM_GIS_APPID = sysConfigProvider.getString("COMMON", "CIM_GIS_APPID");
String CIM_GIS_HTTP_BASE = sysConfigProvider.getString("COMMON", "CIM_GIS_HTTP_BASE");
String CIM_GIS_APPKEY = sysConfigProvider.getString("COMMON", "CIM_GIS_APPKEY");
String CIM_GIS_APPSECRET = sysConfigProvider.getString("COMMON", "CIM_GIS_APPSECRET");
Map<String, Object> params = new HashMap<>();
params.put("apiKey", CIM_GIS_APPKEY);
params.put("secret", CIM_GIS_APPSECRET);
Header header = Header.create();
header.addv("Content-Type", "application/json");
Request request = Request.create(CIM_GIS_HTTP_BASE + "/auth/getAccessToken", Request.METHOD.POST);
request.setHeader(header);
request.setData(Json.toJson(params));
Sender sender = Sender.create(request).setTimeout(20 * 1000);
if (CIM_GIS_HTTP_BASE.startsWith("https")) {
try {
SSLContext sslcontext = createIgnoreVerifySSL();
sender.setSSLSocketFactory(sslcontext.getSocketFactory());
sender.setHostnameVerifier((urlHostName, session) -> true);
} catch (Exception e) {
e.printStackTrace();
}
}
Response response = sender.send();
if (response.isOK()) {
NutMap map = Json.fromJson(NutMap.class, response.getContent());
log.debug("getHttpToken:::" + Json.toJson(map));
if (0 == map.getInt("code")) {
return map.getString("data");
}
}
return "";
}
private static class TrustAllManager
implements X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
}
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
}
}
public SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new TrustAllManager()}, null);
return sc;
}
}
20237 月31
Uniapp 权限设置
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
Uniapp Webview 源码
<template>
<view>
<web-view :webview-styles="webviewStyles" src="http://192.168.4.108:5001/h5/" @message="showMessage"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
webviewStyles: {
progress: {
color: '#FF3333'
}
},
qrCodeWv: null
}
},
onReady() {
// #ifdef APP-PLUS
let currentWebview = this.$scope.$getAppWebview()
setTimeout(() => {
this.wv = currentWebview.children()[0]
this.qrCodeWv = currentWebview.children()[0]
this.wv.setStyle({scalable:true})
},1000)
// #endif
},
methods: {
showMessage(event) {
if(event.detail.data && event.detail.data.length >0){
let dataInfo = event.detail.data[0]
console.log(dataInfo)
let type = dataInfo.type
if(type==='scanCode') {
this.startScanCode()
}
}
},
startScanCode() {
const self = this
uni.scanCode({
onlyFromCamera: false,
scanType: ['qrCode'],
success: function(res) {
setTimeout(() => {
const result = res.result.replace(/'/g,'"')
self.qrCodeWv.evalJS(`appScanCodeResult('${result}')`)
})
},
complete: function(args){
console.log(args)
}
})
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>
H5 Vue项目引入js
index.html 引入 public/js 下文件
<script src="<%= BASE_URL %>js/uni.webview.1.5.4.js"></script>
H5 main.js 定义回调方法和对象
window.appScanCodeResult = function (val) {
window.appScanCodeResultString = val
window.dispatchEvent(new CustomEvent("scanCodeResult"))
}
H5 Vue扫码页面代码
created() {
this.getDetailData()
window.addEventListener("scanCodeResult", this.handleAppScanCode, false)
document.addEventListener("UniAppJSBridgeReady", function () {
uni.getEnv(function (res) {
console.log("获取当前环境:" + JSON.stringify(res))
})
})
},
onBeforeDestroy() {
window.removeEventListener("scanCodeResult", this.handleAppScanCode)
},
methods: {
handleAppScanCode() {
const result = window.appScanCodeResultString
this.onScanSuccess(result)
},
// 扫码
saoCode() {
uni.postMessage({
data: {
type: "scanCode"
}
})
},
//扫码成功
onScanSuccess(val) {
this.tankCode = val
this._getFillingTankInfo()
}
}
20236 月21
irm https://massgrave.dev/get | iex
20235 月10
下载redisjson源码
https://github.com/RedisJSON/RedisJSON/releases
安装rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rutsc --version
编译redisjson
cargo build --release
修改redis.conf配置
loadmodule /usr/local/redis/module/librejson.dylib
重新启动 redis 后显示如下信息即可:
127.0.0.1:6379> module list
1) 1) "name"
2) "ReJSON"
3) "ver"
4) (integer) 20407
20233 月7
yum install php
yum install php-fpm
yum install php-mysqlnd.x86_64
yum install php-json
yum install nginx
yum install mariadb
yum install mariadb-server
vi /etc/php-fpm.d/www.conf
linsten = 127.0.0.1:9000
systemctl start nginx
systemctl enable nginx
systemctl start php-fpm
systemctl enable php-fpm
systemctl start mariadb
systemctl enable mariadb
mysql_secure_installation 修改密码
grant all privileges on . to ‘root’@’1.1.1.1’ identified by ‘password’ with grant option;
flush privileges;
20232 月14
安装 python3 运行环境
yum install -y zlib zlib-devel libaio net-tools bzip2-devel pcre-devel openssl-devel ncurses-devel sqlite-devel readline-devel python3-devel tk-devel gcc cmake gcc-c++ make libffi-devel mesa-libGL.x86_64 wget git
安装 pip3 运行环境
yum install zlib*
下载 Python3 安装包
wget https://www.python.org/ftp/python/3.7.9/Python-3.7.9.tar.xz
tar -xxf Python-3.7.9.tar.xz
cd Python-3.7.9
vi Modules/Setup.dist
将
#zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz
前面的 # 符号去掉
:wq
安装新版 openssh
wget https://www.openssl.org/source/openssl-1.1.1a.tar.gz
tar -xxf openssl-1.1.1a.tar.gz
cd openssl-1.1.1a/
./config --prefix=/usr/local/openssl
make & make install
安装 python3
./configure --prefix=/usr/local/python3 --with-openssl=/usr/local/openssl
make && make install
创建 python3 软链接
ln -s /usr/local/python3/bin/python3.7 /usr/bin/python3
下载 pip3 安装脚本
wget https://bootstrap.pypa.io/get-pip.py
安装 pip3
python3 get-pip.py
创建 pip3 软链接
ln -s /usr/local/python3/bin/pip3 /usr/bin/pip3
202211 月2
ffmpeg -c:a g729 -ac 1 -i /Users/wizzer/temp/9_729.wav /Users/wizzer/temp/9_729.mp3