
tailwindcss 小程序定制化之旅
! https://zhuanlan.zhihu.com/p/405083946
tailwindcss 小程序定制化之旅
前言
tailwindcss
太好用,怎么在小程序里用?
小程序编写的 标签
,class
,还有 css选择器
的支持程度都和 H5 不一样,
所以我们要针对小程序目前的实现,去定制化 tailwindcss
以便来兼容 uni-app
, taro
和 原生开发
定制化 tailwindcss
小程序到底有哪些限制呢?我们要从哪几个方向对 tailwindcss
进行定制呢?
1. 不能用特殊字符的 class
在 view
text
的 class
写特殊字符,在渲染的时候会默认变成空格。
这里给大家直接举例子来直观的表现这个限制:
class="w-1/4 h-1.5"
=>class="w-1 4 h-1 5"
class="hover:text-xs"
=>class="hover text-xs"
class="w-[996rpx]
=>class="w- 996rpx"
聪明的小伙伴们,一看这 3
个例子立马就知道,无法直接使用的场景:
- 部分带有
\/
\.
字符的工具类 tailwindcss
中的variants
tailwindcss
的jit
模式
当然小伙伴们看到不能直接使用这6个字,肯定知道我的意思是可以间接使用的。
比如对 class
进行重命名。
form | to | sample |
---|---|---|
\/ |
-div- |
w-1/4 -> w-1-div-4 |
\. |
-dot- |
w-1.5 -> w-1-dot-5 |
至于 variants
, 由于 wxss
没有这么多选择器,我们暂时置空。
jit
模式目前处于试验阶段,等能方便的自定义解析器之时再用。
2. 无所事事的选择器
先上 wxss 官方文档链接
从里面,我们可以看到目前支持的选择器有:
显然,它比 h5 要少太多啦!
不过我们可以根据这张表进行进一步阉割。
- 去除基于
:not
选择器的corePlugins
,例如space
,divide*
- 去除不支持
*
选择器的corePlugins
, 例如默认添加'*, ::before, ::after'
的插件boxShadow
,ring*
- 清空
tailwind variants
( 这类hover:
focus:
,...
,统统干掉)
3. H5 需要的,小程序不需要
我们知道 tailwindcss
主要由三块组成:
base
对h5默认标签
进行normalize
components
container media 容器布局utilities
工具类
显然在小程序这个场景下 base
,components
都是不需要的。
小程序标签和 h5 完全不同,没有 base
的必要
另外小程序自适应,主要靠 rpx
,而不是靠 pc,小屏,中屏,大屏,所以 components
也不需要。
所以我们只需要在小程序中导入 utilities
另外由于 normalize 标签
和 自适应方案的不同
我们可以把 theme.screens
设为 false
,不去生成 sm:xxx
这类的代码。
同时自然也不需要 preflight
,container
,accessibility
这一类的插件了。
4. 把默认的 rem 转成 rpx
小程序专属自适应单位 rpx
rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为 750rpx。如在 iPhone6 上,屏幕宽度为 375px,共有 750 个物理像素,则 750rpx = 375px = 750 物理像素,1rpx = 0.5px = 1 物理像素。
我们 rem
一般是 rootValue
为 16px
, 那根据这个算法就是 32rpx
。
这一块非常简单,写个插件或者几行代码转化一下就可以。
vscode
实现效果图:
具体实现可以看我附录的代码。
tailwindcss-miniprogram-preset
根据上文的经验写了一个预设 tailwindcss-miniprogram-preset
怎么使用呢?我们只需要在安装初始化 tailwindcss
和 postcss
后, 来安装一下。
yarn add -D tailwindcss-miniprogram-preset
然后在 tailwind.config.js
里,添加它
// tailwind.config.js
module.exports = {
presets: [require('tailwindcss-miniprogram-preset')]
// ...
}
然后在 app.wxss
里
@tailwind utilities;
就可以使用了。
在开发的时候,生成的 wxss
大概有 100+kb
,不过在 purgecss
后,就会非常小了。
purge
默认 process.env.NODE_ENV === 'production'
开启,也可手动开启。
再配合上 vscode 插件 Tailwind CSS IntelliSense 使用,可以直接自动生成智能提示,开发体验很好。
另外也写了一份 uni-app
+ vue3
+ tailwindcss
的模板,有需要可以使用 uni-app-vue3-tailwind-vscode-template
也写了一个在原生小程序中,使用 scss
+ postcss
+ tailwindcss
的例子。接下来下一篇文章,我们就简单谈谈,如何抛弃微信开发者工具的 postcss
功能 , 让我们在原生的小程序开发中,自定义 postcss
和 sass
工具链编译,来享受它们和 tailwindcss
带来的各种好处。
! https://zhuanlan.zhihu.com/p/405083946
tailwindcss 小程序定制化之旅
前言
tailwindcss
太好用,怎么在小程序里用?
小程序编写的 标签
,class
,还有 css选择器
的支持程度都和 H5 不一样,
所以我们要针对小程序目前的实现,去定制化 tailwindcss
以便来兼容 uni-app
, taro
和 原生开发
定制化 tailwindcss
小程序到底有哪些限制呢?我们要从哪几个方向对 tailwindcss
进行定制呢?
1. 不能用特殊字符的 class
在 view
text
的 class
写特殊字符,在渲染的时候会默认变成空格。
这里给大家直接举例子来直观的表现这个限制:
class="w-1/4 h-1.5"
=>class="w-1 4 h-1 5"
class="hover:text-xs"
=>class="hover text-xs"
class="w-[996rpx]
=>class="w- 996rpx"
聪明的小伙伴们,一看这 3
个例子立马就知道,无法直接使用的场景:
- 部分带有
\/
\.
字符的工具类 tailwindcss
中的variants
tailwindcss
的jit
模式
当然小伙伴们看到不能直接使用这6个字,肯定知道我的意思是可以间接使用的。
比如对 class
进行重命名。
form | to | sample |
---|---|---|
\/ |
-div- |
w-1/4 -> w-1-div-4 |
\. |
-dot- |
w-1.5 -> w-1-dot-5 |
至于 variants
, 由于 wxss
没有这么多选择器,我们暂时置空。
jit
模式目前处于试验阶段,等能方便的自定义解析器之时再用。
2. 无所事事的选择器
先上 wxss 官方文档链接
从里面,我们可以看到目前支持的选择器有:
显然,它比 h5 要少太多啦!
不过我们可以根据这张表进行进一步阉割。
- 去除基于
:not
选择器的corePlugins
,例如space
,divide*
- 去除不支持
*
选择器的corePlugins
, 例如默认添加'*, ::before, ::after'
的插件boxShadow
,ring*
- 清空
tailwind variants
( 这类hover:
focus:
,...
,统统干掉)
3. H5 需要的,小程序不需要
我们知道 tailwindcss
主要由三块组成:
base
对h5默认标签
进行normalize
components
container media 容器布局utilities
工具类
显然在小程序这个场景下 base
,components
都是不需要的。
小程序标签和 h5 完全不同,没有 base
的必要
另外小程序自适应,主要靠 rpx
,而不是靠 pc,小屏,中屏,大屏,所以 components
也不需要。
所以我们只需要在小程序中导入 utilities
另外由于 normalize 标签
和 自适应方案的不同
我们可以把 theme.screens
设为 false
,不去生成 sm:xxx
这类的代码。
同时自然也不需要 preflight
,container
,accessibility
这一类的插件了。
4. 把默认的 rem 转成 rpx
小程序专属自适应单位 rpx
rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为 750rpx。如在 iPhone6 上,屏幕宽度为 375px,共有 750 个物理像素,则 750rpx = 375px = 750 物理像素,1rpx = 0.5px = 1 物理像素。
我们 rem
一般是 rootValue
为 16px
, 那根据这个算法就是 32rpx
。
这一块非常简单,写个插件或者几行代码转化一下就可以。
vscode
实现效果图:
具体实现可以看我附录的代码。
tailwindcss-miniprogram-preset
根据上文的经验写了一个预设 tailwindcss-miniprogram-preset
怎么使用呢?我们只需要在安装初始化 tailwindcss
和 postcss
后, 来安装一下。
yarn add -D tailwindcss-miniprogram-preset
然后在 tailwind.config.js
里,添加它
// tailwind.config.js
module.exports = {
presets: [require('tailwindcss-miniprogram-preset')]
// ...
}
然后在 app.wxss
里
@tailwind utilities;
就可以使用了。
在开发的时候,生成的 wxss
大概有 100+kb
,不过在 purgecss
后,就会非常小了。
purge
默认 process.env.NODE_ENV === 'production'
开启,也可手动开启。
再配合上 vscode 插件 Tailwind CSS IntelliSense 使用,可以直接自动生成智能提示,开发体验很好。
另外也写了一份 uni-app
+ vue3
+ tailwindcss
的模板,有需要可以使用 uni-app-vue3-tailwind-vscode-template
也写了一个在原生小程序中,使用 scss
+ postcss
+ tailwindcss
的例子。接下来下一篇文章,我们就简单谈谈,如何抛弃微信开发者工具的 postcss
功能 , 让我们在原生的小程序开发中,自定义 postcss
和 sass
工具链编译,来享受它们和 tailwindcss
带来的各种好处。

