
C++防止头文件被重复引入的3种方法!
在之前我们详细介绍了 C 语言中如何使用宏定义(#ifndef / #define / #endif)来有效避免头文件被重复 #include,此方式在 C++ 多文件编程中也很常用。
举个例子,如下是一个 C++ 项目,其内部含有 school.h 和 student.h 这 2 个头文件以及 main.cpp 源文件,其各自包含的代码为:
//student.h
class Student {
//......
};
//school.h
include "student.h"
class School {
//......
private:
Student stu[50];
};
//main.cpp
include "student.h"
include "school.h"
int main() {
//......
return 0;
}
运行此项目会发现,编译器报“Student 类型重定义”错误。这是因为在 school.h 文件中已经 #include 了一次 "student.h",而在 main.cpp 主程序又同时 #include 了 "school.h" 和 "student.h",即 Student 类的定义被引入了 2 次,C++不允许同一个类被重复定义。
有小伙伴可能想到,既然 School.h 文件中已经引入了 Student 类,那去掉 main.cpp 主程序引入的 student.h 文件不就可以了吗?这样确实可以避免重复引入 Student 类,但此方式并不适用于所有“重复引入”的场景。
C++ 多文件编程中,处理“多次 #include 导致重复引入”问题的方式有以下 3 种。
————————
1) 使用宏定义避免重复引入
在实际多文件开发中,我们往往使用如下的宏定义来避免发生重复引入:
ifndef _NAME_H
define _NAME_H
//头文件内容
endif
其中,_NAME_H 是宏的名称。需要注意的是,这里设置的宏名必须是独一无二的,不要和项目中其他宏的名称相同。
当程序中第一次 #include 该文件时,由于 _NAME_H 尚未定义,所以会定义 _NAME_H 并执行“头文件内容”部分的代码;当发生多次 #include 时,因为前面已经定义了 _NAME_H,所以不会再重复执行“头文件内容”部分的代码。
也就是说,我们可以将前面项目中的 student.h 文件做如下修改:
ifndef _STUDENT_H
define _STUDENT_H
class Student {
//......
};
endif
虽然该项目 main.cpp 文件中仍 #include 了 2 次 "student.h",但鉴于 _STUDENT_H 宏只能定义一次,所以 Student 类也仅会定义一次。再次执行该项目会发现,其可以正常执行。
2) 使用#pragma once避免重复引入
除了前面第一种最常用的方式之外,还可以使用 #pragma one 指令,将其附加到指定文件的最开头位置,则该文件就只会被 #include 一次。
我们知道,#ifndef 是通过定义独一无二的宏来避免重复引入的,这意味着每次引入头文件都要进行识别,所以效率不高。但考虑到 C 和 C++ 都支持宏定义,所以项目中使用 #ifndef 规避可能出现的“头文件重复引入”问题,不会影响项目的可移植性。
和 ifndef 相比,#pragma once 不涉及宏定义,当编译器遇到它时就会立刻知道当前文件只引入一次,所以效率很高。
但值得一提的是,并不是每个版本的编译器都能识别 #pragma once 指令,一些较老版本的编译器就不支持该指令(执行时会发出警告,但编译会继续进行),即 #pragma once 指令的兼容性不是很好。
目前,几乎所有常见的编译器都支持 #pragma once 指令,甚至于 Visual Studio 2017 新建头文件时就会自带该指令。可以这么说,在 C/C++ 中,#pragma once 是一个非标准但却逐渐被很多编译器支持的指令。
除此之外,#pragma once 只能作用于某个具体的文件,而无法向 #ifndef 那样仅作用于指定的一段代码。
这里仍以前面的 "student.h" 文件为例,将其内容修改为:
pragma once
class Student {
//......
};
再次运行项目,同样可以正常执行。
3) 使用_Pragma操作符
C99 标准中新增加了一个和 #pragma 指令类似的 _Pragma 操作符,其可以看做是 #pragma 的增强版,不仅可以实现 #pragma 所有的功能,更重要的是,_Pragma 还能和宏搭配使用。
有关 _Pragma 操作符更多的功能和用法,本节不做详细讲解,这里仅介绍如何用 _Pragma 操作符避免头文件重复引入。
当处理头文件重复引入问题时,可以将如下语句添加到相应文件的开头:
_Pragma("once")
比如,将该语句添加到前面项目中 student.h 文件中的开头位置,再次执行项目,其可以正常执行。
事实上,无论是 C 语言还是 C++,为防止用户重复引入系统库文件,几乎所有库文件中都采用了以上 3 种结构中的一种,这也是为什么重复引入系统库文件编译器也不会报错的原因。
总结
本节介绍了 3 种避免头文件被重复引入的方法,其中 #pragma once 和 _Pragma("once") 可算作一类,其特点是编译效率高,但可移植性差(编译器不支持,会发出警告,但不会中断程序的执行);而 #ifndef 的特点是可移植性高,编译效率差。读者可根据实际情况,挑选最符合实际需要的解决方案。
除非对项目的编译效率有严格的要求,强烈推荐读者选用第一种解决方案,即采用 #ifndef / #define / #endif 组合解决头文件被重复引入。
另外在某些场景中,考虑到编译效率和可移植性,#pragma once 和 #ifndef 经常被结合使用来避免头文件被重复引入。比如说:
pragma once
ifndef _STUDENT_H
define _STUDENT_H
class Student {
//......
};
endif
当编译器可以识别 #pragma once 时,则整个文件仅被编译一次;反之,即便编译器不识别 #pragma once 指令,此时仍有 #ifndef 在发挥作用。
在之前我们详细介绍了 C 语言中如何使用宏定义(#ifndef / #define / #endif)来有效避免头文件被重复 #include,此方式在 C++ 多文件编程中也很常用。
举个例子,如下是一个 C++ 项目,其内部含有 school.h 和 student.h 这 2 个头文件以及 main.cpp 源文件,其各自包含的代码为:
//student.h
class Student {
//......
};
//school.h
include "student.h"
class School {
//......
private:
Student stu[50];
};
//main.cpp
include "student.h"
include "school.h"
int main() {
//......
return 0;
}
运行此项目会发现,编译器报“Student 类型重定义”错误。这是因为在 school.h 文件中已经 #include 了一次 "student.h",而在 main.cpp 主程序又同时 #include 了 "school.h" 和 "student.h",即 Student 类的定义被引入了 2 次,C++不允许同一个类被重复定义。
有小伙伴可能想到,既然 School.h 文件中已经引入了 Student 类,那去掉 main.cpp 主程序引入的 student.h 文件不就可以了吗?这样确实可以避免重复引入 Student 类,但此方式并不适用于所有“重复引入”的场景。
C++ 多文件编程中,处理“多次 #include 导致重复引入”问题的方式有以下 3 种。
————————
1) 使用宏定义避免重复引入
在实际多文件开发中,我们往往使用如下的宏定义来避免发生重复引入:
ifndef _NAME_H
define _NAME_H
//头文件内容
endif
其中,_NAME_H 是宏的名称。需要注意的是,这里设置的宏名必须是独一无二的,不要和项目中其他宏的名称相同。
当程序中第一次 #include 该文件时,由于 _NAME_H 尚未定义,所以会定义 _NAME_H 并执行“头文件内容”部分的代码;当发生多次 #include 时,因为前面已经定义了 _NAME_H,所以不会再重复执行“头文件内容”部分的代码。
也就是说,我们可以将前面项目中的 student.h 文件做如下修改:
ifndef _STUDENT_H
define _STUDENT_H
class Student {
//......
};
endif
虽然该项目 main.cpp 文件中仍 #include 了 2 次 "student.h",但鉴于 _STUDENT_H 宏只能定义一次,所以 Student 类也仅会定义一次。再次执行该项目会发现,其可以正常执行。
2) 使用#pragma once避免重复引入
除了前面第一种最常用的方式之外,还可以使用 #pragma one 指令,将其附加到指定文件的最开头位置,则该文件就只会被 #include 一次。
我们知道,#ifndef 是通过定义独一无二的宏来避免重复引入的,这意味着每次引入头文件都要进行识别,所以效率不高。但考虑到 C 和 C++ 都支持宏定义,所以项目中使用 #ifndef 规避可能出现的“头文件重复引入”问题,不会影响项目的可移植性。
和 ifndef 相比,#pragma once 不涉及宏定义,当编译器遇到它时就会立刻知道当前文件只引入一次,所以效率很高。
但值得一提的是,并不是每个版本的编译器都能识别 #pragma once 指令,一些较老版本的编译器就不支持该指令(执行时会发出警告,但编译会继续进行),即 #pragma once 指令的兼容性不是很好。
目前,几乎所有常见的编译器都支持 #pragma once 指令,甚至于 Visual Studio 2017 新建头文件时就会自带该指令。可以这么说,在 C/C++ 中,#pragma once 是一个非标准但却逐渐被很多编译器支持的指令。
除此之外,#pragma once 只能作用于某个具体的文件,而无法向 #ifndef 那样仅作用于指定的一段代码。
这里仍以前面的 "student.h" 文件为例,将其内容修改为:
pragma once
class Student {
//......
};
再次运行项目,同样可以正常执行。
3) 使用_Pragma操作符
C99 标准中新增加了一个和 #pragma 指令类似的 _Pragma 操作符,其可以看做是 #pragma 的增强版,不仅可以实现 #pragma 所有的功能,更重要的是,_Pragma 还能和宏搭配使用。
有关 _Pragma 操作符更多的功能和用法,本节不做详细讲解,这里仅介绍如何用 _Pragma 操作符避免头文件重复引入。
当处理头文件重复引入问题时,可以将如下语句添加到相应文件的开头:
_Pragma("once")
比如,将该语句添加到前面项目中 student.h 文件中的开头位置,再次执行项目,其可以正常执行。
事实上,无论是 C 语言还是 C++,为防止用户重复引入系统库文件,几乎所有库文件中都采用了以上 3 种结构中的一种,这也是为什么重复引入系统库文件编译器也不会报错的原因。
总结
本节介绍了 3 种避免头文件被重复引入的方法,其中 #pragma once 和 _Pragma("once") 可算作一类,其特点是编译效率高,但可移植性差(编译器不支持,会发出警告,但不会中断程序的执行);而 #ifndef 的特点是可移植性高,编译效率差。读者可根据实际情况,挑选最符合实际需要的解决方案。
除非对项目的编译效率有严格的要求,强烈推荐读者选用第一种解决方案,即采用 #ifndef / #define / #endif 组合解决头文件被重复引入。
另外在某些场景中,考虑到编译效率和可移植性,#pragma once 和 #ifndef 经常被结合使用来避免头文件被重复引入。比如说:
pragma once
ifndef _STUDENT_H
define _STUDENT_H
class Student {
//......
};
endif
当编译器可以识别 #pragma once 时,则整个文件仅被编译一次;反之,即便编译器不识别 #pragma once 指令,此时仍有 #ifndef 在发挥作用。
收起阅读 »
调用安卓系统分享功能,分享非媒体文件到微信
在我的 app 中需要分享 json 文件,看了好多文章大多数都是讲如何分享媒体文件的,比如图片音频什么的,其实调用系统分享功能也是比较简单的,但是分享到微信就会遇到找不到资源的问题,要使用 FileProvider 方式的话就必须要通过原生开发辅助才行,经过无数次的尝试发现微信要获取文件必须要 content:// 开头的 Uri 才行,最后使用了参考文档中的第二种方法 scanFile,目前只是为了达到目的所以代码比较粗糙,欢迎大佬指正
大概思路是这样的:
- 把要分享的文件从 app 私有目录复制到公共目录,这里选了 Download 目录
- 调用 MediaScannerConnection.scanFile 方法,在 onScanCompleted 回调函数中获取正确的 Uri 标识
- 再调用系统分享功能即可
// #ifdef APP-PLUS
plus.android.importClass('android.content.ContentResolver')
const MainActivity = plus.android.runtimeMainActivity(),
Intent = plus.android.importClass('android.content.Intent'),
Uri = plus.android.importClass('android.net.Uri'),
InputStreamReader = plus.android.importClass('java.io.InputStreamReader'),
OutputStreamWriter = plus.android.importClass('java.io.OutputStreamWriter'),
BufferedReader = plus.android.importClass('java.io.BufferedReader'),
BufferedWriter = plus.android.importClass('java.io.BufferedWriter'),
File = plus.android.importClass('java.io.File'),
FileInputStream = plus.android.importClass('java.io.FileInputStream'),
FileOutputStream = plus.android.importClass('java.io.FileOutputStream'),
MediaScannerConnection = plus.android.importClass('android.media.MediaScannerConnection'),
Environment = plus.android.importClass('android.os.Environment'),
SETTINGS_FILENAME = 'settings.json'
// #endif
function share_file() {
// #ifndef APP-PLUS
return false
// #endif
// #ifdef APP-PLUS
plus.io.requestFileSystem(plus.io.PUBLIC_DOCUMENTS, fs => {
fs.root.getFile(SETTINGS_FILENAME, {}, file_entry => {
const listener = new plus.android.implements('android.media.MediaScannerConnection$OnScanCompletedListener', {
'onScanCompleted': (path, uri) => {
console.log('uri: ' + uri.toString())
const intent = new Intent()
.setAction(Intent.ACTION_SEND)
.setType('text/*')
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(Intent.EXTRA_TEXT, 'Share a file')
.putExtra(Intent.EXTRA_STREAM, uri) // Uri.parse(file_entry.fullPath))
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
MainActivity.startActivity(Intent.createChooser(intent, 'Share a file'))
// MainActivity.startActivity(intent)
new File(path).deleteOnExit()
}
})
copy_file_to_public_directory(file_entry.fullPath)
MediaScannerConnection.scanFile(MainActivity, [get_public_directory() + '/' + SETTINGS_FILENAME], null, listener)
return true
}, error => {
uni.showToast({
title: '文件不存在',
icon: 'none',
duration: 2000
})
})
})
// #endif
}
function copy_file_to_public_directory(file_path) {
// #ifndef APP-PLUS
return false
// #endif
// #ifdef APP-PLUS
const input_stream = new FileInputStream(file_path),
output_Stream = new FileOutputStream(get_public_directory() + '/' + SETTINGS_FILENAME),
file_reader = new BufferedReader(new InputStreamReader(input_stream)),
file_writer = new BufferedWriter(new OutputStreamWriter(output_Stream)),
content = file_reader.readLine()
file_writer.write(content, 0, content.length)
file_writer.flush()
file_writer.close()
file_reader.close()
output_Stream.close()
input_stream.close()
console.log('copy file success')
return true
// #endif
}
function get_public_directory() {
// '/storage/emulated/0/Download/temp'
// #ifndef APP-PLUS
return false
// #endif
// #ifdef APP-PLUS
return new File(Environment.getExternalStorageDirectory(), 'Download/temp').getAbsolutePath()
// #endif
}
参考文档:
在我的 app 中需要分享 json 文件,看了好多文章大多数都是讲如何分享媒体文件的,比如图片音频什么的,其实调用系统分享功能也是比较简单的,但是分享到微信就会遇到找不到资源的问题,要使用 FileProvider 方式的话就必须要通过原生开发辅助才行,经过无数次的尝试发现微信要获取文件必须要 content:// 开头的 Uri 才行,最后使用了参考文档中的第二种方法 scanFile,目前只是为了达到目的所以代码比较粗糙,欢迎大佬指正
大概思路是这样的:
- 把要分享的文件从 app 私有目录复制到公共目录,这里选了 Download 目录
- 调用 MediaScannerConnection.scanFile 方法,在 onScanCompleted 回调函数中获取正确的 Uri 标识
- 再调用系统分享功能即可
// #ifdef APP-PLUS
plus.android.importClass('android.content.ContentResolver')
const MainActivity = plus.android.runtimeMainActivity(),
Intent = plus.android.importClass('android.content.Intent'),
Uri = plus.android.importClass('android.net.Uri'),
InputStreamReader = plus.android.importClass('java.io.InputStreamReader'),
OutputStreamWriter = plus.android.importClass('java.io.OutputStreamWriter'),
BufferedReader = plus.android.importClass('java.io.BufferedReader'),
BufferedWriter = plus.android.importClass('java.io.BufferedWriter'),
File = plus.android.importClass('java.io.File'),
FileInputStream = plus.android.importClass('java.io.FileInputStream'),
FileOutputStream = plus.android.importClass('java.io.FileOutputStream'),
MediaScannerConnection = plus.android.importClass('android.media.MediaScannerConnection'),
Environment = plus.android.importClass('android.os.Environment'),
SETTINGS_FILENAME = 'settings.json'
// #endif
function share_file() {
// #ifndef APP-PLUS
return false
// #endif
// #ifdef APP-PLUS
plus.io.requestFileSystem(plus.io.PUBLIC_DOCUMENTS, fs => {
fs.root.getFile(SETTINGS_FILENAME, {}, file_entry => {
const listener = new plus.android.implements('android.media.MediaScannerConnection$OnScanCompletedListener', {
'onScanCompleted': (path, uri) => {
console.log('uri: ' + uri.toString())
const intent = new Intent()
.setAction(Intent.ACTION_SEND)
.setType('text/*')
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(Intent.EXTRA_TEXT, 'Share a file')
.putExtra(Intent.EXTRA_STREAM, uri) // Uri.parse(file_entry.fullPath))
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
MainActivity.startActivity(Intent.createChooser(intent, 'Share a file'))
// MainActivity.startActivity(intent)
new File(path).deleteOnExit()
}
})
copy_file_to_public_directory(file_entry.fullPath)
MediaScannerConnection.scanFile(MainActivity, [get_public_directory() + '/' + SETTINGS_FILENAME], null, listener)
return true
}, error => {
uni.showToast({
title: '文件不存在',
icon: 'none',
duration: 2000
})
})
})
// #endif
}
function copy_file_to_public_directory(file_path) {
// #ifndef APP-PLUS
return false
// #endif
// #ifdef APP-PLUS
const input_stream = new FileInputStream(file_path),
output_Stream = new FileOutputStream(get_public_directory() + '/' + SETTINGS_FILENAME),
file_reader = new BufferedReader(new InputStreamReader(input_stream)),
file_writer = new BufferedWriter(new OutputStreamWriter(output_Stream)),
content = file_reader.readLine()
file_writer.write(content, 0, content.length)
file_writer.flush()
file_writer.close()
file_reader.close()
output_Stream.close()
input_stream.close()
console.log('copy file success')
return true
// #endif
}
function get_public_directory() {
// '/storage/emulated/0/Download/temp'
// #ifndef APP-PLUS
return false
// #endif
// #ifdef APP-PLUS
return new File(Environment.getExternalStorageDirectory(), 'Download/temp').getAbsolutePath()
// #endif
}
参考文档:
收起阅读 »
在线客服系统源码h5|thinkphp在线客服完整源码|网页在线客服源码
法国阿纳托尔曾经说过:企业客服人员早上醒来后通常做的第一件事就是检查手机,看看是否有顾客发来的重要信息,这种行为已经成为我们日常生活方式的一部分。
源码及演示:e.cusscode.top/s
不管原因是什么,我们都有一套日常使用的通信工具电子邮件、电话、网络会议工具或社交网络。对于一个高效运行的企业而言,拥有一套好的源码搭建的在线客服系统,对于提供企业运行效率至关重要!随着流感大流行使在家工作成为一种新的常态,我们面临着前所未有的沟通方式的变化,这使得这些工具不仅是必不可少的,而且现在是必需的。
搭建在线客服系统软件的必要性:
作为全球分布式团队的一部分进行远程工作时,我们必须有一个协作环境。线客服系统在帮助我们保持联系方面起着至关重要的作用。与电子邮件不同,线客服系统提供与全球同事的快速、实时通信。
选择线客服系统源码有很多因素。为了帮助您选择合适的应用程序,在本文中,我将探讨四个开源聊线客服系统工具(当您需要与同事“面对面”时),然后概述一些您应该在有效的通信应用程序中寻找的功能。
1、RockChat
RockChat是一个综合性的交流平台,它将频道分为公共(对任何加入的人开放)或私人(仅限邀请)房间。您还可以直接向登录的用户发送消息;共享文档、链接、照片、视频和gif;进行视频通话;以及在不离开平台的情况下发送音频消息。
源码开源的,但它的独特之处在于它的自助客服系统。您可以将其下载到您的服务器上,无论它是本地服务器还是公共云上的虚拟专用服务器。多开源项目使用Rocket.Chat作为他们的官方交流平台。它在不断地发展,有新的特性和改进。
RockChat最让我喜欢的是它能够根据用户需求进行定制,并且它使用机器学习在用户之间进行自动、实时的消息转换。你也可以在移动设备上下载和聊天。
2、IRC
IRC是一种实时的、基于文本的通信形式。虽然它是最古老的电子通信形式之一,但在许多著名的软件项目中仍然很流行。
IRC频道是独立的在线客服系统。它允许你与多人在一个开放的渠道交谈,或与某人私下一对一的交谈。如果频道名以#开头,则可以假定它是正式的,而以#开头的聊天室是非官方的,通常是随意的。
IRC入门很简单。您的IRC句柄或昵称允许人们找到您,因此它必须是唯一的。但你选择IRC客户完全是你的决定。如果您想要一个比标准IRC客户端功能更丰富的应用程序。
考虑到它的年龄,你为什么还要在IRC上?原因之一是,它仍然是我们所依赖的许多免费和开源项目的所在地。如果您想参与开源软件和社区,可以选择IRC。
3、Zulip

