赞
踩
微信小程序是一种不需要下载也不需要安装就可以使用的应用程序,它把app的功能集成到小程序里面,然后用户就可以在微信里面实现app的基本功能。
首先需要申请一个微信公众平台账号
立即注册>小程序>填写资料>注册
链接:微信公众平台
在注册成功后注意保留自己的appid
链接:开发者工具下载
pages:存放小程序中每个页面的文件夹
index:小程序中的单独页面,每个页面由四个部分组成:
app.js:小程序全局逻辑
app.json:小程序公共配置
app.wxss:小程序公共样式表
app.js文件:
{ "pages": [ "pages/index/index", "pages/logs/logs" ], "window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle": "black" }, "tabBar": { "list": [{ "pagePath": "pagePath", "text": "text", "iconPath": "iconPath", "selectedIconPath": "selectedIconPath" }] }, }
pages
用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径(含文件名) 信息。文件名不需要写文件后缀,框架会自动去寻找对于位置的 .json, .js, .wxml, .wxss 四个文件进行处理。
目录结构:
├── app.js
├── app.json
├── app.wxss
├── pages
│ │── index
│ │ ├── index.wxml
│ │ ├── index.js
│ │ ├── index.json
│ │ └── index.wxss
│ └── logs
│ ├── logs.wxml
│ └── logs.js
└── utils
配置:
"pages": [
"pages/index/index",
"pages/logs/logs"
],
window
用于设置小程序的状态栏、导航条、标题、窗口背景色。
属性 | 描述 |
---|---|
navigationBarBackgroundColor | 导航栏背景颜色 |
navigationBarTextStyle | 导航栏标题颜色,仅支持 black / white |
navigationBarTitleText | 导航栏标题文字内容 |
backgroundColor | 窗口的背景色 |
{
"window": {
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "演示",
"backgroundColor": "#eeeeee"
}
}
tabBar
如果小程序是一个多 tab 应用(客户端窗口的底部或顶部有 tab 栏可以切换页面),可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面。
属性 | 描述 |
---|---|
color | tab 上的文字默认颜色,仅支持十六进制颜色 |
selectedColor | tab 上的文字选中时的颜色,仅支持十六进制颜色 |
backgroundColor | tab 的背景色,仅支持十六进制颜色 |
borderStyle | tabbar 上边框的颜色, 仅支持 black / white |
list | tab 的列表,详见 list 属性说明,最少 2 个、最多 5 个 tab |
"tabBar": {
"list": [{
"pagePath": "pagePath",
"text": "text",
"iconPath": "iconPath",
"selectedIconPath": "selectedIconPath"
}]
},
属性 | 描述 |
---|---|
pagePath | 页面路径,必须在 pages 中先定义 |
text | tab 上按钮文字 |
iconPath | 图片路径,icon 大小限制为 40kb,不支持网络图片。 |
selectedIconPath | 选中时的图片路径,icon 大小限制为 40kb,不支持网络图片。 |
pages>新建目录>新建page
通过新建page创建的页面会自动注册到app.json的pages列表中结尾
编写文本信息,类似于span标签
<!--pages/home/home.wxml-->
<text>pages/home/home.wxml</text>
<text>编写文本信息,类似于span标签</text>
容器,类似于div标签
<!--pages/home/home.wxml-->
<view>容器</view>
<view>类似于div标签</view>
图片标签
<image src="/static/image/1.png"></image>
跳转到非tabBar页面
<navigator url="/pages/redirect/redirect?id=666">跳转到新页面</navigator>
进度条。组件属性的长度单位默认为px,2.4.0起支持传入单位(rpx/px)。
<progress percent="10"/> <!--进度条百分比-->
<progress percent="20" show-info /> <!--右侧显示百分比-->
<progress percent="40" stroke-width="12" /><!--进度条线的宽度-->
<progress percent="60" color="pink" /><!--进度条颜色-->
<progress percent="80" active /><!--进度条从左往右的动画-->
<swiper autoplay="true">
<swiper-item>
<image src="/static/1.gif"></image>
</swiper-item>
<swiper-item>
<image src="/static/2.gif"></image>
</swiper-item>
</swiper>
属性 | 说明 |
---|---|
indicator-dots | 是否显示面板指示点 |
indicator-color | 指示点颜色 |
indicator-active-color | 当前选中的指示点颜色 |
autoplay | 是否自动切换 |
interval | 自动切换时间间隔 |
在小程序中标签的样式用法和css几乎相同,但需要注意的是在小程序中要使用rpx
代替px
rpx: 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
Flex是Flexible Box的缩写,顾名思义为“弹性布局”,用来为盒装模型提供最大的灵活性。
flex布局并不是小程序专属的,它在网站中同样适用
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
display:
指定为flex布局
flex-direction:
规定主轴的方向:row/column
justify-content:
元素在主轴方向上的排列方式:flex-start/flex-end/space-around/space-between
align-items: center:
元素在副轴方向上的排列方式:flex-start/flex-end/space-around/space-between
对标签绑定点击事件
使用bindtap绑定点击事件,通过data-参数名称 的形式传递参数
<view bindtap="clickMe" data-id="123">点击事件</view>
Page({
...
/**
* 点击绑定的事件
*/
clickMe:function(e){
var nid = e.currentTarget.dataset.nid;
console.log(nid);
}
})
显示数据
wxml:
<view>数据:{{message}}</view>
js:
// pages/bind/bind.js
Page({
/**
* 页面的初始数据
*/
data: {
message:"测试数据",
}
)}
数据更新
wxml:
<view>数据:{{message}}</view>
<button bindtap="changeData">点击修改数据</button>
js:
Page({
data: {
message:"初始数据",
},
changeData:function(){
// 修改数据
this.setData({ message: "修改数据"});
}
})
修改data中的局部数据
data: {
percent:[1,2,3],
},
this.setData({
["percent[0]"]:80,
})
双向绑定
wxml
<view>数据:{{message}}</view>
<input bindinput="changeData" value="{{message}}"></input>
Page({
/**
* 页面的初始数据
*/
data: {
message:"初始数据"
},
changeData:function(e){
console.log(e.detail.value)
//更新数据
this.setData({ message: e.detail.value})
}
})
跳转到非tabBar页面
wx.navigateTo({
url: '/pages/Home/Home?Id=' + '1',
}
返回上一页面或多级页面
wx.navigateBack({
delta: 1 //返回的页面数,如果 delta 大于现有页面数,则返回到首页。
});
获取当前页面栈。数组中第一个元素为首页,最后一个元素为当前页面。
var pages = getCurrentPages();
prevPage = pages[pages.length-2];
wx.getUserInfo
wxml:
<button open-type="getUserInfo" bindgetuserinfo="getUserInfo">授权登录</button>
js:
getUserInfo:function(){
wx.getUserInfo({
success: function (res) {
// 调用成功后触发
console.log('success', res)
},
fail: function (res) {
// 调用失败后触发
console.log('fail', res)
}
})
}
wx.chooseLocation
wxml:
<view bindtap="getLocalPath">{{localPath}}</view>
js:
data: {
localPath:"请选择位置",
},
getLocalPath:function(){
var that = this;
wx.chooseLocation({
success: function(res) {
that.setData({localPath:res.address});
},
})
},
wx:for
data: {
dataList:["1","2","3"],
userInfo:{
name:"张三",
age:18
}
},
<view wx:for="{{dataList}}" >{{index}} - {{item}}</view>
<!--指定index和item-->
<view wx:for="{{dataList}}" wx:for-index="idx" wx:for-item="x">{{idx}} - {{x}}</view>
<view wx:if="{{boolean==true}}">
<view class="bg_black"></view>
</view>
<view wx:elif="{{boolean==false}}">
<view class="bg_red"></view>
</view>
<view wx:else>
<view class="bg_red"></view>
</view>
从本地相册选择图片或使用相机拍照。图片只是上传到了内存中。
wx.chooseImage
data: { imageList: [] }, uploadImage:function(){ var that = this; wx.chooseImage({ count:9, //最多可以选择的图片张数 sizeType: ['original', 'compressed'], //所选的图片的尺寸,original原图,compressed压缩图 sourceType: ['album', 'camera'], //选择图片的来源,album从相册选图,camera使用相机 success:function(res){ that.setData({ imageList: that.data.imageList.concat(res.tempFilePaths) }); } }); },
wx.request(Object object)
wx.request({
url: '', //请求路径
data: '', //请求参数
header: {}, //请求头
method: 'GET',//请求方法
dataType: 'json',//返回的数据格式
responseType: 'text',//响应的数据类型
success: function(res) {},
fail: function(res) {},
complete: function(res) {},
})
wx.showToast
wx.showToast({
title: '',//提示的内容
icon: '',//图标 success/loading/none
image: '',//自定义图标的本地路径,image 的优先级高于 icon
duration: 0,//提示的延迟时间
mask: true,//是否显示透明蒙层,防止触摸穿透
success: function(res) {},
fail: function(res) {},
complete: function(res) {},
})
获取值
wx.getStorageSync('userInfo');
设置值
wx.setStorageSync('userInfo',"sdfsfd");
清除值
wx.removeStorageSync("userInfo")
onLoad:
监听页面加载(一次)
onShow:
监听页面显示(每次展示页面都会加载)
onReady:
监听页面初次渲染完成(一次)
onHide:
监听页面隐藏(每次页面隐藏都会加载)
onUnload:
监听页面卸载(卸载页面触发,小程序关闭)
onPullDownRefresh:
监听用户下拉动作(下拉刷新触发需要配置)
onReachBottom:
页面上拉触底事件的处理函数
配置onPullDownRefresh
全局配置:
在所有页面都生效
//app.json
{
"window": {
"backgroundTextStyle": "dark",//下拉刷新时的加载动画
"enablePullDownRefresh": true
}
}
局部配置:
只会在配置的页面中生效
{
"usingComponents": {},
"enablePullDownRefresh": true
}
停止下拉刷新加载:
wx.stopPullDownRefresh();
app.js
App({
/**
* 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
*/
onLaunch: function () {
},
globalData:{
userInfo: null,
}
})
其他页面操作公共值
var app = getApp();
Page({
data: {
},
onShow:function(){
app.globalData
}
});
var dataList = ["1", "2", "3"]
for (var i in dataList) {
(function(data){
wx.request({
url: 'xxxxx',
success: function (res) {
console.log(data);
}
})
})(dataList[i])
}
//将校验之后的手机号发送到后端
wx.request({
url: 'http://127.0.0.1:8000/api/message/',
data: { phone: this.data.phone },
method: 'GET',
success: function (res) {
console.log(res);
}
})
安装:
pip install tencentcloud-sdk-python
# -*- coding: utf-8 -*- from tencentcloud.common import credential from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException # 导入对应产品模块的client models。 from tencentcloud.sms.v20190711 import sms_client, models # 导入可选配置类 from tencentcloud.common.profile.client_profile import ClientProfile from tencentcloud.common.profile.http_profile import HttpProfile try: # 必要步骤: # 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。 # 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。 # 你也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人, # 以免泄露密钥对危及你的财产安全。 # CAM密匙查询: https://console.cloud.tencent.com/cam/capi cred = credential.Credential("secretId", "secretKey") # cred = credential.Credential( # os.environ.get(""), # os.environ.get("") # ) # 实例化一个http选项,可选的,没有特殊需求可以跳过。 httpProfile = HttpProfile() httpProfile.reqMethod = "POST" # post请求(默认为post请求) httpProfile.reqTimeout = 30 # 请求超时时间,单位为秒(默认60秒) httpProfile.endpoint = "sms.tencentcloudapi.com" # 指定接入地域域名(默认就近接入) # 非必要步骤: # 实例化一个客户端配置对象,可以指定超时时间等配置 clientProfile = ClientProfile() clientProfile.signMethod = "TC3-HMAC-SHA256" # 指定签名算法 clientProfile.language = "en-US" clientProfile.httpProfile = httpProfile # 实例化要请求产品(以sms为例)的client对象 # 第二个参数是地域信息,可以直接填写字符串ap-guangzhou,或者引用预设的常量 client = sms_client.SmsClient(cred, "ap-guangzhou", clientProfile) # 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数 # 你可以直接查询SDK源码确定SendSmsRequest有哪些属性可以设置 # 属性可能是基本类型,也可能引用了另一个数据结构 # 推荐使用IDE进行开发,可以方便的跳转查阅各个接口和数据结构的文档说明 req = models.SendSmsRequest() # 基本类型的设置: # SDK采用的是指针风格指定参数,即使对于基本类型你也需要用指针来对参数赋值。 # SDK提供对基本类型的指针引用封装函数 # 帮助链接: # 短信控制台: https://console.cloud.tencent.com/sms/smslist # sms helper: https://cloud.tencent.com/document/product/382/3773 # 短信应用ID: 短信SdkAppid在 [短信控制台] 添加应用后生成的实际SdkAppid,示例如1400006666 req.SmsSdkAppid = "1400787878" # 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名,签名信息可登录 [短信控制台] 查看 req.Sign = "xxx" # 短信码号扩展号: 默认未开通,如需开通请联系 [sms helper] req.ExtendCode = "" # 用户的 session 内容: 可以携带用户侧 ID 等上下文信息,server 会原样返回 req.SessionContext = "xxx" # 国际/港澳台短信 senderid: 国内短信填空,默认未开通,如需开通请联系 [sms helper] req.SenderId = "" # 下发手机号码,采用 e.164 标准,+[国家或地区码][手机号] # 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号 req.PhoneNumberSet = ["+8613711112222"] # 模板 ID: 必须填写已审核通过的模板 ID。模板ID可登录 [短信控制台] 查看 req.TemplateID = "449739" # 模板参数: 若无模板参数,则设置为空 req.TemplateParamSet = ["666"] # 通过client对象调用DescribeInstances方法发起请求。注意请求方法名与请求对象是对应的。 # 返回的resp是一个DescribeInstancesResponse类的实例,与请求对象对应。 resp = client.SendSms(req) # 输出json格式的字符串回包 print(resp.to_json_string(indent=2)) except TencentCloudSDKException as err: print(err)
#生成随机验证码 import random random_code = random.randint(1000,9999) from tencentcloud.common import credential from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException from tencentcloud.sms.v20190711 import sms_client, models from tencentcloud.common.profile.client_profile import ClientProfile from tencentcloud.common.profile.http_profile import HttpProfile try: cred = credential.Credential("secretId", "secretKey") client = sms_client.SmsClient(cred, "ap-guangzhou") req = models.SendSmsRequest() # 短信应用ID: 短信SdkAppid在 [短信控制台] 添加应用后生成的实际SdkAppid,示例如1400006666 req.SmsSdkAppid = "1400787878" # 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名,签名信息可登录 [短信控制台] 查看 req.Sign = "xxx" # 下发手机号码,采用 e.164 标准,+[国家或地区码][手机号] # 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号 req.PhoneNumberSet = ["+8613711112222"] # 模板 ID: 必须填写已审核通过的模板 ID。模板ID可登录 [短信控制台] 查看 req.TemplateID = "449739" # 模板参数: 若无模板参数,则设置为空 req.TemplateParamSet = ["666"] # 通过client对象调用DescribeInstances方法发起请求。注意请求方法名与请求对象是对应的。 # 返回的resp是一个DescribeInstancesResponse类的实例,与请求对象对应。 resp = client.SendSms(req) # 输出json格式的字符串回包 print(resp.to_json_string(indent=2)) except TencentCloudSDKException as err: print(err)
小程序对象存储SDK
1 创建js文件 cos-wx-sdk-v5.js
2 导入js文件
var COS = require('./lib/cos-wx-sdk-v5.js')
3 创建COS SDK 实例
官方推荐方式:后端通过获取临时密钥给到前端,前端计算签名。
小程序:
var cos = new COS({ // 必选参数 getAuthorization: function (options, callback) { wx.request({ url: 'http://127.0.0.1:8000/api/app1/getSecretKey', data: { // 可从 options 取需要的参数 }, success: function (result) { var data = result.data; var credentials = data.credentials; callback({ TmpSecretId: credentials.tmpSecretId, TmpSecretKey: credentials.tmpSecretKey, XCosSecurityToken: credentials.sessionToken, ExpiredTime: data.expiredTime, }); } }); } });
python:
安装sdk
pip install -U cos-python-sdk-v5
class GetSecretKey(APIView): def get(self,request,*args,**kwargs): from sts.sts import Sts from django.conf import settings config = { # 临时密钥有效时长,单位是秒 'duration_seconds': 1800, # 固定密钥 id 'secret_id': settings.TENCENT_SECRET_ID, # 固定密钥 key 'secret_key': settings.TENCENT_SECRET_KEY, # 设置网络代理 # 'proxy': { # 'http': 'xx', # 'https': 'xx' # }, # 换成你的 bucket 'bucket': 'mini-1251317460', # 换成 bucket 所在地区 'region': 'ap-chengdu', # 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径 # 例子: a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用) 'allow_prefix': '*', # 密钥的权限列表。简单上传和分片需要以下的权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/31923 'allow_actions': [ 'name/cos:PostObject', ], } sts = Sts(config) response = sts.get_credential() return Response(response)
4 上传到桶中:
小程序:
cos.postObject({
Bucket: 'xxx-1312568142',
Region: 'ap-beijing',
Key: '文件名'
FilePath: '文件',
onProgress: function (info) {
}
}, function (err, data) {
console.log(err)
console.log(data)
});
小程序支付交互图
调用接口获取登录凭证(code)
//小程序 wx.login({ success:(result) => { // 获取一个临时凭证(只能用一次/5分钟) wx.request({ url: 'http://127.0.0.1:8000/login/', data: { wx_code:result.code //用户登录凭证 }, method: 'POST', dataType: 'json', responseType: 'text', success: (res) => { console.log('登录成功'); } }) } })
通过code在后台换取openid
# python
def post(self,request,*args,**kwargs):
wx_code = request.data.get('wx_code')
#通过code获取openid:
info = {
'appid':"", # 微信小程序 appid
'secret':"", # 微信小程序 appSecret
'js_code':wx_code,# 登录时获取的 code
'grant_type':"authorization_code",# 授权类型
}
result = requests.get(url='https://api.weixin.qq.com/sns/jscode2session',params=info)
# 提取openid
openid = result.json()['openid']
return Response({'tye':True})
获取info_dict返回给小程序生成支付二维码
小程序:
wx.request({ url: 'http://127.0.0.1:8000/payment/', data: { goodsId: this.data.seletedId //页码选中的商品id }, method: 'POST', dataType: 'json', responseType: 'text', success: (res) => { console.log(res.data); wx.requestPayment( { 'timeStamp': res.data.timeStamp, 'nonceStr': res.data.nonceStr, 'package': res.data.package, 'signType': res.data.signType, 'paySign': res.data.paySign, 'success': function (res) { }, 'fail': function (res) { }, 'complete': function (res) { } }) } })
python关键代码:
####################### 1.调用支付统一下单 ###################### info = { 'appid': '', #小程序ID 'mch_id': '', # 商户号 'device_info': '', # 设备号、自定义参数,可以为终端设备号(门店号或收银设备ID),PC网页或公众号内支付可以传"WEB" 'nonce_str': "".join([chr(random.randint(65, 90)) for _ in range(12)]), # 随机字符串,长度要求在32位以内。 'sign_type': "MD5", # 签名类型,默认为MD5 'body': "", # 商品简单描述 'detail': '', # 商品详细描述 'attach': '', # 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。 'out_trade_no': order_random_string, # 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一。 'total_fee': goods_object.price, # 订单总金额,单位为分 'spbill_create_ip': request.META.get('REMOTE_ADDR'), # 终端IP remote_addr = request.META.get('REMOTE_ADDR') 'notify_url': "http://47.93.4.198:8012/pay/notify/", # 异步接收微信支付结果通知的回调地址 'trade_type': 'JSAPI', # 小程序取值如下:JSAPI 'openid':'' # openid } ####################### 2.第一次进行签名 ###################### # 对字典中的key按照ASCII码从小到大排序 # 将排完序的值使用&拼接得到stringA # 使用stringA和pay_key拼接得到stringSignTemp:stringA+"&key=192006250b4c09247ec02edce69f6a2d" # 使用Md5加密stringSignTemp # 将密文转换为大写,得到签名 sign # 把签名再添加到info中 info['sign'] = sign值 pay_key = "192006250b4c09247ec02edce69f6a2d" #商户平台设置的密钥key stringSignTemp = "&".join(["{0}={1}".format(k, info[k]) for k in sorted(info)] + ["{0}={1}".format("key", pay_key, ), ]) import hashlib m = hashlib.md5() m.update(stringSignTemp.encode('utf-8')) info['sign'] = m.hexdigest().upper() # 2 向 https://api.mch.weixin.qq.com/pay/unifiedorder 发请求 (json转换为xml) xml_string = "<xml>{0}</xml>".format("".join(["<{0}>{1}</{0}>".format(k, v) for k, v in info.items()])) prepay = requests.post('https://api.mch.weixin.qq.com/pay/unifiedorder',data=xml_string.encode('utf-8')) # 3 从结果xml中提取 prepay_id from xml.etree import ElementTree as ET root = ET.XML(prepay.content.decode('utf-8')) prepay_dict = {child.tag:child.text for child in root} prepay_id = prepay_dict['prepay_id'] ######################## 3.再次签名 ####################### info_dict = { 'appId': "", # 小程序ID 'timeStamp': str(int(time.time())), # 时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间 'nonceStr': "".join([chr(random.randint(65, 90)) for _ in range(12)]), # 随机字符串,长度为32个字符以下。 'package': 'prepay_id={0}'.format(prepay_id), # 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=* 'signType': 'MD5', # 签名类型,默认为MD5,支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致 } temp = "&".join( ["{0}={1}".format(k, info_dict[k]) for k in sorted(info_dict)] + ["{0}={1}".format("key", pay_key, ), ]) sign2 = md5(temp).upper() info_dict['paySign'] = sign2 # 得到info_dict
def post(self,request,*args,**kwargs): # 1. 获取结果把结果XML转换为字典格式 root = ET.XML(request.body.decode('utf-8')) result = {child.tag: child.text for child in root} # 2. 校验签名是否正确,防止恶意请求。 sign = result.pop('sign') # key为商户平台设置的密钥key key = "" temp = "&".join( ["{0}={1}".format(k, result[k]) for k in sorted(result)] + ["{0}={1}".format("key", key, ), ]) local_sign = md5(temp).upper() # 签名一致 if local_sign == sign: # 根据订单号,进行订单状态修改等操作 out_trade_no = result.get('out_trade_no') response = """<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>""" # 返回固定格式的数据 return Response(response)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。