合肥招uniapp开发工程师,维护产品做持续开发,非外包公司
有兴趣的同学请站内私信或加QQ私聊: 118-178-1455(QQ) 谢谢啦
有兴趣的同学请站内私信或加QQ私聊: 118-178-1455(QQ) 谢谢啦

避免直接改变prop,因为当父组件重新呈现时,该值将被覆盖。 相反,使用基于道具值的
父组件视图
以滑动开关为例 bIsOpenState
<card v-for="(jobItem, index) in ZHiWeiList" :key="index"
:jobName="jobItem.cWorkName"
:jobSalary="jobItem.dGangWeiXinZiBegin+'-'+jobItem.dGangWeiXinZiEnd"
:tagList="jobItem.cZhiWeiYaoQiu"
:place="jobItem.Province+jobItem.City+jobItem.Area+jobItem.cBranchShopAddress"
:userName="jobItem.cLianXiName"
:bIsOpenState="jobItem.bIsOpenState"
:date="jobItem.dFaBuDate"
@toCardDetail="toUpdZhiWei(jobItem)"
@bIsOpenStateChange="bIsOpenStateChange(jobItem.bIsOpenState,jobItem.cZhiWeiCode,index)"
@toUpd="toUpd(jobItem.cZhiWeiCode,index)"
@toDel="toDel(jobItem.cZhiWeiCode,index)"
>
</card>
父组件事件
bIsOpenStateChange(bIsOpenState1,cZhiWeiCode,index){
console.log("bIsOpenStateChange",bIsOpenState1,cZhiWeiCode,index);
let that=this;
console.log(bIsOpenState1);
if(bIsOpenState1)
{
bIsOpenState1=false;
}
else
{
bIsOpenState1=true;
}
console.log("原来",that.ZHiWeiList[index].bIsOpenState);
that.ZHiWeiList[index].bIsOpenState=bIsOpenState1;
// console.log(that.ZHiWeiList);
console.log("改后",that.ZHiWeiList[index].bIsOpenState);
},
toUpd(cZhiWeiCode,index){
console.log("toUpd",cZhiWeiCode,index);
},
toDel(cZhiWeiCode,index){
console.log("toDel",cZhiWeiCode,index);
},
子组件视图
<template>
<view class="re-card bg-white flex-column align-center radius-xs">
<view @click="toCardDetail" style="width: 95%;">
<view class="card-top flex-row">
<view class="job-name">
<text class="text-xl">{{jobName}}</text>
</view>
<view class="job-salary text-bold text-right" style="color: #e4b118;">
<text class="text-xl">{{jobSalary}}</text>
</view>
</view>
<view class="tag-list flex-row">
<view class="tag-item bg-gray">
<text>{{tagList}}</text>
</view>
<!-- <view class="tag-item bg-gray" v-for="(tagItem, index) in tagList" :key="index">
<text>{{tagItem.name}}</text>
</view> -->
</view>
<view class="place margin-top-xs text-gray text-xs">
<text class="fa fa-map-marker"></text>
<text class="margin-left-sm">{{place}}</text>
</view>
<view class="user-info flex-row align-center" style="border-bottom: 2rpx solid #E4B118;">
<image :src="userAvatar" class="avatar-xs"></image>
<text class="text-xs margin-left-sm text-gray">{{userName}}</text>
<text>{{date}}</text>
</view>
</view>
<view style="width: 100%;height: 80rpx;margin-top: 10rpx;">
<u-switch @change="bIsOpenStateChange()" v-model="bIsOpenState1" size="50" active-color="#e4b118" style="float: left;margin-left: 5%;"></u-switch>
<view @click="toUpd()" class="btn-operation">修改</view>
<view @click="toDel()" class="btn-operation">删除</view>
</view>
</view>
</template>
子组件事件
<script>
export default {
name: 'card',
props: {
jobId: {
type: String,
default: ''
},
tagList:'',
// tagList: {
// type: Array,
// default: []
// },
date: {
type: String,
default: ''
},
jobName: {
type: String,
default: ''
},
jobSalary: {
type: String,
default: ''
},
place: {
type: String,
default: ''
},
userName: {
type: String,
default: ''
},
userAvatar: {
type: String,
default: ''
},
offerDate: {
type: String,
default: ''
},
bIsOpenState:{
type:Boolean,
default:false
},
},
data() {
return {
bIsOpenState1:this.bIsOpenState
};
},
methods: {
toCardDetail:function() {
this.$emit('toCardDetail');
},
bIsOpenStateChange:function(){
this.$emit('bIsOpenStateChange');
},
toUpd:function(){
this.$emit('toUpd');
},
toDel:function(){
this.$emit('toDel');
},
}
}
</script>
ps:
避免直接改变属性,因为当父组件重新呈现时,该值将被覆盖。相反,使用基于属性值的数据或计算属性。道具正在变异:“tabIndex
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “tabIndex”
这样的时候,需要再子页面的data里面去创建一个值去接受父页面传递过来的值,这样这个警告就会消失掉
父组件传递过来的tabIndex,在子组件的时候,用props接受了之后,然后在data里面创建一个变量去接受,这样就能去掉这个警告了
子组件获取值是bIsOpenState
定义一个bIsOpenState1来接受这个值
视图绑定用bIsOpenState1
父组件视图
以滑动开关为例 bIsOpenState
<card v-for="(jobItem, index) in ZHiWeiList" :key="index"
:jobName="jobItem.cWorkName"
:jobSalary="jobItem.dGangWeiXinZiBegin+'-'+jobItem.dGangWeiXinZiEnd"
:tagList="jobItem.cZhiWeiYaoQiu"
:place="jobItem.Province+jobItem.City+jobItem.Area+jobItem.cBranchShopAddress"
:userName="jobItem.cLianXiName"
:bIsOpenState="jobItem.bIsOpenState"
:date="jobItem.dFaBuDate"
@toCardDetail="toUpdZhiWei(jobItem)"
@bIsOpenStateChange="bIsOpenStateChange(jobItem.bIsOpenState,jobItem.cZhiWeiCode,index)"
@toUpd="toUpd(jobItem.cZhiWeiCode,index)"
@toDel="toDel(jobItem.cZhiWeiCode,index)"
>
</card>
父组件事件
bIsOpenStateChange(bIsOpenState1,cZhiWeiCode,index){
console.log("bIsOpenStateChange",bIsOpenState1,cZhiWeiCode,index);
let that=this;
console.log(bIsOpenState1);
if(bIsOpenState1)
{
bIsOpenState1=false;
}
else
{
bIsOpenState1=true;
}
console.log("原来",that.ZHiWeiList[index].bIsOpenState);
that.ZHiWeiList[index].bIsOpenState=bIsOpenState1;
// console.log(that.ZHiWeiList);
console.log("改后",that.ZHiWeiList[index].bIsOpenState);
},
toUpd(cZhiWeiCode,index){
console.log("toUpd",cZhiWeiCode,index);
},
toDel(cZhiWeiCode,index){
console.log("toDel",cZhiWeiCode,index);
},
子组件视图
<template>
<view class="re-card bg-white flex-column align-center radius-xs">
<view @click="toCardDetail" style="width: 95%;">
<view class="card-top flex-row">
<view class="job-name">
<text class="text-xl">{{jobName}}</text>
</view>
<view class="job-salary text-bold text-right" style="color: #e4b118;">
<text class="text-xl">{{jobSalary}}</text>
</view>
</view>
<view class="tag-list flex-row">
<view class="tag-item bg-gray">
<text>{{tagList}}</text>
</view>
<!-- <view class="tag-item bg-gray" v-for="(tagItem, index) in tagList" :key="index">
<text>{{tagItem.name}}</text>
</view> -->
</view>
<view class="place margin-top-xs text-gray text-xs">
<text class="fa fa-map-marker"></text>
<text class="margin-left-sm">{{place}}</text>
</view>
<view class="user-info flex-row align-center" style="border-bottom: 2rpx solid #E4B118;">
<image :src="userAvatar" class="avatar-xs"></image>
<text class="text-xs margin-left-sm text-gray">{{userName}}</text>
<text>{{date}}</text>
</view>
</view>
<view style="width: 100%;height: 80rpx;margin-top: 10rpx;">
<u-switch @change="bIsOpenStateChange()" v-model="bIsOpenState1" size="50" active-color="#e4b118" style="float: left;margin-left: 5%;"></u-switch>
<view @click="toUpd()" class="btn-operation">修改</view>
<view @click="toDel()" class="btn-operation">删除</view>
</view>
</view>
</template>
子组件事件
<script>
export default {
name: 'card',
props: {
jobId: {
type: String,
default: ''
},
tagList:'',
// tagList: {
// type: Array,
// default: []
// },
date: {
type: String,
default: ''
},
jobName: {
type: String,
default: ''
},
jobSalary: {
type: String,
default: ''
},
place: {
type: String,
default: ''
},
userName: {
type: String,
default: ''
},
userAvatar: {
type: String,
default: ''
},
offerDate: {
type: String,
default: ''
},
bIsOpenState:{
type:Boolean,
default:false
},
},
data() {
return {
bIsOpenState1:this.bIsOpenState
};
},
methods: {
toCardDetail:function() {
this.$emit('toCardDetail');
},
bIsOpenStateChange:function(){
this.$emit('bIsOpenStateChange');
},
toUpd:function(){
this.$emit('toUpd');
},
toDel:function(){
this.$emit('toDel');
},
}
}
</script>
ps:
避免直接改变属性,因为当父组件重新呈现时,该值将被覆盖。相反,使用基于属性值的数据或计算属性。道具正在变异:“tabIndex
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “tabIndex”
这样的时候,需要再子页面的data里面去创建一个值去接受父页面传递过来的值,这样这个警告就会消失掉
父组件传递过来的tabIndex,在子组件的时候,用props接受了之后,然后在data里面创建一个变量去接受,这样就能去掉这个警告了
子组件获取值是bIsOpenState
定义一个bIsOpenState1来接受这个值
视图绑定用bIsOpenState1