Zulip是一个流行的在线客服系统源码,遵循基于主题的线程模型。在Zulip,你订阅流,就像在IRC频道或Rocket.Chat中一样。但是每个Zulip流都会打开一个独特的主题,这有助于您以后跟踪对话,从而使其更有条理。
与其他平台一样,它支持emojis、内嵌图像、视频和tweet预览。它还支持LaTeX共享数学公式或公式,并支持标记和语法高亮显示以共享代码。
Zulip是跨平台的,它提供用于构建您自己的集成的api。我特别喜欢Zulip与GitHub的集成特性:如果我正在处理一个问题,我可以使用Zulip的标记链接回pull请求ID。
Zulip是开源的(您可以访问源代码在GitHub上),免费使用,但它为内部支持付费,LDAP集成和更多存储。
4、Let's Chat
Let's Chat是一个小型团队的自托管的在线客服系统源码解决方案。它运行在Node.js和MongoDB上,只需点击几下,就可以部署到本地服务器或托管服务上。它是免费的,开源的源代码在GitHub上提供。
Let'sChat与其他开源聊天工具的区别在于它的企业特性:它支持LDAP和Kerberos身份验证。它还具有新用户想要的所有功能:您可以在存档中搜索消息历史记录,并用username之类的名字标记人物。
我喜欢Let'sChat的地方是它有私人和密码保护的房间、图像嵌入、GIPHY支持和代码粘贴。它在不断地发展,并在bucket中添加更多的特性。
选择在线客服系统源码的要点:
各种各样的在线客服系统源码让你很难选择一个。以下是一些选择在线客服系统源码的一般准则。
具有交互式界面和简单导航的工具是理想的。
最好是寻找一个功能强大并允许人们以各种方式使用它的工具。
与您使用的工具的集成可以在您的决策中发挥重要作用。有些工具与GitHub、GitLab和某些应用程序有很好的无缝集成,这是一个很有用的特性。
使用能够在基于云的服务上托管的工具非常方便。
聊天服务的安全性应该考虑在内。许多组织和个人都需要在专用服务器上托管服务。
提供丰富的私人和私人聊天室设置。
由于人们比以往任何时候都更依赖在线服务,所以有一个备用通信平台是明智之举,由于这些服务在不断更新,您可能会发现自己连接到多个通道,因此集成变得非常有价值。
法国阿纳托尔曾经说过:企业客服人员早上醒来后通常做的第一件事就是检查手机,看看是否有顾客发来的重要信息,这种行为已经成为我们日常生活方式的一部分。
源码及演示:e.cusscode.top/s
不管原因是什么,我们都有一套日常使用的通信工具电子邮件、电话、网络会议工具或社交网络。对于一个高效运行的企业而言,拥有一套好的源码搭建的在线客服系统,对于提供企业运行效率至关重要!随着流感大流行使在家工作成为一种新的常态,我们面临着前所未有的沟通方式的变化,这使得这些工具不仅是必不可少的,而且现在是必需的。
搭建在线客服系统软件的必要性:
作为全球分布式团队的一部分进行远程工作时,我们必须有一个协作环境。线客服系统在帮助我们保持联系方面起着至关重要的作用。与电子邮件不同,线客服系统提供与全球同事的快速、实时通信。
选择线客服系统源码有很多因素。为了帮助您选择合适的应用程序,在本文中,我将探讨四个开源聊线客服系统工具(当您需要与同事“面对面”时),然后概述一些您应该在有效的通信应用程序中寻找的功能。
1、RockChat
RockChat是一个综合性的交流平台,它将频道分为公共(对任何加入的人开放)或私人(仅限邀请)房间。您还可以直接向登录的用户发送消息;共享文档、链接、照片、视频和gif;进行视频通话;以及在不离开平台的情况下发送音频消息。
源码开源的,但它的独特之处在于它的自助客服系统。您可以将其下载到您的服务器上,无论它是本地服务器还是公共云上的虚拟专用服务器。多开源项目使用Rocket.Chat作为他们的官方交流平台。它在不断地发展,有新的特性和改进。
RockChat最让我喜欢的是它能够根据用户需求进行定制,并且它使用机器学习在用户之间进行自动、实时的消息转换。你也可以在移动设备上下载和聊天。
2、IRC
IRC是一种实时的、基于文本的通信形式。虽然它是最古老的电子通信形式之一,但在许多著名的软件项目中仍然很流行。
IRC频道是独立的在线客服系统。它允许你与多人在一个开放的渠道交谈,或与某人私下一对一的交谈。如果频道名以#开头,则可以假定它是正式的,而以#开头的聊天室是非官方的,通常是随意的。
IRC入门很简单。您的IRC句柄或昵称允许人们找到您,因此它必须是唯一的。但你选择IRC客户完全是你的决定。如果您想要一个比标准IRC客户端功能更丰富的应用程序。
考虑到它的年龄,你为什么还要在IRC上?原因之一是,它仍然是我们所依赖的许多免费和开源项目的所在地。如果您想参与开源软件和社区,可以选择IRC。
3、Zulip
Zulip是一个流行的在线客服系统源码,遵循基于主题的线程模型。在Zulip,你订阅流,就像在IRC频道或Rocket.Chat中一样。但是每个Zulip流都会打开一个独特的主题,这有助于您以后跟踪对话,从而使其更有条理。
与其他平台一样,它支持emojis、内嵌图像、视频和tweet预览。它还支持LaTeX共享数学公式或公式,并支持标记和语法高亮显示以共享代码。
Zulip是跨平台的,它提供用于构建您自己的集成的api。我特别喜欢Zulip与GitHub的集成特性:如果我正在处理一个问题,我可以使用Zulip的标记链接回pull请求ID。
Zulip是开源的(您可以访问源代码在GitHub上),免费使用,但它为内部支持付费,LDAP集成和更多存储。
4、Let's Chat
Let's Chat是一个小型团队的自托管的在线客服系统源码解决方案。它运行在Node.js和MongoDB上,只需点击几下,就可以部署到本地服务器或托管服务上。它是免费的,开源的源代码在GitHub上提供。
Let'sChat与其他开源聊天工具的区别在于它的企业特性:它支持LDAP和Kerberos身份验证。它还具有新用户想要的所有功能:您可以在存档中搜索消息历史记录,并用username之类的名字标记人物。
我喜欢Let'sChat的地方是它有私人和密码保护的房间、图像嵌入、GIPHY支持和代码粘贴。它在不断地发展,并在bucket中添加更多的特性。
选择在线客服系统源码的要点:
各种各样的在线客服系统源码让你很难选择一个。以下是一些选择在线客服系统源码的一般准则。
具有交互式界面和简单导航的工具是理想的。
最好是寻找一个功能强大并允许人们以各种方式使用它的工具。
与您使用的工具的集成可以在您的决策中发挥重要作用。有些工具与GitHub、GitLab和某些应用程序有很好的无缝集成,这是一个很有用的特性。
使用能够在基于云的服务上托管的工具非常方便。
聊天服务的安全性应该考虑在内。许多组织和个人都需要在专用服务器上托管服务。
提供丰富的私人和私人聊天室设置。
由于人们比以往任何时候都更依赖在线服务,所以有一个备用通信平台是明智之举,由于这些服务在不断更新,您可能会发现自己连接到多个通道,因此集成变得非常有价值。
收起阅读 »
uni-app 内置国际化方案说明
uni-app 从 3.1.5 版本开始框架内置组件开始完善国际化支持
>+ App平台、H5平台 优化 uni.showModal、uni.showActionSheet 等 API 内置国际化支持
>+ App平台 优化 应用退出提示内置国际化支持
>+ App平台 优化 uni.scanCode、uni.previewImage 等 API 内置国际化支持
>+ H5平台 优化 picker、video 组件内置国际化支持
这些组件内置如下语言
- 中文简体 zh-Hans
- 中文繁体 zh-Hant
- 英语 en
- 法语 fr
- 西班牙语 es
组件和接口显示会根据系统语言环境自动切换,未支持的系统语言环境会显示为英文。
uni-app 3.2.5 版本以下当使用 vue-i18n 时,会使用 vue-i18n 设置的语言。
uni-app 3.2.5 版本开始请在 manifest.json 内配置,或者调用 uni.setLocale 进行设置,具体参考 locale.md。
uni-app 从 3.1.5 版本开始框架内置组件开始完善国际化支持
>+ App平台、H5平台 优化 uni.showModal、uni.showActionSheet 等 API 内置国际化支持
>+ App平台 优化 应用退出提示内置国际化支持
>+ App平台 优化 uni.scanCode、uni.previewImage 等 API 内置国际化支持
>+ H5平台 优化 picker、video 组件内置国际化支持
这些组件内置如下语言
- 中文简体 zh-Hans
- 中文繁体 zh-Hant
- 英语 en
- 法语 fr
- 西班牙语 es
组件和接口显示会根据系统语言环境自动切换,未支持的系统语言环境会显示为英文。
uni-app 3.2.5 版本以下当使用 vue-i18n 时,会使用 vue-i18n 设置的语言。
uni-app 3.2.5 版本开始请在 manifest.json 内配置,或者调用 uni.setLocale 进行设置,具体参考 locale.md。
收起阅读 »
星援App开发者一审获刑五年,系“蔡徐坤微博转发过亿”幕后推手
2018年,“明星蔡徐坤一条微博转发量过亿”事件引发舆论对流量造假的关注。按照当时的微博用户数量,转发量一亿意味着每三个微博用户中就有一人转发了蔡徐坤的微博。人民日报官微评论称:“一亿转发量”,你们也真敢刷。
2019年6月,操纵上述微博刷量事件的幕后推手“星援”APP被查。日前,中国裁判文书网公布了“星援”APP开发者蔡坤苗的判决书,其因提供侵入计算机信息系统程序罪一审获刑五年。
北京市丰台区法院审理查明,2018年1月至2019年3月间,被告人蔡坤苗未获得被害单位北京微梦创科网络技术有限公司授权而自行开发“星援”APP,有偿为他人提供不需要登录新浪微博客户端即可转发微博博文及自动批量转发微博博文的服务。后大量用户以向“星援”APP充值的形式有偿使用该软件,并通过运行上述软件侵入新浪微博服务器。
经鉴定,“星援”APP通过截取新浪微博服务器中对应账号的相关数据,后使用与其截取数据相同的网络数据格式向该服务器提交数据并完成与该服务器的交互,以实现不登录新浪微博客户端即可转发微博博文的功能以及自动批量转发微博博文的功能。经统计,至案发时该软件已有用户使用19万余个控制端微博账号登录,被告人蔡坤苗获取违法所得人民币6253752.86元。
大学肄业的“95后”开发微博刷量APP
北京市丰台区法院公布的判决书显示,“星援”APP的开发者为蔡坤苗,其于1995年5月30日出生于福建省泉州市,大学肄业,系泉州市星援网络科技有限公司法定代表人。蔡坤苗因涉嫌犯破坏计算机信息系统罪,于2019年4月11日被逮捕。
2019年11月27日,北京市丰台区检察院指控被告人蔡坤苗犯提供侵入、非法控制计算机信息系统程序、工具罪,向丰台区法院提起公诉。
法院审理查明
2018年1月至2019年3月间,被告人蔡坤苗未获得北京微梦创科网络技术有限公司授权而自行开发“星援”APP,有偿为他人提供不需要登录新浪微博客户端即可转发微博博文及自动批量转发微博博文的服务。后大量用户以向“星援”APP充值的形式有偿使用该软件,并通过运行上述软件侵入新浪微博服务器。
经鉴定
“星援”APP通过截取新浪微博服务器中对应账号的相关数据,后使用与其截取数据相同的网络数据格式向该服务器提交数据并完成与该服务器的交互,以实现不登录新浪微博客户端即可转发微博博文的功能以及自动批量转发微博博文的功能。经统计,至案发时该软件已有用户使用19万余个控制端微博账号登录,上述控制端账号绑定微博账号×××余万个(原文如此),被告人蔡坤苗获取违法所得人民币6253752.86元。
2019年3月8日,被告人蔡坤苗被北京市公安局丰台分局太平桥派出所民警抓获,其到案后如实供述基本犯罪事实。
北京微梦创科网络技术有限公司员工李某称:“我们发现有一个叫‘星援’的APP破解了新浪微博的技术参数、算法,能对微博进行转发、评论、点赞等,影响了正常业务和系统稳定。2018年5月份的一天,我用手机刷微博时发现一个叫‘星援’的APP。这个APP可以大量转发或者评论同一条微博。我感觉这个APP可能有损我公司的利益,就跟公司领导进行了汇报。我们做了技术分析,直到现在才破解出来。过程中我们也收到用户的投诉,说‘星援’APP影响了微博的正常榜单和内容,同时也影响了系统的稳定和正常运行。”
相关司法鉴定意见书证明
使用新浪微博账号信息登录星援APP,在不登录微博客户端的情况下,可实现转发新浪微博博文的功能。使用新浪微博账号登录星援APP,通过该软件提供的配置界面,在配置相关参数后,可实现自动批量转发新浪微博博文的功能。
上述鉴定意见书显示,星援APP通过绑定微博账号的操作获取到微博用户的账号信息后,请求微博的服务器,从微博服务器返回的请求中获取相应账号的uid等信息,再通过结合密钥和特定算法的方式,生成微博加密数字签名s值,结合其他参数,使用与“新浪微博客户端”转发微博时相同的网络数据格式,将该数据提交给“新浪微博服务器”,该数据被“新浪微博服务器”误认为是“新浪微博客户端”提交的网络数据,进而和星援APP发生了数据交互,从而实现了不需要登陆“新浪微博客户端”即可转发新浪微博博文的功能。该APP还拥有通过绑定多个账号、多次重复请求,同时在转发微博博文时随机生成不同的硬件设备信息,实现自动批量转发新浪微博博文的功能。
17万微博用户绑定了3000万个微博“小号”
被告人蔡坤苗供述:“2018年3月,我自己做了一个名为星援的手机APP软件,并注册了一个网络工作室。2018年8月,我成立了泉州市星援网络科技有限公司,并担任公司法定代表人。”
蔡坤苗供述称,其公司主要经营两款手机应用软件,分别是星援和应援宝。这两款软件均是对接新浪微博的,客户通过这两款软件可以登录自己的微博账号实现批量转发、点赞和评论操作,而且绑定的微博数量没有上限,不用再人工登录每个微博账号进行重复操作。星援、应援宝两款手机软件通过用户的微博账号、密码登陆,登陆的时候不需要再另行注册。这两款软件的用户可以批量操作在软件端绑定的账号,更加快速的进行微博转发(行话叫抡博)、评论、点赞。微博客户端只能使用一个账号登陆进行操作,而星援、应援宝两款软件可以同时登陆多个微博账号进行相关操作。这两款软件在功能上是一样的,只是名字不一样。
蔡坤苗称,星援、应援宝两款软件可以加快明星粉丝,提升转发评论的数据量,满足数据的需求,“我于2019年2月份查看后台数据,星援、应援宝共有微博‘大号’用户17余万个,这17余万用户大约绑定了3000余万个微博‘小号’。‘星援’‘应援宝’一共有微博中的明星群管理员×××余个。微博‘大号’是常用的微博账号,有粉丝的老号。微博‘小号’是新注册或注册时间短的账号,也就是为转发增量而准备的账号。2019年2月份左右,我查了一下银行账户,‘星援’累计充值人民币700余万元,应援宝使用人数比较少,大概充值有10余万元。”
蔡坤苗供述称,他将犯罪所得主要用于买房和公司开销了,“我在泉州城东中骏世界城买了一处住宅,目前还在建设没有交房,费用大约100余万元。我还在泉州城东中骏世界城买了两个底商登记在我父亲蔡某名下,费用大约300万到400万之间,具体多少钱记不清了。其余资金用于日常开销、员工工资支出等。公司人事是陈某,每月工资7000元。UI设计是苏某和一个男孩,每月工资7000元。”
判决书显示
被害单位北京微梦创科网络技术有限公司的诉讼代理人在审理期间提供的证据证明,被告人蔡坤苗恶意开发的“星援”APP在未经北京微梦创科网络技术有限公司授权的情况下自动批量转发微博,大量转发的微博严重干扰了明星势力榜排行的数据,并导致排行系统功能受到实质性的影响;被告人蔡坤苗的行为给北京微梦创科网络技术有限公司造成应急人工支出45986.2元、2018年第四季度的服务器支出10376934元。
不过,法院审理后认为,上述诉讼代理人认为被告人蔡坤苗给被害单位造成经济损失人民币10422920.2元的意见,经查,相关证据均为被害单位单方材料,尚不足以证实与星援APP的关联性,故不予采纳。
北京市丰台区法院审理后认为,被告人蔡坤苗提供专门用于侵入计算机信息系统的程序,情节特别严重,其行为已构成提供侵入计算机信息系统程序罪,应予处罚。鉴于被告人蔡坤苗到案后如实供述基本犯罪事实,故对其予以从轻处罚。
2020年12月31日,被告人蔡坤苗被判犯提供侵入计算机信息系统程序罪,判处有期徒刑五年,并处罚金人民币十万元;继续追缴被告人蔡坤苗违法所得予以没收。
此文章【来源:澎湃新闻】,转载自【北晚新视觉网】,如有不当联系邮箱:pufa@dcloud.io 删除。原文链接
2018年,“明星蔡徐坤一条微博转发量过亿”事件引发舆论对流量造假的关注。按照当时的微博用户数量,转发量一亿意味着每三个微博用户中就有一人转发了蔡徐坤的微博。人民日报官微评论称:“一亿转发量”,你们也真敢刷。
2019年6月,操纵上述微博刷量事件的幕后推手“星援”APP被查。日前,中国裁判文书网公布了“星援”APP开发者蔡坤苗的判决书,其因提供侵入计算机信息系统程序罪一审获刑五年。
北京市丰台区法院审理查明,2018年1月至2019年3月间,被告人蔡坤苗未获得被害单位北京微梦创科网络技术有限公司授权而自行开发“星援”APP,有偿为他人提供不需要登录新浪微博客户端即可转发微博博文及自动批量转发微博博文的服务。后大量用户以向“星援”APP充值的形式有偿使用该软件,并通过运行上述软件侵入新浪微博服务器。
经鉴定,“星援”APP通过截取新浪微博服务器中对应账号的相关数据,后使用与其截取数据相同的网络数据格式向该服务器提交数据并完成与该服务器的交互,以实现不登录新浪微博客户端即可转发微博博文的功能以及自动批量转发微博博文的功能。经统计,至案发时该软件已有用户使用19万余个控制端微博账号登录,被告人蔡坤苗获取违法所得人民币6253752.86元。
大学肄业的“95后”开发微博刷量APP
北京市丰台区法院公布的判决书显示,“星援”APP的开发者为蔡坤苗,其于1995年5月30日出生于福建省泉州市,大学肄业,系泉州市星援网络科技有限公司法定代表人。蔡坤苗因涉嫌犯破坏计算机信息系统罪,于2019年4月11日被逮捕。
2019年11月27日,北京市丰台区检察院指控被告人蔡坤苗犯提供侵入、非法控制计算机信息系统程序、工具罪,向丰台区法院提起公诉。
法院审理查明
2018年1月至2019年3月间,被告人蔡坤苗未获得北京微梦创科网络技术有限公司授权而自行开发“星援”APP,有偿为他人提供不需要登录新浪微博客户端即可转发微博博文及自动批量转发微博博文的服务。后大量用户以向“星援”APP充值的形式有偿使用该软件,并通过运行上述软件侵入新浪微博服务器。
经鉴定
“星援”APP通过截取新浪微博服务器中对应账号的相关数据,后使用与其截取数据相同的网络数据格式向该服务器提交数据并完成与该服务器的交互,以实现不登录新浪微博客户端即可转发微博博文的功能以及自动批量转发微博博文的功能。经统计,至案发时该软件已有用户使用19万余个控制端微博账号登录,上述控制端账号绑定微博账号×××余万个(原文如此),被告人蔡坤苗获取违法所得人民币6253752.86元。
2019年3月8日,被告人蔡坤苗被北京市公安局丰台分局太平桥派出所民警抓获,其到案后如实供述基本犯罪事实。
北京微梦创科网络技术有限公司员工李某称:“我们发现有一个叫‘星援’的APP破解了新浪微博的技术参数、算法,能对微博进行转发、评论、点赞等,影响了正常业务和系统稳定。2018年5月份的一天,我用手机刷微博时发现一个叫‘星援’的APP。这个APP可以大量转发或者评论同一条微博。我感觉这个APP可能有损我公司的利益,就跟公司领导进行了汇报。我们做了技术分析,直到现在才破解出来。过程中我们也收到用户的投诉,说‘星援’APP影响了微博的正常榜单和内容,同时也影响了系统的稳定和正常运行。”
相关司法鉴定意见书证明
使用新浪微博账号信息登录星援APP,在不登录微博客户端的情况下,可实现转发新浪微博博文的功能。使用新浪微博账号登录星援APP,通过该软件提供的配置界面,在配置相关参数后,可实现自动批量转发新浪微博博文的功能。
上述鉴定意见书显示,星援APP通过绑定微博账号的操作获取到微博用户的账号信息后,请求微博的服务器,从微博服务器返回的请求中获取相应账号的uid等信息,再通过结合密钥和特定算法的方式,生成微博加密数字签名s值,结合其他参数,使用与“新浪微博客户端”转发微博时相同的网络数据格式,将该数据提交给“新浪微博服务器”,该数据被“新浪微博服务器”误认为是“新浪微博客户端”提交的网络数据,进而和星援APP发生了数据交互,从而实现了不需要登陆“新浪微博客户端”即可转发新浪微博博文的功能。该APP还拥有通过绑定多个账号、多次重复请求,同时在转发微博博文时随机生成不同的硬件设备信息,实现自动批量转发新浪微博博文的功能。
17万微博用户绑定了3000万个微博“小号”
被告人蔡坤苗供述:“2018年3月,我自己做了一个名为星援的手机APP软件,并注册了一个网络工作室。2018年8月,我成立了泉州市星援网络科技有限公司,并担任公司法定代表人。”
蔡坤苗供述称,其公司主要经营两款手机应用软件,分别是星援和应援宝。这两款软件均是对接新浪微博的,客户通过这两款软件可以登录自己的微博账号实现批量转发、点赞和评论操作,而且绑定的微博数量没有上限,不用再人工登录每个微博账号进行重复操作。星援、应援宝两款手机软件通过用户的微博账号、密码登陆,登陆的时候不需要再另行注册。这两款软件的用户可以批量操作在软件端绑定的账号,更加快速的进行微博转发(行话叫抡博)、评论、点赞。微博客户端只能使用一个账号登陆进行操作,而星援、应援宝两款软件可以同时登陆多个微博账号进行相关操作。这两款软件在功能上是一样的,只是名字不一样。
蔡坤苗称,星援、应援宝两款软件可以加快明星粉丝,提升转发评论的数据量,满足数据的需求,“我于2019年2月份查看后台数据,星援、应援宝共有微博‘大号’用户17余万个,这17余万用户大约绑定了3000余万个微博‘小号’。‘星援’‘应援宝’一共有微博中的明星群管理员×××余个。微博‘大号’是常用的微博账号,有粉丝的老号。微博‘小号’是新注册或注册时间短的账号,也就是为转发增量而准备的账号。2019年2月份左右,我查了一下银行账户,‘星援’累计充值人民币700余万元,应援宝使用人数比较少,大概充值有10余万元。”
蔡坤苗供述称,他将犯罪所得主要用于买房和公司开销了,“我在泉州城东中骏世界城买了一处住宅,目前还在建设没有交房,费用大约100余万元。我还在泉州城东中骏世界城买了两个底商登记在我父亲蔡某名下,费用大约300万到400万之间,具体多少钱记不清了。其余资金用于日常开销、员工工资支出等。公司人事是陈某,每月工资7000元。UI设计是苏某和一个男孩,每月工资7000元。”
判决书显示
被害单位北京微梦创科网络技术有限公司的诉讼代理人在审理期间提供的证据证明,被告人蔡坤苗恶意开发的“星援”APP在未经北京微梦创科网络技术有限公司授权的情况下自动批量转发微博,大量转发的微博严重干扰了明星势力榜排行的数据,并导致排行系统功能受到实质性的影响;被告人蔡坤苗的行为给北京微梦创科网络技术有限公司造成应急人工支出45986.2元、2018年第四季度的服务器支出10376934元。
不过,法院审理后认为,上述诉讼代理人认为被告人蔡坤苗给被害单位造成经济损失人民币10422920.2元的意见,经查,相关证据均为被害单位单方材料,尚不足以证实与星援APP的关联性,故不予采纳。
北京市丰台区法院审理后认为,被告人蔡坤苗提供专门用于侵入计算机信息系统的程序,情节特别严重,其行为已构成提供侵入计算机信息系统程序罪,应予处罚。鉴于被告人蔡坤苗到案后如实供述基本犯罪事实,故对其予以从轻处罚。
2020年12月31日,被告人蔡坤苗被判犯提供侵入计算机信息系统程序罪,判处有期徒刑五年,并处罚金人民币十万元;继续追缴被告人蔡坤苗违法所得予以没收。
此文章【来源:澎湃新闻】,转载自【北晚新视觉网】,如有不当联系邮箱:pufa@dcloud.io 删除。原文链接
收起阅读 »
安卓设置系统休眠时间-安卓原生方法
//获取默认休眠时间
@UniJSMethod(uiThread = true)
public void GetDormant(final JSCallback callback) {
try{
Context context = mWXSDKInstance.getContext();
int systemGravity = Settings.System.getInt(context.getContentResolver(),android.provider.Settings.System.SCREEN_OFF_TIMEOUT,0);
callback.invoke(systemGravity);
}catch (Exception ex){
callback.invoke(false);
Log.e(TAG, "setDormant: "+ex);
}
}
//设置系统休眠时间
@UniJSMethod(uiThread = true)
public void setDormant(int time,final JSCallback callback) {
try{
Context context = mWXSDKInstance.getContext();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.System.canWrite(context)) {
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + context.getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} else {
//有了权限,具体的动作
Settings.System.putInt(context.getContentResolver(),
Settings.System.SCREEN_OFF_TIMEOUT, time);
Uri uri = Settings.System
.getUriFor(Settings.System.SCREEN_OFF_TIMEOUT);
context.getContentResolver().notifyChange(uri, null);
Log.e(TAG, "setDormant: 设置完成" );
callback.invoke(true);
}
}
}catch (Exception ex){
callback.invoke(false);
Log.e(TAG, "setDormant: "+ex);
}
}
//获取默认休眠时间
@UniJSMethod(uiThread = true)
public void GetDormant(final JSCallback callback) {
try{
Context context = mWXSDKInstance.getContext();
int systemGravity = Settings.System.getInt(context.getContentResolver(),android.provider.Settings.System.SCREEN_OFF_TIMEOUT,0);
callback.invoke(systemGravity);
}catch (Exception ex){
callback.invoke(false);
Log.e(TAG, "setDormant: "+ex);
}
}
//设置系统休眠时间
@UniJSMethod(uiThread = true)
public void setDormant(int time,final JSCallback callback) {
try{
Context context = mWXSDKInstance.getContext();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.System.canWrite(context)) {
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + context.getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} else {
//有了权限,具体的动作
Settings.System.putInt(context.getContentResolver(),
Settings.System.SCREEN_OFF_TIMEOUT, time);
Uri uri = Settings.System
.getUriFor(Settings.System.SCREEN_OFF_TIMEOUT);
context.getContentResolver().notifyChange(uri, null);
Log.e(TAG, "setDormant: 设置完成" );
callback.invoke(true);
}
}
}catch (Exception ex){
callback.invoke(false);
Log.e(TAG, "setDormant: "+ex);
}
}
收起阅读 »

