You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
497 lines
14 KiB
497 lines
14 KiB
|
2 months ago
|
<template>
|
||
|
|
<view class="page1">
|
||
|
|
<view class="voice-model" v-if="recordState == true">
|
||
|
|
<img src="/static/images/maikefeng.png" alt="">
|
||
|
|
<view class="voice-text">语音识别中...</view>
|
||
|
|
</view>
|
||
|
|
<view class="top" ref="top">
|
||
|
|
<view @tap="backPage" style="width: 40px;height: 40px;position: absolute;top: 100rpx;left: 30rpx;">
|
||
|
|
<uni-icons type="left" color="#000" size="27"></uni-icons>
|
||
|
|
</view>
|
||
|
|
<view class="title">对话</view>
|
||
|
|
</view>
|
||
|
|
<view class="content" :style="{height:height - 165 +'px'}">
|
||
|
|
<view class="prompt">
|
||
|
|
<view class="prompt-title">
|
||
|
|
<view class="hello-right"></view>
|
||
|
|
<view class="ai-bot"></view>
|
||
|
|
<view class="hello-left">
|
||
|
|
<text style="font-size: 40rpx;font-weight: 800;line-height: 56rpx;color: #fff;">Hi</text>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
<view class="prompt-title-text">
|
||
|
|
<text>欢迎使用Ai助手,为了提高语音及文字识别准确率,建议您按照以下规则操作:</text>
|
||
|
|
<text style="color: #FF9797;">1.语音规则:(颜色在前,尺码在后)</text>
|
||
|
|
<text>例1:“货号87-12白色M码10件”</text>
|
||
|
|
<text>例2:“货号87-12,所有颜色所有尺码10件”</text>
|
||
|
|
<text style="color: #FF9797;">2.建议您不同商品用“货号”两字分隔</text>
|
||
|
|
<text>例:“<text style="color: #FF9797;">货号87-12</text>白色M码10件,<text style="color: #FF9797;">货号ZK001</text>黑色L码10件”</text>
|
||
|
|
<text>3.如需手动输入,则要点击“确认”按钮发送对话</text>
|
||
|
|
<text>4.录入完成后点击开始识别按钮进行AI识别</text>
|
||
|
|
<text>5.点击可查看<text @tap="goTutorial" style="color: blue;">使用教程</text></text>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
<view class="prompt" style="height: 80rpx;line-height: 80rpx;padding-left: 20rpx;">
|
||
|
|
<text>您当前选择的客户是:{{khName.name}}</text>
|
||
|
|
</view>
|
||
|
|
<view style="width: 100%;height: 100rpx;text-align: center;font-size: 11px;color: #777;line-height: 100rpx;">
|
||
|
|
点击可编辑语音输入的内容~
|
||
|
|
</view>
|
||
|
|
<view style="width: 526rpx;float: right;margin-right:20rpx;text-align: left;padding-bottom: 60rpx;">
|
||
|
|
<view style="width: 526rpx;display: block;float: right;" v-for="(item,index) in msgList" :key="index">
|
||
|
|
<view @tap="editTextBtn(item,index)" style="display: inline-block;width: auto;height: auto;min-height: 40px;background: linear-gradient(127.96deg, #6585fa 0%, #6ad5fe 100%);color: #fff;padding: 20rpx 10px;border-radius: 10px;border-bottom-right-radius: 0;margin-bottom: 20px;float: right;">
|
||
|
|
{{item.text}}
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
<view @tap="addReg" style="width: 150rpx;position: absolute;bottom: 86px;z-index: 99;right: 10px;height: 60rpx;text-align: center;line-height: 60rpx;color: #fff;border-radius: 5px;background: linear-gradient(90deg, #FF9797, #FFC1E0);">
|
||
|
|
开始识别
|
||
|
|
</view>
|
||
|
|
<view class="bottom">
|
||
|
|
<view style="width:10%;height:90rpx;line-height:90rpx;margin-top:20rpx;text-align: center;">
|
||
|
|
<uni-icons v-if="isVoice" @tap="switchChat(false)" type="chat" size="26"></uni-icons>
|
||
|
|
<uni-icons v-if="!isVoice" @tap="switchChat(true)" type="mic" size="26"></uni-icons>
|
||
|
|
</view>
|
||
|
|
<view style="width: 76%;height: 90rpx;line-height: 90rpx;text-align: center;background: #eee;margin-top: 10px;border-radius: 10px;font-size: 30rpx;color: #777;">
|
||
|
|
<view v-if="isVoice" @touchstart="kaishi" @touchend="jieshu">
|
||
|
|
<text>按住 说话</text>
|
||
|
|
</view>
|
||
|
|
<view v-if="!isVoice" style="width: 100%;height: 90rpx;line-height: 90rpx;border-radius: 10px;text-align: left;padding-left: 20rpx;">
|
||
|
|
<input type="text" v-model="editText" placeholder="请输入对话内容" style="height: 90rpx;">
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
<view v-if="!isVoice" @tap="inputSaveText" style="width:12%;background: linear-gradient(90deg, #60F3FF, #088FEB);height:70rpx;line-height:70rpx;text-align:center;margin:15px 0 0 1%;color:#fff;border-radius:5px;">
|
||
|
|
确定
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
|
||
|
|
<!-- 弹出规格选择 -->
|
||
|
|
<uni-popup ref="popup" background-color="#fff">
|
||
|
|
<view class="popup-content">
|
||
|
|
<view class="popup-title">
|
||
|
|
<text>修改当前内容</text>
|
||
|
|
<uni-icons @tap='close' type="closeempty" color='red' size="16"
|
||
|
|
style="height:40rpx;line-height: 40rpx;position: absolute !important;bottom:0;right: 30rpx;"></uni-icons>
|
||
|
|
</view>
|
||
|
|
<view class="popup-container">
|
||
|
|
<textarea maxlength="-1" v-model="editText" style="padding: 20rpx;width:100%;border:1px solid #eee;"></textarea>
|
||
|
|
<view class="popup-bottom">
|
||
|
|
<view @tap="saveText" style="width: 100%;height: 70rpx;line-height: 70rpx;text-align: center;border-radius: 0;background: linear-gradient(90deg, #60F3FF, #088FEB);color: #fff;">
|
||
|
|
确认无误
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
</uni-popup>
|
||
|
|
<view class="mask-model" v-if="isNoVoice">貌似没有检测到您上次的语音录入信息,正在反复识别中</view>
|
||
|
|
</view>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
var plugin = requirePlugin("WechatSI")
|
||
|
|
let manager = plugin.getRecordRecognitionManager()
|
||
|
|
export default {
|
||
|
|
components: {},
|
||
|
|
data() {
|
||
|
|
return {
|
||
|
|
isVoice:true,
|
||
|
|
isNoVoice:false,
|
||
|
|
height:0,
|
||
|
|
khName:{},
|
||
|
|
msgList:[],
|
||
|
|
editText:'',
|
||
|
|
index:'',
|
||
|
|
recordState: false
|
||
|
|
}
|
||
|
|
},
|
||
|
|
onShow() {
|
||
|
|
|
||
|
|
},
|
||
|
|
onLoad(option) {
|
||
|
|
this.height = wx.getSystemInfoSync().windowHeight
|
||
|
|
|
||
|
|
this.khName = JSON.parse(option.khName)
|
||
|
|
|
||
|
|
this.initRecord();
|
||
|
|
},
|
||
|
|
methods: {
|
||
|
|
switchChat(type){
|
||
|
|
this.isVoice = type
|
||
|
|
},
|
||
|
|
editTextBtn(item,index){
|
||
|
|
this.editText = item.text
|
||
|
|
this.index = index
|
||
|
|
this.$refs.popup.open()
|
||
|
|
|
||
|
|
},
|
||
|
|
saveText(){
|
||
|
|
this.msgList[this.index].text = this.editText
|
||
|
|
this.$forceUpdate()
|
||
|
|
this.editText = ''
|
||
|
|
this.close()
|
||
|
|
},
|
||
|
|
close(){
|
||
|
|
this.$refs.popup.close()
|
||
|
|
},
|
||
|
|
//正则匹配处理“2十9”等情况
|
||
|
|
convertStringCorrectly(str) {
|
||
|
|
var regexForSingleTen = /(\d+)十(?!\d)/g;
|
||
|
|
var regexForFollowedByDigit = /(\d+)十(?=\d)/g;
|
||
|
|
var step1Result = str.replace(regexForSingleTen, '$10');
|
||
|
|
var finalResult = step1Result.replace(regexForFollowedByDigit, '$1');
|
||
|
|
|
||
|
|
return finalResult;
|
||
|
|
},
|
||
|
|
spliceMsg(res){
|
||
|
|
let regex = /嗯|啊|儿|阿|恩/g;
|
||
|
|
return res.replace(regex, '')
|
||
|
|
},
|
||
|
|
convertChineseToArabic(str) {
|
||
|
|
const chineseNumToArabic = {
|
||
|
|
'零': 0, '一': 1, '二': 2, '两': 2, '三': 3,
|
||
|
|
'四': 4, '五': 5, '六': 6, '七': 7, '八': 8,
|
||
|
|
'九': 9,'杠':'-','刚':'-','军色':'均色','叉':'X','井':'#',
|
||
|
|
'时间':'10件','事件':'10件','世间':'10件','实践':'10件','实件':'10件',
|
||
|
|
'景':'#','警':'#','颈':'#','括号':'货号','名城':'名称','明城':'名称','名成':'名称','名程':'名称',
|
||
|
|
};
|
||
|
|
const regex = /(零|一|二|两|三|四|五|六|七|八|九|杠|刚|军色|叉|井|时间|事件|世间|实践|实件|景|警|颈|括号|名城|名程|名成|明城)/g;
|
||
|
|
return str.replace(regex, match => chineseNumToArabic[match]);
|
||
|
|
},
|
||
|
|
inputSaveText(){
|
||
|
|
let convertedStr = this.convertChineseToArabic(this.editText);
|
||
|
|
if(convertedStr.indexOf('点') != -1){
|
||
|
|
convertedStr = this.replaceCharAfterNumber(convertedStr,'点','.')
|
||
|
|
}
|
||
|
|
if(convertedStr.indexOf('货号,') != -1){
|
||
|
|
convertedStr = convertedStr.replace(/货号,/g,'货号')
|
||
|
|
}
|
||
|
|
if(convertedStr.indexOf('货号') != -1){
|
||
|
|
convertedStr = convertedStr.replace(/货号/g,'货号:')
|
||
|
|
}
|
||
|
|
if(convertedStr.indexOf(',数量') != -1){
|
||
|
|
convertedStr = convertedStr.replace(/,数量/g,'数量')
|
||
|
|
}
|
||
|
|
if(convertedStr.indexOf('数量,') != -1){
|
||
|
|
convertedStr = convertedStr.replace(/数量,/g,'数量')
|
||
|
|
}
|
||
|
|
if(convertedStr.indexOf('数量') != -1){
|
||
|
|
convertedStr = convertedStr.replace(/数量/g,',数量:')
|
||
|
|
}
|
||
|
|
convertedStr = this.convertStringCorrectly(convertedStr)
|
||
|
|
convertedStr = this.spliceMsg(convertedStr)
|
||
|
|
if(convertedStr.indexOf(',') == 0){
|
||
|
|
convertedStr = convertedStr.substr(1)
|
||
|
|
}
|
||
|
|
if (convertedStr.startsWith("号")) {
|
||
|
|
convertedStr = "货号" + convertedStr.substr(1);
|
||
|
|
}
|
||
|
|
let getMsg = convertedStr
|
||
|
|
if(this.editText == ''){
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
let data = {
|
||
|
|
text:getMsg
|
||
|
|
}
|
||
|
|
this.msgList.push(data)
|
||
|
|
this.editText = ''
|
||
|
|
},
|
||
|
|
//按住语音识别,开始
|
||
|
|
kaishi() {
|
||
|
|
if(this.isNoVoice == false){
|
||
|
|
this.recordState = true
|
||
|
|
uni.vibrateShort();
|
||
|
|
manager.start({
|
||
|
|
duration: 60000,
|
||
|
|
lang: "zh_CN"
|
||
|
|
});
|
||
|
|
}
|
||
|
|
},
|
||
|
|
//松开语音识别,结束
|
||
|
|
jieshu() {
|
||
|
|
this.recordState = false
|
||
|
|
manager.stop()
|
||
|
|
},
|
||
|
|
replaceCharAfterNumber(str, charToFind, charToReplace) {
|
||
|
|
const regex = new RegExp(`\\d${charToFind}`, 'g');
|
||
|
|
return str.replace(regex, (match) => {
|
||
|
|
return match.replace(charToFind, charToReplace);
|
||
|
|
});
|
||
|
|
},
|
||
|
|
//语音识别功能初始化
|
||
|
|
initRecord() {
|
||
|
|
let that = this;
|
||
|
|
manager.stop()
|
||
|
|
// 识别结束事件
|
||
|
|
manager.onStop = (res) => {
|
||
|
|
let convertedStr = this.convertChineseToArabic(res.result);
|
||
|
|
if(convertedStr.indexOf('点') != -1){
|
||
|
|
convertedStr = that.replaceCharAfterNumber(convertedStr,'点','.')
|
||
|
|
}
|
||
|
|
if(convertedStr.indexOf('货号,') != -1){
|
||
|
|
convertedStr = convertedStr.replace(/货号,/g,'货号')
|
||
|
|
}
|
||
|
|
if(convertedStr.indexOf('货号') != -1){
|
||
|
|
convertedStr = convertedStr.replace(/货号/g,'货号:')
|
||
|
|
}
|
||
|
|
if(convertedStr.indexOf(',数量') != -1){
|
||
|
|
convertedStr = convertedStr.replace(/,数量/g,'数量')
|
||
|
|
}
|
||
|
|
if(convertedStr.indexOf('数量,') != -1){
|
||
|
|
convertedStr = convertedStr.replace(/数量,/g,'数量')
|
||
|
|
}
|
||
|
|
if(convertedStr.indexOf('数量') != -1){
|
||
|
|
convertedStr = convertedStr.replace(/数量/g,',数量:')
|
||
|
|
}
|
||
|
|
convertedStr = this.convertStringCorrectly(convertedStr)
|
||
|
|
convertedStr = this.spliceMsg(convertedStr)
|
||
|
|
if(convertedStr.indexOf(',') == 0){
|
||
|
|
convertedStr = convertedStr.substr(1)
|
||
|
|
}
|
||
|
|
if (convertedStr.indexOf('号') == 0) {
|
||
|
|
convertedStr = "货号" + convertedStr.substr(1);
|
||
|
|
}
|
||
|
|
let data = {
|
||
|
|
text:convertedStr
|
||
|
|
}
|
||
|
|
that.msgList.push(data)
|
||
|
|
that.$forceUpdate()
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
// 识别错误事件
|
||
|
|
manager.onError = (res) => {
|
||
|
|
if(res.retcode == '-30011'){
|
||
|
|
that.isNoVoice = true
|
||
|
|
}
|
||
|
|
if(res.retcode == '-30004'){
|
||
|
|
// uni.hideLoading()
|
||
|
|
that.isNoVoice = false
|
||
|
|
uni.hideToast()
|
||
|
|
uni.showToast({
|
||
|
|
title: "未识别到声音信息,请重新录入",
|
||
|
|
icon: 'none'
|
||
|
|
})
|
||
|
|
}
|
||
|
|
if (res.retcode == '-40001') {
|
||
|
|
uni.showToast({
|
||
|
|
title: '使用次数超限制,请联系管理员!',
|
||
|
|
icon: 'none'
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
addReg() {
|
||
|
|
if(this.msgList.length <= 0){
|
||
|
|
this.tui.toast("小助手没有检测到可识别的内容哦~")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
this.tui.request("/app/sale/saveOrder", "POST", {
|
||
|
|
userId:this.khName.id,
|
||
|
|
userName:this.khName.name,
|
||
|
|
aiFlag:1,
|
||
|
|
status: 7,
|
||
|
|
area:this.khName.area,
|
||
|
|
city:this.khName.city,
|
||
|
|
province:this.khName.province,
|
||
|
|
receiveAddress:this.khName.address
|
||
|
|
}, false, false).then((res) => {
|
||
|
|
if (res.code == 200) {
|
||
|
|
this.goHangOrder(res.result.id)
|
||
|
|
} else {
|
||
|
|
this.tui.toast(res.message)
|
||
|
|
}
|
||
|
|
}).catch((res) => {
|
||
|
|
this.tui.toast(res)
|
||
|
|
})
|
||
|
|
},
|
||
|
|
goHangOrder(saleId){
|
||
|
|
let text = ' '
|
||
|
|
for(let i=0;i<this.msgList.length;i++){
|
||
|
|
this.msgList[i].text
|
||
|
|
text += this.msgList[i].text + ' '
|
||
|
|
}
|
||
|
|
|
||
|
|
this.tui.request("/app/sale/buyAiSync", "POST", {
|
||
|
|
aiMsg:text,
|
||
|
|
saleId:saleId,
|
||
|
|
}, false, true).then((res) => {
|
||
|
|
if(res.code == 200){
|
||
|
|
uni.navigateBack({
|
||
|
|
delta: 1
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}).catch((res) => {
|
||
|
|
this.tui.toast(res)
|
||
|
|
})
|
||
|
|
},
|
||
|
|
backPage(){
|
||
|
|
uni.navigateBack({
|
||
|
|
delta: 1
|
||
|
|
})
|
||
|
|
},
|
||
|
|
goTutorial(){
|
||
|
|
uni.navigateTo({
|
||
|
|
url: `/package2/other/tutorialList`
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style lang="scss">
|
||
|
|
page,
|
||
|
|
.page1 {
|
||
|
|
height:100%;
|
||
|
|
background: #F1F5FB;
|
||
|
|
}
|
||
|
|
|
||
|
|
.top {
|
||
|
|
width: 100%;
|
||
|
|
height: 180rpx;
|
||
|
|
opacity: 1;
|
||
|
|
overflow: hidden;
|
||
|
|
display: flex;
|
||
|
|
}
|
||
|
|
.title{
|
||
|
|
color: #000;
|
||
|
|
height: 80rpx;
|
||
|
|
line-height: 80rpx;
|
||
|
|
margin-top: 94rpx;
|
||
|
|
width: 100%;
|
||
|
|
text-align: center;
|
||
|
|
font-size: 32rpx;
|
||
|
|
font-weight: bold;
|
||
|
|
}
|
||
|
|
.content{
|
||
|
|
overflow:scroll;
|
||
|
|
}
|
||
|
|
.bottom{
|
||
|
|
width: 100%;
|
||
|
|
height: 150rpx;
|
||
|
|
display: flex;
|
||
|
|
background: #fff;
|
||
|
|
}
|
||
|
|
.prompt {
|
||
|
|
background: #fff;
|
||
|
|
width: 75%;
|
||
|
|
height: auto;
|
||
|
|
border-radius: 10px;
|
||
|
|
display: block;
|
||
|
|
overflow: hidden;
|
||
|
|
border-bottom-left-radius: 0;
|
||
|
|
margin: 20rpx 0 0 20rpx;
|
||
|
|
padding-bottom: 20rpx;
|
||
|
|
}
|
||
|
|
|
||
|
|
.prompt-title {
|
||
|
|
position: relative;
|
||
|
|
width: 300rpx;
|
||
|
|
margin: 40rpx 40rpx 20rpx 40rpx;
|
||
|
|
}
|
||
|
|
|
||
|
|
.prompt-title-text {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
color: #777;
|
||
|
|
font-size: 26rpx;
|
||
|
|
width: 90%;
|
||
|
|
margin: 0 auto;
|
||
|
|
line-height: 40rpx;
|
||
|
|
}
|
||
|
|
.ai-bot {
|
||
|
|
position: absolute;
|
||
|
|
top: -8rpx;
|
||
|
|
left: 10rpx;
|
||
|
|
width: 70rpx;
|
||
|
|
height: 60rpx;
|
||
|
|
background-size: 100% !important;
|
||
|
|
background: url(https://jewel-shop.oss-cn-beijing.aliyuncs.com/66dc640d9e8f4749a234d9ef2af1b257.png) no-repeat;
|
||
|
|
}
|
||
|
|
.hello-right {
|
||
|
|
position: absolute;
|
||
|
|
left: 5px;
|
||
|
|
bottom: 0rpx;
|
||
|
|
width: 120rpx;
|
||
|
|
height: 2px;
|
||
|
|
opacity: 1;
|
||
|
|
background: linear-gradient(180deg, #6585fa 0%, #6ad5fe 100%);
|
||
|
|
}
|
||
|
|
|
||
|
|
.hello-left {
|
||
|
|
width: 102rpx;
|
||
|
|
height: 56rpx;
|
||
|
|
opacity: 1;
|
||
|
|
margin-left: 100rpx;
|
||
|
|
background: linear-gradient(127.96deg, #6585fa 0%, #6ad5fe 100%);
|
||
|
|
border-radius: 3px;
|
||
|
|
text-align: center;
|
||
|
|
-webkit-transform: skewX(8deg);
|
||
|
|
transform: skewX(-6deg);
|
||
|
|
}
|
||
|
|
.popup-content {
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
padding: 15px;
|
||
|
|
width: 500rpx;
|
||
|
|
height: 550rpx;
|
||
|
|
background-color: #fff;
|
||
|
|
}
|
||
|
|
.voice-model {
|
||
|
|
width: 300rpx;
|
||
|
|
height: 300rpx;
|
||
|
|
display: flex;
|
||
|
|
justify-content: center;
|
||
|
|
flex-flow: column;
|
||
|
|
position: fixed;
|
||
|
|
left: 50%;
|
||
|
|
top: 45%;
|
||
|
|
background: rgba(0, 0, 0, 0.5);
|
||
|
|
border-radius: 20rpx;
|
||
|
|
color: #fff;
|
||
|
|
text-align: center;
|
||
|
|
margin-left: -150rpx;
|
||
|
|
z-index: 99;
|
||
|
|
}
|
||
|
|
|
||
|
|
.voice-model img {
|
||
|
|
width: 200rpx;
|
||
|
|
height: 200rpx;
|
||
|
|
margin: 0 auto;
|
||
|
|
}
|
||
|
|
.popup-title {
|
||
|
|
font-size: 36rpx;
|
||
|
|
font-weight: bold;
|
||
|
|
text-align: center;
|
||
|
|
position: relative;
|
||
|
|
}
|
||
|
|
|
||
|
|
.popup-container {
|
||
|
|
margin-top: 20rpx;
|
||
|
|
}
|
||
|
|
|
||
|
|
.popup-bottom {
|
||
|
|
display: flex;
|
||
|
|
height: 80rpx;
|
||
|
|
color: #fff;
|
||
|
|
line-height: 80rpx;
|
||
|
|
margin-top: 50rpx;
|
||
|
|
}
|
||
|
|
.mask-model{
|
||
|
|
width: 60%;
|
||
|
|
height: 100rpx;
|
||
|
|
position: fixed;
|
||
|
|
top: 0;
|
||
|
|
left: 0;
|
||
|
|
right: 0;
|
||
|
|
bottom: 0;
|
||
|
|
margin: auto;
|
||
|
|
text-align: center;
|
||
|
|
background: rgba(0,0,0,0.7);
|
||
|
|
color: #eee;
|
||
|
|
padding: 5px;
|
||
|
|
border-radius: 5px;
|
||
|
|
z-index: 99;
|
||
|
|
}
|
||
|
|
</style>
|