窃取结算密钥、编写非法结算程序,15 个月窃取 608 万:三人分别被判 11 年、10 年、缓刑
分享汇科技(北京)有限公司(以下简称分享汇公司)与某科技有限责任公司(以下简称PP租车公司)系关联公司。罗某某于2014年6月30日至2015年8月18日期间就职于分享汇公司,担任高级开发工程师。
罗某某与李某系同学关系、与庄某系夫妻关系。
罗某某在工作期间发现PP租车公司与某支付机构之间的资金结算交易、对账系统存在管控漏洞,遂通过其窃取的PP租车公司与某支付机构的资金结算密钥,编写相应的非法结算程序密钥,冒充PP租车公司身份,向某支付机构发送资金结算请求,使某支付机构将资金转入其指定的银行账户。
同时,其通过在PP租车公司自动化对账系统服务器上安装恶意程序,于每日自动化对账系统核实前一日某支付机构对账单之前,对某支付机构对账单中记录的非法资金结算记录进行修改,从而规避PP租车公司自动化对账系统的检查。
2015年5月至2016年2月期间,由罗某某制作后台程序,李某购买虚拟服务器、银行卡,并利用上述漏洞向某支付机构发送虚假的转账请求,分多次从PP租车公司窃取共计人民币3687948元;2016年3月至7月期间,罗某某采用上述方法继续从PP租车公司窃取人民币2394014元,并指使庄某在本市多处的ATM取款机上取现共计人民币一百余万元。
2016年6月底,PP租车公司财务人员进行财务审核时发现公司的账目存在异常后报案,同年8月15日,公安机关将罗某某、庄某抓获归案。同日,罗某某协助公安机关将李某抓获归案。公安机关从罗某某处起获的赃款人民币1666495.09元,从李某处起获的赃款人民币1177980元均已发还爱车汇公司。后庄某退赔爱车汇公司人民币1727518.91元,李某在家属的帮助下退赔爱车汇公司人民币830000元。
另查,李某购买的位于本市昌平区天通中苑的房产1套,其中有人民币789331.28元系赃款,现该房产已查封在案。
庭审过程中,公诉人当庭宣读并出示了公安机关在侦查过程中调取的下列证据:
罗某某的供述证实:
2014年5月,其在PP租车公司上班期间发现公司的管理有漏洞,公司的服务器里有公司财务给某支付机构发送转账指令的密钥。
2015年三四月份的时候,其跟同学李某吃饭,李某问其在PP租车公司有什么赚钱的路子,其就跟李某说了这个事。李某当时说考虑考虑,让其做一个技术上的调研看看是否可行。后其用PP租车公司的工作电脑进入公司的系统查看系统源代码和运行机制,发现公司的对账机制是T+1机制,比如银行当天到账,但对账单会在第二天发给公司,其当时觉得能够利用这个漏洞,之后其把这事跟李某说了。李某说要测试一下看看效果,有没有什么问题,并让其做一个后台给他使用。后其做了一个后台程序,李某买了一个服务器,其把程序部署到服务器上,具体的操作都由李某去做。经过一段时间的测试,大概到2015年6月份左右,其二人正式开始利用PP租车公司的系统漏洞把备付金转到私人账号上。其先进入公司的程序,到里面找到公司和银行结算的密钥下载下来,然后修改公司的程序,使自己制作的程序可以修改、控制公司的程序,之后其二人可以通过其制作的程序向某支付机构提交转账申请,这是以PP租车公司的密钥提交的申请,在提交申请时,其二人会把要收钱的银行卡信息一并提交,这样某支付机构就会把公司的钱直接打到其二人指定的银行卡里。因为当天结算后,某支付机构会在第二天才把对账单发到公司的FTP服务器里,其制作的程序会自动到公司的FTP服务器里篡改某支付机构发来的对账单,把转钱的记录删除。通过打时间差的方式,在每天公司对账之前把对账单篡改了就行,这样公司就发现不了对账单出现问题了。李某是在阿里云上买的虚拟服务器,虚拟服务器的IP地址其记不清了,当时其用的是自己的苹果笔记本电脑,里面应该有记录。
李某做的时候跟其说他转出200多万元,2015年7月份左右,李某找到其说他做完了要分一点钱给其,之后就分多笔给其打了46万元。到了2015年十一二月份,李某开始用现金给其钱,说这样安全,每次多少不固定,大概给其三四次钱,总共不到60万元,李某一共给其105万元。其当时跟李某商量从PP租车公司弄钱的时候约定弄出来的钱一人一半,其认为李某给的钱有点少,因为都是李某在操作,其不知道详细情况,于是就自己登陆上去操作。2016年4月至7月期间,其开始自己做,前后一共从PP租车公司转出230万元到自己指定的账户。这些账户都是其在网上论坛里买的,一共是10张银行卡,每张卡配1张身份证和1个U盾。
其是2015年8月从PP租车公司离职的,2015年五六月份开始做的时候都是李某在操作,其只是提供了程序,之后在2016年4月份其才自己开始做。其自己做的时候李某没有再从PP租车公司的账户上往外转账,其之所以知道是因为其做的程序上面有记录,这之后没有他登陆的记录,现在这些记录都已经删除了。
2016年7月中下旬,其让其爱人庄某拿着银行卡去取钱,其每次都开车送她去ATM机上取钱,其跟庄某说做点伪装再去,让她带个帽子、眼镜。她刚开始不知道这是什么钱,后来到了八月份其告诉庄某这些钱是其通过PP租车公司的漏洞转出来的,她这时才知道,这之后其又强求庄某取了一两次钱。
证人肖某、陈某的证言证实:
2016年6月30日,公司财务人员进行财务审核时发现公司的账目存在异常,掌握这一情况后公司的技术人员开始介入调查,经过技术调查后发现从2015年5月9日开始,有人冒充公司的身份,向某支付机构发起虚假的转账请求,截止到2016年7月2日共从公司非法转走600多万元。
嫌疑人获取了其公司的密钥,然后在向某支付机构发起的报文请求中使用了该密钥进行加密,某支付机构对密钥进行核对后确认是其公司发起的请求,于是就将资金打入嫌疑人指定的账户内,然后嫌疑人通过获取其公司FTP的用户名和密码,直接登录其公司的FTP服务器下载对账单,修改后再上传,篡改对账文件,通过修改对账文件使账目和转账金额一致。
证人钟某的证言证实:
罗某于2014年6月30日入职爱车汇公司,2015年8月18日因个人原因离职。罗某在职期间一直是技术员,在其手下工作,负责公司的基础系统构架,参与开发公司内部管理系统,包括支付系统、短信网关、还有其他一些小系统。罗某只负责系统的开发,系统投入运行后他是没有权利使用的,没有从某支付机构提现的权限,没有管理公司与某支付机构交易密钥的权限,也没有登录公司与某支付机构对账的FTP服务器的权限。公司的FTP是有专人负责的,其本人以及公司的领导都不知道账号、密码。密匙就放在服务器上,公司平时也强调要保证密匙的安全,大家也都知道密匙涉及钱的问题,其所在的技术部门是不可以涉及到公司财务工作的。罗某因为开发系统需要用到这台服务器,他有权限登录存放密钥的服务器,因为这个服务器还部署了很多功能,公司很多系统都要用到这台服务器。
证人魏某的证言证实:
其是爱车汇公司的技术员,负责密钥的更新和维护,但是其本人不能使用,密钥已经与程序连接在一起,爱车汇公司的所有交易都是通过系统自动进行的,任何人都不能使用这个密钥,只有程序在使用。罗某在职期间可以登录存放密钥的服务器,但是没有权利对密钥进行任何操作。
爱车汇公司出具的工作说明证实:
按照PP租车公司2016年7月之前的机制,如果有异常访问在每天17点之前将FTP服务器上某支付机构下发的对账文件下载,修改后再重新上传,则PP自动化程序核对的就是修改后的对账文件。PP租车发送给某支付机构请求的服务器必须有一个IP地址来作为这台机器的标识,这个IP地址从2015年5月份到2016年7月份都没有更换过,而且只有一个IP地址向某支付机构发送代付请求,该IP地址为×××。在2016年7月3日之前,PP租车公司和某支付机构之间的通信没有增加白名单的限制,所以如果是其他IP向某支付机构发送请求,只要有对应的私钥和密钥,都可以申请转账成功。
2015年5月9日至2016年7月2日,通过某支付机构提供的提现记录和PP租车公司记录的提现记录对比,发现共发生520405笔提现记录,其中518548笔来自爱车汇公司服务器(×××)发起的请求,另有1857笔系非经爱车汇公司提起的提现请求。
法院裁决:
罗某某单独或伙同李某以非法占有为目的,秘密窃取公司钱款,数额特别巨大,其二人的行为均已构成盗窃罪,应予惩处;庄某明知是犯罪所得而予以转移,情节严重,其行为已构成掩饰、隐瞒犯罪所得罪,应予惩处。北京市海淀区人民检察院指控罗某某、李某犯盗窃罪,庄某犯掩饰、隐瞒犯罪所得罪的事实清楚,证据确实、充分,指控罪名成立。
关于本案的定性问题,经查,罗某某在PP租车公司担任高级开发工程师职务,主要工作职责为基础系统开发,并没有向某支付机构发送提现请求的权利,其工作内容与财务无关。同时,证人钟某、魏某的证言可以证实罗某某虽因职务所需有权登陆储存资金结算密钥的服务器,但其无权对密钥进行任何性质的操作,也无权登陆PP租车公司用于与某支付机构进行对账的服务器,PP租车公司的银行密钥亦有专人进行维护、更新。
综上,罗某某系利用其熟悉密钥工作原理和公司对账机制的便利条件而非职务上的便利实施了犯罪行为,故其行为不符合职务侵占罪的构成特征。罗某某、李某的主观目的在于利用系统存在的漏洞,通过窃取密匙、冒充公司身份发送资金结算请求的方式,达到非法占有公司钱款的目的,其二人对计算机的操作仅是犯罪手段以及掩盖犯罪事实的方法,故应当以盗窃罪追究其二人的刑事责任。综上,对于辩方提出的本案应定性为职务侵占罪以及破坏计算机信息系统罪的意见,法院不予采纳。
关于本案犯罪金额问题,经查,罗某某、李某存在事先意思联络、事中相互配合的行为,其二人的行为共同导致了PP租车公司资金损失的后果,应共同对盗窃罪既遂承担责任。
但2016年2月以后,李某放弃继续犯罪,罗某某采用相同手段继续实施盗窃行为并独自占有了所获赃款,其犯罪行为虽然利用了此前与李某共同实施犯罪时的程序和服务器,但二被告人前期的共同犯罪行为与罗某某后续单独实施犯罪造成的后果之间不存在因果关系,故李某仅应对其所参与部分的犯罪数额承担责任。综上,对于辩方提出的关于李某犯罪数额的意见,法院予以采纳;对于辩方提出的罗某某犯罪数额的意见,本院不予采纳。但在共同犯罪中,李某积极参与并有购置服务器、购买银行卡、套现、分配赃款等行为,其与罗某某各有分工、相互配合,所起作用基本相当,依法不应认定为从犯,故对于辩方提出的李某系从犯的意见,法院不予采纳。
鉴于罗某某协助公安机关抓获其他犯罪嫌疑人,系立功;罗某某、李某、庄某能如实供述自己的罪行,认罪态度较好,同时考虑到罗某某、李某退赔了大部分违法所得,弥补了被害单位的大部分经济损失,且庄某获得了被害单位的谅解,本院依法对罗某某、李某、庄某从轻处罚,并对庄某适用缓刑。辩护人其余部分相关辩护意见,本院酌予采纳。依照《中华人民共和国刑法》第二百六十四条,第三百一十二条第一款,第二十五条第一款,第六十七条第三款,第六十八条,第七十二条第一款、第三款,第七十三条第二款、第三款,第五十三条第一款,第六十四条之规定,判决如下:
一、罗某某犯盗窃罪,判处有期徒刑十一年,罚金人民币十万元。
二、李某犯盗窃罪,判处有期徒刑十年,罚金人民币十万元。
三、庄某犯掩饰、隐瞒犯罪所得罪,判处有期徒刑三年,缓刑三年,罚金人民币二万元。
四、责令罗某某向被害单位某科技有限责任公司退赔人民币三十三万六千四百五十六元三角一分、李某向被害单位某科技有限责任公司退赔人民币三十四万三千五百一十一元六角九分。
五、依法追缴李某位于本市昌平区天通中苑房产中与赃款人民币七十八万九千三百三十一元二角八分对应的收益。
【转自公众号:云头条】,声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢。 邮箱地址:pufa@dcloud.io 。
分享汇科技(北京)有限公司(以下简称分享汇公司)与某科技有限责任公司(以下简称PP租车公司)系关联公司。罗某某于2014年6月30日至2015年8月18日期间就职于分享汇公司,担任高级开发工程师。
罗某某与李某系同学关系、与庄某系夫妻关系。
罗某某在工作期间发现PP租车公司与某支付机构之间的资金结算交易、对账系统存在管控漏洞,遂通过其窃取的PP租车公司与某支付机构的资金结算密钥,编写相应的非法结算程序密钥,冒充PP租车公司身份,向某支付机构发送资金结算请求,使某支付机构将资金转入其指定的银行账户。
同时,其通过在PP租车公司自动化对账系统服务器上安装恶意程序,于每日自动化对账系统核实前一日某支付机构对账单之前,对某支付机构对账单中记录的非法资金结算记录进行修改,从而规避PP租车公司自动化对账系统的检查。
2015年5月至2016年2月期间,由罗某某制作后台程序,李某购买虚拟服务器、银行卡,并利用上述漏洞向某支付机构发送虚假的转账请求,分多次从PP租车公司窃取共计人民币3687948元;2016年3月至7月期间,罗某某采用上述方法继续从PP租车公司窃取人民币2394014元,并指使庄某在本市多处的ATM取款机上取现共计人民币一百余万元。
2016年6月底,PP租车公司财务人员进行财务审核时发现公司的账目存在异常后报案,同年8月15日,公安机关将罗某某、庄某抓获归案。同日,罗某某协助公安机关将李某抓获归案。公安机关从罗某某处起获的赃款人民币1666495.09元,从李某处起获的赃款人民币1177980元均已发还爱车汇公司。后庄某退赔爱车汇公司人民币1727518.91元,李某在家属的帮助下退赔爱车汇公司人民币830000元。
另查,李某购买的位于本市昌平区天通中苑的房产1套,其中有人民币789331.28元系赃款,现该房产已查封在案。
庭审过程中,公诉人当庭宣读并出示了公安机关在侦查过程中调取的下列证据:
罗某某的供述证实:
2014年5月,其在PP租车公司上班期间发现公司的管理有漏洞,公司的服务器里有公司财务给某支付机构发送转账指令的密钥。
2015年三四月份的时候,其跟同学李某吃饭,李某问其在PP租车公司有什么赚钱的路子,其就跟李某说了这个事。李某当时说考虑考虑,让其做一个技术上的调研看看是否可行。后其用PP租车公司的工作电脑进入公司的系统查看系统源代码和运行机制,发现公司的对账机制是T+1机制,比如银行当天到账,但对账单会在第二天发给公司,其当时觉得能够利用这个漏洞,之后其把这事跟李某说了。李某说要测试一下看看效果,有没有什么问题,并让其做一个后台给他使用。后其做了一个后台程序,李某买了一个服务器,其把程序部署到服务器上,具体的操作都由李某去做。经过一段时间的测试,大概到2015年6月份左右,其二人正式开始利用PP租车公司的系统漏洞把备付金转到私人账号上。其先进入公司的程序,到里面找到公司和银行结算的密钥下载下来,然后修改公司的程序,使自己制作的程序可以修改、控制公司的程序,之后其二人可以通过其制作的程序向某支付机构提交转账申请,这是以PP租车公司的密钥提交的申请,在提交申请时,其二人会把要收钱的银行卡信息一并提交,这样某支付机构就会把公司的钱直接打到其二人指定的银行卡里。因为当天结算后,某支付机构会在第二天才把对账单发到公司的FTP服务器里,其制作的程序会自动到公司的FTP服务器里篡改某支付机构发来的对账单,把转钱的记录删除。通过打时间差的方式,在每天公司对账之前把对账单篡改了就行,这样公司就发现不了对账单出现问题了。李某是在阿里云上买的虚拟服务器,虚拟服务器的IP地址其记不清了,当时其用的是自己的苹果笔记本电脑,里面应该有记录。
李某做的时候跟其说他转出200多万元,2015年7月份左右,李某找到其说他做完了要分一点钱给其,之后就分多笔给其打了46万元。到了2015年十一二月份,李某开始用现金给其钱,说这样安全,每次多少不固定,大概给其三四次钱,总共不到60万元,李某一共给其105万元。其当时跟李某商量从PP租车公司弄钱的时候约定弄出来的钱一人一半,其认为李某给的钱有点少,因为都是李某在操作,其不知道详细情况,于是就自己登陆上去操作。2016年4月至7月期间,其开始自己做,前后一共从PP租车公司转出230万元到自己指定的账户。这些账户都是其在网上论坛里买的,一共是10张银行卡,每张卡配1张身份证和1个U盾。
其是2015年8月从PP租车公司离职的,2015年五六月份开始做的时候都是李某在操作,其只是提供了程序,之后在2016年4月份其才自己开始做。其自己做的时候李某没有再从PP租车公司的账户上往外转账,其之所以知道是因为其做的程序上面有记录,这之后没有他登陆的记录,现在这些记录都已经删除了。
2016年7月中下旬,其让其爱人庄某拿着银行卡去取钱,其每次都开车送她去ATM机上取钱,其跟庄某说做点伪装再去,让她带个帽子、眼镜。她刚开始不知道这是什么钱,后来到了八月份其告诉庄某这些钱是其通过PP租车公司的漏洞转出来的,她这时才知道,这之后其又强求庄某取了一两次钱。
证人肖某、陈某的证言证实:
2016年6月30日,公司财务人员进行财务审核时发现公司的账目存在异常,掌握这一情况后公司的技术人员开始介入调查,经过技术调查后发现从2015年5月9日开始,有人冒充公司的身份,向某支付机构发起虚假的转账请求,截止到2016年7月2日共从公司非法转走600多万元。
嫌疑人获取了其公司的密钥,然后在向某支付机构发起的报文请求中使用了该密钥进行加密,某支付机构对密钥进行核对后确认是其公司发起的请求,于是就将资金打入嫌疑人指定的账户内,然后嫌疑人通过获取其公司FTP的用户名和密码,直接登录其公司的FTP服务器下载对账单,修改后再上传,篡改对账文件,通过修改对账文件使账目和转账金额一致。
证人钟某的证言证实:
罗某于2014年6月30日入职爱车汇公司,2015年8月18日因个人原因离职。罗某在职期间一直是技术员,在其手下工作,负责公司的基础系统构架,参与开发公司内部管理系统,包括支付系统、短信网关、还有其他一些小系统。罗某只负责系统的开发,系统投入运行后他是没有权利使用的,没有从某支付机构提现的权限,没有管理公司与某支付机构交易密钥的权限,也没有登录公司与某支付机构对账的FTP服务器的权限。公司的FTP是有专人负责的,其本人以及公司的领导都不知道账号、密码。密匙就放在服务器上,公司平时也强调要保证密匙的安全,大家也都知道密匙涉及钱的问题,其所在的技术部门是不可以涉及到公司财务工作的。罗某因为开发系统需要用到这台服务器,他有权限登录存放密钥的服务器,因为这个服务器还部署了很多功能,公司很多系统都要用到这台服务器。
证人魏某的证言证实:
其是爱车汇公司的技术员,负责密钥的更新和维护,但是其本人不能使用,密钥已经与程序连接在一起,爱车汇公司的所有交易都是通过系统自动进行的,任何人都不能使用这个密钥,只有程序在使用。罗某在职期间可以登录存放密钥的服务器,但是没有权利对密钥进行任何操作。
爱车汇公司出具的工作说明证实:
按照PP租车公司2016年7月之前的机制,如果有异常访问在每天17点之前将FTP服务器上某支付机构下发的对账文件下载,修改后再重新上传,则PP自动化程序核对的就是修改后的对账文件。PP租车发送给某支付机构请求的服务器必须有一个IP地址来作为这台机器的标识,这个IP地址从2015年5月份到2016年7月份都没有更换过,而且只有一个IP地址向某支付机构发送代付请求,该IP地址为×××。在2016年7月3日之前,PP租车公司和某支付机构之间的通信没有增加白名单的限制,所以如果是其他IP向某支付机构发送请求,只要有对应的私钥和密钥,都可以申请转账成功。
2015年5月9日至2016年7月2日,通过某支付机构提供的提现记录和PP租车公司记录的提现记录对比,发现共发生520405笔提现记录,其中518548笔来自爱车汇公司服务器(×××)发起的请求,另有1857笔系非经爱车汇公司提起的提现请求。
法院裁决:
罗某某单独或伙同李某以非法占有为目的,秘密窃取公司钱款,数额特别巨大,其二人的行为均已构成盗窃罪,应予惩处;庄某明知是犯罪所得而予以转移,情节严重,其行为已构成掩饰、隐瞒犯罪所得罪,应予惩处。北京市海淀区人民检察院指控罗某某、李某犯盗窃罪,庄某犯掩饰、隐瞒犯罪所得罪的事实清楚,证据确实、充分,指控罪名成立。
关于本案的定性问题,经查,罗某某在PP租车公司担任高级开发工程师职务,主要工作职责为基础系统开发,并没有向某支付机构发送提现请求的权利,其工作内容与财务无关。同时,证人钟某、魏某的证言可以证实罗某某虽因职务所需有权登陆储存资金结算密钥的服务器,但其无权对密钥进行任何性质的操作,也无权登陆PP租车公司用于与某支付机构进行对账的服务器,PP租车公司的银行密钥亦有专人进行维护、更新。
综上,罗某某系利用其熟悉密钥工作原理和公司对账机制的便利条件而非职务上的便利实施了犯罪行为,故其行为不符合职务侵占罪的构成特征。罗某某、李某的主观目的在于利用系统存在的漏洞,通过窃取密匙、冒充公司身份发送资金结算请求的方式,达到非法占有公司钱款的目的,其二人对计算机的操作仅是犯罪手段以及掩盖犯罪事实的方法,故应当以盗窃罪追究其二人的刑事责任。综上,对于辩方提出的本案应定性为职务侵占罪以及破坏计算机信息系统罪的意见,法院不予采纳。
关于本案犯罪金额问题,经查,罗某某、李某存在事先意思联络、事中相互配合的行为,其二人的行为共同导致了PP租车公司资金损失的后果,应共同对盗窃罪既遂承担责任。
但2016年2月以后,李某放弃继续犯罪,罗某某采用相同手段继续实施盗窃行为并独自占有了所获赃款,其犯罪行为虽然利用了此前与李某共同实施犯罪时的程序和服务器,但二被告人前期的共同犯罪行为与罗某某后续单独实施犯罪造成的后果之间不存在因果关系,故李某仅应对其所参与部分的犯罪数额承担责任。综上,对于辩方提出的关于李某犯罪数额的意见,法院予以采纳;对于辩方提出的罗某某犯罪数额的意见,本院不予采纳。但在共同犯罪中,李某积极参与并有购置服务器、购买银行卡、套现、分配赃款等行为,其与罗某某各有分工、相互配合,所起作用基本相当,依法不应认定为从犯,故对于辩方提出的李某系从犯的意见,法院不予采纳。
鉴于罗某某协助公安机关抓获其他犯罪嫌疑人,系立功;罗某某、李某、庄某能如实供述自己的罪行,认罪态度较好,同时考虑到罗某某、李某退赔了大部分违法所得,弥补了被害单位的大部分经济损失,且庄某获得了被害单位的谅解,本院依法对罗某某、李某、庄某从轻处罚,并对庄某适用缓刑。辩护人其余部分相关辩护意见,本院酌予采纳。依照《中华人民共和国刑法》第二百六十四条,第三百一十二条第一款,第二十五条第一款,第六十七条第三款,第六十八条,第七十二条第一款、第三款,第七十三条第二款、第三款,第五十三条第一款,第六十四条之规定,判决如下:
一、罗某某犯盗窃罪,判处有期徒刑十一年,罚金人民币十万元。
二、李某犯盗窃罪,判处有期徒刑十年,罚金人民币十万元。
三、庄某犯掩饰、隐瞒犯罪所得罪,判处有期徒刑三年,缓刑三年,罚金人民币二万元。
四、责令罗某某向被害单位某科技有限责任公司退赔人民币三十三万六千四百五十六元三角一分、李某向被害单位某科技有限责任公司退赔人民币三十四万三千五百一十一元六角九分。
五、依法追缴李某位于本市昌平区天通中苑房产中与赃款人民币七十八万九千三百三十一元二角八分对应的收益。
【转自公众号:云头条】,声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢。 邮箱地址:pufa@dcloud.io 。
收起阅读 »
关于uni-app,使用企业微信的经验小谈。
wx.config wx.agentConfig undefined 的问提。
原因: 是uni-app自身在window下面挂载了wx的全局变量。导致微信引入的二个js,wx异常。
解决办法: 在App.vue 中,onLaunch 加载方法中,动态引入这二个js。这个方法只支持 h5 开发
onLaunch: function () {
let that = this;
const script1 = document.createElement("script");
script1.setAttribute("type", "text/javascript");
script1.setAttribute("referrerpolicy", "origin");
script1.setAttribute("src", "https://res.wx.qq.com/open/js/jweixin-1.2.0.js");
document.head.appendChild(script1);
script1.onload = function () {
const script2 = document.createElement("script");
script2.setAttribute("type", "text/javascript");
script2.setAttribute("referrerpolicy", "origin");
script2.setAttribute("src", "https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js");
document.head.appendChild(script2);
script2.onload = () => {
// 执行wx.config的逻辑
};
};
}
wx.config 方法 和 wx.agentConfig 方法如何使用
因为我自己在这一步上面卡了很久,所以把自己现在写的分享出来
// 这个api其实是我的接口地址,www.xxxx.com/api/
import { api } from "./request.api";
let obj = {
async registered() {
let token = uni.getStorageSync("token");
let data = await new Promise((res) => {
uni.request({
url: api + "work/GetOPenTenantDataConfig",
method: "get",
data: {
auth_token: token
},
success: ({ data }) => {
res(data.result);
}
});
});
wx.config({
beta: true, // 必须这么写,否则wx.invoke调用形式的jsapi会有问题
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: data.corpid, // 必填,企业微信的corpID
timestamp: data.timeStamp, // 必填,生成签名的时间戳
nonceStr: data.noncestr, // 必填,生成签名的随机串
signature: data.signature, // 必填,签名,见 附录-JS-SDK使用权限签名算法
jsApiList: [] // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
});
wx.ready(() => {
obj.agentConfig(token);
});
wx.error(function (res) {
console.log(res);
});
},
async agentConfig(token) {
let data = await new Promise((res) => {
uni.request({
url: api + "work/GetOPenAgentDataConfig",
method: "get",
data: {
auth_token: token
},
success: ({ data }) => {
res(data.result);
}
});
});
wx.agentConfig({
corpid: data.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致
agentid: data.agentid, // 必填,企业微信的应用id (e.g. 1000247)
timestamp: data.timeStamp, // 必填,生成签名的时间戳
nonceStr: data.noncestr, // 必填,生成签名的随机串
signature: data.signature, // 必填,签名,见附录1
jsApiList: [],
success: (res) => {
console.log(res);
},
fail: (error) => {
console.log(error);
}
});
}
};
module.exports = obj;
user组件 我的需求是只需要显示名称就好了。
<template>
<ww-open-data type="userName" :openid="openid" />
</template>
<script>
export default {
props: ["openid"], // 特别提醒 这里的openid 其实就是用户的userid。后台以为需要userid转成openid。导致在这个小问题上,调试了很久。
mounted() {
WWOpenData.bind(document.querySelectorAll("ww-open-data"));
}
};
</script>
wx.config wx.agentConfig undefined 的问提。
原因: 是uni-app自身在window下面挂载了wx的全局变量。导致微信引入的二个js,wx异常。
解决办法: 在App.vue 中,onLaunch 加载方法中,动态引入这二个js。这个方法只支持 h5 开发
onLaunch: function () {
let that = this;
const script1 = document.createElement("script");
script1.setAttribute("type", "text/javascript");
script1.setAttribute("referrerpolicy", "origin");
script1.setAttribute("src", "https://res.wx.qq.com/open/js/jweixin-1.2.0.js");
document.head.appendChild(script1);
script1.onload = function () {
const script2 = document.createElement("script");
script2.setAttribute("type", "text/javascript");
script2.setAttribute("referrerpolicy", "origin");
script2.setAttribute("src", "https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js");
document.head.appendChild(script2);
script2.onload = () => {
// 执行wx.config的逻辑
};
};
}
wx.config 方法 和 wx.agentConfig 方法如何使用
因为我自己在这一步上面卡了很久,所以把自己现在写的分享出来
// 这个api其实是我的接口地址,www.xxxx.com/api/
import { api } from "./request.api";
let obj = {
async registered() {
let token = uni.getStorageSync("token");
let data = await new Promise((res) => {
uni.request({
url: api + "work/GetOPenTenantDataConfig",
method: "get",
data: {
auth_token: token
},
success: ({ data }) => {
res(data.result);
}
});
});
wx.config({
beta: true, // 必须这么写,否则wx.invoke调用形式的jsapi会有问题
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: data.corpid, // 必填,企业微信的corpID
timestamp: data.timeStamp, // 必填,生成签名的时间戳
nonceStr: data.noncestr, // 必填,生成签名的随机串
signature: data.signature, // 必填,签名,见 附录-JS-SDK使用权限签名算法
jsApiList: [] // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
});
wx.ready(() => {
obj.agentConfig(token);
});
wx.error(function (res) {
console.log(res);
});
},
async agentConfig(token) {
let data = await new Promise((res) => {
uni.request({
url: api + "work/GetOPenAgentDataConfig",
method: "get",
data: {
auth_token: token
},
success: ({ data }) => {
res(data.result);
}
});
});
wx.agentConfig({
corpid: data.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致
agentid: data.agentid, // 必填,企业微信的应用id (e.g. 1000247)
timestamp: data.timeStamp, // 必填,生成签名的时间戳
nonceStr: data.noncestr, // 必填,生成签名的随机串
signature: data.signature, // 必填,签名,见附录1
jsApiList: [],
success: (res) => {
console.log(res);
},
fail: (error) => {
console.log(error);
}
});
}
};
module.exports = obj;
user组件 我的需求是只需要显示名称就好了。
<template>
<ww-open-data type="userName" :openid="openid" />
</template>
<script>
export default {
props: ["openid"], // 特别提醒 这里的openid 其实就是用户的userid。后台以为需要userid转成openid。导致在这个小问题上,调试了很久。
mounted() {
WWOpenData.bind(document.querySelectorAll("ww-open-data"));
}
};
</script>
收起阅读 »