uni-app 屏幕旋转
/
输入参数
portrait-primary:竖屏主方向
portrait-secondary: 竖屏次方向
landscape-primary:横屏主方向
landscape-secondary:横屏次方向
portrait:竖屏方向(primary + secondary)
landscape:横屏方向(primary + secondary)
natural:设备的自然方向
any: 锁定四个方向,即锁定当前屏幕方向
/
plus.screen.lockOrientation('landscape-primary');
/
输入参数
portrait-primary:竖屏主方向
portrait-secondary: 竖屏次方向
landscape-primary:横屏主方向
landscape-secondary:横屏次方向
portrait:竖屏方向(primary + secondary)
landscape:横屏方向(primary + secondary)
natural:设备的自然方向
any: 锁定四个方向,即锁定当前屏幕方向
/
plus.screen.lockOrientation('landscape-primary');
收起阅读 »

可恶!老年手机里植入木马程序 非法获利6600余万元
近日,攀枝花市公安局东区分局成功破获一起非法控制计算机信息系统案件,打掉了三个控制“老年”手机非法获利的犯罪团伙。
去年3月,攀枝花市公安局东区分局接到一条线索,称一名75岁退休老人收到一条诈骗短信,被以刷单的方式诈骗资金6400元,然而这位老人他使用是一款老年手机。
民警发现该手机号向200余个手机发送了380条短信。通过调查发现该手机被植入了控制手机的木马程序,被外部服务器控制向他人发送诈骗短信。发送诈骗短信的电话是攀枝花市东区一居民孙某。经过进一步侦查工作,发现该团伙是以陈某某为首的犯罪团伙,他们在深圳注册了专门的科技公司生产手机,将植入木马功能的老年机销向市场,进行非法控制获取非法利益。该手机一旦被人购买插卡使用,便会主动将手机号码发送给犯罪团伙,并自动与科技公司的后台服务器发生联网,达到控制目标手机的目的。
随后专案组兵分三路,分别前往深圳、浙江、重庆开展收网工作,抓获了涉案人员25人,并起获了大量的后台服务器数据和尚未出售的装有木马的手机2万余部。随后调取后台服务数据显示,涉及受害手机达600余万部,涉案金额达4亿元。受害者遍及全国31个省、直辖市、自治区,犯罪团伙非法获利6600余万元。
民警提醒:部分非正规厂家生产的老年机可能存在被植入木马的隐患,因此我们在购买老年机的时候要选择正规厂商正规的品牌购买,一旦发现自己的资费有问题的时候,要去运营商查看相关情况,以防被不法分子利用。
此文章【来源:四川观察】,转载自【腾讯网】,如有不当联系邮箱:pufa@dcloud.io 删除。原文链接
版权归原作者所有,向原创致敬。
近日,攀枝花市公安局东区分局成功破获一起非法控制计算机信息系统案件,打掉了三个控制“老年”手机非法获利的犯罪团伙。
去年3月,攀枝花市公安局东区分局接到一条线索,称一名75岁退休老人收到一条诈骗短信,被以刷单的方式诈骗资金6400元,然而这位老人他使用是一款老年手机。
民警发现该手机号向200余个手机发送了380条短信。通过调查发现该手机被植入了控制手机的木马程序,被外部服务器控制向他人发送诈骗短信。发送诈骗短信的电话是攀枝花市东区一居民孙某。经过进一步侦查工作,发现该团伙是以陈某某为首的犯罪团伙,他们在深圳注册了专门的科技公司生产手机,将植入木马功能的老年机销向市场,进行非法控制获取非法利益。该手机一旦被人购买插卡使用,便会主动将手机号码发送给犯罪团伙,并自动与科技公司的后台服务器发生联网,达到控制目标手机的目的。
随后专案组兵分三路,分别前往深圳、浙江、重庆开展收网工作,抓获了涉案人员25人,并起获了大量的后台服务器数据和尚未出售的装有木马的手机2万余部。随后调取后台服务数据显示,涉及受害手机达600余万部,涉案金额达4亿元。受害者遍及全国31个省、直辖市、自治区,犯罪团伙非法获利6600余万元。
民警提醒:部分非正规厂家生产的老年机可能存在被植入木马的隐患,因此我们在购买老年机的时候要选择正规厂商正规的品牌购买,一旦发现自己的资费有问题的时候,要去运营商查看相关情况,以防被不法分子利用。
此文章【来源:四川观察】,转载自【腾讯网】,如有不当联系邮箱:pufa@dcloud.io 删除。原文链接
版权归原作者所有,向原创致敬。

