一 首页功能跳转
gotoCollection(){
wx.navigateTo({
url: '/pages/collection/collection'
})
},
gotoFace(){
wx.navigateTo({
url: '/pages/face/face'
})
},
gotoVoice(){
wx.navigateTo({
url: '/pages/voice/voice'
})
},
gotoActivity(){
wx.navigateTo({
url: '/pages/activity/activity',
})
},
gotoHeart(){
wx.navigateTo({
url: '/pages/heart/heart',
})
},
gotoGoods(){
wx.navigateTo({
url: '/pages/goods/goods',
})
},
二 首页轮播图接口和公告接口
2.1 后端
class Banner(models.Model):
img = models.ImageField(upload_to='banner', default='banner1.png', verbose_name='图片')
order = models.IntegerField(verbose_name='顺序')
create_time = models.DateTimeField(auto_now=True, verbose_name='创建时间')
is_delete = models.BooleanField(default=False, verbose_name='是否删除')
class Meta:
verbose_name_plural = '轮播图'
class Notice(models.Model):
title = models.CharField(max_length=64, verbose_name='公共标题')
content = models.TextField(verbose_name='内容')
igm=models.ImageField(upload_to='notice', default='notice.png', verbose_name='公告图片')
create_time = models.DateTimeField(auto_now=True, verbose_name='创建时间')
class Meta:
verbose_name_plural = '公告表'
from rest_framework.mixins import ListModelMixin
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
from .models import Banner, Notice
from .serializer import BannerSerializer, NoticeSerializer
class BannerView(GenericViewSet, ListModelMixin):
queryset = Banner.objects.all().filter(is_delete=False).order_by('order')[:2]
serializer_class = BannerSerializer
def list(self, request, *args, **kwargs):
res = super().list(request, *args, **kwargs)
notice = Notice.objects.all().order_by('create_time').first()
serializer = NoticeSerializer(instance=notice)
return Response({'code': 100, 'msg': '成功', 'banner': res.data, 'notice': serializer.data})
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('banner', BannerView, 'banner')
urlpatterns = [
]
urlpatterns += router.urls
from rest_framework import serializers
from .models import Banner,Notice
class BannerSerializer(serializers.ModelSerializer):
class Meta:
model = Banner
fields = '__all__'
class NoticeSerializer(serializers.ModelSerializer):
class Meta:
model = Notice
fields = ['id','title']
2.2 前端
import api from '../../config/settings.js'
// const api = require("../../config/settings.js")
Page({
data: {
banner_list: ['/images/banner/banner1.png'],
notice:'社区最大交友平台上线啦~~'
},
onLoad(options) {
console.log(api)
wx.request({
url: api.banner,
method:'GET',
success:(res)=>{
console.log(res.data)
if(res.data.code==100){
this.setData({
banner_list:res.data.banner,
notice:res.data.notice.title
})
}else{
wx.showToast({
title: '轮播图网络加载失败',
})
}
}
})
},
gotoCollection() {
wx.navigateTo({
url: '/pages/collection/collection'
})
},
gotoFace() {
wx.navigateTo({
url: '/pages/face/face'
})
},
gotoVoice() {
wx.navigateTo({
url: '/pages/voice/voice'
})
},
gotoActivity() {
wx.navigateTo({
url: '/pages/activity/activity',
})
},
gotoHeart() {
wx.navigateTo({
url: '/pages/heart/heart',
})
},
gotoGoods() {
wx.navigateTo({
url: '/pages/goods/goods',
})
},
})
<!-- 轮播图 -->
<view class="banner">
<swiper autoplay indicator-dots circular indicator-color='#FFFFF' interval='3000'>
<swiper-item wx:for="{{banner_list}}" wx:key="*this">
<image src="{{item.img}}" mode="widthFix" />
</swiper-item>
</swiper>
</view>
<van-notice-bar
left-icon="volume-o"
text="{{notice}}"
/>
const rootUrl = 'http://127.0.0.1:8000/app01';
module.exports = {
welcome:rootUrl+'/welcome/',
banner:rootUrl+'/banner/',
}
三 信息采集
3.1 新建页面collection