mui ajax 请求 在ios13后出现 abort 问题
前些天调试项目,原本在Android端开发后的代码,发现在ios13就请求不了,查了文档才发现
为适应iOS13起苹果公司将UIWebview列为私有API的问题,从HBuilderX 2.2.5+版本已将iOS上默认内核由UIWebview调整为WKWebview。但WKWebview有更严格的跨域限制,普通xhr或ajax联网会报错:Script error.filename:lineno:0错误;此时必须使用plus.net.XMLHttpRequest,详见:https://ask.dcloud.net.cn/article/36348,所以在WKWebview下,请务必在plus ready后再调用mui.ajax,(注意这一句,plus reday 后才执行
后来我根据上述调整了代码
mui.plusReady(function() {
mui.ajax('http://server-name/login.php',{
data:{
username:'username',
password:'password'
},
dataType:'json',//服务器返回json格式数据
type:'post',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
headers:{'Content-Type':'application/json'},
success:function(data){
//服务器返回响应,根据响应结果,分析是否登录成功;
...
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
});
发现还是报错,后面经过查询其他贴纸发现,在mui.ajax 还需要加上crossDomain : true //强制5+ 跨域后解决!!!
mui.plusReady(function() {
mui.ajax('http://server-name/login.php',{
data:{
username:'username',
password:'password'
},
dataType:'json',//服务器返回json格式数据
type:'post',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
crossDomain: true, //强制使用5+跨域
headers:{'Content-Type':'application/json'},
success:function(data){
//服务器返回响应,根据响应结果,分析是否登录成功;
...
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
});
前些天调试项目,原本在Android端开发后的代码,发现在ios13就请求不了,查了文档才发现
为适应iOS13起苹果公司将UIWebview列为私有API的问题,从HBuilderX 2.2.5+版本已将iOS上默认内核由UIWebview调整为WKWebview。但WKWebview有更严格的跨域限制,普通xhr或ajax联网会报错:Script error.filename:lineno:0错误;此时必须使用plus.net.XMLHttpRequest,详见:https://ask.dcloud.net.cn/article/36348,所以在WKWebview下,请务必在plus ready后再调用mui.ajax,(注意这一句,plus reday 后才执行
后来我根据上述调整了代码
mui.plusReady(function() {
mui.ajax('http://server-name/login.php',{
data:{
username:'username',
password:'password'
},
dataType:'json',//服务器返回json格式数据
type:'post',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
headers:{'Content-Type':'application/json'},
success:function(data){
//服务器返回响应,根据响应结果,分析是否登录成功;
...
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
});
发现还是报错,后面经过查询其他贴纸发现,在mui.ajax 还需要加上crossDomain : true //强制5+ 跨域后解决!!!
mui.plusReady(function() {
mui.ajax('http://server-name/login.php',{
data:{
username:'username',
password:'password'
},
dataType:'json',//服务器返回json格式数据
type:'post',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
crossDomain: true, //强制使用5+跨域
headers:{'Content-Type':'application/json'},
success:function(data){
//服务器返回响应,根据响应结果,分析是否登录成功;
...
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
});
收起阅读 »