编写微信小程序报渲染层错误[1]
问题:在编写微信小程序用到组件调用时,在子组件内部将props中的属性值动态赋给data中的某个状态值时,报 渲染层错误” Expect END descriptor with depth 1 but get another,
原因:我在组件created生命函数中直接赋的值,在网上查的资料说是微信小程序中不能这样修改数据,得用seData()函数修改。后来定义了个方法,在方法中实现动态赋值,然后在生命函数中调用这个方法就行了
问题:在编写微信小程序用到组件调用时,在子组件内部将props中的属性值动态赋给data中的某个状态值时,报 渲染层错误” Expect END descriptor with depth 1 but get another,
原因:我在组件created生命函数中直接赋的值,在网上查的资料说是微信小程序中不能这样修改数据,得用seData()函数修改。后来定义了个方法,在方法中实现动态赋值,然后在生命函数中调用这个方法就行了

uni-app mDNS
// #ifdef APP-PLUS
let vm = this;
let mServerType = '_http._tcp.'; //服务类型
let NsdServiceInfo = plus.android.importClass('android.net.nsd.NsdServiceInfo');
let NsdManager = plus.android.importClass('android.net.nsd.NsdManager');
let Context = plus.android.importClass('android.content.Context');
// 导入后可以使用new方法创建类的实例对象
let nsd_service_info = new NsdServiceInfo();
let nsd_manager = new NsdManager();
//获取应用主Activity实例对象系统服务NSD_SERVICE方法
let mNsdManager = plus.android.runtimeMainActivity().getSystemService(Context.NSD_SERVICE);
//实列API接口监听回调函数
let mDiscoveryListener = plus.android.implements('android.net.nsd.NsdManager$DiscoveryListener', {
onServiceFound: function(service) {
//先发现设备服务再执行连接获取数据
//导入service类
plus.android.importClass(service);
//实列化连接服务接口监听回调函数
//注意NsdManager$ResolveListener中间使用$不是“.”
let mResolveListener = plus.android.implements('android.net.nsd.NsdManager$ResolveListener', {
onServiceResolved: function(services) {
//连接服务
let name = services.getServiceName();
let port = services.getPort();
let ip = services.getHost();
plus.android.importClass(ip); //导入services.getHost()类
ip = ip.getHostAddress();
let arry = {
name: name,
port: port,
ip: ip
};
console.log(arry)
if(name == "esp8266"){
mNsdManager.stopServiceDiscovery(mResolveListener);
}
}
});
mNsdManager.resolveService(service, mResolveListener); //启动连接服务
}
});
// 导入mNsdManager Java类对象
plus.android.importClass(mNsdManager);
mNsdManager.discoverServices(mServerType, 1, mDiscoveryListener); //启动监听服务(类型,常量,回调函数)参考java discoverServices需要携带的参数类型
// #endif
// #ifdef APP-PLUS
let vm = this;
let mServerType = '_http._tcp.'; //服务类型
let NsdServiceInfo = plus.android.importClass('android.net.nsd.NsdServiceInfo');
let NsdManager = plus.android.importClass('android.net.nsd.NsdManager');
let Context = plus.android.importClass('android.content.Context');
// 导入后可以使用new方法创建类的实例对象
let nsd_service_info = new NsdServiceInfo();
let nsd_manager = new NsdManager();
//获取应用主Activity实例对象系统服务NSD_SERVICE方法
let mNsdManager = plus.android.runtimeMainActivity().getSystemService(Context.NSD_SERVICE);
//实列API接口监听回调函数
let mDiscoveryListener = plus.android.implements('android.net.nsd.NsdManager$DiscoveryListener', {
onServiceFound: function(service) {
//先发现设备服务再执行连接获取数据
//导入service类
plus.android.importClass(service);
//实列化连接服务接口监听回调函数
//注意NsdManager$ResolveListener中间使用$不是“.”
let mResolveListener = plus.android.implements('android.net.nsd.NsdManager$ResolveListener', {
onServiceResolved: function(services) {
//连接服务
let name = services.getServiceName();
let port = services.getPort();
let ip = services.getHost();
plus.android.importClass(ip); //导入services.getHost()类
ip = ip.getHostAddress();
let arry = {
name: name,
port: port,
ip: ip
};
console.log(arry)
if(name == "esp8266"){
mNsdManager.stopServiceDiscovery(mResolveListener);
}
}
});
mNsdManager.resolveService(service, mResolveListener); //启动连接服务
}
});
// 导入mNsdManager Java类对象
plus.android.importClass(mNsdManager);
mNsdManager.discoverServices(mServerType, 1, mDiscoveryListener); //启动监听服务(类型,常量,回调函数)参考java discoverServices需要携带的参数类型
// #endif
收起阅读 »