<view class="container">
<view class="top">
<view class="tip">今日采集数量(人)</view>
<view class="count">{{dataDict.today_count}}</view>
</view>
<view class="function">
<view class="menu" style="border-right:1rpx solid #ddd;" bindtap="bindToForm">
<text class="fa fa-camera-retro"></text> 信息采集
</view>
<view class="menu" bindtap="bindToStatistics">
<text class="fa fa-pie-chart" ></text> 数据统计
</view>
</view>
<view class="table">
<view class="item">
<view class="title">社区信息列表({{dataDict.today_count}}人)</view>
</view>
<view class="item" wx:for="{{dataDict.result}}" wx:for-item="row" wx:key="index">
<view class="record">
<view class="avatar">
<image src="{{row.avatar}}"></image>
</view>
<view class="desc">
<view class="username">{{row.name}}</view>
<view>
<view class="txt-group">
<label class="zh">网格区域</label>
<label class="en"> | {{row.area.desc}}</label>
</view>
<view class="area">
<label class="fa fa-map-marker"></label> {{row.area.name}}
</view>
</view>
</view>
<view class="delete" bindtap="doDeleteRow" data-nid="{{row.id}}" data-index="{{index}}" >
<label class="iconfont icon-shanchu"></label>
</view>
</view>
</view>
</view>
</view>
.top {
background-color:
height: 200rpx;
display: flex;
flex-direction: column;
align-items: center;
color: white;
}
.top .tip {
font-size: 22rpx;
font-weight: 100;
}
.top .count {
padding: 10rpx;
font-size: 58rpx;
}
.function {
display: flex;
flex-direction: row;
justify-content: space-around;
background-color:
}
.function .menu {
font-size: 28rpx;
margin: 25rpx 0;
color: white;
width: 50%;
text-align: center;
flex-direction: row;
flex-direction: column;
align-items: center;
}
.table .item {
border-bottom: 1rpx solid
}
.table .item .title{
margin: 20rpx 30rpx;
padding-left: 10rpx;
border-left: 5rpx solid
font-size: 26rpx;
}
.record{
margin: 30rpx 40rpx;
display: flex;
flex-direction: row;
justify-content: flex-start;
}
.record .avatar{
width: 200rpx;
height: 200rpx;
}
.record .avatar image{
width: 100%;
height: 100%;
border-radius: 30rpx;
}
.record .desc{
margin: 0 40rpx;
}
.desc{
width: 290rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.desc .username{
margin-top: 25rpx;
font-size: 38rpx;
}
.txt-group{
font-size: 27rpx;
margin: 10rpx 0;
}
.txt-group .zh{
color:
}
.txt-group .en{
color:
}
.area{
color:
font-weight: bold;
}
.delete{
width: 100rpx;
color: red;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
}
var app = getApp();
var api = require("../../config/settings.js")
Page({
/**
* 页面的初始数据
*/
data: {
dataDict: {
result: [
{
"id": 45,
"name": "张铁蛋",
"area": "#19",
"avatar": "/images/img/b.jpg"
},
{
"id": 45,
"name": "刘亦菲",
"area": "#19",
"avatar": "/images/img/b.jpg"
}
],
today_count: 66,
}
},
bindToStatistics(e){
wx.navigateTo({
url: '/pages/statistics/statistics'
})
},
bindToForm(e){
wx.navigateTo({
url: '/pages/form/form'
})
},
refresh() {
//1.发送网络请求
//2.数据绑定
wx.showLoading({
mask: true
})
wx.request({
url: api.collection,
method: "GET",
success: (res) => {
this.setData({
dataDict: res.data
})
},
complete() {
wx.hideLoading()
}
})
},
doDeleteRow(e){
wx.showModal({
title: '确认是否删除?',
confirmColor: "#ff461f",
success: (res) => {
if (!res.confirm) {
return
}
var nid = e.currentTarget.dataset.nid
wx.showLoading({
title: '删除中',
mask:true
})
wx.request({
url: api.collection + nid + '/',
method:'DELETE',
success:(res) =>{
this.refresh()
},
complete() {
wx.hideLoading()
}
})
}
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
//发送网络请求...
this.refresh();
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
this.refresh();
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log("到底了");
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
{
"usingComponents": {},
"navigationBarBackgroundColor": "#01ccb6",
"navigationBarTitleText": "",
"enablePullDownRefresh": true,
"navigationBarTextStyle": "white",
"backgroundColor": "#01ccb6"
}
3.2 后端
class Collection(models.Model):
name = models.CharField(max_length=32, verbose_name='采集人员姓名')
name_pinyin=models.CharField(max_length=32, verbose_name='姓名拼音',null=True)
avatar = models.ImageField(upload_to='collection/%Y/%m/%d/', default='default.png', verbose_name='头像')
create_time = models.DateTimeField(auto_now=True, verbose_name='采集时间')
area = models.ForeignKey(to='Area', null=True, verbose_name='网格区域', on_delete=models.CASCADE)
class Meta:
verbose_name_plural = '采集表'
def __str__(self):
return self.name
class Area(models.Model):
name = models.CharField(max_length=32, verbose_name='网格区域名')
desc = models.CharField(max_length=32, verbose_name='网格简称')
user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE, null=True, verbose_name="负责用户")
class Meta:
verbose_name_plural = '区域表'
def __str__(self):
return self.name
class UserInfo(models.Model):
name = models.CharField(verbose_name="姓名", max_length=32)
avatar = models.FileField(verbose_name="头像", max_length=128, upload_to='avatar')
create_date = models.DateField(verbose_name="日期", auto_now_add=True)
score = models.IntegerField(verbose_name="积分", default=0)
class Meta:
verbose_name_plural = '用户表'
def __str__(self):
return self.name
from datetime import datetime
class CollectionView(GenericViewSet, ListModelMixin,DestroyModelMixin):
queryset = Collection.objects.all().filter(create_time__gte=datetime.now().date())
serializer_class = CollectionSerializer
def list(self, request, *args, **kwargs):
res=super().list(request, *args, **kwargs)
today_count=len(self.get_queryset())
return Response({'code':100,'msg':'成功','result':res.data,'today_count':today_count})
class CollectionSerializer(serializers.ModelSerializer):
class Meta:
model = Collection
fields = ['id','name','avatar','area']
depth=1
3.3 引入矢量图
-注册成功
-加入购物车
-在购物车中添加至项目
-static/css/iconfont.wxss
@import "/static/css/iconfont.wxss";
<text class="iconfont icon-anquan">
四 信息采集详情页
4.1 小程序端-拍照页面
page{
height: 100%;
}
.camera{
height: 80%;
width: 100%;
}
.function{
height: 20%;
background-color: black;
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
}
.record image{
width: 160rpx;
height: 160rpx;
}
.switch{
color: white;
width: 80rpx;
height: 80rpx;
}
.switch image{
width: 80rpx;
height: 80rpx;
}
<!--pages/camera/camera.wxml-->
<camera class="camera" device-position="{{ backFront ? 'back' : 'front' }}" flash="off" frame-size="medium" ></camera>
<view class="function">
<view class="switch"> </view>
<view class="record" bindtap="takePhoto">
<image src="/images/camera/record_on.png"></image>
</view>
<view class="switch" bindtap="switchCamera">
<image src="/images/camera/rotate-camera-white.png"></image>
</view>
</view>
Page({
data: {
backFront:true
},
switchCamera(e) {
var old = this.data.backFront
this.setData({
backFront: !old
})
},
takePhoto:function(){
const ctx = wx.createCameraContext()
ctx.takePhoto({
quality: 'high',
success: (res) => {
// 获取照片
//console.log(res);
// 对上一个页面中的值,进行修改
var pages = getCurrentPages();
var prevPage = pages[pages.length - 2];
// 把上个页面的图片位置设为刚刚拍的照
prevPage.setData({
avatar: res.tempImagePath
})
//跳转回上一个页面 [v1,v2,v2]
wx.navigateBack({});
}
})
},
})
4.2 小程序端-采集页面
var api = require("../../config/settings.js")
Page({
/**
* 页面的初始数据
*/
data: {
avatar: "/images/camera/camera.png",
objectArray: [{
id: 1,
name: '2单元1号楼'
},
{
id: 2,
name: '2单元2号楼'
}
],
index: -1,
name:""
},
onLoad(){
wx.request({
url: api.area,
method:'GET',
success:(res)=>{
this.setData({
objectArray:res.data
})
}
})
},
postUser(e){
wx.showLoading({
title: '提交中',
mask:true
})
wx.uploadFile({
url: api.collection,
filePath: this.data.avatar,
name: 'avatar',
formData: {
'name': this.data.name,
'area': this.data.objectArray[this.data.index].id
},
success(res) {
console.log(res);
// 上一个页面新增数据
// 上传成功
// 跳转回上一页
wx.navigateBack({});
},
complete() {
wx.hideLoading()
}
})
},
bindPickerChange(e) {
this.setData({
index: e.detail.value
})
},
bindToCamera(e){
wx.navigateTo({
url: '/pages/camera/camera',
})
},
})
<!--pages/form/form.wxml-->
<view class="avatar">
<image src='{{avatar}}' bindtap="bindToCamera"></image>
</view>
<view class="form">
<view class="row-group">
<input placeholder="请填写姓名" placeholder-class='txt' model:value="{{name}}" bindinput="bindNameChange" />
</view>
<view class="picker-group">
<picker bindchange="bindPickerChange" value="{{index}}" range="{{objectArray}}" range-key="name">
<view wx:if="{{ index > -1}}" class="picker-txt picker">当前网格:{{objectArray[index].name}}</view>
<view wx:else class="picker-txt" >请选择网格</view>
</picker>
</view>
<view>
<button class="submit" bindtap="postUser" > 提 交 </button>
</view>
</view>
/* pages/form/form.wxss */
.avatar{
display: flex;
flex-direction: column;
align-items: center;
}
.avatar image {
margin-top: 140rpx;
width: 300rpx;
height: 300rpx;
border-radius: 30rpx;
border: 1px solid
}
.form{
padding: 40rpx;
}
.form .row-group{
padding: 10rpx 0;
border-bottom: 1rpx solid
position: relative;
margin-top: 30rpx;
}
.form .row-group text{
font-size: 28rpx;
padding:20rpx 0;
}
.form .row-group input{
padding: 10rpx 0;
}
.form .row-group .txt{
color:
font-size: 28rpx;
}
.form .picker-group{
border-bottom: 1rpx solid
}
.form .picker-group .picker-txt{
color:
font-size: 28rpx;
padding: 40rpx 0 20rpx 0;
}
.form .picker-group .picker{
color: black;
}
.form .submit{
margin-top: 80rpx;
color:
border: 2rpx solid
background-color:
font-size: 32rpx;
font-weight: bold;
}
4.3 采集页面后端
class AreaView(GenericViewSet, ListModelMixin):
queryset = Area.objects.all()
serializer_class = AreaSerializer
from datetime import datetime
class CollectionView(GenericViewSet, ListModelMixin, DestroyModelMixin, CreateModelMixin):
queryset = Collection.objects.all().filter(create_time__gte=datetime.now().date())
serializer_class = CollectionSerializer
def get_serializer_class(self):
if self.action == 'create':
return CollectionSaveSerializer
else:
return CollectionSerializer
def list(self, request, *args, **kwargs):
res = super().list(request, *args, **kwargs)
today_count = len(self.get_queryset())
return Response({'code': 100, 'msg': '成功', 'result': res.data, 'today_count': today_count})
class Area(models.Model):
name = models.CharField(max_length=32, verbose_name='网格区域名')
desc = models.CharField(max_length=32, verbose_name='网格简称')
user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE, null=True, verbose_name="负责用户")
class Meta:
verbose_name_plural = '区域表'
def __str__(self):
return self.name
class UserInfo(models.Model):
name = models.CharField(verbose_name="姓名", max_length=32)
avatar = models.FileField(verbose_name="头像", max_length=128, upload_to='avatar')
create_date = models.DateField(verbose_name="日期", auto_now_add=True)
score = models.IntegerField(verbose_name="积分", default=0)
class Meta:
verbose_name_plural = '用户表'
def __str__(self):
return self.name
router.register('area', AreaView, 'area')
class CollectionSaveSerializer(serializers.ModelSerializer):
class Meta:
model = Collection
fields = [ 'name', 'avatar', 'area']
def create(self, validated_data):
validated_data['name_pinyin'] = validated_data.get('name')
instance=super().create(validated_data)
return instance
class AreaSerializer(serializers.ModelSerializer):
class Meta:
model = Area
fields = ['id', 'name', 'desc']
五 人脸识别
5.1 使用步骤
https://cloud.baidu.com/product/face.html


5.2 上传-删除-匹配人脸
from aip import AipFace
import base64
from pypinyin import lazy_pinyin, Style
class BaiDuAI:
def __init__(self,APP_ID='62643893',API_KEY='hfAwQUE1fwyCjXG01ZCHbaSG',SECRET_KEY='qgxJneAt0ovmGA2rLrdq99GEFs1apjte'):
""" 你的 APPID AK SK """
self.APP_ID = APP_ID
self.API_KEY = API_KEY
self.SECRET_KEY = SECRET_KEY
self.client = AipFace(self.APP_ID, self.API_KEY, self.SECRET_KEY)
def name_to_pinyin(self,text):
style = Style.TONE3
name_list=lazy_pinyin(text, style=style)
return ''.join(name_list)
def add_user(self):
data = base64.b64encode(open('./gtl.png','rb').read()).decode('utf-8')
image = data
imageType = "BASE64"
groupId = "100"
userId=self.name_to_pinyin('古天乐')
""" 调用人脸注册 """
self.client.addUser(image, imageType, groupId, userId);
""" 如果有可选参数 """
options = {}
options["user_info"] = "彭于晏"
options["quality_control"] = "NORMAL"
options["liveness_control"] = "LOW"
options["action_type"] = "REPLACE"
""" 带参数调用人脸注册 """
self.client.addUser(image, imageType, groupId, userId, options)
def search(self):
data = base64.b64encode(open('./pyy2.png', 'rb').read()).decode('utf-8')
image = data
imageType = "BASE64"
groupIdList = "100,2"
""" 调用人脸搜索 """
self.client.search(image, imageType, groupIdList);
""" 如果有可选参数 """
options = {}
options["match_threshold"] = 70
options["quality_control"] = "NORMAL"
options["liveness_control"] = "LOW"
options["max_user_num"] = 3
""" 带参数调用人脸搜索 """
res=self.client.search(image, imageType, groupIdList, options)
print(res)
def delete(self):
userId = "user1"
groupId = "group1"
faceToken = "face_token_23123"
""" 调用人脸删除 """
self.client.faceDelete(userId, groupId, faceToken);
if __name__ == '__main__':
ai=BaiDuAI()
ai.search()
5.3 项目中集成
class CollectionSaveSerializer(serializers.ModelSerializer):
class Meta:
model = Collection
fields = ['name', 'avatar', 'area']
def create(self, validated_data):
from libs.baidu_ai import BaiDuAI
baidu=BaiDuAI()
avatar_file_object = validated_data.get('avatar')
print(avatar_file_object)
name = validated_data.get('name')
name_pinyin=baidu.name_to_pinyin(name)
res=baidu.add_user(avatar_file_object,name,name_pinyin)
validated_data['name_pinyin'] = name_pinyin
validated_data['face_token'] = res.get('result').get('face_token')
instance=super().create(validated_data)
return instance
def destroy(self, request, *args, **kwargs):
from libs.baidu_ai import BaiDuAI
instance = self.get_object()
baidu=BaiDuAI()
res=baidu.delete(instance.name_pinyin,face_token=instance.face_token)
print(res)
self.perform_destroy(instance)
return Response()
六 语音识别
收费方案
def speed(file_object):
from aip import AipSpeech
APP_ID = ''
API_KEY = ''
SECRET_KEY = ''
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
data = file_object.read()
return client.asr(data, 'pcm', 16000, {'dev_pid': 1537})
免费方案
\site-packages\speech_recognition\pocketsphinx-data
1.WAV
2.AIFF/AIFF-C
3.FLAC
import speech_recognition as sr
audio_file = './test1.wav'
r = sr.Recognizer()
with sr.AudioFile(audio_file) as source:
audio = r.record(source)
result = r.recognize_sphinx(audio, language="zh-CN")
print(result)