unipush服务端推送PHP版RestAPI V2 的离线/在线推送
关于unipush的推送还是用个推的文档和SDK,下载个推的SDK整合进PHP框架里,然后开始表演了。刚开始在网上找真的都是老版本的,RestAPI V2 的几乎没有涉及,旧SDK的可能以后都要不支持了,所以建议大家更换新版本的SDK。话不多说,上代码:
$title为推送标题,$content为推送内容,$payload为点击通知加自定义消息,$cid为推送cid,$package为APP包名,"APPKEY","APPID","MasterSecret"这几个要传入你真实的。以下是单推例子,更多推送就不多说了。
function pushToSingleByCid($title,$content,$payload,$cid,$package){
//创建API,APPID等配置参考 环境要求 进行获取
$api = new \GTClient_unipush("https://restapi.getui.com","APPKEY","APPID","MasterSecret");
//设置推送参数
$push = new \GTPushRequest();
$osn = date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
$push->setRequestId((string)$osn);
$message = new \GTPushMessage();
$channel = new \GTPushChannel();
$notify = new \GTNotification();
$thirdnotify = new \GTThirdNotification();
$ups = new \GTUps();
$gtAndroid = new \GTAndroid();
$notify->setTitle($title);
$notify->setBody($content);
$thirdnotify->setTitle($title);
$thirdnotify->setBody($content);
if(is_array($payload))
$pj = json_encode($payload);
else
$pj = $payload;
$notify-> setPayload($pj);
$thirdnotify-> setPayload($pj);
$intent = "intent:#Intent;launchFlags=0x14000000;action=android.intent.action.oppopush;component={$package}/io.dcloud.PandoraEntry;S.UP-OL-SU=true;S.title={$title};S.content={$content};S.payload={$pj};end";
$notify->setClickType("intent");
$thirdnotify->setClickType("intent");
$notify->setIntent($intent);
$thirdnotify->setIntent($intent);
echo $intent;
//点击通知后续动作,目前支持以下后续动作:
//1、intent:打开应用内特定页面url:打开网页地址。2、payload:自定义消息内容启动应用。3、payload_custom:自定义消息内容不启动应用。4、startapp:打开应用首页。5、none:纯通知,无后续动作
$notify->setIntent($intent);
// $notify->setChannelLevel(3);
// $touchuan=['title'=>$title,'content'=>$content,'payload'=>$package];
//$message->setTransmission(json_encode($touchuan));//个推透传
$message->setNotification($notify);
$upsback= $ups->setNotification($thirdnotify);
// $upsback= $ups->setTransmission(json_encode($touchuan));//厂商透传
$gtAndroid->setUps($ups);
$channel->setAndroid($gtAndroid);
$push->setPushMessage($message);
$push->setPushChannel( $channel);
$push->setCid($cid);
//处理返回结果
$result = $api->pushApi()->pushToSingleByCid($push);
// print_r($result);
}
关于unipush的推送还是用个推的文档和SDK,下载个推的SDK整合进PHP框架里,然后开始表演了。刚开始在网上找真的都是老版本的,RestAPI V2 的几乎没有涉及,旧SDK的可能以后都要不支持了,所以建议大家更换新版本的SDK。话不多说,上代码:
$title为推送标题,$content为推送内容,$payload为点击通知加自定义消息,$cid为推送cid,$package为APP包名,"APPKEY","APPID","MasterSecret"这几个要传入你真实的。以下是单推例子,更多推送就不多说了。
function pushToSingleByCid($title,$content,$payload,$cid,$package){
//创建API,APPID等配置参考 环境要求 进行获取
$api = new \GTClient_unipush("https://restapi.getui.com","APPKEY","APPID","MasterSecret");
//设置推送参数
$push = new \GTPushRequest();
$osn = date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
$push->setRequestId((string)$osn);
$message = new \GTPushMessage();
$channel = new \GTPushChannel();
$notify = new \GTNotification();
$thirdnotify = new \GTThirdNotification();
$ups = new \GTUps();
$gtAndroid = new \GTAndroid();
$notify->setTitle($title);
$notify->setBody($content);
$thirdnotify->setTitle($title);
$thirdnotify->setBody($content);
if(is_array($payload))
$pj = json_encode($payload);
else
$pj = $payload;
$notify-> setPayload($pj);
$thirdnotify-> setPayload($pj);
$intent = "intent:#Intent;launchFlags=0x14000000;action=android.intent.action.oppopush;component={$package}/io.dcloud.PandoraEntry;S.UP-OL-SU=true;S.title={$title};S.content={$content};S.payload={$pj};end";
$notify->setClickType("intent");
$thirdnotify->setClickType("intent");
$notify->setIntent($intent);
$thirdnotify->setIntent($intent);
echo $intent;
//点击通知后续动作,目前支持以下后续动作:
//1、intent:打开应用内特定页面url:打开网页地址。2、payload:自定义消息内容启动应用。3、payload_custom:自定义消息内容不启动应用。4、startapp:打开应用首页。5、none:纯通知,无后续动作
$notify->setIntent($intent);
// $notify->setChannelLevel(3);
// $touchuan=['title'=>$title,'content'=>$content,'payload'=>$package];
//$message->setTransmission(json_encode($touchuan));//个推透传
$message->setNotification($notify);
$upsback= $ups->setNotification($thirdnotify);
// $upsback= $ups->setTransmission(json_encode($touchuan));//厂商透传
$gtAndroid->setUps($ups);
$channel->setAndroid($gtAndroid);
$push->setPushMessage($message);
$push->setPushChannel( $channel);
$push->setCid($cid);
//处理返回结果
$result = $api->pushApi()->pushToSingleByCid($push);
// print_r($result);
}
收起阅读 »

基于uniapp+yii2的全套OA办公系统,提供前后端源码,支持多端部署
简介
UNI办公系统主要为国内企业提供办公自动化信息服务,功能如:工作流、工作审批(报修申请、报销申请、领用申请、申购申请、请假申请、出差申请、加班申请、用工申请、接待申请、用车申请);个人中心(公告管理、消息管理、工作日志、我的日程、工作总结);知识管理(新闻动态、管理制度、下载中心等);日常管理(资产管理、车辆管理、档案管理、考勤管理、巡更巡检、合同管理、后勤采购、就餐统计、通讯录);人事管理(员工信息、奖惩管理、社保管理等)、考勤管理(班次管理、排班管理、我的排班、签到签退);巡更巡检(地点管理、巡更班次、巡更计划、我的排班、巡更记录);意见反馈、站点帮助、在线客服、一键换肤等功能模块。
系统前端基于uniapp开发,后端基于php开发;该系统可独立部署在自己的服务器,且支持单企业版和多企业版本;可后台根据用户角色权限控制手机端功能模块的显示;目前已适配H5、微信小程序、安卓和ios,如果在试用或购买后发现问题,欢迎您随时提出。
咨询
作者QQ:21931118 QQ群:1107210028
如您已下载本插件,可加入QQ群一起讨论,作者不承诺技术支持;
演示
- 后台演示账号:后台不开源,不免费提供后台账号及接口
- 手机端测试版:测试版自己加群下载,账密:18986860001/18986860001(请扫码H5或者安卓,苹果和小程序版不提供测试账号)
- 业务合作:加Q私聊
- 官方网站:unioa插件市场
手机端部分截图
后台部分截图
安装插件
已安装插件
工作流列表
工作流配置
流程状态
配置审核人员
支持指定人员审核和指定角色审核
工作流转
新增流程节点
待办工作
已办工作
如果审核失误,在下一级没有审核的情况下,可点击重审按钮进行重新审核,流程将重新转入申请状态。
审核工作
创建申请
查看进度
如果工作已有人员进行审核,进入工作流转后,用户不能编辑和删除该工作。
企业管理人员可自定义工作类型
班次管理
排班管理
我的排班
签到列表
新建打卡
插件市场 总有一款插件适合你!
开始使用
- 将项目导入HBuildX
- 修改配置文件config/index.conf.js内配置对应参数
- 运行即可体验
发行微信小程序
在HBuildx顶部菜单点击运行->运行到微信小程序
使用微信开发者工具上传版本并审核通过即可
注意:小程序需额外配置服务器域名
发行H5
在HBuildx顶部菜单点击发行->网站-H5手机版
在弹出的对话框中输入网站标题和域名即可,将编译后的资源部署到服务器(虚拟主机)
需注意HBx直接部署网页托管需要最新版,老版本没有这个选项,可以自己到web控制台进行托管。
点击发行,等待项目编译部署即可。
如果您不想购买服务器,那就来uniCloud白嫖一波吧~
发行ios版和安卓版
在HBuildx顶部菜单点击发行->原生App-云打包,
在弹出的对话框中选择证书文件和输入密码即可。
隐私、权限声明
-
本插件需要申请的系统权限列表:
1.定位权限 2.拍照权限 3.相册权限
-
本插件采集的数据、发送的服务器地址、以及数据用途说明:
无
-
本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:
无
简介
UNI办公系统主要为国内企业提供办公自动化信息服务,功能如:工作流、工作审批(报修申请、报销申请、领用申请、申购申请、请假申请、出差申请、加班申请、用工申请、接待申请、用车申请);个人中心(公告管理、消息管理、工作日志、我的日程、工作总结);知识管理(新闻动态、管理制度、下载中心等);日常管理(资产管理、车辆管理、档案管理、考勤管理、巡更巡检、合同管理、后勤采购、就餐统计、通讯录);人事管理(员工信息、奖惩管理、社保管理等)、考勤管理(班次管理、排班管理、我的排班、签到签退);巡更巡检(地点管理、巡更班次、巡更计划、我的排班、巡更记录);意见反馈、站点帮助、在线客服、一键换肤等功能模块。
系统前端基于uniapp开发,后端基于php开发;该系统可独立部署在自己的服务器,且支持单企业版和多企业版本;可后台根据用户角色权限控制手机端功能模块的显示;目前已适配H5、微信小程序、安卓和ios,如果在试用或购买后发现问题,欢迎您随时提出。
咨询
作者QQ:21931118 QQ群:1107210028
如您已下载本插件,可加入QQ群一起讨论,作者不承诺技术支持;
演示
- 后台演示账号:后台不开源,不免费提供后台账号及接口
- 手机端测试版:测试版自己加群下载,账密:18986860001/18986860001(请扫码H5或者安卓,苹果和小程序版不提供测试账号)
- 业务合作:加Q私聊
- 官方网站:unioa插件市场
手机端部分截图
后台部分截图
安装插件
已安装插件
工作流列表
工作流配置
流程状态
配置审核人员
支持指定人员审核和指定角色审核
工作流转
新增流程节点
待办工作
已办工作
如果审核失误,在下一级没有审核的情况下,可点击重审按钮进行重新审核,流程将重新转入申请状态。
审核工作
创建申请
查看进度
如果工作已有人员进行审核,进入工作流转后,用户不能编辑和删除该工作。
企业管理人员可自定义工作类型
班次管理
排班管理
我的排班
签到列表
新建打卡
插件市场 总有一款插件适合你!
开始使用
- 将项目导入HBuildX
- 修改配置文件config/index.conf.js内配置对应参数
- 运行即可体验
发行微信小程序
在HBuildx顶部菜单点击运行->运行到微信小程序
使用微信开发者工具上传版本并审核通过即可
注意:小程序需额外配置服务器域名
发行H5
在HBuildx顶部菜单点击发行->网站-H5手机版
在弹出的对话框中输入网站标题和域名即可,将编译后的资源部署到服务器(虚拟主机)
需注意HBx直接部署网页托管需要最新版,老版本没有这个选项,可以自己到web控制台进行托管。
点击发行,等待项目编译部署即可。
如果您不想购买服务器,那就来uniCloud白嫖一波吧~
发行ios版和安卓版
在HBuildx顶部菜单点击发行->原生App-云打包,
在弹出的对话框中选择证书文件和输入密码即可。
隐私、权限声明
-
本插件需要申请的系统权限列表:
1.定位权限 2.拍照权限 3.相册权限
-
本插件采集的数据、发送的服务器地址、以及数据用途说明:
无
-
本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:
无