Browse Source

提交

yun
douzhuo 2 years ago
parent
commit
8fe9582866
100 changed files with 36379 additions and 0 deletions
  1. +12
    -0
      .hbuilderx/launch.json
  2. +425
    -0
      App.vue
  3. +2
    -0
      audios.js
  4. +28
    -0
      components/gaoyia-parse/components/wxParseAudio.vue
  5. +94
    -0
      components/gaoyia-parse/components/wxParseImg.vue
  6. +55
    -0
      components/gaoyia-parse/components/wxParseTable.vue
  7. +98
    -0
      components/gaoyia-parse/components/wxParseTemplate0.vue
  8. +88
    -0
      components/gaoyia-parse/components/wxParseTemplate1.vue
  9. +88
    -0
      components/gaoyia-parse/components/wxParseTemplate10.vue
  10. +86
    -0
      components/gaoyia-parse/components/wxParseTemplate11.vue
  11. +88
    -0
      components/gaoyia-parse/components/wxParseTemplate2.vue
  12. +88
    -0
      components/gaoyia-parse/components/wxParseTemplate3.vue
  13. +88
    -0
      components/gaoyia-parse/components/wxParseTemplate4.vue
  14. +88
    -0
      components/gaoyia-parse/components/wxParseTemplate5.vue
  15. +88
    -0
      components/gaoyia-parse/components/wxParseTemplate6.vue
  16. +88
    -0
      components/gaoyia-parse/components/wxParseTemplate7.vue
  17. +88
    -0
      components/gaoyia-parse/components/wxParseTemplate8.vue
  18. +88
    -0
      components/gaoyia-parse/components/wxParseTemplate9.vue
  19. +15
    -0
      components/gaoyia-parse/components/wxParseVideo.vue
  20. +261
    -0
      components/gaoyia-parse/libs/html2json.js
  21. +156
    -0
      components/gaoyia-parse/libs/htmlparser.js
  22. +209
    -0
      components/gaoyia-parse/libs/wxDiscode.js
  23. +258
    -0
      components/gaoyia-parse/parse.css
  24. +228
    -0
      components/gaoyia-parse/parse.vue
  25. +75
    -0
      components/html2canvas/html2canvas.vue
  26. +462
    -0
      components/long_audio/long_audio.vue
  27. +735
    -0
      components/r-canvas/r-canvas.js
  28. +26
    -0
      components/r-canvas/r-canvas.vue
  29. +10
    -0
      components/uniapp-zaudio/dist/util.d.ts
  30. +73
    -0
      components/uniapp-zaudio/dist/util.js
  31. +213
    -0
      components/uniapp-zaudio/dist/zaudio.d.ts
  32. +658
    -0
      components/uniapp-zaudio/dist/zaudio.js
  33. +2
    -0
      components/uniapp-zaudio/index.js
  34. +356
    -0
      components/uniapp-zaudio/index.scss
  35. BIN
      components/uniapp-zaudio/static/go.png
  36. BIN
      components/uniapp-zaudio/static/loading.png
  37. BIN
      components/uniapp-zaudio/static/loading2.png
  38. BIN
      components/uniapp-zaudio/static/next.png
  39. BIN
      components/uniapp-zaudio/static/pausebtn.png
  40. BIN
      components/uniapp-zaudio/static/pausebtn2.png
  41. BIN
      components/uniapp-zaudio/static/playbtn.png
  42. BIN
      components/uniapp-zaudio/static/playbtn2.png
  43. BIN
      components/uniapp-zaudio/static/prev.png
  44. +416
    -0
      components/uniapp-zaudio/zaudio.vue
  45. +87
    -0
      components/yz-audio/audioBg.js
  46. +119
    -0
      components/yz-audio/index.scss
  47. BIN
      components/yz-audio/static/backimg.png
  48. BIN
      components/yz-audio/static/bg.png
  49. BIN
      components/yz-audio/static/bg_act.png
  50. BIN
      components/yz-audio/static/loading.png
  51. BIN
      components/yz-audio/static/loading2.png
  52. BIN
      components/yz-audio/static/pausebtn.png
  53. BIN
      components/yz-audio/static/playbtn.png
  54. +432
    -0
      components/yz-audio/yz-audio.vue
  55. +84
    -0
      config.js
  56. +39
    -0
      main.js
  57. +131
    -0
      manifest.json
  58. +49
    -0
      package-lock.json
  59. +625
    -0
      pages.json
  60. +186
    -0
      pages/center/Piabodata/Customerportrait/Detailsofthesearch.vue
  61. +2439
    -0
      pages/center/Piabodata/Customerportrait/Receivedetailabout.vue
  62. +717
    -0
      pages/center/Piabodata/Customerportrait/Receivingrecords.vue
  63. +405
    -0
      pages/center/Piabodata/Employeesstatistics.vue
  64. +495
    -0
      pages/center/Piabodata/Groupcontrast.vue
  65. +642
    -0
      pages/center/Piabodata/StaffAnalysis.vue
  66. +1131
    -0
      pages/center/Piabodata/Theteamcompared.vue
  67. +1414
    -0
      pages/center/Piabodata/TrendAnalysis.vue
  68. +479
    -0
      pages/center/Piabodata/Userinsightinto.vue
  69. +752
    -0
      pages/center/Piabodata/index.vue
  70. +151
    -0
      pages/center/Piabodata/selectGroup.vue
  71. +150
    -0
      pages/center/Piabodata/selectTeam.vue
  72. +1163
    -0
      pages/center/consumer/consumerDetail.vue
  73. +495
    -0
      pages/center/consumer/edit.vue
  74. +1075
    -0
      pages/center/consumer/index.vue
  75. +322
    -0
      pages/center/consumer/newFollowup/newFollowup.vue
  76. +1511
    -0
      pages/center/prohibited/details.vue
  77. +773
    -0
      pages/center/prohibited/index.vue
  78. +1025
    -0
      pages/center/records/index.vue
  79. +275
    -0
      pages/center/records/recordSearch.vue
  80. +453
    -0
      pages/index/customer.vue
  81. +182
    -0
      pages/index/guide.vue
  82. +1064
    -0
      pages/index/index.vue
  83. +626
    -0
      pages/index/learning.vue
  84. +305
    -0
      pages/index/personal.vue
  85. +1537
    -0
      pages/learning/Equinoctial/index.vue
  86. +1567
    -0
      pages/learning/Equinoctial/index2.vue
  87. +237
    -0
      pages/learning/Equinoctiallearning.vue
  88. +146
    -0
      pages/learning/Keywordsearch.vue
  89. +1685
    -0
      pages/learning/Thefulltext/index.vue
  90. +1506
    -0
      pages/learning/Thefulltext/index2.vue
  91. +144
    -0
      pages/learning/Thefulltext/search.vue
  92. +348
    -0
      pages/login/Setthepassword.vue
  93. +250
    -0
      pages/login/Verification.vue
  94. +262
    -0
      pages/login/Verifythelogin.vue
  95. +324
    -0
      pages/login/index.vue
  96. +328
    -0
      pages/login/yinzhongmalogin.vue
  97. +116
    -0
      pages/mine/ScoringPlaylist.vue
  98. +237
    -0
      pages/mine/calibration.vue
  99. +239
    -0
      pages/mine/consultanonduty/index.vue
  100. +1824
    -0
      pages/mine/details.vue

+ 12
- 0
.hbuilderx/launch.json View File

@@ -4,11 +4,23 @@
"configurations": [{
"default" :
{
<<<<<<< HEAD
"launchtype" : "local"
},
"mp-weixin" :
{
"launchtype" : "local"
=======
"launchtype" : "remote"
},
"h5" :
{
"launchtype" : "remote"
},
"mp-weixin" :
{
"launchtype" : "remote"
>>>>>>> dev
},
"type" : "uniCloud"
}


+ 425
- 0
App.vue View File

@@ -0,0 +1,425 @@
<script>
import Vue from 'vue'
//app.js
var config = require("./config");
export default {
onLaunch(options) {
uni.getSystemInfo({
success: function(e) {
console.log(e, 'adjsakljdklasjdklsakjdslakjd')
// #ifdef MP-WEIXIN
Vue.prototype.StatusBar = e.statusBarHeight;
let custom = wx.getMenuButtonBoundingClientRect();
Vue.prototype.Custom = custom;
Vue.prototype.CustomBar = custom.bottom + custom.top - e.statusBarHeight;
Vue.prototype.windowHeight = e.safeArea.height
// #endif
Vue.mixin({
data() {
return {
StatusBar: Vue.prototype.StatusBar,
CustomBar: Vue.prototype.CustomBar,
windowHeight: Vue.prototype.windowHeight
};
},

methods: {
// 时分秒转换为秒
TIMEEVENT(e) {
var time = e;
var len = time.split(':')
if (len.length == 3) {
var hour = time.split(':')[0];
var min = time.split(':')[1];
var sec = time.split(':')[2];
return Number(hour * 3600) + Number(min * 60) + Number(sec);
}
if (len.length == 2) {
var min = time.split(':')[0];
var sec = time.split(':')[1];
return Number(min * 60) + Number(sec);
}
if (len.length == 1) {
var sec = time.split(':')[0];
return Number(sec);
}
},
// 目前使用页面为录音页面
SPEAKERSTYLE(index) {
let obj = {
color: '',
}
switch (index) {
case 1:
obj.color = '#60CBEC';
break;
case 2:
obj.color = '#EC8B47';
break;
case 3:
obj.color = '#4F861E';
break;
case 5:
obj.color = '#4980C8';
break;
case 6:
obj.color = '#60CBEC';
break;
case 7:
obj.color = '#EC8B47';
break;
case 8:
obj.color = '#4F861E';
break;
default:
obj.color = '#9F61C8';
break;
}
return obj
},
},

filters: {
// ASCII码转换 大写字母A是65 演讲人是从1开始所以num+64
toCapital(num) {
let str = ''
if (num) {
str = String.fromCharCode(num + 64)
}
return str
}
}
});
}
});

if (wx.canIUse('getUpdateManager')) {
const updateManager = wx.getUpdateManager()
updateManager.onCheckForUpdate(function(res) {
if (res.hasUpdate) {
updateManager.onUpdateReady(function() {
uni.showModal({
title: '更新提示',
cancelColor: "#999999",
content: '新版本已经准备好,是否重启应用?',
success: function(res) {
if (res.confirm) {
updateManager.applyUpdate()
}
}
})
})
updateManager.onUpdateFailed(function() {
uni.showModal({
title: '已经有新版本了哟~',
cancelColor: "#999999",
content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~'
})
})
}
})
} else {
uni.showModal({
title: '提示',
cancelColor: "#999999",
content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
})
}
const token = uni.getStorageSync("weapp_session_login_data")
if (typeof token.token != "string") {
return
}
this.$u.get("/user/getUser").then(data => {
uni.setStorageSync("weapp_session_userInfo_data", data)
})
this.$u.get("/user/getMenu").then(data => {
uni.setStorageSync("weapp_session_Menu_data", data)
})


wx.setInnerAudioOption({
obeyMuteSwitch: false
});
},
onShow(options) {
const token = uni.getStorageSync("weapp_session_login_data")
if (typeof token.token != "string") {
console.log("没有")
return
} else {
this.infoscoket()
}
},
onHide() {},
methods: {
infoscoket() {
let pushon = uni.getStorageSync('weapp_session_userInfo_data').loginName
uni.connectSocket({
url: 'wss://hfju.com/ws?uid=' + pushon + '_applets',
header: {
"content-type": "application/json",
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
}
});
uni.onSocketOpen(function(res) {
console.log('WebSocket连接已打开!');
});
uni.onSocketError(function(res) {
console.log('WebSocket连接打开失败,请检查!');
});
uni.onSocketMessage(function(res) {
console.log('收到服务器内容:' + res.data);
let cedata = JSON.stringify(res);
let data = JSON.parse(cedata);
let zdata = JSON.parse(data.data)
if (zdata.to == "recCmd") {
uni.$emit('update', {
msg: '页面更新'
})
return
}
uni.showModal({
title: '提示',
content: zdata.to + '的设备电量过低请检查!',
cancelText: "取消", // 取消按钮的文字
confirmText: "查看", // 确认按钮文字
success: function(res) {
if (res.confirm) {
console.log('用户点击确定');
uni.navigateTo({
url: `/pages/main/toviewtherecording/index?jump=` + "jump"
})

} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
});
},
Closewebsocke() {
uni.closeSocket();
uni.onSocketClose(function(res) {
console.log('WebSocket 已关闭!');
});
},
}
};
</script>

<style>
@import "./app.css";
</style>
<style lang="scss">
@import "uview-ui/index.scss";

/*每个页面公共css */
//图表样式等
.single {
width: 100%;
background: #FFFFFF;

.title {
width: 100%;
height: 90rpx;
border-bottom: 1rpx solid #E0E0E0;
display: flex;

.title1 {
flex: 2;
font-size: 30rpx;
font-weight: 600;
color: #333333;
line-height: 90rpx;
text-indent: 30rpx;
}

.title3 {
flex: 3;
height: 90rpx;
display: flex;
align-items: center;
justify-content: flex-end;

.title3-box {
display: flex;
align-items: center;
width: 25%;
justify-content: center;

.activecltab {
border-bottom: 2px solid #2671E2;
}
}
}

.title2 {
flex: 3;
height: 90rpx;
display: flex;
align-items: center;

.title2-che {
width: 178rpx;
height: 48rpx;
background: #FFFFFF;
border-radius: 6rpx;
border: 1px solid #E0E0E0;
line-height: 48rpx;
font-size: 28rpx;
font-weight: 400;
color: #666666;
text-indent: 12rpx;
margin-left: 35rpx;
position: relative;

.righttochoose {
width: 18rpx;
height: 24rpx;
position: absolute;
top: 12rpx;
right: 12rpx;
}
}
}
}

.swiper-box {
width: 97%;
margin: 0 auto;
}

.hejibox {
width: 100%;
height: 80rpx;
display: flex;

.heji {
width: 50%;
height: 100%;
font-size: 28rpx;
font-weight: 400;
color: #666666;
line-height: 80rpx;
text-indent: 30rpx;
}
}

.danwei {
width: 100%;
height: 40rpx;
font-size: 24rpx;
font-weight: 400;
color: #999999;
line-height: 40rpx;
text-indent: 30rpx;
}

.uchaserbox {
width: 95%;
height: 470rpx;
}

.jindu {
width: 100%;
height: 300rpx;

.jindu-box {
width: 100%;
padding-left: 30rpx;
padding-right: 30rpx;

.jindu-boxche {
width: 100%;
height: 46rpx;
display: flex;
align-items: center;
height: 50rpx;

.jindu-name {
width: 120rpx;
font-size: 28rpx;
color: #666666;
}

.jindu-zxl {
width: 120rpx;
font-size: 26rpx;
margin-left: 16rpx;
color: #666666;
text-align: center;
}
}
}
}
}

//时间切换的样式
.boxtittab {
width: 100;
height: 92rpx;
background: #FFFFFF;
border: 1px solid #E0E0E0;
display: flex;
align-items: center;

.tabbox {
flex: 1;
height: 100%;
text-align: center;
line-height: 92rpx;
color: #666666;
font-size: 28rpx;
display: flex;
justify-content: center;

.activecllasscet {
width: 96rpx;
border-bottom: 2px solid #2671E2;
}
}
}

//多个格子的样式
.boxzonglan {
width: 100%;
min-height: 496rpx;
background: #FFFFFF;
padding: 30rpx 30rpx 30rpx 30rpx;

.zonglantit {
font-size: 30rpx;
color: #333333;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
}

.zonglanbox {
width: 100%;
display: flex;
flex-wrap: wrap;
margin-top: 24rpx;

.grid {
width: 50%;
height: 128rpx;
border: 1px solid #E0E0E0;

.audonum {
color: #666666;
text-indent: 40rpx;
font-size: 26rpx;
margin-top: 20rpx;
}

.num {
color: #333333;
text-indent: 40rpx;
font-size: 32rpx;
font-weight: 600;
margin-top: 10rpx;
}
}
}
}
</style>

+ 2
- 0
audios.js
File diff suppressed because it is too large
View File


+ 28
- 0
components/gaoyia-parse/components/wxParseAudio.vue View File

@@ -0,0 +1,28 @@
<template>
<!-- '<audio/>' 组件不再维护,建议使用能力更强的 'uni.createInnerAudioContext' 接口 有时间再改-->
<!--增加audio标签支持-->
<audio
:id="node.attr.id"
:class="node.classStr"
:style="node.styleStr"
:src="node.attr.src"
:loop="node.attr.loop"
:poster="node.attr.poster"
:name="node.attr.name"
:author="node.attr.author"
controls></audio>
</template>
<script>
export default {
name: 'wxParseAudio',
props: {
node: {
type: Object,
default() {
return {};
},
},
},
};
</script>

+ 94
- 0
components/gaoyia-parse/components/wxParseImg.vue View File

@@ -0,0 +1,94 @@
<template>
<image
:mode="node.attr.mode"
:lazy-load="node.attr.lazyLoad"
:class="node.classStr"
:style="newStyleStr || node.styleStr"
:data-src="node.attr.src"
:src="node.attr.src"
@tap="wxParseImgTap"
@load="wxParseImgLoad"
/>
</template>
<script>
export default {
name: 'wxParseImg',
data() {
return {
newStyleStr: '',
preview: true
};
},
inject: ['parseWidth'],
mounted() {},
props: {
node: {
type: Object,
default() {
return {};
}
}
},
methods: {
wxParseImgTap(e) {
if (!this.preview) return;
const { src } = e.currentTarget.dataset;
if (!src) return;
let parent = this.$parent;
while (!parent.preview || typeof parent.preview !== 'function') {
// TODO 遍历获取父节点执行方法
parent = parent.$parent;
}
parent.preview(src, e);
},
// 图片视觉宽高计算函数区
wxParseImgLoad(e) {
const { src } = e.currentTarget.dataset;
if (!src) return;
let { width, height } = e.mp.detail;
const recal = this.wxAutoImageCal(width, height);
const { imageheight, imageWidth } = recal;
const { padding, mode } = this.node.attr;//删除padding
// const { mode } = this.node.attr;
const { styleStr } = this.node;
const imageHeightStyle = mode === 'widthFix' ? '' : `height: ${imageheight}px;`;
this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px; padding: 0 ${+padding}px;`;//删除padding
// this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px;`;
},
// 计算视觉优先的图片宽高
wxAutoImageCal(originalWidth, originalHeight) {
// 获取图片的原始长宽
const windowWidth = this.parseWidth.value;
const results = {};
if (originalWidth < 60 || originalHeight < 60) {
const { src } = this.node.attr;
let parent = this.$parent;
while (!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.removeImageUrl(src);
this.preview = false;
}
// 判断按照那种方式进行缩放
if (originalWidth > windowWidth) {
// 在图片width大于手机屏幕width时候
results.imageWidth = windowWidth;
results.imageheight = windowWidth * (originalHeight / originalWidth);
} else {
// 否则展示原来的数据
results.imageWidth = originalWidth;
results.imageheight = originalHeight;
}
return results;
}
}
};
</script>

+ 55
- 0
components/gaoyia-parse/components/wxParseTable.vue View File

@@ -0,0 +1,55 @@
<template>
<div class='tablebox'>
<rich-text :nodes="nodes" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
</div>
</template>
<script>
export default {
name: 'wxParseTable',
props: {
node: {
type: Object,
default() {
return {};
},
},
},
inject: ['parseSelect'],
data() {
return {
nodes:[]
};
},
mounted() {
this.nodes=this.loadNode([this.node]);
},
methods: {
loadNode(node) {
let obj = [];
for (let children of node) {
if (children.node=='element') {
let t = {
name:children.tag,
attrs: {
class: children.classStr,
// style: children.styleStr,
},
children: children.nodes?this.loadNode(children.nodes):[]
}
obj.push(t)
} else if(children.node=='text'){
obj.push({
type: 'text',
text: children.text
})
}
}
return obj
}
}
};
</script>
<style>
@import url("../parse.css");
</style>

+ 98
- 0
components/gaoyia-parse/components/wxParseTemplate0.vue View File

@@ -0,0 +1,98 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node"/>
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
// #ifdef APP-PLUS | H5
import wxParseTemplate from './wxParseTemplate0';
// #endif
// #ifdef MP
import wxParseTemplate from './wxParseTemplate1';
// #endif
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
// #ifdef APP-PLUS | H5
name: 'wxParseTemplate',
// #endif
// #ifdef MP
name: 'wxParseTemplate0',
// #endif
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;// TODO currentTarget才有dataset
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {// TODO 遍历获取父节点执行方法
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

+ 88
- 0
components/gaoyia-parse/components/wxParseTemplate1.vue View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate2';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate1',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

+ 88
- 0
components/gaoyia-parse/components/wxParseTemplate10.vue View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate11';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate10',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

+ 86
- 0
components/gaoyia-parse/components/wxParseTemplate11.vue View File

@@ -0,0 +1,86 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<rich-text :nodes="node" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<rich-text :nodes="node" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<rich-text :nodes="node" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<rich-text :nodes="node" :class="node.classStr" :style="'user-select:' + parseSelect"></rich-text>
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate11',
props: {
node: {},
},
components: {
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

+ 88
- 0
components/gaoyia-parse/components/wxParseTemplate2.vue View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate3';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate2',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

+ 88
- 0
components/gaoyia-parse/components/wxParseTemplate3.vue View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate4';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate3',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

+ 88
- 0
components/gaoyia-parse/components/wxParseTemplate4.vue View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate5';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate4',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

+ 88
- 0
components/gaoyia-parse/components/wxParseTemplate5.vue View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate6';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate5',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

+ 88
- 0
components/gaoyia-parse/components/wxParseTemplate6.vue View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate7';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate6',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

+ 88
- 0
components/gaoyia-parse/components/wxParseTemplate7.vue View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate8';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate7',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

+ 88
- 0
components/gaoyia-parse/components/wxParseTemplate8.vue View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate9';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate8',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

+ 88
- 0
components/gaoyia-parse/components/wxParseTemplate9.vue View File

@@ -0,0 +1,88 @@
<template>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<button v-if="node.tag == 'button'" type="default" size="mini" :class="node.classStr" :style="node.styleStr">
<wx-parse-template :node="node" />
</button>
<!--a类型-->
<view v-else-if="node.tag == 'a'" @click="wxParseATap(node.attr,$event)" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--li类型-->
<view v-else-if="node.tag == 'li'" :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
<!--table类型-->
<wx-parse-table v-else-if="node.tag == 'table'" :class="node.classStr" :style="node.styleStr" :node="node" />
<!--br类型-->
<!-- #ifndef H5 -->
<text v-else-if="node.tag == 'br'">\n</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<br v-else-if="node.tag == 'br'">
<!-- #endif -->
<!--video类型-->
<wx-parse-video :node="node" v-else-if="node.tag == 'video'"/>
<!--audio类型-->
<wx-parse-audio :node="node" v-else-if="node.tag == 'audio'"/>
<!--img类型-->
<wx-parse-img :node="node" v-else-if="node.tag == 'img'" :style="node.styleStr"/>
<!--其他标签-->
<view v-else :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text' ">{{node.text}}</block>
</template>
<script>
import wxParseTemplate from './wxParseTemplate10';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
import wxParseTable from './wxParseTable';
export default {
name: 'wxParseTemplate9',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
wxParseTable
},
methods: {
wxParseATap(attr,e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e, attr);
}
}
};
</script>

+ 15
- 0
components/gaoyia-parse/components/wxParseVideo.vue View File

@@ -0,0 +1,15 @@
<template>
<!--增加video标签支持,并循环添加-->
<view :class="node.classStr" :style="node.styleStr">
<video :class="node.classStr" :style="node.styleStr" class="video-video" :src="node.attr.src"></video>
</view>
</template>
<script>
export default {
name: 'wxParseVideo',
props: {
node: {},
},
};
</script>

+ 261
- 0
components/gaoyia-parse/libs/html2json.js View File

@@ -0,0 +1,261 @@
/**
* html2Json 改造来自: https://github.com/Jxck/html2json
*
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
import wxDiscode from './wxDiscode';
import HTMLParser from './htmlparser';
function makeMap(str) {
const obj = {};
const items = str.split(',');
for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
return obj;
}
// Block Elements - HTML 5
const block = makeMap('br,code,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video');
// Inline Elements - HTML 5
const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var');
// Elements that you can, intentionally, leave open
// (and which close themselves)
const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
function removeDOCTYPE(html) {
const isDocument = /<body.*>([^]*)<\/body>/.test(html);
return isDocument ? RegExp.$1 : html;
}
function trimHtml(html) {
return html
.replace(/<!--.*?-->/gi, '')
.replace(/\/\*.*?\*\//gi, '')
.replace(/[ ]+</gi, '<')
.replace(/<script[^]*<\/script>/gi, '')
.replace(/<style[^]*<\/style>/gi, '');
}
function getScreenInfo() {
const screen = {};
wx.getSystemInfo({
success: (res) => {
screen.width = res.windowWidth;
screen.height = res.windowHeight;
},
});
return screen;
}
function html2json(html, customHandler, imageProp, host) {
// 处理字符串
html = removeDOCTYPE(html);
html = trimHtml(html);
html = wxDiscode.strDiscode(html);
// 生成node节点
const bufArray = [];
const results = {
nodes: [],
imageUrls: [],
};
const screen = getScreenInfo();
function Node(tag) {
this.node = 'element';
this.tag = tag;
this.$screen = screen;
}
HTMLParser(html, {
start(tag, attrs, unary) {
// node for this element
const node = new Node(tag);
if (bufArray.length !== 0) {
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
}
if (block[tag]) {
node.tagType = 'block';
} else if (inline[tag]) {
node.tagType = 'inline';
} else if (closeSelf[tag]) {
node.tagType = 'closeSelf';
}
node.attr = attrs.reduce((pre, attr) => {
const { name } = attr;
let { value } = attr;
if (name === 'class') {
node.classStr = value;
}
// has multi attibutes
// make it array of attribute
if (name === 'style') {
node.styleStr = value;
}
if (value.match(/ /)) {
value = value.split(' ');
}
// if attr already exists
// merge it
if (pre[name]) {
if (Array.isArray(pre[name])) {
// already array, push to last
pre[name].push(value);
} else {
// single value, make it array
pre[name] = [pre[name], value];
}
} else {
// not exist, put it
pre[name] = value;
}
return pre;
}, {});
// 优化样式相关属性
if (node.classStr) {
node.classStr += ` ${node.tag}`;
} else {
node.classStr = node.tag;
}
if (node.tagType === 'inline') {
node.classStr += ' inline';
}
// 对img添加额外数据
if (node.tag === 'img') {
let imgUrl = node.attr.src;
imgUrl = wxDiscode.urlToHttpUrl(imgUrl, imageProp.domain);
Object.assign(node.attr, imageProp, {
src: imgUrl || '',
});
if (imgUrl) {
results.imageUrls.push(imgUrl);
}
}
// 处理a标签属性
if (node.tag === 'a') {
node.attr.href = node.attr.href || '';
}
// 处理font标签样式属性
if (node.tag === 'font') {
const fontSize = [
'x-small',
'small',
'medium',
'large',
'x-large',
'xx-large',
'-webkit-xxx-large',
];
const styleAttrs = {
color: 'color',
face: 'font-family',
size: 'font-size',
};
if (!node.styleStr) node.styleStr = '';
Object.keys(styleAttrs).forEach((key) => {
if (node.attr[key]) {
const value = key === 'size' ? fontSize[node.attr[key] - 1] : node.attr[key];
node.styleStr += `${styleAttrs[key]}: ${value};`;
}
});
}
// 临时记录source资源
if (node.tag === 'source') {
results.source = node.attr.src;
}
if (customHandler.start) {
customHandler.start(node, results);
}
if (unary) {
// if this tag doesn't have end tag
// like <img src="hoge.png"/>
// add to parents
const parent = bufArray[0] || results;
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
} else {
bufArray.unshift(node);
}
},
end(tag) {
// merge into parent tag
const node = bufArray.shift();
if (node.tag !== tag) {
console.error('invalid state: mismatch end tag');
}
// 当有缓存source资源时于于video补上src资源
if (node.tag === 'video' && results.source) {
node.attr.src = results.source;
delete results.source;
}
if (customHandler.end) {
customHandler.end(node, results);
}
if (bufArray.length === 0) {
results.nodes.push(node);
} else {
const parent = bufArray[0];
if (!parent.nodes) {
parent.nodes = [];
}
parent.nodes.push(node);
}
},
chars(text) {
if (!text.trim()) return;
const node = {
node: 'text',
text,
};
if (customHandler.chars) {
customHandler.chars(node, results);
}
if (bufArray.length === 0) {
results.nodes.push(node);
} else {
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
}
},
});
return results;
}
export default html2json;

+ 156
- 0
components/gaoyia-parse/libs/htmlparser.js View File

@@ -0,0 +1,156 @@
/**
*
* htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
// Regular Expressions for parsing tags and attributes
const startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z0-9_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
const endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
const attr = /([a-zA-Z0-9_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
function makeMap(str) {
const obj = {};
const items = str.split(',');
for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
return obj;
}
// Empty Elements - HTML 5
const empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr');
// Block Elements - HTML 5
const block = makeMap('address,code,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video');
// Inline Elements - HTML 5
const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var');
// Elements that you can, intentionally, leave open
// (and which close themselves)
const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
// Attributes that have their values filled in disabled="disabled"
const fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected');
function HTMLParser(html, handler) {
let index;
let chars;
let match;
let last = html;
const stack = [];
stack.last = () => stack[stack.length - 1];
function parseEndTag(tag, tagName) {
// If no tag name is provided, clean shop
let pos;
if (!tagName) {
pos = 0;
} else {
// Find the closest opened tag of the same type
tagName = tagName.toLowerCase();
for (pos = stack.length - 1; pos >= 0; pos -= 1) {
if (stack[pos] === tagName) break;
}
}
if (pos >= 0) {
// Close all the open elements, up the stack
for (let i = stack.length - 1; i >= pos; i -= 1) {
if (handler.end) handler.end(stack[i]);
}
// Remove the open elements from the stack
stack.length = pos;
}
}
function parseStartTag(tag, tagName, rest, unary) {
tagName = tagName.toLowerCase();
if (block[tagName]) {
while (stack.last() && inline[stack.last()]) {
parseEndTag('', stack.last());
}
}
if (closeSelf[tagName] && stack.last() === tagName) {
parseEndTag('', tagName);
}
unary = empty[tagName] || !!unary;
if (!unary) stack.push(tagName);
if (handler.start) {
const attrs = [];
rest.replace(attr, function genAttr(matches, name) {
const value = arguments[2] || arguments[3] || arguments[4] || (fillAttrs[name] ? name : '');
attrs.push({
name,
value,
escaped: value.replace(/(^|[^\\])"/g, '$1\\"'), // "
});
});
if (handler.start) {
handler.start(tagName, attrs, unary);
}
}
}
while (html) {
chars = true;
if (html.indexOf('</') === 0) {
match = html.match(endTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(endTag, parseEndTag);
chars = false;
}
// start tag
} else if (html.indexOf('<') === 0) {
match = html.match(startTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(startTag, parseStartTag);
chars = false;
}
}
if (chars) {
index = html.indexOf('<');
let text = '';
while (index === 0) {
text += '<';
html = html.substring(1);
index = html.indexOf('<');
}
text += index < 0 ? html : html.substring(0, index);
html = index < 0 ? '' : html.substring(index);
if (handler.chars) handler.chars(text);
}
if (html === last) throw new Error(`Parse Error: ${html}`);
last = html;
}
// Clean up any remaining tags
parseEndTag();
}
export default HTMLParser;

+ 209
- 0
components/gaoyia-parse/libs/wxDiscode.js View File

@@ -0,0 +1,209 @@
// HTML 支持的数学符号
function strNumDiscode(str) {
str = str.replace(/&forall;|&#8704;|&#x2200;/g, '∀');
str = str.replace(/&part;|&#8706;|&#x2202;/g, '∂');
str = str.replace(/&exist;|&#8707;|&#x2203;/g, '∃');
str = str.replace(/&empty;|&#8709;|&#x2205;/g, '∅');
str = str.replace(/&nabla;|&#8711;|&#x2207;/g, '∇');
str = str.replace(/&isin;|&#8712;|&#x2208;/g, '∈');
str = str.replace(/&notin;|&#8713;|&#x2209;/g, '∉');
str = str.replace(/&ni;|&#8715;|&#x220b;/g, '∋');
str = str.replace(/&prod;|&#8719;|&#x220f;/g, '∏');
str = str.replace(/&sum;|&#8721;|&#x2211;/g, '∑');
str = str.replace(/&minus;|&#8722;|&#x2212;/g, '−');
str = str.replace(/&lowast;|&#8727;|&#x2217;/g, '∗');
str = str.replace(/&radic;|&#8730;|&#x221a;/g, '√');
str = str.replace(/&prop;|&#8733;|&#x221d;/g, '∝');
str = str.replace(/&infin;|&#8734;|&#x221e;/g, '∞');
str = str.replace(/&ang;|&#8736;|&#x2220;/g, '∠');
str = str.replace(/&and;|&#8743;|&#x2227;/g, '∧');
str = str.replace(/&or;|&#8744;|&#x2228;/g, '∨');
str = str.replace(/&cap;|&#8745;|&#x2229;/g, '∩');
str = str.replace(/&cup;|&#8746;|&#x222a;/g, '∪');
str = str.replace(/&int;|&#8747;|&#x222b;/g, '∫');
str = str.replace(/&there4;|&#8756;|&#x2234;/g, '∴');
str = str.replace(/&sim;|&#8764;|&#x223c;/g, '∼');
str = str.replace(/&cong;|&#8773;|&#x2245;/g, '≅');
str = str.replace(/&asymp;|&#8776;|&#x2248;/g, '≈');
str = str.replace(/&ne;|&#8800;|&#x2260;/g, '≠');
str = str.replace(/&le;|&#8804;|&#x2264;/g, '≤');
str = str.replace(/&ge;|&#8805;|&#x2265;/g, '≥');
str = str.replace(/&sub;|&#8834;|&#x2282;/g, '⊂');
str = str.replace(/&sup;|&#8835;|&#x2283;/g, '⊃');
str = str.replace(/&nsub;|&#8836;|&#x2284;/g, '⊄');
str = str.replace(/&sube;|&#8838;|&#x2286;/g, '⊆');
str = str.replace(/&supe;|&#8839;|&#x2287;/g, '⊇');
str = str.replace(/&oplus;|&#8853;|&#x2295;/g, '⊕');
str = str.replace(/&otimes;|&#8855;|&#x2297;/g, '⊗');
str = str.replace(/&perp;|&#8869;|&#x22a5;/g, '⊥');
str = str.replace(/&sdot;|&#8901;|&#x22c5;/g, '⋅');
return str;
}
// HTML 支持的希腊字母
function strGreeceDiscode(str) {
str = str.replace(/&Alpha;|&#913;|&#x391;/g, 'Α');
str = str.replace(/&Beta;|&#914;|&#x392;/g, 'Β');
str = str.replace(/&Gamma;|&#915;|&#x393;/g, 'Γ');
str = str.replace(/&Delta;|&#916;|&#x394;/g, 'Δ');
str = str.replace(/&Epsilon;|&#917;|&#x395;/g, 'Ε');
str = str.replace(/&Zeta;|&#918;|&#x396;/g, 'Ζ');
str = str.replace(/&Eta;|&#919;|&#x397;/g, 'Η');
str = str.replace(/&Theta;|&#920;|&#x398;/g, 'Θ');
str = str.replace(/&Iota;|&#921;|&#x399;/g, 'Ι');
str = str.replace(/&Kappa;|&#922;|&#x39a;/g, 'Κ');
str = str.replace(/&Lambda;|&#923;|&#x39b;/g, 'Λ');
str = str.replace(/&Mu;|&#924;|&#x39c;/g, 'Μ');
str = str.replace(/&Nu;|&#925;|&#x39d;/g, 'Ν');
str = str.replace(/&Xi;|&#925;|&#x39d;/g, 'Ν');
str = str.replace(/&Omicron;|&#927;|&#x39f;/g, 'Ο');
str = str.replace(/&Pi;|&#928;|&#x3a0;/g, 'Π');
str = str.replace(/&Rho;|&#929;|&#x3a1;/g, 'Ρ');
str = str.replace(/&Sigma;|&#931;|&#x3a3;/g, 'Σ');
str = str.replace(/&Tau;|&#932;|&#x3a4;/g, 'Τ');
str = str.replace(/&Upsilon;|&#933;|&#x3a5;/g, 'Υ');
str = str.replace(/&Phi;|&#934;|&#x3a6;/g, 'Φ');
str = str.replace(/&Chi;|&#935;|&#x3a7;/g, 'Χ');
str = str.replace(/&Psi;|&#936;|&#x3a8;/g, 'Ψ');
str = str.replace(/&Omega;|&#937;|&#x3a9;/g, 'Ω');
str = str.replace(/&alpha;|&#945;|&#x3b1;/g, 'α');
str = str.replace(/&beta;|&#946;|&#x3b2;/g, 'β');
str = str.replace(/&gamma;|&#947;|&#x3b3;/g, 'γ');
str = str.replace(/&delta;|&#948;|&#x3b4;/g, 'δ');
str = str.replace(/&epsilon;|&#949;|&#x3b5;/g, 'ε');
str = str.replace(/&zeta;|&#950;|&#x3b6;/g, 'ζ');
str = str.replace(/&eta;|&#951;|&#x3b7;/g, 'η');
str = str.replace(/&theta;|&#952;|&#x3b8;/g, 'θ');
str = str.replace(/&iota;|&#953;|&#x3b9;/g, 'ι');
str = str.replace(/&kappa;|&#954;|&#x3ba;/g, 'κ');
str = str.replace(/&lambda;|&#955;|&#x3bb;/g, 'λ');
str = str.replace(/&mu;|&#956;|&#x3bc;/g, 'μ');
str = str.replace(/&nu;|&#957;|&#x3bd;/g, 'ν');
str = str.replace(/&xi;|&#958;|&#x3be;/g, 'ξ');
str = str.replace(/&omicron;|&#959;|&#x3bf;/g, 'ο');
str = str.replace(/&pi;|&#960;|&#x3c0;/g, 'π');
str = str.replace(/&rho;|&#961;|&#x3c1;/g, 'ρ');
str = str.replace(/&sigmaf;|&#962;|&#x3c2;/g, 'ς');
str = str.replace(/&sigma;|&#963;|&#x3c3;/g, 'σ');
str = str.replace(/&tau;|&#964;|&#x3c4;/g, 'τ');
str = str.replace(/&upsilon;|&#965;|&#x3c5;/g, 'υ');
str = str.replace(/&phi;|&#966;|&#x3c6;/g, 'φ');
str = str.replace(/&chi;|&#967;|&#x3c7;/g, 'χ');
str = str.replace(/&psi;|&#968;|&#x3c8;/g, 'ψ');
str = str.replace(/&omega;|&#969;|&#x3c9;/g, 'ω');
str = str.replace(/&thetasym;|&#977;|&#x3d1;/g, 'ϑ');
str = str.replace(/&upsih;|&#978;|&#x3d2;/g, 'ϒ');
str = str.replace(/&piv;|&#982;|&#x3d6;/g, 'ϖ');
str = str.replace(/&middot;|&#183;|&#xb7;/g, '·');
return str;
}
function strcharacterDiscode(str) {
// 加入常用解析
// str = str.replace(/&nbsp;|&#32;|&#x20;/g, "&nbsp;");
// str = str.replace(/&ensp;|&#8194;|&#x2002;/g, '&ensp;');
// str = str.replace(/&#12288;|&#x3000;/g, '<span class=\'spaceshow\'> </span>');
// str = str.replace(/&emsp;|&#8195;|&#x2003;/g, '&emsp;');
// str = str.replace(/&quot;|&#34;|&#x22;/g, "\"");
// str = str.replace(/&apos;|&#39;|&#x27;/g, "&apos;");
// str = str.replace(/&acute;|&#180;|&#xB4;/g, "´");
// str = str.replace(/&times;|&#215;|&#xD7;/g, "×");
// str = str.replace(/&divide;|&#247;|&#xF7;/g, "÷");
// str = str.replace(/&amp;|&#38;|&#x26;/g, '&amp;');
// str = str.replace(/&lt;|&#60;|&#x3c;/g, '&lt;');
// str = str.replace(/&gt;|&#62;|&#x3e;/g, '&gt;');
str = str.replace(/&nbsp;|&#32;|&#x20;/g, "<span class='spaceshow'> </span>");
str = str.replace(/&ensp;|&#8194;|&#x2002;/g, '<span class=\'spaceshow\'> </span>');
str = str.replace(/&#12288;|&#x3000;/g, '<span class=\'spaceshow\'> </span>');
str = str.replace(/&emsp;|&#8195;|&#x2003;/g, '<span class=\'spaceshow\'> </span>');
str = str.replace(/&quot;|&#34;|&#x22;/g, "\"");
str = str.replace(/&quot;|&#39;|&#x27;/g, "'");
str = str.replace(/&acute;|&#180;|&#xB4;/g, "´");
str = str.replace(/&times;|&#215;|&#xD7;/g, "×");
str = str.replace(/&divide;|&#247;|&#xF7;/g, "÷");
str = str.replace(/&amp;|&#38;|&#x26;/g, '&');
str = str.replace(/&lt;|&#60;|&#x3c;/g, '<');
str = str.replace(/&gt;|&#62;|&#x3e;/g, '>');
return str;
}
// HTML 支持的其他实体
function strOtherDiscode(str) {
str = str.replace(/&OElig;|&#338;|&#x152;/g, 'Œ');
str = str.replace(/&oelig;|&#339;|&#x153;/g, 'œ');
str = str.replace(/&Scaron;|&#352;|&#x160;/g, 'Š');
str = str.replace(/&scaron;|&#353;|&#x161;/g, 'š');
str = str.replace(/&Yuml;|&#376;|&#x178;/g, 'Ÿ');
str = str.replace(/&fnof;|&#402;|&#x192;/g, 'ƒ');
str = str.replace(/&circ;|&#710;|&#x2c6;/g, 'ˆ');
str = str.replace(/&tilde;|&#732;|&#x2dc;/g, '˜');
str = str.replace(/&thinsp;|$#8201;|&#x2009;/g, '<span class=\'spaceshow\'> </span>');
str = str.replace(/&zwnj;|&#8204;|&#x200C;/g, '<span class=\'spaceshow\'>‌</span>');
str = str.replace(/&zwj;|$#8205;|&#x200D;/g, '<span class=\'spaceshow\'>‍</span>');
str = str.replace(/&lrm;|$#8206;|&#x200E;/g, '<span class=\'spaceshow\'>‎</span>');
str = str.replace(/&rlm;|&#8207;|&#x200F;/g, '<span class=\'spaceshow\'>‏</span>');
str = str.replace(/&ndash;|&#8211;|&#x2013;/g, '–');
str = str.replace(/&mdash;|&#8212;|&#x2014;/g, '—');
str = str.replace(/&lsquo;|&#8216;|&#x2018;/g, '‘');
str = str.replace(/&rsquo;|&#8217;|&#x2019;/g, '’');
str = str.replace(/&sbquo;|&#8218;|&#x201a;/g, '‚');
str = str.replace(/&ldquo;|&#8220;|&#x201c;/g, '“');
str = str.replace(/&rdquo;|&#8221;|&#x201d;/g, '”');
str = str.replace(/&bdquo;|&#8222;|&#x201e;/g, '„');
str = str.replace(/&dagger;|&#8224;|&#x2020;/g, '†');
str = str.replace(/&Dagger;|&#8225;|&#x2021;/g, '‡');
str = str.replace(/&bull;|&#8226;|&#x2022;/g, '•');
str = str.replace(/&hellip;|&#8230;|&#x2026;/g, '…');
str = str.replace(/&permil;|&#8240;|&#x2030;/g, '‰');
str = str.replace(/&prime;|&#8242;|&#x2032;/g, '′');
str = str.replace(/&Prime;|&#8243;|&#x2033;/g, '″');
str = str.replace(/&lsaquo;|&#8249;|&#x2039;/g, '‹');
str = str.replace(/&rsaquo;|&#8250;|&#x203a;/g, '›');
str = str.replace(/&oline;|&#8254;|&#x203e;/g, '‾');
str = str.replace(/&euro;|&#8364;|&#x20ac;/g, '€');
str = str.replace(/&trade;|&#8482;|&#x2122;/g, '™');
str = str.replace(/&larr;|&#8592;|&#x2190;/g, '←');
str = str.replace(/&uarr;|&#8593;|&#x2191;/g, '↑');
str = str.replace(/&rarr;|&#8594;|&#x2192;/g, '→');
str = str.replace(/&darr;|&#8595;|&#x2193;/g, '↓');
str = str.replace(/&harr;|&#8596;|&#x2194;/g, '↔');
str = str.replace(/&crarr;|&#8629;|&#x21b5;/g, '↵');
str = str.replace(/&lceil;|&#8968;|&#x2308;/g, '⌈');
str = str.replace(/&rceil;|&#8969;|&#x2309;/g, '⌉');
str = str.replace(/&lfloor;|&#8970;|&#x230a;/g, '⌊');
str = str.replace(/&rfloor;|&#8971;|&#x230b;/g, '⌋');
str = str.replace(/&loz;|&#9674;|&#x25ca;/g, '◊');
str = str.replace(/&spades;|&#9824;|&#x2660;/g, '♠');
str = str.replace(/&clubs;|&#9827;|&#x2663;/g, '♣');
str = str.replace(/&hearts;|&#9829;|&#x2665;/g, '♥');
str = str.replace(/&diams;|&#9830;|&#x2666;/g, '♦');
return str;
}
function strDiscode(str) {
str = strNumDiscode(str);
str = strGreeceDiscode(str);
str = strcharacterDiscode(str);
str = strOtherDiscode(str);
return str;
}
function urlToHttpUrl(url, domain) {
if (/^\/\//.test(url)) {
return `https:${url}`;
} else if (/^\//.test(url)) {
return `https://${domain}${url}`;
}
return url;
}
export default {
strDiscode,
urlToHttpUrl,
};

+ 258
- 0
components/gaoyia-parse/parse.css View File

@@ -0,0 +1,258 @@
/**
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
/**
* 请在全局下引入该文件,@import '/static/wxParse.css';
*/
.wxParse {
user-select:none;
width: 100%;
font-family: Helvetica, "PingFangSC", 'Microsoft Yahei', '微软雅黑', Arial, sans-serif;
color: #333;
line-height: 1.5;
font-size: 1em;
text-align:justify;/* //左右两端对齐 */
}
.wxParse view ,.wxParse uni-view{
word-break: break-word;
}
.wxParse .p {
padding-bottom: 0.5em;
clear: both;
/* letter-spacing: 0;//字间距 */
}
.wxParse .inline {
display: inline;
margin: 0;
padding: 0;
}

.wxParse .div {
margin: 0;
padding: 0;
display: block;
}

.wxParse .h1{
font-size: 2em;
line-height: 1.2em;
margin: 0.67em 0;
}
.wxParse .h2{
font-size: 1.5em;
margin: 0.83em 0;
}
.wxParse .h3{
font-size: 1.17em;
margin: 1em 0;
}
.wxParse .h4{
margin: 1.33em 0;
}
.wxParse .h5{
font-size: 0.83em;
margin: 1.67em 0;
}
.wxParse .h6{
font-size: 0.83em;
margin: 1.67em 0;
}

.wxParse .h1,
.wxParse .h2,
.wxParse .h3,
.wxParse .h4,
.wxParse .h5,
.wxParse .h6,
.wxParse .b,
.wxParse .strong{
font-weight: bolder;
}

.wxParse .i,
.wxParse .cite,
.wxParse .em,
.wxParse .var,
.wxParse .address {
font-style: italic;
}
.wxParse .spaceshow{
white-space: pre;
}
.wxParse .pre,
.wxParse .tt,
.wxParse .code,
.wxParse .kbd,
.wxParse .samp {
font-family: monospace;
}
.wxParse .pre {
overflow: auto;
background: #f5f5f5;
padding: 16upx;
white-space: pre;
margin: 1em 0upx;
font-size: 24upx;
}
.wxParse .code {
overflow: auto;
padding: 16upx;
white-space: pre;
margin: 1em 0upx;
background: #f5f5f5;
font-size: 24upx;
}

.wxParse .big {
font-size: 1.17em;
}

.wxParse .small,
.wxParse .sub,
.wxParse .sup {
font-size: 0.83em;
}

.wxParse .sub {
vertical-align: sub;
}
.wxParse .sup {
vertical-align: super;
}

.wxParse .s,
.wxParse .strike,
.wxParse .del {
text-decoration: line-through;
}

.wxParse .strong,
.wxParse .text,
.wxParse .span,
.wxParse .s {
display: inline;
}

.wxParse .a {
color: deepskyblue;
}

.wxParse .video {
text-align: center;
margin: 22upx 0;
}

.wxParse .video-video {
width: 100%;
}
.wxParse .uni-image{
max-width: 100%;
}
.wxParse .img {
display: block;
max-width: 100%;
margin-bottom: 0em;/* //与p标签底部padding同时修改 */
overflow: hidden;
}

.wxParse .blockquote {
margin: 10upx 0;
padding: 22upx 0 22upx 22upx;
font-family: Courier, Calibri, "宋体";
background: #f5f5f5;
border-left: 6upx solid #dbdbdb;
}
.wxParse .blockquote .p {
margin: 0;
}
.wxParse .ul, .wxParse .ol {
display: block;
margin: 1em 0;
padding-left: 2em;
}
.wxParse .ol {
list-style-type: disc;
}
.wxParse .ol {
list-style-type: decimal;
}
.wxParse .ol>weixin-parse-template,.wxParse .ul>weixin-parse-template {
display: list-item;
align-items: baseline;
text-align: match-parent;
}

.wxParse .ol>.li,.wxParse .ul>.li {
display: list-item;
align-items: baseline;
text-align: match-parent;
}
.wxParse .ul .ul, .wxParse .ol .ul {
list-style-type: circle;
}
.wxParse .ol .ol .ul, .wxParse .ol .ul .ul, .wxParse .ul .ol .ul, .wxParse .ul .ul .ul {
list-style-type: square;
}

.wxParse .u {
text-decoration: underline;
}
.wxParse .hide {
display: none;
}
.wxParse .del {
display: inline;
}
.wxParse .figure {
overflow: hidden;
}
.wxParse .tablebox{
overflow: auto;
background-color: #f5f5f5;
background: #f5f5f5;
font-size: 13px;
padding: 8px;
}
.wxParse .table .table,.wxParse .table{
border-collapse:collapse;
box-sizing: border-box;
/* 内边框 */
/* width: 100%; */
overflow: auto;
white-space: pre;
}
.wxParse .tbody{
border-collapse:collapse;
box-sizing: border-box;
/* 内边框 */
border: 1px solid #dadada;
}
.wxParse .table .thead, .wxParse .table .tfoot, .wxParse .table .th{
border-collapse:collapse;
box-sizing: border-box;
background: #ececec;
font-weight: 40;
}
.wxParse .table .tr {
border-collapse:collapse;
box-sizing: border-box;
/* border: 2px solid #F0AD4E; */
overflow:auto;
}
.wxParse .table .th,
.wxParse .table .td{
border-collapse:collapse;
box-sizing: border-box;
border: 2upx solid #dadada;
overflow:auto;
}
.wxParse .audio, .wxParse .uni-audio-default{
display: block;
}

+ 228
- 0
components/gaoyia-parse/parse.vue View File

@@ -0,0 +1,228 @@
<!--**
* forked from:https://github.com/F-loat/mpvue-wxParse
*
* github地址: https://github.com/dcloudio/uParse
*
* for: uni-app框架下 富文本解析
*
* 优化 by gaoyia@qq.com https://github.com/gaoyia/parse
*/-->

<template>
<!--基础元素-->
<div class="wxParse" :class="className" :style="'user-select:' + userSelect">
<block v-for="(node, index) of nodes" :key="index" v-if="!loading">
<wxParseTemplate :node="node" />
</block>
</div>
</template>

<script>
import HtmlToJson from './libs/html2json';
import wxParseTemplate from './components/wxParseTemplate0';

export default {
name: 'wxParse',
props: {
// user-select:none;
userSelect: {
type: String,
default: 'text' //none |text| all | element
},
imgOptions: {
type: [Object, Boolean],
default: function() {
return {
loop: false,
indicator: 'number',
longPressActions: false
// longPressActions: {
// itemList: ['发送给朋友', '保存图片', '收藏'],
// success: function (res) {
// console.log('选中了第' + (res.tapIndex + 1) + '个按钮');
// },
// fail: function (res) {
// console.log(res.errMsg);
// }
// }
// }
}
}
},
loading: {
type: Boolean,
default: false
},
className: {
type: String,
default: ''
},
content: {
type: String,
default: ''
},
noData: {
type: String,
default: '<div style="color: red;">数据不能为空</div>'
},
startHandler: {
type: Function,
default () {
return node => {
node.attr.class = null;
node.attr.style = null;
};
}
},
endHandler: {
type: Function,
default: null
},
charsHandler: {
type: Function,
default: null
},
imageProp: {
type: Object,
default () {
return {
mode: 'aspectFit',
padding: 0,
lazyLoad: false,
domain: ''
};
}
}
},
components: {
wxParseTemplate
},
data() {
return {
nodes: {},
imageUrls: [],
wxParseWidth: {
value: 0
}
};
},
computed: {},
mounted() {
this.setHtml()
},
methods: {
setHtml() {
this.getWidth().then((data) => {
this.wxParseWidth.value = data;
})
let {
content,
noData,
imageProp,
startHandler,
endHandler,
charsHandler
} = this;
let parseData = content || noData;
let customHandler = {
start: startHandler,
end: endHandler,
chars: charsHandler
};
let results = HtmlToJson(parseData, customHandler, imageProp, this);

this.imageUrls = results.imageUrls;
// this.nodes = results.nodes;
this.nodes = [];
results.nodes.forEach((item) => {
setTimeout(() => {
this.nodes.push(item)
}, 0);
})
},
getWidth() {
return new Promise((res, rej) => {
// #ifndef MP-ALIPAY || MP-BAIDU
uni.createSelectorQuery()
.in(this)
.select('.wxParse')
.fields({
size: true,
scrollOffset: true
},
data => {
res(data.width);
}
).exec();
// #endif
// #ifdef MP-BAIDU
const query = swan.createSelectorQuery();
query.select('.wxParse').boundingClientRect();
query.exec(obj => {
const rect = obj[0]
if (rect) {
res(rect.width);
}
});
// #endif
// #ifdef MP-ALIPAY
my.createSelectorQuery()
.select('.wxParse')
.boundingClientRect().exec((ret) => {
res(ret[0].width);
});
// #endif
});
},
navigate(href, $event, attr) {
console.log(href, attr);
this.$emit('navigate', href, $event);
},
preview(src, $event) {
if (!this.imageUrls.length || typeof this.imgOptions === 'boolean') {
} else {
uni.previewImage({
current: src,
urls: this.imageUrls,
loop: this.imgOptions.loop,
indicator: this.imgOptions.indicator,
longPressActions: this.imgOptions.longPressActions
});
}
this.$emit('preview', src, $event);
},
removeImageUrl(src) {
const {
imageUrls
} = this;
imageUrls.splice(imageUrls.indexOf(src), 1);
}
},
// 父组件中提供
provide() {
return {
parseWidth: this.wxParseWidth,
parseSelect: this.userSelect
// 提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
};
},
watch: {
content(){
this.setHtml()
}
// content: {
// handler: function(newVal, oldVal) {
// if (newVal !== oldVal) {
//
// }
// },
// deep: true
// }
}
};
</script>

+ 75
- 0
components/html2canvas/html2canvas.vue View File

@@ -0,0 +1,75 @@
<template>
<view>
<view class="html2canvas" :prop="domId" :change:prop="html2canvas.create">
<slot></slot>
</view>
</view>
</template>

<script>
import { base64ToPath } from '@/static/libs/image-tools.js';
export default {
name: 'html2canvas',
props: {
domId: {
type: String,
required: true
}
},
methods: {
async renderFinish(base64) {
try{
const imgPath = await base64ToPath(base64, '.jpeg');
this.$emit('renderFinish', imgPath);
}catch(e){
//TODO handle the exception
console.log('html2canvas error', e)
}
},
showLoading() {
uni.showToast({
title: "正在生成海报",
icon: "none",
mask: true,
duration: 100000
})
},
hideLoading() {
uni.hideToast();
}
}
}
</script>

<script module="html2canvas" lang="renderjs">
import html2canvas from 'html2canvas';
export default {
methods: {
async create(domId) {
try {
this.$ownerInstance.callMethod('showLoading', true);
const timeout = setTimeout(async ()=> {
const shareContent = document.querySelector(domId);
const canvas = await html2canvas(shareContent,{
width: shareContent.offsetWidth,//设置canvas尺寸与所截图尺寸相同,防止白边
height: shareContent.offsetHeight,//防止白边
logging: true,
useCORS: true
});
const base64 = canvas.toDataURL('image/jpeg', 1);
this.$ownerInstance.callMethod('renderFinish', base64);
this.$ownerInstance.callMethod('hideLoading', true);
clearTimeout(timeout);
}, 500);
} catch(error){
console.log(error)
}
}
}
}
</script>


<style lang="scss">

</style>

+ 462
- 0
components/long_audio/long_audio.vue View File

@@ -0,0 +1,462 @@
<template>
<view>
<!-- 播放块 -->
<view class="bottomhead">
<view class="audio-play" @tap="changePlayState">
<image class="image" mode="widthFix"
:src="audioPlay ? 'https://qufang.oss-cn-beijing.aliyuncs.com/upload/icon/xcx/jjycrm/pause.png' : 'https://qufang.oss-cn-beijing.aliyuncs.com/upload/icon/xcx/jjycrm/play.png'">
</image>
</view>
<view class="audio-slider">
<view class="audio-time">
<text>{{currentTimeStr}}</text>
</view>
<slider class="slider" min="0" :max="sliderMax" @change="sliderChangeComplate" block-size="14"
:value="sliderValue" activeColor="blue"></slider>
<view class="audio-time">
<text>{{timeStr}}</text>
</view>
</view>
</view>
</view>
</template>
<script>
var util = require("@/utils/util.js");
var config = require("@/config");
export default {
name: "long_audio",
data() {
return {
audioPlay: false, //当前的播放状态控制
sliderValue: 0, //进度条最小值
sliderMax: 0, //进度条最大值
innerAudioContext:null, //播放实例
currentTimeStr: "00:00", //当前进度的时间
timeStr: "00:00", //总的时间
recordPath: "",
luyinList: [], //录音文件
newluyinList: [],
dialogList: [], //录音识别列表
csdFileindex: 0,
date: "", //年月日
scrollId: "",
playNow: 0,
alltimeStr: "00:00:00",
};
},
props:{
customerId:'',
infos:null,
roleindex:0
},
mounted() {
this.roleindex = 0;
this.innerAudioContext = uni.createInnerAudioContext();
this.innerAudioContext.autoplay = false;
this.innerAudioContext.title = '音频';
this.onPlay()
this.onPause()
this.onCanplay()
this.onEnded()
this.onSeeking()
this.onSeeked()
this.TimeUpdate()
this.init(this.infos)
},
destroyed() {
//暂停
this.innerAudioContext.pause()
// 销毁
// this.innerAudioContext.destroy();
},
methods: {
onPlay() {
this.innerAudioContext.onPlay(() => {
// 播放监听
console.log('播放!');
this.audioPlay = true;
wx.enableAlertBeforeUnload({
message: "是否确认退出详情页面?",
success: function(res) {
console.log("方法注册成功:", res);
},
fail: function(errMsg) {
console.log("方法注册失败:", errMsg);
},
});
});
},
onPause() {
this.innerAudioContext.onPause(() => {
wx.disableAlertBeforeUnload({
success: function(res) {
console.log(res)
},
fail: function(e) {
console.log(e)
}
});
// 暂停监听
console.log('暂停播放!');
this.audioPlay = false
});
},
onCanplay() {
this.innerAudioContext.onCanplay((callback) => {
console.log("缓冲回调", this.innerAudioContext.duration);
})
},
onEnded() {
this.innerAudioContext.onEnded(() => {
// 结束播放监听
console.log('播放结束!');
this.audioPlay = false;
});
},
onSeeking() {
this.innerAudioContext.onSeeking((res) => {
console.log("进行跳转", res);
})
},
onSeeked() {
this.innerAudioContext.onSeeked((res) => {
console.log("结束跳转", res);
this.$forceUpdate()
});
},
TimeUpdate() {
this.innerAudioContext.onTimeUpdate(() => {
// var pages = getCurrentPages();
// if(pages[pages.length-1].route!="pages/mine/details2"){
// this.innerAudioContext.destroy();
// }
const {
currentTime,
duration
} = this.innerAudioContext;
console.log(currentTime, 'TimeUpdate, currentTime')
this.playNow = parseInt(currentTime * 1000)
uni.$emit("playNows", this.playNow)
console.log(this.playNow)
if (this.dialogList.length == 0) {
return
} else {
const message = this.dialogList[0].message;
for (let i = 0; i < message.length; i++) {
if (Number(message[i].bg) < this.playNow && Number(message[i].ed) > this.playNow) {
this.scrollId = "dialog" + this.csdFileindex + "text" + message[i].bg;
uni.$emit("scrollIds", this.scrollId)
break;
}
}
}
const currTimeStr = this.formatTime(currentTime);
this.sliderValue = parseInt(currentTime);
// 变动的时间
this.currentTimeStr = currTimeStr;
//进度条最大值
this.sliderMax = this.luyinList[this.csdFileindex].recordDuration;
this.$forceUpdate()
});
},
//分角色标记刷新
fenjiaoseunfo() {
var bgcd = this.sliderValue * 1000;
this.newluyinList = [];
this.dialogList = [];
uni.request({
url: config.service.getCorpusAnal + '?corpusId=' + this.luyinList[this.csdFileindex].id +
"&bg=" + bgcd + "&speaker=" + this.roleindex + '&num=50', //仅为示例,并非真实接口地址。
method: "GET",
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
success: (data) => {
this.tablist = [];
let jsonInfo = JSON.parse(data.data.data.audioContent);
for (var i = 0; i <= data.data.data.speakerNum; i++) {
if (i === 0) {
this.tablist.push({
name: '全部'
})
} else {
this.tablist.push({
name: String.fromCharCode(i + 64)
})
}
}

if (data.data.data.speaker == null) {
this.roleindexbiaoji = 0;
this.dshfkjsdkksodofydwfkhwdfkjh = 0;
} else {
this.tablist[data.data.data.speaker].name = this.tablist[data.data.data.speaker]
.name + "顾问";
this.roleindexbiaoji = data.data.data.speaker - 1;
this.dshfkjsdkksodofydwfkhwdfkjh = data.data.data.speaker - 1;
}
if (this.roleindex > this.tablist.length - 1) {
this.roleindex = this.tablist.length - 1
this.fenjiaoseunfo()
}


this.speaker = data.data.data.speaker;
//上拉标记点
this.textindex = data.data.data.index;
//下拉标记点
this.toptextindex = data.data.data.index;

jsonInfo.forEach(item => {
item.message = JSON.parse(item.onebest)
item.backindex = this.csdFileindex
})
console.log(jsonInfo)

this.newluyinList = jsonInfo;
if (this.textindex == null) {
return
} else {
this.dialogList.push(jsonInfo[this.textindex]);
}
}
})
},
// 获取转义后的对话结果
getCorpusAnalysis(info) {
this.dialogList = [];
this.newluyinList = []
uni.request({
url: config.service.getCorpusAnal + '?corpusId=' + this.luyinList[this.csdFileindex].id +
"&bg=" + info.bg + "&speaker=" + this.roleindex + '&num=50', //仅为示例,并非真实接口地址。
method: "GET",
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
success: (data) => {
this.tablist = [];
this.roleindexbiaoji = 0;
let jsonInfo = JSON.parse(data.data.data.audioContent);
for (var i = 0; i <= data.data.data.speakerNum; i++) {
if (i === 0) {
this.tablist.push({
name: '全部'
})
} else {
this.tablist.push({
name: String.fromCharCode(i + 64)
})
}
}
if (data.data.data.speaker == null) {
this.dshfkjsdkksodofydwfkhwdfkjh = 0;
} else {
this.tablist[data.data.data.speaker].name = this.tablist[data.data.data.speaker]
.name + "顾问";
this.roleindexbiaoji = data.data.data.speaker - 1;
this.dshfkjsdkksodofydwfkhwdfkjh = data.data.data.speaker - 1;
}
this.speaker = data.data.data.speaker;
//上拉标记点
this.textindex = data.data.data.index;
//下拉标记点
this.toptextindex = data.data.data.index;
jsonInfo.forEach(item => {
item.message = JSON.parse(item.onebest)
item.backindex = this.csdFileindex;
if (info.onebest) {
item.message.forEach(che => {
if (che.onebest == info.onebest) {
che.onebest =
`<font style='color: red'>${che.onebest}</font>`;
}
})
}
})
this.newluyinList = jsonInfo;
this.dialogList.push(jsonInfo[this.textindex]);
var itc = parseInt(info.bg / 1000)
this.adasdasdasd(itc)
}
})
},
init(info) {
this.sliderMax = 0; //进度条最大值
this.timeStr = "00:00"; //总的时间
const parames = {
pageNum: 1,
pageSize: 100,
query: {
customerId: this.customerId
}
}
this.$u.post("/corpus/findByPage", parames).then(res => {
if (res && res.length) {
let alltime = 1 + res[0].recordDuration;
this.calibration = res[0].calibration;
if (this.calibration == 0) {
this.kehuyixiangcenterindex = 0;
} else {
this.kehuyixiangcenterindex = 1;
}
this.alltimeStr = this.getTime(alltime)
if (info.bg != 0) {
this.luyinList = res;
this.recordPath = res[0].recordPath
this.sliderMax = this.getTime(res[0].recordDuration)
this.timeStr = this.getTime(res[0].recordDuration)
this.date = res[0].receptionTime;
this.getCorpusAnalysis(info);
this.creatAudio()
} else {
this.luyinList = res;
this.recordPath = res[0].recordPath
this.sliderMax = this.getTime(res[0].recordDuration)
this.timeStr = this.getTime(res[0].recordDuration)
this.date = res[0].receptionTime;
this.getCorpusAnalysis(info);
this.creatAudio()
}
}
})
},
//搜索跳转
adasdasdasd(e) {
const currTimeStr = this.formatTime(e)
this.currentTimeStr = currTimeStr
this.innerAudioContext.seek(e);
if (uni.getStorageSync('entrance') == 1) {
return
} else {
this.innerAudioContext.play();
}
},
getTime(time) {
return util.formatSecond(time)
},
// 录音暂停播放
changePlayState() {
if (this.audioPlay == false) {
this.innerAudioContext.play();
} else {
this.innerAudioContext.pause()
}
},
//音频前进回退
sliderChangeComplate(e) {
let platetime = e.detail.value * 1000;
this.dialogList = []
uni.request({
url: config.service.fastForward + '?corpusId=' + this.luyinList[this.csdFileindex].id +
"&bg=" + platetime, //仅为示例,并非真实接口地址。
method: "GET",
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
success: (data) => {
this.textindex = data.data.data.index;
this.toptextindex = data.data.data.index;
if (data.data.data.index > this.newluyinList.length) {
this.dialogList.push(this.newluyinList[0])
} else {
this.dialogList.push(this.newluyinList[data.data.data.index])
}
console.log(e.detail, '1233333333333333333333333333333333333333333333333333333333333')
const currTimeStr = this.formatTime(e.detail.value)
this.currentTimeStr = currTimeStr
this.innerAudioContext.seek(e.detail.value);
this.innerAudioContext.play();
}
})
},
//录音实例
creatAudio() {
this.innerAudioContext = uni.createInnerAudioContext();
if (uni.getStorageSync('entrance') == 1) {
this.innerAudioContext.autoplay = false;
} else {
this.innerAudioContext.autoplay = true;
}
this.innerAudioContext.src = this.recordPath;
this.innerAudioContext.title = '音频';
this.onPlay()
this.onPause()
this.onCanplay()
this.onEnded()
this.onSeeking()
this.onSeeked()
this.TimeUpdate()
},
formatTime(num) {
//格式化时间格式
num = num.toFixed(0);
let second = num % 60;
if (second < 10) second = '0' + second;
let min = Math.floor(num / 60);
if (min < 10) min = '0' + min;
return min + ":" + second;
},
}
}
</script>
<style lang="scss">
.bottomhead {
width: 100%;
height: 81rpx;
border-bottom: 1px solid #E0E0E0;
display: flex;
justify-content: space-between;
align-items: center;
.audio-slider {
width: 87%;
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 30rpx;
}
.audio-slider .slider {
width: 100%;
padding: 0px 15rpx;
box-sizing: border-box;
}
.audio-time {
width: 110rpx;
text-align: right;
font-size: 26rpx;
line-height: 28rpx;
color: #70798D;
display: flex;
justify-content: space-between;
}
.audio-play {
width: 48rpx;
height: 48rpx;
flex-shrink: 0;
}
.audio-play .image {
width: 100%;
height: 100%;
margin-left: 30rpx;
}
}
</style>

+ 735
- 0
components/r-canvas/r-canvas.js View File

@@ -0,0 +1,735 @@
export default{
data(){
return{
system_info:{}, //system info
canvas_width:0, //canvas width px
canvas_height:0, //canvas height px
ctx:null, //canvas object
canvas_id:null, //canvas id
hidden:false,//Whether to hide canvas
scale:1,//canvas scale
r_canvas_scale:1,
if_ctx:true
}
},
methods:{
/**
* save r-canvas.vue object
* @param {Object} that
*/
// saveThis(that){
// rCanvasThis = that
// },
/**
* Draw round rect text
* @param {Object} config
* @param {Number} config.x x坐标
* @param {Number} config.y y坐标
* @param {Number} config.w 宽度
* @param {Number} config.h 高度
* @param {Number} config.radius 圆角弧度
* @param {String} config.fill_color 矩形颜色
*/
fillRoundRect(config) {
return new Promise((resolve,reject)=>{
let x = this.compatibilitySize(parseFloat(config.x)*this.scale)
let y = this.compatibilitySize(parseFloat(config.y)*this.scale)
let w = this.compatibilitySize(parseFloat(config.w)*this.scale)
let h = this.compatibilitySize(parseFloat(config.h)*this.scale)
let radius = config.radius?parseFloat(config.radius)*this.scale:10*this.scale
let fill_color = config.fill_color || "black"
// The diameter of the circle must be less than the width and height of the rectangle
if (2 * radius > w || 2 * radius > h) {
reject("The diameter of the circle must be less than the width and height of the rectangle")
return false;
}
this.ctx.save();
this.ctx.translate(x, y);
//
this.drawRoundRectPath({
w: w,
h: h,
radius: radius
});
this.ctx.fillStyle = fill_color
this.ctx.fill();
this.ctx.restore();
resolve()
})
},
/**
* Draws the sides of a rounded rectangle
* @param {Object} config
* @param {Number} config.w 宽度
* @param {Number} config.h 高度
* @param {Number} config.radius 圆角弧度
*/
drawRoundRectPath(config) {
this.ctx.beginPath(0);
this.ctx.arc(config.w - config.radius, config.h - config.radius, config.radius, 0, Math.PI / 2);
this.ctx.lineTo(config.radius, config.h);
this.ctx.arc(config.radius, config.h - config.radius, config.radius, Math.PI / 2, Math.PI);
this.ctx.lineTo(0, config.radius);
this.ctx.arc(config.radius, config.radius, config.radius, Math.PI, Math.PI * 3 / 2);
this.ctx.lineTo(config.w - config.radius, 0);
this.ctx.arc(config.w - config.radius, config.radius, config.radius, Math.PI * 3 / 2, Math.PI * 2);
this.ctx.lineTo(config.w, config.h - config.radius);
this.ctx.closePath();
},
/**
* Draw special Text,line wrapping is not supported
* @param {Object} config
* @param {String} config.text 文字
* @param {Number} config.x x坐标
* @param {Number} config.y y坐标
* @param {String} config.font_color 文字颜色
* @param {String} config.font_family 文字字体
* @param {Number} config.font_size 文字大小(px)
*/
drawSpecialText(params){
let general = params.general
let list = params.list
return new Promise(async (resolve,reject)=>{
if(!general){
reject("general cannot be empty:101")
return;
}else if(list && list.length>0){
for(let i in list){
if(i != 0){
let font_size = list[i-1].font_size?parseFloat(list[i-1].font_size):20
this.ctx.setFontSize(font_size)
general.x = parseFloat(general.x) + this.ctx.measureText(list[i-1].text).width
}
list[i].x = general.x
list[i].y = general.y + (list[i].margin_top?parseFloat(list[i].margin_top):0)
await this.drawText(list[i])
}
resolve()
}else{
reject("The length of config arr is less than 0")
return;
}
})
},
/**
* array delete empty
* @param {Object} arr
*/
arrDeleteEmpty(arr){
let newArr = []
for(let i in arr){
if(arr[i]){
newArr.push(arr[i])
}
}
return newArr
},
/**
* Draw Text,support line
* @param {Object} config
* @param {String} config.text 文字
* @param {Number} config.max_width 文字最大宽度(大于宽度自动换行)
* @param {Number} config.line_height 文字上下行间距
* @param {Number} config.x x坐标
* @param {Number} config.y y坐标
* @param {String} config.font_color 文字颜色
* @param {String} config.font_family 文字字体 默认值:Arial
* @param {String} config.text_align 文字对齐方式(left/center/right)
* @param {Number} config.font_size 文字大小(px)
* @param {Boolean} config.line_through_height 中划线大小
* @param {Boolean} config.line_through_color 中划线颜色
* @param {String} config.font_style 规定文字样式
* @param {String} config.font_variant 规定字体变体
* @param {String} config.font_weight 规定字体粗细
* @param {String} config.line_through_cap 线末端类型
* @param {String} config.line_clamp 最大行数
* @param {String} config.line_clamp_hint 超过line_clamp后,尾部显示的自定义标识 如 ...
* @param {String} config.is_line_break 是否开启换行符换行
*
*/
drawText(config,configuration = {}){
configuration['line_num'] = configuration.line_num?configuration.line_num:0
configuration['text_width'] = configuration.text_width?configuration.text_width:0
return new Promise(async (resolve,reject)=>{
if(config.text){
let draw_width = 0,draw_height = 0,draw_x = config.x,draw_y = config.y
let font_size = config.font_size?(parseFloat(config.font_size)*this.scale):(20*this.scale)
let font_color = config.font_color || "#000"
let font_family = config.font_family || "Arial"
let line_height = config.line_height || config.font_size || 20
let text_align = config.text_align || "left"
let font_weight = config.font_weight || "normal"
let font_variant = config.font_variant || "normal"
let font_style = config.font_style || "normal"
let line_clamp_hint = config.line_clamp_hint || '...'
let lineBreakJoinText = ""
let max_width = config.max_width?parseFloat(config.max_width)*this.scale:0
// checkout is line break
if(config.is_line_break){
let splitTextArr = config.text.split(/[\n]/g)
if(splitTextArr && splitTextArr.length > 0){
let newSplitTextArr = this.arrDeleteEmpty(splitTextArr)
if(newSplitTextArr && newSplitTextArr.length > 0){
lineBreakJoinText = newSplitTextArr.slice(1).join("\n")
config.text = newSplitTextArr[0]
}else{
reject("Text cannot be empty:103")
return
}
}else{
reject("Text cannot be empty:102")
return
}
}
this.ctx.setFillStyle(font_color) // color
this.ctx.textAlign = text_align;
this.ctx.font = `${font_style} ${font_variant} ${font_weight} ${parseInt(font_size)}px ${font_family}`
if(configuration.text_width >= this.ctx.measureText(config.text).width){
draw_width = configuration.text_width
}else if(max_width > 0){
draw_width = max_width < this.ctx.measureText(config.text).width ? this.resetCompatibilitySize(max_width) : this.resetCompatibilitySize(this.ctx.measureText(config.text).width)
}else{
draw_width = this.ctx.measureText(config.text).width
}
configuration.text_width = draw_width / this.scale
if( max_width && this.compatibilitySize(this.ctx.measureText(config.text).width) > this.compatibilitySize(max_width)){
let current_text = ""
let text_arr = config.text.split("")
for(let i in text_arr){
if( this.compatibilitySize(this.ctx.measureText(current_text+text_arr[i]).width) > this.compatibilitySize(max_width) ){
// Hyphenation that is greater than the drawable width continues to draw
if(config.line_clamp && parseInt(config.line_clamp) == 1){
// Subtracting the current_text tail width from the line_clamp_hint width
let current_text_arr = current_text.split('')
let json_current_text = ''
while(true){
current_text_arr = current_text_arr.slice(1)
json_current_text = current_text_arr.join('')
if(this.compatibilitySize(this.ctx.measureText(json_current_text).width) <= this.compatibilitySize(this.ctx.measureText(line_clamp_hint).width)){
current_text = current_text.replace(json_current_text,'')
break;
}
}
configuration.line_num += 1
this.ctx.setFontSize(parseInt(this.compatibilitySize(font_size))) // font size
this.ctx.fillText(current_text + line_clamp_hint, this.compatibilitySize(parseFloat(config.x)*this.scale), this.compatibilitySize(parseFloat(config.y)*this.scale));
}else{
configuration.line_num += 1
this.ctx.setFontSize(parseInt(this.compatibilitySize(font_size))) // font size
this.ctx.fillText(current_text, this.compatibilitySize(parseFloat(config.x)*this.scale), this.compatibilitySize(parseFloat(config.y)*this.scale));
config.text = text_arr.slice(i).join("")
config.y = config.y + line_height
if(config.line_clamp){
config.line_clamp = parseInt(config.line_clamp) - 1
}
await this.drawText(config,configuration)
}
break;
}else{
current_text = current_text+text_arr[i]
}
}
}else{
if(config.line_through_height){
let x = parseFloat(config.x)*this.scale
let w
let y = parseFloat(config.y)*this.scale - (font_size / 2.6)
if(text_align == "left"){
w = this.ctx.measureText(config.text).width/1.1 + parseFloat(config.x)*this.scale
}else if(text_align == "right"){
w = parseFloat(config.x)*this.scale - this.ctx.measureText(config.text).width/1.1
}else if(text_align == "center"){
x = parseFloat(config.x)*this.scale - this.ctx.measureText(config.text).width / 1.1 / 2
w = parseFloat(config.x)*this.scale + this.ctx.measureText(config.text).width / 1.1 / 2
}
this.drawLineTo({
x:x,
y:y,
w:w,
h:y,
line_width:config.line_through_height,
line_color:config.line_through_color,
line_cap:config.line_through_cap
})
}
configuration.line_num += 1
this.ctx.setFontSize(parseInt(this.compatibilitySize(font_size))) // font size
this.ctx.fillText(config.text, this.compatibilitySize(parseFloat(config.x)*this.scale), this.compatibilitySize(parseFloat(config.y)*this.scale));
if(config.line_clamp){
config.line_clamp = parseInt(config.line_clamp) - 1
}
}
if(lineBreakJoinText){
await this.drawText({...config,text:lineBreakJoinText,y:config.y + line_height},configuration)
}
draw_height = config.font_size * configuration.line_num
draw_width = configuration.text_width
resolve({draw_width,draw_height,draw_x,draw_y})
}else{
reject("Text cannot be empty:101")
}
})
},
/**
* Draw Line
* @param {Object} config
* @param {Object} config.x x坐标
* @param {Object} config.y y坐标
* @param {Object} config.w 线的宽度
* @param {Object} config.h 线的高度
* @param {Object} config.line_width 线的宽度
* @param {Object} config.line_color 线条颜色
*/
drawLineTo(config){
let x = this.compatibilitySize(config.x)
let y = this.compatibilitySize(config.y)
let w = this.compatibilitySize(config.w)
let h = this.compatibilitySize(config.h)
let line_width = config.line_width?parseFloat(config.line_width)*this.scale:1*this.scale
let line_color = config.line_color || "black"
let line_cap = config.line_cap || "butt"
this.ctx.beginPath()
this.ctx.lineCap = line_cap
this.ctx.lineWidth = line_width
this.ctx.strokeStyle = line_color
this.ctx.moveTo(x,y)
this.ctx.lineTo(w,h)
this.ctx.stroke()
},
/**
* Compatibility px
* @param {Object} size
*/
compatibilitySize(size) {
let canvasSize = (parseFloat(size) / 750) * this.system_info.windowWidth
canvasSize = parseFloat(canvasSize * 2)
return canvasSize
},
/**
* Restore compatibility px
* @param {Object} size
*/
resetCompatibilitySize(size) {
let canvasSize = (parseFloat(size/2)/this.system_info.windowWidth) * 750
return canvasSize
},
/**
* Init canvas
*/
init(config){
return new Promise(async (resolve,reject)=>{
if(!config.canvas_id){
reject("Canvas ID cannot be empty, please refer to the usage example")
return;
}
this.hidden = config.hidden
this.canvas_id = config.canvas_id
let system_info = await uni.getSystemInfoSync()
this.system_info = system_info
this.scale = config.scale&&parseFloat(config.scale)>0?parseInt(config.scale):1
this.canvas_width = (config.canvas_width ? this.compatibilitySize(config.canvas_width) : system_info.windowWidth) * this.scale
this.canvas_height = (config.canvas_height ? this.compatibilitySize(config.canvas_height) : system_info.windowHeight) * this.scale,
this.r_canvas_scale = 1/this.scale
this.ctx = uni.createCanvasContext(this.canvas_id,this)
this.setCanvasConfig({
global_alpha:config.global_alpha?parseFloat(config.global_alpha):1,
backgroundColor:config.background_color?config.background_color:"#fff"
})
resolve()
})
},
/**
* clear canvas all path
*/
clearCanvas(){
return new Promise(async (resolve,reject)=>{
if(!this.ctx){
reject("canvas is not initialized:101")
return
}else{
this.ctx.clearRect(0,0,parseFloat(this.canvas_width)*this.scale,parseFloat(this.canvas_height)*this.scale)
await this.draw()
resolve()
}
})
},
/**
* Set canvas config
* @param {Object} config
*/
setCanvasConfig(config){
this.ctx.globalAlpha = config.global_alpha
this.ctx.fillStyle = config.backgroundColor
this.ctx.fillRect(0, 0, parseFloat(this.canvas_width)*this.scale, parseFloat(this.canvas_height)*this.scale)
},
/**
* set canvas width
* @param {Object} width
*/
setCanvasWidth(width){
if(!width){
uni.showToast({
title:'setCanvasWidth:width error',
icon:'none'
})
}
this.canvas_width = this.compatibilitySize(parseFloat(width)) * this.scale
this.ctx.width = this.canvas_width
},
/**
* set canvas height
* @param {Object} height
*/
setCanvasHeight(height){
if(!height){
uni.showToast({
title:'setCanvasWidth:height error',
icon:'none'
})
}
this.canvas_height = this.compatibilitySize(parseFloat(height)) * this.scale
this.ctx.height = this.canvas_height
},
/**
* Draw to filepath
*/
draw(callback){
return new Promise((resolve,reject)=>{
let stop = setTimeout(()=>{
this.ctx.draw(false,setTimeout(()=>{
uni.canvasToTempFilePath({
canvasId: this.canvas_id,
quality: 1,
success: (res)=>{
console.log('res',res)
resolve(res)
callback && callback(res)
},
fail:(err)=>{
reject(JSON.stringify(err)|| "Failed to generate poster:101")
}
},this)
},300))
clearTimeout(stop)
},300)
})
},
/**
* draw rect
* @param {Number} config.x x坐标
* @param {Number} config.y y坐标
* @param {Number} config.w 图形宽度(px)
* @param {Number} config.h 图形高度(px)
* @param {Number} config.color 图形颜色
* @param {Number} config.is_radius 是否开启圆图(1.1.6及以下版本废弃,请使用border_radius)
* @param {Number} config.border_width 边框大小
* @param {Number} config.border_color 边框颜色
*
*/
drawRect(config){
return new Promise(async (resolve,reject)=>{
if(!config.border_width || config.border_width <=0){
config.border_width = 0
}else{
config.border_width = parseFloat(config.border_width)
}
if(parseFloat(config.border_width) > 0){
let sub_config = JSON.parse(JSON.stringify(config))
sub_config.border_width = 0
sub_config.w = config.w + config.border_width
sub_config.h = config.h + config.border_width
sub_config.color = config.border_color || 'black'
if(sub_config.border_radius){
sub_config.border_radius = parseFloat(sub_config.border_radius) + parseFloat(config.border_width) / 2
}
await this.drawRect(sub_config)
}
let color = config.color || 'white'
config.x = (parseFloat(config.x) + config.border_width / 2)
config.y = (parseFloat(config.y) + config.border_width / 2)
config['color'] = color
this.ctx.fillStyle = color;
if(config.is_radius || config.border_radius){
this.setNativeBorderRadius(config)
this.ctx.fill()
}else{
console.log('config.border_width',config.border_width)
this.ctx.fillRect(this.compatibilitySize(config.x*this.scale),this.compatibilitySize(config.y*this.scale),this.compatibilitySize(parseFloat(config.w)*this.scale),this.compatibilitySize(parseFloat(config.h)*this.scale))
}
resolve()
})
},
/**
* Draw image
* @param {Object} config
* @param {String} config.url 图片链接
* @param {Number} config.x x坐标
* @param {Number} config.y y坐标
* @param {Number} config.w 图片宽度(px)
* @param {Number} config.h 图片高度(px)
* @param {Number} config.border_width 边大小
* @param {Number} config.border_color 边颜色
* @param {Number} config.is_radius 是否开启圆图(1.1.6及以下版本废弃,请使用border_radius)
* @param {Number} config.border_radius 圆角弧度
*/
drawImage(config){
return new Promise(async (resolve,reject)=>{
if(config.url){
let type = 0 // 1、network image 2、native image 3、base64 image
let image_url
let reg = /^https?/ig;
if(reg.test(config.url)){
type = 1
}else{
if((config.url.indexOf("data:image/png;base64") != -1) || config.url.indexOf("data:image/jpeg;base64") != -1 || config.url.indexOf("data:image/gif;base64") != -1){
type = 3
}else{
type = 2
}
}
if(type == 1){
// network image
await this.downLoadNetworkFile(config.url).then(res=>{ // two function
image_url = res
}).catch(err=>{
reject(err)
return;
})
}else if(type == 2){
// native image
const imageInfoResult = await uni.getImageInfo({
src: config.url
});
try{
if(imageInfoResult.length <= 1){
reject(imageInfoResult[0].errMsg + ':404')
return
}
}catch(e){
reject(e+':500')
return
}
let base64 = await this.urlToBase64({url:imageInfoResult[1].path})
// #ifdef MP-WEIXIN
await this.base64ToNative({url:base64}).then(res=>{
image_url = res
}).catch(err=>{
reject(JSON.stringify(err)+":501")
return;
})
// #endif
// #ifndef MP-WEIXIN
image_url = base64
// #endif
}else if(type == 3){
// #ifdef MP-WEIXIN
await this.base64ToNative({url:config.url}).then(res=>{
image_url = res
}).catch(err=>{
reject(JSON.stringify(err)+":500")
return;
})
// #endif
// #ifndef MP-WEIXIN
image_url = config.url
// #endif
}else{
reject("Other Type Errors:101")
return
}
if(config.border_width){
let border_radius = 0
if(config.border_radius){
let multiple = config.w / config.border_radius
border_radius = (parseFloat(config.w) + parseFloat(config.border_width)) / multiple
}
// drawRect
await this.drawRect({
x:parseFloat(config.x) - parseFloat(config.border_width)/2,
y:parseFloat(config.y) - parseFloat(config.border_width)/2,
w:parseFloat(config.w) + parseFloat(config.border_width),
h:parseFloat(config.h) + parseFloat(config.border_width),
color:config.border_color,
border_radius:border_radius,
border_width:config.border_width,
is_radius:config.is_radius
})
}

if(config.border_radius){
config.color = config.color?config.color:'rgba(0,0,0,0)'
// 圆角有白边,+0.5的误差
config.w = config.w + 0.3
config.h = config.h + 0.3
this.setNativeBorderRadius(config)
}else if(config.is_radius){
//已废弃 is_radius
this.ctx.setStrokeStyle("rgba(0,0,0,0)")
this.ctx.save()
this.ctx.beginPath()
this.ctx.arc(this.compatibilitySize(parseFloat(config.x)*this.scale+parseFloat(config.w)*this.scale/2), this.compatibilitySize(parseFloat(config.y)*this.scale+parseFloat(config.h)*this.scale/2), this.compatibilitySize(parseFloat(config.w)*this.scale/2), 0, 2 * Math.PI, false)
this.ctx.stroke();
this.ctx.clip()
}
await this.ctx.drawImage(image_url,this.compatibilitySize(parseFloat(config.x)*this.scale),this.compatibilitySize(parseFloat(config.y)*this.scale),this.compatibilitySize(parseFloat(config.w)*this.scale),this.compatibilitySize(parseFloat(config.h)*this.scale))
this.ctx.restore() //Restore previously saved drawing context
resolve()
}else{
let err_msg = "Links cannot be empty:101"
reject(err_msg)
}
})
},
/**
* base64 to native available path
* @param {Object} config
*/
base64ToNative(config){
return new Promise((resolve,reject)=>{
let fileName = new Date().getTime()
var filePath = `${wx.env.USER_DATA_PATH}/${fileName}_rCanvas.png`
wx.getFileSystemManager().writeFile({
filePath: filePath,
data: config.url.replace(/^data:\S+\/\S+;base64,/, ''),
encoding: 'base64',
success: function() {
resolve(filePath)
},
fail: function(error) {
reject(error)
}
})
})
},
/**
* native url to base64
* @param {Object} config
*/
urlToBase64(config){
return new Promise(async (resolve,reject)=>{
if (typeof window != 'undefined') {
await this.downLoadNetworkFile(config.url).then(res=>{ // two function
resolve(res)
}).catch(err=>{
reject(err)
})
}else if (typeof plus != 'undefined') {
plus.io.resolveLocalFileSystemURL(config.url,(obj)=>{
obj.file((file)=>{
let fileReader = new plus.io.FileReader()
fileReader.onload = (res)=>{
resolve(res.target.result)
}
fileReader.onerror = (err)=>{
reject(err)
}
fileReader.readAsDataURL(file)
}, (err)=>{
reject(err)
})
},(err)=>{
reject(err)
})
}else if(typeof wx != 'undefined'){
wx.getFileSystemManager().readFile({
filePath: config.url,
encoding: 'base64',
success: function(res) {
resolve('data:image/png;base64,' + res.data)
},
fail: function(error) {
reject(error)
}
})
}
})
},
setNativeBorderRadius(config){
let border_radius = config.border_radius?(parseFloat(config.border_radius)*this.scale):(20*this.scale)
if ((parseFloat(config.w)*this.scale) < 2 * border_radius) border_radius = (parseFloat(config.w)*this.scale) / 2;
if ((parseFloat(config.h)*this.scale) < 2 * border_radius) border_radius = (parseFloat(config.h)*this.scale) / 2;
this.ctx.beginPath();
this.ctx.moveTo(this.compatibilitySize((parseFloat(config.x)*this.scale) + border_radius), this.compatibilitySize((parseFloat(config.y)*this.scale)));
this.ctx.arcTo(this.compatibilitySize((parseFloat(config.x)*this.scale) + (parseFloat(config.w)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale)), this.compatibilitySize((parseFloat(config.x)*this.scale) + (parseFloat(config.w)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale) + (parseFloat(config.h)*this.scale)), this.compatibilitySize(border_radius));
this.ctx.arcTo(this.compatibilitySize((parseFloat(config.x)*this.scale) + (parseFloat(config.w)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale) + (parseFloat(config.h)*this.scale)), this.compatibilitySize((parseFloat(config.x)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale) + (parseFloat(config.h)*this.scale)), this.compatibilitySize(border_radius));
this.ctx.arcTo((this.compatibilitySize(parseFloat(config.x)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale) + (parseFloat(config.h)*this.scale)), this.compatibilitySize((parseFloat(config.x)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale)), this.compatibilitySize(border_radius));
this.ctx.arcTo(this.compatibilitySize((parseFloat(config.x)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale)), this.compatibilitySize((parseFloat(config.x)*this.scale) + (parseFloat(config.w)*this.scale)), this.compatibilitySize((parseFloat(config.y)*this.scale)), this.compatibilitySize(border_radius));
this.ctx.closePath();
this.ctx.strokeStyle = config.color || config.border_color || 'rgba(0,0,0,0)'; // 设置绘制边框的颜色
this.ctx.stroke();
this.ctx.save()
this.ctx.clip();
},
/**
* Download network file
* @param {Object} url : download url
*/
downLoadNetworkFile(url){
return new Promise((resolve,reject)=>{
uni.downloadFile({
url,
success:(res)=>{
if(res.statusCode == 200){
resolve(res.tempFilePath)
}else{
reject("Download Image Fail:102")
}
},
fail:(err)=>{
reject("Download Image Fail:101")
}
})
})
},
/**
* Save image to natice
* @param {Object} filePath : native imageUrl
*/
saveImage(filePath){
return new Promise((resolve,reject)=>{
if(!filePath){
reject("FilePath cannot be null:101")
return;
}
// #ifdef H5
var createA = document.createElement("a");
createA.download = filePath;
createA.href = filePath;
document.body.appendChild(createA);
createA.click();
createA.remove();
resolve()
// #endif
// #ifndef H5
uni.saveImageToPhotosAlbum({
filePath: filePath,
success:(res)=>{
resolve(res)
},
fail:(err)=>{
reject(err)
}
})
// #endif
})
}
}
}

+ 26
- 0
components/r-canvas/r-canvas.vue View File

@@ -0,0 +1,26 @@
<template>
<view>
<view class="r-canvas-component" :style="{width:canvas_width/scale+'px',height:canvas_height/scale+'px'}" :class="{'hidden':hidden}">
<canvas class="r-canvas" v-if="canvas_id" :canvas-id="canvas_id" :id="canvas_id" :style="{width:canvas_width+'px',height:canvas_height+'px','transform': `scale(${r_canvas_scale})`}"></canvas>
</view>
</view>
</template>

<script>
import rCanvasJS from "./r-canvas.js"
export default {
mixins:[rCanvasJS]
}
</script>
<style>
.r-canvas{
transform-origin: 0 0;
}
.r-canvas-component{
overflow: hidden;
}
.r-canvas-component.hidden{
position: fixed;
top:-5000upx;
}
</style>

+ 10
- 0
components/uniapp-zaudio/dist/util.d.ts View File

@@ -0,0 +1,10 @@
export declare function formatSeconds(seconds: number | string): string;
export declare function throttle(fn: Function, wait: number): Function;
export declare class EventBus {
private _events;
constructor();
protected on(event: any, action: any, fn: () => {}): void;
private has;
protected emit(event: any, data?: any): void;
protected off(event: any, action: any): void;
}

+ 73
- 0
components/uniapp-zaudio/dist/util.js View File

@@ -0,0 +1,73 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.EventBus = exports.throttle = exports.formatSeconds = void 0;

function formatSeconds(seconds) {
var result = typeof seconds === "string" ? parseFloat(seconds) : seconds;
if (isNaN(result)) return "";
let h = Math.floor(result / 3600) < 10 ? "0" + Math.floor(result / 3600) : Math.floor(result / 3600);
let m = Math.floor((result / 60) % 60) < 10 ? "0" + Math.floor((result / 60) % 60) : Math.floor((result / 60) % 60);
let s = Math.floor(result % 60) < 10 ? "0" + Math.floor(result % 60) : Math.floor(result % 60);

return `${h}:${m}:${s}`;
//time为毫秒数
}
exports.formatSeconds = formatSeconds;

function throttle(fn, wait) {
let previous = 0;
return function(...arg) {
let context = this;
let now = Date.now();
//每隔一段时间执行一次;
if (now - previous > wait) {
fn.apply(context, arg);
previous = now;
}
};
}
exports.throttle = throttle;
class EventBus {
constructor() {
this._events = new Map();
}
on(event, action, fn) {
let arr = this._events.get(event);
let hasAction = arr ?
arr.findIndex((i) => i.action == action) :
-1;
if (hasAction > -1) {
return;
}
this._events.set(event, [
...(this._events.get(event) || []),
{
action,
fn,
},
]);
}
has(event) {
return this._events.has(event);
}
emit(event, data) {
if (!this.has(event)) {
return;
}
let arr = this._events.get(event);
arr.forEach((i) => {
i.fn(data);
});
}
off(event, action) {
if (!this.has(event)) {
return;
}
let arr = this._events.get(event);
let newdata = arr.filter((i) => i.action !== action);
this._events.set(event, [...newdata]);
}
}
exports.EventBus = EventBus;

+ 213
- 0
components/uniapp-zaudio/dist/zaudio.d.ts View File

@@ -0,0 +1,213 @@
interface audio {
src: string;
title: string;
singer: string;
coverImgUrl: string;
}
interface audioInfo extends audio {
current: string;
duration: string;
duration_value: number;
current_value: number;
}
declare enum zaudioCbName {
onWaiting = "waiting",
onError = "error",
onTimeUpdate = "playing",
onCanplay = "canPlay",
onPause = "pause",
onEnded = "ended",
setAudio = "setAudio",
updateAudio = "updateAudio",
seek = "seek",
onStop = "stop",
syncStateOn = "syncStateOn"
}
import { EventBus } from "./util";
/**
* ZAudio类
* @class ZAudio
* @constructor
* @param {String} defaultCover 音频默认封面
* @param {Boolean} continuePlay 继续播放,错误播放或结束播放后执行
* @param {Boolean} autoPlay 自动播放,部分浏览器不支持
* @property {Number} renderIndex 当前渲染索引
* @property {<audioinfo>} renderinfo 当前渲染数据
* @property {Array<audio>} audiolist 音频列表数组
* @property {<audioinfo>} playinfo 当前播放数据
* @property {Boolean} paused 音频暂停状态
* @property {Number} playIndex 当前播放索引
* @property {Boolean} renderIsPlay 渲染与播放是否一致
*
* @method on(event, action, fn) 回调函数注册业务事件
* @method off(event, action) 回调函数中卸载业务事件
* @method setRender(data) 指定音频, 渲染到zaudio组件
* @method syncRender() 同步并渲染当前的播放状态
* @method operate(index) 播放或暂停指定索引的音频
* @method setAudio(list) 覆盖音频列表
* @method updateAudio(list) 添加音频列表
* @method stop() 强制暂停当前播放音频
* @method stepPlay(count) 快进快退
* @method syncStateOn(action, cb) 注册一个用于同步获取当前播放状态的事件
* @method syncStateOff(action) 卸载用于同步获取当前播放状态的事件
*
*
* **/
export default class ZAudio extends EventBus {
static version: string;
loading: boolean;
renderIndex: number;
audiolist: Array<audio>;
renderinfo: audioInfo;
playinfo: audioInfo;
paused: boolean;
uPause: boolean;
audioCtx: any;
autoPlay: boolean;
defaultCover: string;
continuePlay: boolean;
constructor(options: {
defaultCover: string;
autoPlay: boolean;
continuePlay: boolean;
});
private init;
checkEventParams(event: zaudioCbName, action: string | symbol, fn?: () => {}): boolean;
/**
* @description 回调中卸载业务事件
* @param {<zaudioCbName>} event 回调名称枚举值
* @param {Sting|Symbol} action 业务函数名,用于区分不同业务
* @returns undefined
* **/
off(event: zaudioCbName, action: string | symbol): void;
/**
* @description 回调中注册业务事件
* @param {<zaudioCbName>} event 回调名称枚举值
* @param {Sting|Symbol} action 业务函数名,用于区分不同业务
* @param {function(object|string|number|undefined):undefined} fn 业务函数, 参数或为音频状态
* @returns undefined
* **/
on(event: zaudioCbName, action: string | symbol, fn: () => {}): void;
/**
* @description 订阅触发音频回调
* @param {<zaudioCbName>} event 回调名称枚举值,具体看zaudioCbName
* @param {object|string|number|undefined} data 订阅触发回调时,传的音频属性
* @returns undefined
* **/
emit(event: zaudioCbName, data?: any): void;
private commit;
private onWaitingHandler;
private onCanplayHandler;
private onPlayHandler;
private onPauseHandler;
private onStopHandler;
private onEndedHandler;
private throttlePlaying;
private onTimeUpdateHandler;
private onErrorHandler;
/**
* @description 实时渲染当前状态
* @returns undefined
* **/
syncRender(): void;
/**
* @description 注册一个实时获取ZAudio属性的方法
* @param {String} action 自定义业务名
* @param {Funtion} fn 实时获取ZAudio属性回调
* @returns undefined
* **/
syncStateOn(action: string, fn: () => {}): void;
/**
* @description 卸载实时获取ZAudio属性的方法
* @param {String} action 自定义业务名
* @returns undefined
* **/
syncStateOff(action: string): void;
/**
* @description 订阅实时获取ZAudio属性的方法
* @returns undefined
* **/
private syncStateEmit;
/**
* @description 跳转播放
* @param {Number} value 跳转位置
* @returns undefined
* **/
seek(value: number): void;
/**
* @description 快进
* @param {Number} value 跳转位置
* @returns undefined
* **/
stepPlay(value: number): void;
/**
* @description 获取下一首歌曲索引(用于渲染和播放)
* @param {Number} count 切换数量
* @returns number
* **/
private getNextKey;
/**
* @description 切歌
* @param {Number} count 数量
* @returns undefined
* **/
changeplay(count: number): void;
/**
* @description 手动播放或暂停, 并渲染对应的数据
* @param {Number|String|<audioInfo>|undefined} key 索引或音频对象
* @returns undefined
* **/
operate(key?: number | string | audioInfo): void;
/**
* @description 强制暂停播放
* @returns undefined
* **/
stop(): void;
private operation;
/**
* @description 覆盖音频
* @param {Array<audio>} data 音频数组
* @returns undefined
* **/
setAudio(data: Array<audio>): void;
/**
* @description 添加音频
* @param {Array<audio>} data 音频数组
* @returns undefined
* **/
updateAudio(data: Array<audio>): void;
/**
* @description 设置当前播放信息
* @param {<audioInfo>} data 音频对象
* @returns undefined
* **/
setPlayinfo<T extends keyof audioInfo>(data: audioInfo): void;
/**
* @description 设置暂停状态
* @param {boolean} data 布尔值
* @returns undefined
* **/
setPause(data: boolean): void;
/**
* @description 设置loading
* @param {boolean} data 布尔值
* @returns undefined
* **/
setLoading(data: boolean): void;
/**
* @description 设置通话时暂停状态
* @param {boolean} data 布尔值
* @returns undefined
* **/
setUnnormalPause(data: boolean): void;
/**
* @description 设置渲染
* @param {number | string | audioInfo} data 索引或渲染信息
* @returns undefined
* **/
setRender(data: number | string | audioInfo): void;
get playIndex(): number;
get renderIsPlay(): boolean;
private appCheckReplay;
}
export {};

+ 658
- 0
components/uniapp-zaudio/dist/zaudio.js View File

@@ -0,0 +1,658 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function(thisArg, _arguments, P, generator) {
function adopt(value) {
return value instanceof P ? value : new P(function(resolve) {
resolve(value);
});
}
return new(P || (P = Promise))(function(resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}

function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}

function step(result) {
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", {
value: true
});
var zaudioCbName;
(function(zaudioCbName) {
zaudioCbName["onWaiting"] = "waiting";
zaudioCbName["onError"] = "error";
zaudioCbName["onTimeUpdate"] = "playing";
zaudioCbName["onCanplay"] = "canPlay";
zaudioCbName["onPause"] = "pause";
zaudioCbName["onEnded"] = "ended";
zaudioCbName["setAudio"] = "setAudio";
zaudioCbName["updateAudio"] = "updateAudio";
zaudioCbName["seek"] = "seek";
zaudioCbName["onStop"] = "stop";
zaudioCbName["syncStateOn"] = "syncStateOn";
})(zaudioCbName || (zaudioCbName = {}));
let zaudioCbNameArr = [];
for (const key in zaudioCbName) {
if (Object.prototype.hasOwnProperty.call(zaudioCbName, key)) {
const item = zaudioCbName[key];
zaudioCbNameArr.push(item);
}
}
const util_1 = require("./util");
/**
* ZAudio类
* @class ZAudio
* @constructor
* @param {String} defaultCover 音频默认封面
* @param {Boolean} continuePlay 继续播放,错误播放或结束播放后执行
* @param {Boolean} autoPlay 自动播放,部分浏览器不支持
* @property {Number} renderIndex 当前渲染索引
* @property {<audioinfo>} renderinfo 当前渲染数据
* @property {Array<audio>} audiolist 音频列表数组
* @property {<audioinfo>} playinfo 当前播放数据
* @property {Boolean} paused 音频暂停状态
* @property {Number} playIndex 当前播放索引
* @property {Boolean} renderIsPlay 渲染与播放是否一致
*
* @method on(event, action, fn) 回调函数注册业务事件
* @method off(event, action) 回调函数中卸载业务事件
* @method setRender(data) 指定音频, 渲染到zaudio组件
* @method syncRender() 同步并渲染当前的播放状态
* @method operate(index) 播放或暂停指定索引的音频
* @method setAudio(list) 覆盖音频列表
* @method updateAudio(list) 添加音频列表
* @method stop() 强制暂停当前播放音频
* @method stepPlay(count) 快进快退
* @method syncStateOn(action, cb) 注册一个用于同步获取当前播放状态的事件
* @method syncStateOff(action) 卸载用于同步获取当前播放状态的事件
*
*
* **/
class ZAudio extends util_1.EventBus {
constructor(options) {
super();
this.loading = false;
this.renderIndex = 0;
this.audiolist = [];
this.renderinfo = {
current: "00:00:00",
duration: "00:00:00",
duration_value: 0,
current_value: 0,
src: "",
title: "",
singer: "",
coverImgUrl: "",
};
this.playinfo = {
current: "00:00:00",
duration: "00:00:00",
duration_value: 0,
current_value: 0,
src: "",
title: "",
singer: "",
coverImgUrl: "",
};
this.paused = true;
this.uPause = false;
this.autoPlay = false;
this.defaultCover = "";
this.continuePlay = true;
//fix: 防抖触发音频播放中事件
this.throttlePlaying = util_1.throttle(() => {
this.emit(zaudioCbName.onTimeUpdate, this.playinfo);
this.syncStateEmit();
}, 1000);
let {
defaultCover,
autoPlay,
continuePlay
} = options;
this.defaultCover = defaultCover;
this.autoPlay = autoPlay;
this.continuePlay = continuePlay;
this.init();
}
init() {
// #ifndef H5
var audioCtx = uni.getBackgroundAudioManager();
// #endif
// #ifdef H5
var audioCtx = uni.createInnerAudioContext();
audioCtx.autoplay = this.autoPlay;
// #endif
this.audioCtx = audioCtx;
this.audioCtx.onWaiting(this.onWaitingHandler.bind(this));
this.audioCtx.onCanplay(this.onCanplayHandler.bind(this));
this.audioCtx.onPlay(this.onPlayHandler.bind(this));
this.audioCtx.onPause(this.onPauseHandler.bind(this));
this.audioCtx.onStop(this.onStopHandler.bind(this));
this.audioCtx.onEnded(this.onEndedHandler.bind(this));
this.audioCtx.onTimeUpdate(this.onTimeUpdateHandler.bind(this));
this.audioCtx.onError(this.onErrorHandler.bind(this));
//fix: 修复iOS原生音频切换不起作用
// #ifdef APP-PLUS
if (uni.getSystemInfoSync().platform == "ios") {
const bgMusic = plus.audio.createPlayer();
bgMusic.addEventListener("prev", () => {
this.changeplay(-1);
});
bgMusic.addEventListener("next", () => {
this.changeplay(1);
});
}
// #endif
// #ifndef H5
setTimeout(() => {
if (this.autoPlay) {
this.operate();
}
}, 500);
// #endif
this.appCheckReplay();
}
//检测on off的参数
checkEventParams(event, action, fn) {
if (zaudioCbNameArr.indexOf(event) < 0) {
console.error(`参数${event}错误, 必须为${zaudioCbNameArr.join(" | ")}中某一项`);
return false;
}
if (typeof action !== "string" && typeof action !== "symbol") {
console.error(`参数${action}错误, 参数必须为string或symbol类型`);
return false;
}
if (fn && typeof fn !== "function") {
console.error("fn参数错误");
return false;
}
return true;
}
/**
* @description 回调中卸载业务事件
* @param {<zaudioCbName>} event 回调名称枚举值
* @param {Sting|Symbol} action 业务函数名,用于区分不同业务
* @returns undefined
* **/
off(event, action) {
if (!this.checkEventParams(event, action))
return;
super.off(event, action);
}
/**
* @description 回调中注册业务事件
* @param {<zaudioCbName>} event 回调名称枚举值
* @param {Sting|Symbol} action 业务函数名,用于区分不同业务
* @param {function(object|string|number|undefined):undefined} fn 业务函数, 参数或为音频状态
* @returns undefined
* **/
on(event, action, fn) {
if (!this.checkEventParams(event, action))
return;
super.on(event, action, fn);
}
/**
* @description 订阅触发音频回调
* @param {<zaudioCbName>} event 回调名称枚举值,具体看zaudioCbName
* @param {object|string|number|undefined} data 订阅触发回调时,传的音频属性
* @returns undefined
* **/
emit(event, data) {
super.emit(event, data);
}
commit(action, data) {
typeof this[action] === "function" && this[action](data);
}
onWaitingHandler() {
this.commit("setLoading", true);
this.emit(zaudioCbName.onWaiting, true);
this.syncStateEmit();
}
onCanplayHandler() {
this.emit(zaudioCbName.onCanplay, this.playinfo);
this.commit("setLoading", false);
this.syncStateEmit();
}
onPlayHandler() {
// #ifdef APP-PLUS
this.commit("setPlayinfo", {
duration: util_1.formatSeconds(this.audioCtx.duration),
duration_value: this.audioCtx.duration,
});
// #endif
this.commit("setPause", false);
this.commit("setUnnormalPause", false);
}
onPauseHandler() {
this.commit("setPause", true);
this.emit(zaudioCbName.onPause);
this.syncStateEmit();
}
onStopHandler() {
this.commit("setPause", true);
this.emit(zaudioCbName.onStop);
this.syncStateEmit();
}
onEndedHandler() {
this.commit("setPause", true);
this.audioCtx.startTime = 0;
this.commit("setPlayinfo", {
current: "00:00:00",
current_value: 0,
src: "",
});
this.emit(zaudioCbName.onEnded);
this.syncStateEmit();
//续播
if (this.continuePlay) {
this.changeplay(1);
} else {
let nextkey = this.getNextKey(1);
this.commit("setRender", nextkey);
}
}
onTimeUpdateHandler() {
if (this.renderIsPlay) {
//fix: 解决播放进度大于总进度问题
let currentTime = this.audioCtx.currentTime
// let currentTime = this.audioCtx.currentTime > this.audioCtx.duration ?
// this.audioCtx.duration :
// this.audioCtx.currentTime;
this.commit("setPlayinfo", {
current: util_1.formatSeconds(currentTime),
current_value: currentTime,
});
// #ifndef APP-PLUS
//fix: 解决小程序与h5无法获取总进度的问题
if (this.audioCtx.duration != this.playinfo.duration_value) {
this.commit("setPlayinfo", {
duration: util_1.formatSeconds(this.audioCtx.duration),
duration_value: this.audioCtx.duration,
});
}
// #endif
}
this.throttlePlaying();
}
onErrorHandler() {
this.commit("setPause", true);
this.commit("setRender", {
src: "",
title: "",
singer: "",
coverImgUrl: "",
});
this.commit("setPlayinfo", {
current: "00:00:00",
current_value: 0,
duration: "00:00:00",
duration_value: 0,
title: "",
src: "",
});
this.emit(zaudioCbName.onError);
this.syncStateEmit();
if (this.continuePlay) {
this.changeplay(1);
}
}
/**
* @description 实时渲染当前状态
* @returns undefined
* **/
syncRender() {
this.setRender(this.playIndex);
}
/**
* @description 注册一个实时获取ZAudio属性的方法
* @param {String} action 自定义业务名
* @param {Funtion} fn 实时获取ZAudio属性回调
* @returns undefined
* **/
syncStateOn(action, fn) {
typeof fn === "function" && this.on(zaudioCbName.syncStateOn, action, fn);
}
/**
* @description 卸载实时获取ZAudio属性的方法
* @param {String} action 自定义业务名
* @returns undefined
* **/
syncStateOff(action) {
this.off(zaudioCbName.syncStateOn, action);
}
/**
* @description 订阅实时获取ZAudio属性的方法
* @returns undefined
* **/
syncStateEmit() {
this.emit(zaudioCbName.syncStateOn, {
renderIndex: this.renderIndex,
audiolist: this.audiolist,
renderinfo: this.renderinfo,
playinfo: this.playinfo,
paused: this.paused,
playIndex: this.playIndex,
renderIsPlay: this.renderIsPlay,
loading: this.loading,
});
}
/**
* @description 跳转播放
* @param {Number} value 跳转位置
* @returns undefined
* **/
seek(value) {
let val = value > this.audioCtx.duration ? this.audioCtx.duration : value;
this.audioCtx.seek(val);
this.commit("setPlayinfo", {
current: util_1.formatSeconds(val),
current_value: val,
});
// setTimeout(() => {
// this.emit(zaudioCbName.seek, this.playinfo.current);
// }, 0);
this.emit(zaudioCbName.seek, this.playinfo.current);
}
/**
* @description 快进
* @param {Number} value 跳转位置
* @returns undefined
* **/
stepPlay(value) {
if (this.renderIsPlay) {
let pos = this.playinfo.current_value + value;
this.seek(pos);
}
}
/**
* @description 获取下一首歌曲索引(用于渲染和播放)
* @param {Number} count 切换数量
* @returns number
* **/
getNextKey(count) {
let nextkey = this.renderIndex;
nextkey += count;
nextkey =
nextkey < 0 ?
this.audiolist.length - 1 :
nextkey > this.audiolist.length - 1 ?
0 :
nextkey;
return nextkey;
}
/**
* @description 切歌
* @param {Number} count 数量
* @returns undefined
* **/
changeplay(count) {
let nextkey = this.getNextKey(count);
this.commit("setPause", true);
this.operate(nextkey);
}
/**
* @description 手动播放或暂停, 并渲染对应的数据
* @param {Number|String|<audioInfo>|undefined} key 索引或音频对象
* @returns undefined
* **/
operate(key) {
key !== undefined && this.commit("setRender", key);
this.operation();
}
/**
* @description 强制暂停播放
* @returns undefined
* **/
stop() {
this.audioCtx.pause();
this.commit("setPause", true);
this.commit("setUnnormalPause", true);
this.emit(zaudioCbName.onStop);
}
//播放,暂停事件判断,
//播放数据与渲染数据相同时: 播放->暂停, 暂停->播放
//播放数据与渲染数据不相同时: 播放渲染音频
operation() {
return __awaiter(this, void 0, void 0, function*() {
const {
duration,
current,
duration_value,
current_value,
src,
} = this.playinfo;
const {
src: renderSrc,
title: renderTitle,
singer: renderSinger,
coverImgUrl: renderCoverImgUrl,
} = this.renderinfo;
let renderIsPlay = this.renderIsPlay;
let paused = this.paused;
if (!renderIsPlay) {
//渲染与播放地址 不同
this.audioCtx.src = renderSrc;
this.audioCtx.title = renderTitle;
this.audioCtx.singer = renderSinger;
this.audioCtx.coverImgUrl = renderCoverImgUrl || this.defaultCover;
this.audioCtx.startTime = 0;
this.audioCtx.seek(0);
this.audioCtx.play();
this.commit("setPause", false);
this.commit("setPlayinfo", {
src: renderSrc,
title: renderTitle,
singer: renderSinger,
coverImgUrl: renderCoverImgUrl,
});
} else {
if (paused) {
//渲染与播放地址相同
this.audioCtx.play();
this.audioCtx.startTime = current_value;
// this.audioCtx.seek(current_value);
this.commit("setPause", false);
this.commit("setPlayinfo", {
src: renderSrc,
title: renderTitle,
singer: renderSinger,
coverImgUrl: renderCoverImgUrl,
});
} else {
this.audioCtx.pause();
this.commit("setPause", true);
this.commit("setUnnormalPause", true);
}
}
});
}
/**
* @description 覆盖音频
* @param {Array<audio>} data 音频数组
* @returns undefined
* **/
setAudio(data) {
this.audiolist = [...data];
this.emit(zaudioCbName.setAudio, this.audiolist);
this.syncStateEmit();
}
/**
* @description 添加音频
* @param {Array<audio>} data 音频数组
* @returns undefined
* **/
updateAudio(data) {
this.audiolist.push(...data);
this.emit(zaudioCbName.updateAudio, this.audiolist);
this.syncStateEmit();
}
/**
* @description 设置当前播放信息
* @param {<audioInfo>} data 音频对象
* @returns undefined
* **/
setPlayinfo(data) {
for (let i in data) {
this.playinfo[i] = data[i];
}
}
/**
* @description 设置暂停状态
* @param {boolean} data 布尔值
* @returns undefined
* **/
setPause(data) {
this.paused = data;
}
/**
* @description 设置loading
* @param {boolean} data 布尔值
* @returns undefined
* **/
setLoading(data) {
this.loading = data;
}
/**
* @description 设置通话时暂停状态
* @param {boolean} data 布尔值
* @returns undefined
* **/
setUnnormalPause(data) {
this.uPause = data;
}
/**
* @description 设置渲染
* @param {number | string | audioInfo} data 索引或渲染信息
* @returns undefined
* **/
setRender(data) {
if (this.audiolist.length == 0)
return;
if (typeof data === "number" || typeof data === "string") {
this.renderIndex = typeof data === "string" ? parseInt(data) : data;
this.renderinfo = {
src: this.audiolist[this.renderIndex].src,
title: this.audiolist[this.renderIndex].title,
singer: this.audiolist[this.renderIndex].singer,
coverImgUrl: this.audiolist[this.renderIndex].coverImgUrl,
current: "00:00:00",
duration: "00:00:00",
current_value: 0,
duration_value: 100,
};
} else {
this.renderinfo = data;
let renderIndex = this.audiolist.findIndex((i) => i.src == data.src);
if (renderIndex >= 0) {
this.renderIndex = renderIndex;
}
}
this.syncStateEmit();
}
//当前索引
get playIndex() {
let index = this.audiolist.findIndex((i) => i.src == this.playinfo.src);
return index <= 0 ? 0 : index;
}
//渲染与播放是否一致
get renderIsPlay() {
return this.renderinfo.src == this.playinfo.src;
}
//app端判断电话来电后, 音频意外中断之后的继续播放
appCheckReplay() {
let _t = this;
// #ifdef APP-PLUS
try {
if (uni.getSystemInfoSync().platform == "android") {
var main = plus.android.runtimeMainActivity();
var Context = plus.android.importClass("android.content.Context");
var telephonyManager = plus.android.importClass("android.telephony.TelephonyManager");
var telephonyManager = plus.android
.runtimeMainActivity()
.getSystemService(Context.TELEPHONY_SERVICE);
var receiver = plus.android.implements("io.dcloud.android.content.BroadcastReceiver", {
onReceive: function(intent) {
//实现onReceiver回调函数
plus.android.importClass(intent);
var telephonyManager = plus.android.importClass(
"android.telephony.TelephonyManager");
var telephonyManager = plus.android
.runtimeMainActivity()
.getSystemService(Context.TELEPHONY_SERVICE);
var phonetype = telephonyManager.getCallState();
var phoneNumber = intent.getStringExtra(telephonyManager
.EXTRA_INCOMING_NUMBER);
if (phonetype == 0 && !_t.uPause) {
_t.audioCtx.play();
}
},
});
var IntentFilter = plus.android.importClass("android.content.IntentFilter");
var filter = new IntentFilter();
filter.addAction(telephonyManager.ACTION_PHONE_STATE_CHANGED); //监听开关
main.registerReceiver(receiver, filter); //注册监听
} else if (uni.getSystemInfoSync().platform == "ios") {
var callstatus = false;
var CTCall = plus.ios.importClass("CTCall");
var CTCallCenter = plus.ios.importClass("CTCallCenter");
var center = new CTCallCenter();
center.init();
center.setCallEventr(function(ctCall) {
callstatus = !callstatus;
if (!callstatus && !_t.uPause) {
_t.audioCtx.play();
} else {
_t.audioCtx.pause();
}
});
}
} catch (err) {
console.warn(err);
}
// #endif
}
// 重置当前的参数
resetDatas() {
this.loading = false;
this.renderIndex = 0;
this.audiolist = [];
this.renderinfo = {
current: "00:00:00",
duration: "00:00:00",
duration_value: 0,
current_value: 0,
src: "",
title: "",
singer: "",
coverImgUrl: "",
};
this.playinfo = {
current: "00:00:00",
duration: "00:00:00",
duration_value: 0,
current_value: 0,
src: "",
title: "",
singer: "",
coverImgUrl: "",
};
}
}
exports.default = ZAudio;
ZAudio.version = "2.2.51";

+ 2
- 0
components/uniapp-zaudio/index.js View File

@@ -0,0 +1,2 @@
import ZAudio from "./dist/zaudio.js";
export default ZAudio

+ 356
- 0
components/uniapp-zaudio/index.scss View File

@@ -0,0 +1,356 @@
@mixin textoverflow() {
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
@keyframes rowup {
0% {
-webkit-transform: translate(-50%, -50%) rotate(0deg);
transform-origin: center center;
}

100% {
-webkit-transform: translate(-50%, -50%) rotate(360deg);
transform-origin: center center;
}
}

.imt-audio.theme1 {
padding: 0 30upx 30upx;
background: #fff;

.top {
& > view:nth-child(2) {
.title {
font-weight: bold;
font-size: 34rpx;
margin-top: 50rpx;
text-align: center;
}

.singer {
color: #999;
font-size: 26rpx;
margin-top: 10rpx;
text-align: center;
margin-bottom: 18rpx;
}
}
}

.audio-wrapper {
display: flex;
align-items: center;
width: 90%;
margin: 0 auto;
}

.audio-button-box {
display: flex;
align-items: center;
margin: 40rpx auto 0;
justify-content: space-around;
height: 100rpx
}

.audio-number {
font-size: 24upx;
line-height: 1;
color: #333;
}

.audio-slider {
flex: 1;
margin: 0 30rpx 0 35rpx;
}

.audio-control-wrapper {
margin: 20rpx auto;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}

.cover {
width: 350rpx;
height: 350rpx;
box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.3);
border-radius: 5px;
}
.playbox{
width: 100rpx;
height: 100rpx;
display:flex;
align-items: center;
justify-content: center;
}
.play,
.pause {
width: 100rpx;
height: 100rpx;
&.loading{
width: 80rpx;
height: 80rpx;
animation: rotating 2s linear infinite;
}
}

.prevbtn,
.nextbtn {
width: 40rpx;
height: 40rpx;
}

.prevplay {
width: 40rpx;
height: 40rpx;
transform: rotateZ(180deg);
}

.nextplay {
width: 40rpx;
height: 40rpx;
}
}

.imt-audio.theme2 {
background: #fff;
border: 1px solid #cecece;
width: 100%;
margin: 0 auto;
overflow: hidden;

.top {
background: #fff;
display: flex;
align-items: center;
height: 150rpx;

& > view:nth-child(2) {
flex: 1;
margin: 0 30rpx;

.title {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 24rpx;
text{
font-size: 30rpx;
text-align: left;
max-width: 100%;
@include textoverflow;
flex: 1;
}
.audio-number {
font-size: 24upx;
line-height: 1;
color: #333;
}
}

.singer {
color: #999;
font-size: 26rpx;
margin-top: 10rpx;
text-align: left;
margin-bottom: 18rpx;
max-width: 100%;
@include textoverflow;
}
}
}




.cover {
width: 120rpx;
height: 120rpx;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
border: 2px solid #fff;
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards;
}

.cover.on {
-webkit-animation: 10s rowup linear infinite normal;
animation: 10s rowup linear infinite normal;
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards;
}
.audio-control-wrapper{
width: 150rpx;
height: 150rpx;
display: flex;
align-items:center;
justify-content: center;
background: #efefef;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
.play {
width: 80rpx;
height: 80rpx;
z-index: 99;
background: rgba(0, 0, 0, 0.4);
border-radius: 50%;
&.loading{
width: 60rpx;
height: 60rpx;
animation: rotating 2s linear infinite;
}
}

.prevbtn {
width: 48rpx;
height: 48rpx;
margin-right: 40rpx;
}

.nextbtn {
width: 48rpx;
height: 48rpx;
margin-left: 40rpx;
}
}

.imt-audio.theme3 {
background: #ccc;
width: 100%;
overflow: hidden;
display: flex;
padding: 40rpx 20rpx;
box-sizing: border-box;
max-height: 200rpx;
position:relative;
.top {
width: 140rpx;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}

.audio-wrapper {
display: flex;
flex-direction: column;
flex: 1;
color: #fff;
margin-left: 20rpx;

.titlebox {
display: flex;
line-height: 46rpx;
margin-bottom: 30rpx;
.title {
font-size: 30rpx;
max-width: 50%;
@include textoverflow;
}

.singer {
margin-left: 20rpx;
font-size: 28rpx;
max-width: 50%;
@include textoverflow;
}
}
}
.slidebox {
display: flex;
justify-content: space-between;
width: 96%;
view{
&:first-child{
font-size: 28rpx;
}
&:last-child{
font-size: 28rpx;
text{
&:last-child{
margin-left: 40rpx;
}
}
}
}
}
/deep/ .uni-slider-tap-area {
padding: 0;
}
/deep/ .uni-slider-wrapper {
min-height: 0;
}
/deep/ .uni-slider-handle-wrapper {
height: 4px;
}
.audio-slider {
position: absolute;
top: 0;
margin: 0;
width: 100%;
left: 0;
padding: 0;
}

.cover {
width: 120rpx;
height: 120rpx;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards;
}

.play {
width: 80rpx;
height: 80rpx;
z-index: 99;
background: rgba(0, 0, 0, 0.4);
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
&.loading{
width: 60rpx;
height: 60rpx;
animation: rotating_theme3 2s linear infinite;
}
}
}

@keyframes rotating {
0% {
transform: rotateZ(0deg)
}
100% {
transform: rotateZ(360deg)
}
}
@keyframes rotating_theme3 {
0% {
transform: translate(-50%, -50%) rotateZ(0deg)
}
100% {
transform: translate(-50%, -50%) rotateZ(360deg)
}
}

BIN
components/uniapp-zaudio/static/go.png View File

Before After
Width: 48  |  Height: 48  |  Size: 333 B

BIN
components/uniapp-zaudio/static/loading.png View File

Before After
Width: 48  |  Height: 48  |  Size: 331 B

BIN
components/uniapp-zaudio/static/loading2.png View File

Before After
Width: 48  |  Height: 48  |  Size: 333 B

BIN
components/uniapp-zaudio/static/next.png View File

Before After
Width: 48  |  Height: 44  |  Size: 535 B

BIN
components/uniapp-zaudio/static/pausebtn.png View File

Before After
Width: 130  |  Height: 123  |  Size: 189 B

BIN
components/uniapp-zaudio/static/pausebtn2.png View File

Before After
Width: 84  |  Height: 92  |  Size: 137 B

BIN
components/uniapp-zaudio/static/playbtn.png View File

Before After
Width: 130  |  Height: 130  |  Size: 274 B

BIN
components/uniapp-zaudio/static/playbtn2.png View File

Before After
Width: 84  |  Height: 84  |  Size: 181 B

BIN
components/uniapp-zaudio/static/prev.png View File

Before After
Width: 48  |  Height: 44  |  Size: 508 B

+ 416
- 0
components/uniapp-zaudio/zaudio.vue View File

@@ -0,0 +1,416 @@
<template>
<view class="imt-audio" :class="[`${theme}`]" v-if="audiolist.length > 0">

<template v-if="theme == 'theme4'">
<view class="imt-audios">
<view class="top">
<view class="audio-control-wrapper">
<image :src="require('./static/loading.png')" v-if="loading" class="play loading"></image>
<template v-else>
<image :src="require('./static/playbtn.png')" alt="" @click="operate" class="play"
v-if="renderData('paused')"></image>
<image :src="require('./static/pausebtn.png')" alt="" @click="operate" class="play" v-else>
</image>
</template>
</view>
</view>
<view class="audio-wrapper">
<view class="audio-flex">
<text>
{{renderData('current')}}
</text>
<slider class="audio-slider" :activeColor="themeColor" block-size="16"
:value="renderData('current_value')" :max="renderData('duration_value')" @change="change"
:disabled="!renderIsPlay"></slider>
<text v-if="!duration">
{{renderData('duration')}}
</text>
<text v-else>{{ duration }}</text>
</view>
</view>
</view>
</template>
<template v-if="theme == 'theme3'">
<slider class="audio-slider" :activeColor="themeColor" block-size="0" :value="renderData('current_value')"
:max="renderData('duration_value')" @change="change" :disabled="!renderIsPlay"></slider>

<view class="top">
<view class="audio-control-wrapper">
<image :src="renderData('coverImgUrl')" mode="aspectFill" class="cover"
:class="{ on: !renderData('paused') }"></image>

<image :src="require('./static/loading.png')" v-if="loading" class="play loading"></image>
<template v-else>
<image :src="require('./static/playbtn.png')" alt="" @click="operate" class="play"
v-if="renderData('paused')"></image>
<image :src="require('./static/pausebtn.png')" alt="" @click="operate" class="play" v-else>
</image>
</template>
</view>
</view>
<view class="audio-wrapper">
<view class="titlebox">
<view class="title">{{ renderData('title') }}</view>
<view class="singer">{{ renderData('singer') }}</view>
</view>

<view class="slidebox">
<view>{{ renderData('current') }}/ {{ renderData('duration') }}</view>
<view>
<text @click="changeplay(-1)">上一首</text>
<text @click="changeplay(1)">下一首</text>
</view>
</view>
</view>
</template>

<template v-if="theme == 'theme2'">
<view class="top">
<view class="audio-control-wrapper" :style="{backgroundImage: `url(${renderData('coverImgUrl')})`}">
<image :src="require('./static/loading.png')" v-if="loading" class="play loading"></image>
<template v-else>
<image :src="require('./static/playbtn.png')" alt="" @click="operate" class="play"
v-if="renderData('paused')"></image>
<image :src="require('./static/pausebtn.png')" alt="" @click="operate" class="play" v-else>
</image>
</template>
</view>

<view>
<view class="title">
<text>{{ renderData('title') }}</text>
<view class="audio-number">{{ renderData('current') }}/{{ renderData('duration') }}</view>
</view>
<view class="singer">{{ renderData('singer') }}</view>
</view>
</view>
</template>

<template v-if="theme == 'theme1'">
<view class="top">
<view class="audio-control-wrapper">
<image :src="renderData('coverImgUrl')" mode="aspectFill" class="cover"
:class="{ on: !renderData('paused') }"></image>
</view>

<view>
<view class="title">{{ renderData('title') }}</view>
<view class="singer">{{ renderData('singer') }}</view>
</view>
</view>
<view class="audio-wrapper">
<view class="audio-number">{{ renderData('current') }}</view>
<slider class="audio-slider" :activeColor="themeColor" block-size="16"
:value="renderData('current_value')" :max="renderData('duration_value')" @change="change"
:disabled="!renderIsPlay"></slider>
<view class="audio-number">{{ renderData('duration') }}</view>
</view>

<view class="audio-button-box">
<!-- 块退15s -->
<image :src="require('./static/prev.png')" class="prevbtn" @click="stepPlay(-15)" mode="widthFix">
</image>
<!-- 上一首 -->
<image :src="require('./static/go.png')" class="prevplay" @click="changeplay(-1)" mode="widthFix">
</image>
<div class="playbox">
<image :src="require('./static/loading2.png')" v-if="loading" class="play loading"></image>
<template v-else>
<!-- 播放 -->
<image :src="require('./static/playbtn2.png')" alt="" @click="operate" class="play"
v-if="renderData('paused')"></image>
<!-- 暂停 -->
<image :src="require('./static/pausebtn2.png')" alt="" @click="operate" class="pause" v-else>
</image>
</template>
</div>
<!-- 下一首 -->
<image :src="require('./static/go.png')" class="nextplay" @click="changeplay(1)" mode="widthFix">
</image>
<!-- 快进15s -->
<image :src="require('./static/next.png')" class="nextbtn" @click="stepPlay(15)" mode="widthFix">
</image>
</view>
</template>

</view>
</template>

<script>
export default {
props: {
theme: {
type: String, // 主题 'theme1' or 'theme2'
default: 'theme1'
},
themeColor: {
type: String,
default: '#42b983'
},
duration: {
type: String,
default: ""
}
},
data() {
return {
playinfo: this.$zaudio.playinfo,
audiolist: this.$zaudio.audiolist,
paused: this.$zaudio.paused,
renderIsPlay: this.$zaudio.renderIsPlay,
audio: this.$zaudio.renderinfo,
loading: this.$zaudio.loading,
action: Symbol('zaudio')
};
},
computed: {
renderData() {
return name => {
if (!this.renderIsPlay) {
if (name == 'paused') {
return true;
}
return this.audio[name];
} else {
if (name == 'paused') {
return this.paused;
}
return this.playinfo[name];
}
};
}
},
mounted() {
this.$nextTick(() => {
let action = this.action;
this.$zaudio.syncStateOn(action, ({
audiolist,
paused,
playinfo,
renderIsPlay,
renderinfo,
loading,
}) => {
this.audiolist = audiolist;
this.paused = paused;
this.playinfo = playinfo;
this.renderIsPlay = renderIsPlay;
this.audio = renderinfo;
this.loading = loading;
});
this.$zaudio.syncRender()
});
},
methods: {
// 转换时间
formatSeconds(seconds) {
var result = typeof seconds === "string" ? parseFloat(seconds) : seconds;
if (isNaN(result)) return "";
let h = Math.floor(result / 3600) < 10 ?
"0" + Math.floor(result / 3600) :
Math.floor(result / 3600);
let m = Math.floor((result / 60) % 60) < 10 ?
"0" + Math.floor((result / 60) % 60) :
Math.floor((result / 60) % 60) + h * 60;
let s = Math.floor(result % 60) < 10 ?
"0" + Math.floor(result % 60) :
Math.floor(result % 60);
return `${h}:${m}:${s}`;
},
//播放or暂停
operate() {
this.$zaudio.operate();
},
//进度拖到
change(event) {
if (this.renderIsPlay) {
console.log('组件内', event)
this.$zaudio.seek(Math.floor(event.detail.value));
}
},
//快进
stepPlay(value) {
this.$zaudio.stepPlay(value);
},
//切歌
changeplay(count) {
this.$zaudio.changeplay(count);
},
},
beforeDestroy() {
this.$zaudio.playinfo.duration = '00:00:00'
this.$zaudio.playinfo.duration_value = '00:00:00'
//组件卸载时卸载业务逻辑
let action = this.action;
this.$zaudio.syncStateOff(action)
this.$zaudio.stop()
}
};
</script>

<style scoped lang="scss">
@import './index.scss';

// #ifdef MP-WEIXIN
.theme3 .audio-slider {
margin-top: -8px !important;
}

// #endif


@mixin textoverflow() {
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}

@keyframes rowup {
0% {
-webkit-transform: translate(-50%, -50%) rotate(0deg);
transform-origin: center center;
}

100% {
-webkit-transform: translate(-50%, -50%) rotate(360deg);
transform-origin: center center;
}
}

.imt-audios {
position: relative;
width: 100%;
height: 81rpx;
display: flex;
box-sizing: border-box;
background: #fff;

.top {
position: relative;
width: 100rpx;
}

.audio-wrapper {
position: relative;
padding: 0 20rpx;
display: flex;
flex: 1;
color: #fff;

.popup {
position: absolute;
right: 32rpx;
top: -122rpx;
z-index: 100;
width: 136rpx;
height: 122rpx;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background: #fff;
border: 1rpx solid #E0E0E0;
transition: all 0.25s linear;
opacity: 0;

image {
width: 32rpx;
height: 32rpx;
}

text {
margin-top: 10rpx;
color: #333;
font-size: 24rpx;
}

.act-test {
color: #2671E2;
}
}

.close {
opacity: 1;
}
}

.slidebox {
flex-shrink: 0;
display: flex;
align-items: center;

.slide-img {
width: 32rpx;
height: 8rpx;
}
}

/deep/ .uni-slider-tap-area {
padding: 0;
}

/deep/ .uni-slider-wrapper {
min-height: 0;
}

/deep/ .uni-slider-handle-wrapper {
height: 6px;
}

.audio-slider {
flex-grow: 1;
}

.play {
width: 48rpx;
height: 48rpx;
z-index: 99;
background: rgba(0, 0, 0, 0.4);
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

&.loading {
width: 48rpx;
height: 48rpx;
animation: rotating_theme3 2s linear infinite;
}
}
}

.audio-flex {
padding: 0 32rpx 0 0;
flex-grow: 1;
display: flex;
align-items: center;

text {
color: #70798D;
}
}

@keyframes rotating {
0% {
transform: rotateZ(0deg)
}

100% {
transform: rotateZ(360deg)
}
}

@keyframes rotating_theme3 {
0% {
transform: translate(-50%, -50%) rotateZ(0deg)
}

100% {
transform: translate(-50%, -50%) rotateZ(360deg)
}
}
</style>

+ 87
- 0
components/yz-audio/audioBg.js View File

@@ -0,0 +1,87 @@
import {
mapState,
mapActions,
mapMutations
} from 'vuex'
export const audios = {
data() {
return {
isBgPlay: false, // 是否禁止拖拽进度条
}
},

computed: {
...mapState(['bgAudioMannager']),
},

methods: {
setAudio(obj) {
this.bgAudioMannager.title = '录音音频';
this.bgAudioMannager.src = obj.src
this.bgAudioMannager.startTime = obj.currentTime
},

setAudioFunc() {
this.bgAudioMannager.onCanplay(() => {
console.log('可以播放');
});
this.bgAudioMannager.onStop(() => {
console.log('停止播放');
this.isBgPlay = false
});

this.bgAudioMannager.onPause(() => {
console.log('暂停播放');
this.isBgPlay = false
// 设置当前暂停的视频播放位置
// this.seek(this.bgAudioMannager.currentTime)
// this.play()
});
this.bgAudioMannager.onEnded(() => {
console.log('自然播放结束事件');
this.isBgPlay = false
});
this.bgAudioMannager.onError((res) => {
console.log(res.errMsg);
console.log(res.errCode);
});

this.bgAudioMannager.onTimeUpdate(() => {
this.isBgPlay = true
this.duration = this.bgAudioMannager.duration;
this.currentTime = this.bgAudioMannager.currentTime;
this.$emit('timeUpdate', {
duration: this.bgAudioMannager.duration,
currentTime: this.bgAudioMannager.currentTime
})
});
},
// 背景音频暂停
audioPause() {
this.bgAudioMannager.pause()
},
// 背景音频播放
audioPlay() {
this.pause()
this.bgAudioMannager.play()
},
//背景音频指定秒数播放
audioSeek(t) {
this.bgAudioMannager.seek(t)
},
// 停止背景音频播放
stopAduio() {
console.log(this.bgAudioMannager)
this.bgAudioMannager.pause()
if (this.bgAudioMannager && this.bgAudioMannager.src) {
this.bgAudioMannager.src = ''
}
}
}
}

+ 119
- 0
components/yz-audio/index.scss View File

@@ -0,0 +1,119 @@
@mixin textoverflow() {
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
@keyframes rowup {
0% {
-webkit-transform: translate(-50%, -50%) rotate(0deg);
transform-origin: center center;
}

100% {
-webkit-transform: translate(-50%, -50%) rotate(360deg);
transform-origin: center center;
}
}
.imt-audio{
position:relative;
width: 100%;
display: flex;
box-sizing: border-box;
background: #fff;
overflow: hidden;
.top {
width: 140rpx;
position: relative;
}

.audio-wrapper {
display: flex;
flex-direction: column;
flex: 1;
color: #fff;
margin-left: 20rpx;
}
.slidebox {
display: flex;
justify-content: space-between;
width: 96%;
}
/deep/ .uni-slider-tap-area {
padding: 0;
}
/deep/ .uni-slider-wrapper {
min-height: 0;
}
/deep/ .uni-slider-handle-wrapper {
height: 6px;
}
.audio-slider {
padding-top: 10rpx;
margin-left: 150rpx;
position: absolute;
bottom: 40rpx;
width: 75vw;
left: 0;
padding: 0;
}

// .cover {
// width: 120rpx;
// height: 120rpx;
// box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
// position: absolute;
// top: 50%;
// left: 50%;
// transform: translate(-50%, -50%);
// animation-fill-mode: forwards;
// -webkit-animation-fill-mode: forwards;
// }

.play {
width: 48rpx;
height: 48rpx;
z-index: 99;
background: rgba(0, 0, 0, 0.4);
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
&.loading{
width: 48rpx;
height: 48rpx;
animation: rotating_theme3 2s linear infinite;
}
}
}

@keyframes rotating {
0% {
transform: rotateZ(0deg)
}
100% {
transform: rotateZ(360deg)
}
}
@keyframes rotating_theme3 {
0% {
transform: translate(-50%, -50%) rotateZ(0deg)
}
100% {
transform: translate(-50%, -50%) rotateZ(360deg)
}
}

.hItem
{
margin-left: 16rpx;
}

.extrButton
{
font-size: 36rpx;
}

BIN
components/yz-audio/static/backimg.png View File

Before After
Width: 64  |  Height: 16  |  Size: 594 B

BIN
components/yz-audio/static/bg.png View File

Before After
Width: 64  |  Height: 64  |  Size: 1.8 KiB

BIN
components/yz-audio/static/bg_act.png View File

Before After
Width: 64  |  Height: 64  |  Size: 1.9 KiB

BIN
components/yz-audio/static/loading.png View File

Before After
Width: 48  |  Height: 48  |  Size: 331 B

BIN
components/yz-audio/static/loading2.png View File

Before After
Width: 48  |  Height: 48  |  Size: 333 B

BIN
components/yz-audio/static/pausebtn.png View File

Before After
Width: 130  |  Height: 123  |  Size: 189 B

BIN
components/yz-audio/static/playbtn.png View File

Before After
Width: 130  |  Height: 130  |  Size: 274 B

+ 432
- 0
components/yz-audio/yz-audio.vue View File

@@ -0,0 +1,432 @@
<template>
<view class="imt-audio">
<template>
<view class="top">
<view class="audio-control-wrapper">
<image :src="require('./static/loading.png')" v-if="playState=='loading'" class="play loading">
</image>
<template v-else>
<image :src="require('./static/playbtn.png')" alt="play" @click="play" class="play"
v-if="playState=='pause'"></image>
<image :src="require('./static/pausebtn.png')" alt="pause" @click="pause" class="play" v-else>
</image>
</template>
</view>
</view>
<view class="audio-wrapper">
<view class="audio-flex">
<text>
{{formatSeconds(currentTime)}}
</text>
<slider class="audio-slider" block-size="12" :max="duration" :value="currentTime"
@change="sliderChange" @changing="sliderChanging"></slider>
<text>
{{formatSeconds(duration)}}
</text>
</view>

<view class="slidebox" @click="showTip">
<slot name="extraCtrls">
<image class="slide-img" :src="require('./static/backimg.png')" mode=""></image>
</slot>
</view>
<!-- 后台播放按钮区域 -->
<view class="popup" v-if="show" :class="{close: closeing}" @click="checkPlayer">
<template v-if="!isBgPlay">
<image :src="require('./static/bg.png')" mode=""></image>
</template>
<template v-else>
<image :src="require('./static/bg_act.png')" mode=""></image>
</template>
<text :class="{'act-test': isBgPlay}">后台播放</text>
</view>
</view>
<!--video在ios中不能完全隐藏,否则无法播放-->
<video id="videoPlayer" :autoplay="true" class="videoPlayer" :src="src" :muted="false"
style="width: 10rpx;height:10rpx;" @play="playerOnPlay" @pause="playerOnPause" @ended="playerOnEnded"
@timeupdate="playerOnTimeupdate" @waiting="playerOnWaiting" @error="playerOnError"></video>
</template>
</view>
</template>

<script>
/*
createInnerAudioContext()是audio组件的内部实现,不能熄屏播放、不能后台播放、不能倍速播放。
getBackgroundAudioManager() 可以熄屏播放、后台播放,不能倍速播放。缺点是响应速度很慢,无法实现精细、及时的进度控制,而且可能被别的程序占用。
因此这里只能用video来实现,video能倍速播放,不能熄屏播放、不能后台播放。而且避免了用createInnerAudioContext()实现的跳转到别的页面,还在播放的问题
因此应用程序可以在需要后台播放的时候(需要用户操作触发),再暂停这个控件的播放,然后自己用getBackgroundAudioManager实现后台播放
*/

import Vue from 'vue';
import {
mapMutations
} from 'vuex'
import {
audios
} from './audioBg.js'
export default {
mixins: [audios],
props: {
nowFileTime: {
type: [String, Number],
default: 0
},
},

watch: {
nowFileTime(oValue, nValue) {
this.duration = nValue
}
},

data() {
return {
src: '', //
poster: "",
name: "...",
singer: "...",
duration: 0,
currentTime: 0,
playState: "pause", //"loading"/"playing"/"pause"
isSliderChanging: false,
isFirst: false, // 是否阻止第一次赋值
audio: null, // 音频对象
show: false, // 控制展示用的
closeing: false, // 默认关闭
};
},
created() {
// 自定义组件,需要传递第二个参数为this,否则后续的pause等操作不起作用
this.videoCtx = uni.createVideoContext("videoPlayer", this);
this.audio = uni.createInnerAudioContext();
this.audio.autoplay = false;
this.createAudio()
this.setAudioFunc()
},

mounted() {
this.audio.onCanplay((e) => {
if (this.audio.duration != 0) {
this.playState = "pause"
this.$forceUpdate()
}
})
},

methods: {
...mapMutations(['createAudio', 'stopAduio']),
setSrc(value) {
console.log(this, ' 我打印this')
this.src = value;
console.log(this.src, '我在这儿里更换src')
// 获取当前音频的总时长
this.audio.src = value;
},

setPoster(value) {
this.poster = value;
},
setName(value) {
this.name = value;
},
setSinger(value) {
this.singer = value;
},

playerOnPlay(e) {
this.playState = "playing";
console.log('playerOnPlay', e)
this.$emit("play");
},
playerOnPause(e) {
this.playState = "pause";
console.log('playerOnPause', e)
this.$emit("pause");
},
playerOnEnded(e) {
this.playState = "pause";
console.log('playerOnEnded', e)
this.$emit("ended");
},

playerOnTimeupdate(e) {
if (this.isFirst) this.playState = "playing";
this.isFirst = true
this.duration = e.detail.duration;
this.currentTime = e.detail.currentTime;
this.$emit("timeUpdate", e.detail);
},

playerOnWaiting(e) {
this.playState = "loading";
console.log('playerOnWaiting', e)
},
playerOnError(e) {
console.log('playerOnError', e)
this.playState = "pause";
this.$emit("error", e);
},
formatSeconds(seconds) {
var result = typeof seconds === "string" ? parseFloat(seconds) : seconds;
if (isNaN(result)) return "";
let h = Math.floor(result / 3600) < 10 ?
"0" + Math.floor(result / 3600) :
Math.floor(result / 3600);
let m = Math.floor((result / 60) % 60) < 10 ?
"0" + Math.floor((result / 60) % 60) :
Math.floor((result / 60) % 60) + h * 60;
let s = Math.floor(result % 60) < 10 ?
"0" + Math.floor(result % 60) :
Math.floor(result % 60);
return `${h}:${m}:${s}`;
},
stop() {
this.videoCtx.stop();
},
seek(t) {
this.videoCtx.seek(t);
},
play() {
// if (this.videoCtx.currentTime != this.videoCtx.currentTime) {
// this.seek(this.currentTime)
// }
console.log('触发方法play')
this.videoCtx.play(); //在有的H5浏览器里,如果play不是用户触发的,则play()会报错
// 暂停后台播放
this.stopAduio()
},
pause() {
console.log('触发方法pause')
this.videoCtx.pause();
},
playbackRate(value) {
this.videoCtx.playbackRate(value);
//playbackRate不能在play之前或者之后立即调用,否则只有很少几率会成功
},
sliderChange(e) {
this.isSliderChanging = false;
//要通过e.detail.value获取,否则如果通过dom去读取slider的value
//就会存在滚动条拖不动的情况
// this.videoCtx.seek(e.detail.value);
let type = 'audio'
if (this.bgAudioMannager.paused === false) {
type = 'bgAudio'
}
this.$emit('sliderChangeComplate', { ...e, isType: type })
},
sliderChanging(e) {
this.isSliderChanging = true;
console.log(e, '当前正在改变')
},
// 关闭后台播放按钮
closeTip() {
this.closeing = false
setTimeout(() => {
this.show = false
}, 250)
},
// 展示后台播放按钮
showTip() {
this.show = true
setTimeout(() => {
this.closeing = true
}, 50)
},

// 点击后台播放音频事件
backAudio() {
this.pause()
let obj = {
src: this.src,
currentTime: this.currentTime
}
this.setAudio(obj)
},

// 切换播放源
checkPlayer() {
this.closeTip()
if (this.bgAudioMannager.paused === false) {
this.stopAduio()
} else {
this.backAudio()
}
}
},
}
</script>

<style lang="scss">
// @import './index.scss';
@mixin textoverflow() {
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}

@keyframes rowup {
0% {
-webkit-transform: translate(-50%, -50%) rotate(0deg);
transform-origin: center center;
}

100% {
-webkit-transform: translate(-50%, -50%) rotate(360deg);
transform-origin: center center;
}
}

.imt-audio {
position: relative;
width: 100%;
height: 81rpx;
display: flex;
box-sizing: border-box;
background: #fff;

.top {
position: relative;
width: 100rpx;
}

.audio-wrapper {
position: relative;
padding: 0 20rpx;
display: flex;
flex: 1;
color: #fff;
.popup {
position: absolute;
right: 32rpx;
top: -122rpx;
z-index: 100;
width: 136rpx;
height: 122rpx;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background: #fff;
border: 1rpx solid #E0E0E0;
transition: all 0.25s linear;
opacity: 0;
image {
width: 32rpx;
height: 32rpx;
}
text {
margin-top: 10rpx;
color: #333;
font-size: 24rpx;
}
.act-test {
color: #2671E2;
}
}
.close {
opacity: 1;
}
}

.slidebox {
flex-shrink: 0;
display: flex;
align-items: center;
.slide-img {
width: 32rpx;
height: 8rpx;
}
}

/deep/ .uni-slider-tap-area {
padding: 0;
}

/deep/ .uni-slider-wrapper {
min-height: 0;
}

/deep/ .uni-slider-handle-wrapper {
height: 6px;
}

.audio-slider {
flex-grow: 1;
}

.play {
width: 48rpx;
height: 48rpx;
z-index: 99;
background: rgba(0, 0, 0, 0.4);
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

&.loading {
width: 48rpx;
height: 48rpx;
animation: rotating_theme3 2s linear infinite;
}
}
}

.audio-flex {
padding: 0 32rpx 0 0;
flex-grow: 1;
display: flex;
align-items: center;

text {
color: #70798D;
}
}

@keyframes rotating {
0% {
transform: rotateZ(0deg)
}

100% {
transform: rotateZ(360deg)
}
}

@keyframes rotating_theme3 {
0% {
transform: translate(-50%, -50%) rotateZ(0deg)
}

100% {
transform: translate(-50%, -50%) rotateZ(360deg)
}
}

.hItem {
margin-left: 16rpx;
}

.extrButton {
font-size: 36rpx;
}

.videoPlayer {
position: absolute;
left: 0;
bottom: 0;
z-index: -1;
}
</style>

+ 84
- 0
config.js View File

@@ -0,0 +1,84 @@
import { host, iMServiceHost } from './utils/domain.js'

var config = {
service: {
host,
iMServiceHost,
getStage:`${host}/customer/getStage`,
//验证toen
verify:`${host}/user/verify`,
//登录
login: `${host}/user/login`,
//获取用户信息
getUser: `${host}/user/getUser`,
//获取权限
getMenu:`${host}/user/getMenu`,
//发送验证码
sendCode:`${host}/user/sendCode`,
//验证码校验
plogin:`${host}/user/plogin`,
//忘记密码
forgotPassword:`${host}/user/forgotPassword`,
//修改密码
updatePassword: `${host}/user/resetPwd`,
//修改用户信息
upload: `${host}/user/update`,
// 上传头像
uploadHeadImg:`${host}/user/uploadHeadPortrait`,
//分点学习标签
findSelectedLabel:`${host}/addtodigest/findSelectedLabel`,
//获取全部学习
findAllZATD:`${host}/addtodigest/findAllZATD`,
//查询点赞列表
likegetLike:`${host}/like/getLike`,
// 获取评论
cmmentList:`${host}/comment/list`,
// 新增评论
saveCmment:`${host}/comment/saveCmment`,
// 新增文件评论
saveCmmentUpload:`${host}/comment/upload`,
// 点赞
saveLike:`${host}/like/saveLike`,
// 取消点赞
cancelLike:`${host}/like/cancelLike`,
//同音转译接口3
getCorpusAnal: `${host}/corpus/splicAudioPlay`,
//转写内容获取快进时间是第几个文件
fastForward:`${host}/corpus/fastForward`,
//标记顾问
markConsultant:`${host}/corpus/markConsultant`,
//同音转译接口
getSpeechAnalysis: `${host}/cms/mobile/getBytargetId`,
//同音转译接口2
getCorpusAnalysis: `${host}/corpus/audioPlay`,
//查询设备电量
findElectricity:`${host}/equipment/findElectricity`,
//首页设备查询
findEquipmentState:`${host}/cusLvStatistics/findEquipmentState`,
//首页实时统计
realTimeStatistics:`${host}/cusLvStatistics/realTimeStatistics`,
//首页本周工作
workThisWeek:`${host}/cusLvStatistics/workThisWeek`,
//查询是否开启选择顾问权限
getSelfAssignedByHouseId:`${host}/user/getSelfAssignedByHouseId`,
//确认加精
addATD:`${host}/addtodigest/addATD`,
//取消加精
delATD:`${host}/addtodigest/delATD`,
// 获取客户来源列表
sourceList: `${host}/customer/sourceList`,
// 升级公告
updateList: `${host}/zkMessage/messageList`,
// 升级公告更新阅读
updateRead: `${host}/zkMessage/updateFlag`,
// 隐私协议
privacyAgr: `${host}/zkPrivate/findById`,
//首页更新弹框
updatePopup: `${host}/zkMessage/showMessage`,
//首页首次更新弹框
firstShowPopup: `${host}/zkMessage/firstShow`,
//消息未读数
notReadNum: `${host}/zkMessage/findFlagCount`,
}
};
module.exports = config;

+ 39
- 0
main.js View File

@@ -0,0 +1,39 @@
import Vue from 'vue';
import App from './App';
import dayjs from './utils/dayjs.min.js'
import store from './store/index.js'
import ZAudio from '@/components/uniapp-zaudio/index.js'
Vue.config.productionTip = false;

let zaudio = new ZAudio({
continuePlay: false, //续播
autoPlay: false, // 自动播放 部分浏览器不支持
})

Vue.prototype.$zaudio = zaudio
Vue.prototype.$dayjs = dayjs;
Vue.prototype.$store = store;

import common from 'utils/common.js'
Vue.prototype.$noMultipleClicks = common.noMultipleClicks;

// 引入全局uView
import uView from 'uview-ui'
Vue.use(uView);



import http from '@/utils/http.js'

Vue.use(http, app)



App.mpType = 'app';

const app = new Vue({
...App,
store
});
app.$mount();

+ 131
- 0
manifest.json View File

@@ -0,0 +1,131 @@
{
"name" : "去房智控管家",
"appid" : "__UNI__D88F14A",
"description" : "AI营销助理",
"versionName" : "1.1.0",
"versionCode" : "100",
"transformPx" : false,
"app-plus" : {
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
"modules" : {
"Push" : {},
"UIWebview" : {},
"Webview-x5" : {}
},
"distribute" : {
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
],
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ]
},
"ios" : {
"idfa" : false
},
"sdkConfigs" : {
"ad" : {},
"oauth" : {}
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
}
}
}
},
"quickapp" : {},
"mp-weixin" : {
"appid" : "wx8f883dca5ecc5510",
"setting" : {
"urlCheck" : false,
"es6" : true,
"postcss" : true,
"minified" : true
},
"usingComponents" : true,
"permission" : {},
"requiredBackgroundModes" : [ "audio" ],
"plugins" : {
"WechatSI" : {
"version" : "0.3.4",
"provider" : "wx069ba97219f66d99"
}
},
"uniStatistics" : {
"enable" : true
}
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true,
"uniStatistics" : {
"enable" : false
}
},
"h5" : {
"router" : {
"base" : "/pages/login/guide"
}
}
}

+ 49
- 0
package-lock.json View File

@@ -0,0 +1,49 @@
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="
},
"css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"requires": {
"utrie": "^1.0.2"
}
},
"html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"requires": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
}
},
"text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"requires": {
"utrie": "^1.0.2"
}
},
"utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"requires": {
"base64-arraybuffer": "^1.0.2"
}
},
"wxml2canvas": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/wxml2canvas/-/wxml2canvas-1.0.1.tgz",
"integrity": "sha512-AdWvxgTjJtW/m6Cki1cwGO0HOERKU8O9V3RcCz8UyqJbrPF7e8Nv27/epYiIs64HlbPTKWTLl7ECjQi6UVducA=="
}
}
}

+ 625
- 0
pages.json View File

@@ -0,0 +1,625 @@
{
"easycom": {
"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
},
//这个pages里只放这五个页面,新增页面时请对应的放到下面的分包里
"pages": [
// {
// "path": "pages/mine/registerForm",
// "style": {
// "navigationBarTitleText": "访客登记表",
// "navigationBarBackgroundColor": "#2671E2",
// "navigationBarTextStyle": "white"
// }

// },
// {
// "path": "pages/mine/registerResult",
// "style": {
// "navigationBarTitleText": "访客登记表",
// "navigationBarBackgroundColor": "#2671E2",
// "navigationBarTextStyle": "white"
// }
// },
{
"path": "pages/index/guide",
"style": {
"navigationBarBackgroundColor": "#008EF2",
"navigationBarTextStyle": "white",
"navigationStyle": "custom"
}
},
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "智控管家",
"navigationBarBackgroundColor": "#2671E2",
"navigationBarTextStyle": "white",
"enablePullDownRefresh": true
}
},
{
"path": "pages/index/customer",
"style": {
"navigationBarTitleText": "接待",
"navigationBarBackgroundColor": "#2671E2",
"navigationBarTextStyle": "white"
}
}, {
"path": "pages/index/learning",
"style": {
"navigationBarTitleText": "学习",
"navigationBarBackgroundColor": "#2671E2",
"navigationBarTextStyle": "white",
"enablePullDownRefresh": true
}
}, {
"path": "pages/index/personal",
"style": {
"navigationBarTitleText": "我的",
"navigationBarBackgroundColor": "#2671E2",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/reportExcel/dayReport",
"style": {
"navigationBarTitleText": "数智工牌日报",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
},
{
"path": "pages/reportExcel/weekReport",
"style": {
"navigationBarTitleText": "数智工牌周报",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
}
],
//这下面是分包
"subPackages": [{
"root": "pages/login", //登录相关
"name": "login",
"pages": [{
"path": "index"
},
{
"path": "Verification",
"style": {
"navigationBarTitleText": "验证码登录",
"navigationBarBackgroundColor": "#008EF2",
"navigationBarTextStyle": "white",
"navigationStyle": "custom"
}
},
{
"path": "yinzhongmalogin",
"style": {
"navigationBarTitleText": "验证码登录",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "Setthepassword",
"style": {
"navigationBarTitleText": "设置密码",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "Verifythelogin",
"style": {
"navigationBarTitleText": "验证码登录",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
}



]
},
{
"root": "pages/mine", //个人中心
"name": "mine",
"pages": [{
"path": "details",
"style": {
"navigationBarTitleText": "详情",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "details2",
"style": {
"navigationBarTitleText": "详情",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "detailsNew",
"style": {
"navigationBarTitleText": "详情",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "calibration",
"style": {
"navigationBarTitleText": "校验",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "ScoringPlaylist",
"style": {
"navigationBarTitleText": "匹配标签",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},

{
"path": "Myprofile",
"style": {
"navigationBarTitleText": "编辑资料",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "nickname",
"style": {
"navigationBarTitleText": "编辑昵称",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "signature",
"style": {
"navigationBarTitleText": "编辑签名",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "Changehepassword",
"style": {
"navigationBarTitleText": "修改密码",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "subscribe",
"style": {
"navigationBarTitleText": "消息订阅",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},

{
"path": "reception/addreception",
"style": {
"navigationBarTitleText": "新增接待",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "reception/consultant",
"style": {
"navigationBarTitleText": "选择顾问",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "consultanonduty/index",
"style": {
"navigationBarTitleText": "值班顾问",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true
}
},
{
"path": "equipment/index",
"style": {
"navigationBarTitleText": "设备管理",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true
}
},
{
"path": "messageList",
"style": {
"navigationBarTitleText": "消息",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}

}, {
"path": "selectBuilding",
"style": {
"navigationBarTitleText": "切换项目",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}

}, {
"path": "registerCode",
"style": {
"navigationBarTitleText": "访客登记码",
"navigationBarBackgroundColor": "#2671E2",
"navigationBarTextStyle": "white"
}

}, {
"path": "registerForm",
"style": {
"navigationBarTitleText": "访客登记表",
"navigationBarBackgroundColor": "#2671E2",
"navigationBarTextStyle": "white"
}

},
{
"path": "registerResult",
"style": {
"navigationBarTitleText": "访客登记表",
"navigationBarBackgroundColor": "#2671E2",
"navigationBarTextStyle": "white"
}

}, {
"path": "messageDetail",
"style": {
"navigationBarTitleText": "公告详情",
"navigationBarBackgroundColor": "#2671E2",
"navigationBarTextStyle": "white"
}
}, {
"path": "messageDetails",
"style": {
"navigationBarTitleText": "隐私协议",
"navigationBarBackgroundColor": "#fff",
"navigationBarTextStyle": "black"
}

}
]
},
{
"root": "pages/learning", //学习
"name": "learning",
"pages": [{
"path": "Thefulltext/index",
"style": {
"navigationBarTitleText": "全文学习",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "Thefulltext/index2",
"style": {
"navigationBarTitleText": "全文学习",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "Thefulltext/search",
"style": {
"navigationBarTitleText": "搜索",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "Keywordsearch",
"style": {
"navigationBarTitleText": "搜索",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "Equinoctiallearning",
"style": {
"navigationBarTitleText": "分点学习",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true
}
},
{
"path": "Equinoctial/index",
"style": {
"navigationBarTitleText": "分点学习",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "Equinoctial/index2",
"style": {
"navigationBarTitleText": "分点学习",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
}


]
},
{
"root": "pages/center", //中心逻辑的模块都放到这里
"name": "center",
"pages": [{
"path": "Piabodata/index",
"style": {
"navigationBarTitleText": "销讲数据",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true
}
},
{
"path": "Piabodata/Groupcontrast",
"style": {
"navigationBarTitleText": "集团对比",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true
}
},
{
"path": "Piabodata/Theteamcompared",
"style": {
"navigationBarTitleText": "团队对比",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true
}
},
{
"path": "Piabodata/selectTeam",
"style": {
"navigationBarTitleText": "选择团队",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "Piabodata/selectGroup",
"style": {
"navigationBarTitleText": "选择项目",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "Piabodata/Userinsightinto",
"style": {
"navigationBarTitleText": "客户画像",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true
}
},
{
"path": "Piabodata/TrendAnalysis",
"style": {
"navigationBarTitleText": "趋势分析",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true
}
},
{
"path": "Piabodata/StaffAnalysis",
"style": {
"navigationBarTitleText": "员工分析",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true
}
},

{
"path": "Piabodata/Customerportrait/Detailsofthesearch",
"style": {
"navigationBarTitleText": "搜索",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "Piabodata/Customerportrait/Receivedetailabout",
"style": {
"navigationBarTitleText": "详情",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "Piabodata/Customerportrait/Receivingrecords",
"style": {
"navigationBarTitleText": "列表",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "Piabodata/Employeesstatistics",
"style": {
"navigationBarTitleText": "顾问排名",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true
}
},

{
"path": "records/index",
"style": {
"navigationBarTitleText": "接待记录",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true
}
},
{
"path": "records/recordSearch",
"style": {
"navigationBarTitleText": "搜索",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "prohibited/index",
"style": {
"navigationBarTitleText": "违禁记录",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true
}
},
{
"path": "prohibited/details",
"style": {
"navigationBarTitleText": "违禁详情",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": false
}
},
{
"path": "consumer/index",
"style": {
"navigationBarTitleText": "客户管理",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black",
"enablePullDownRefresh": true
}
},
{
"path": "consumer/consumerSearch",
"style": {
"navigationBarTitleText": "搜索",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "consumer/consumerDetail",
"style": {
"navigationBarTitleText": "客户详情",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "consumer/remind",
"style": {
"navigationBarTitleText": "添加提醒",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "consumer/edit",
"style": {
"navigationBarTitleText": "编辑客户",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
},
{
"path": "consumer/newFollowup/newFollowup",
"style": {
"navigationBarTitleText": "写跟进",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
}
]
}
],

"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于小程序位置接口的效果展示"
}
},
"networkTimeout": {
"request": 10000,
"downloadFile": 10000
},
"debug": false,
"tabBar": {
"color": "#8E8E8E",
"selectedColor": "#1296db",
"borderStyle": "white",
"list": [{
"pagePath": "pages/index/index"
// "iconPath": "/static/images/tabBar/home.png",
// "selectedIconPath": "/static/images/tabBar/homeActive.png",
// "text": "首页"
},
{
"pagePath": "pages/index/customer"
// "iconPath": "/static/images/tabBar/customer.png",
// "selectedIconPath": "/static/images/tabBar/customerActive.png",
// "text": "接待"
},
{
"pagePath": "pages/index/learning"
// "iconPath": "/static/images/tabBar/voice.png",
// "selectedIconPath": "/static/images/tabBar/voiceActive.png",
// "text": "学习"
},
{
"pagePath": "pages/index/personal"
// "iconPath": "/static/images/tabBar/user.png",
// "selectedIconPath": "/static/images/tabBar/userActive.png",
// "text": "个人"
}
]
},
"sitemapLocation": "sitemap.json",
"globalStyle": {
"backgroundColor": "#F6F6F6",
"backgroundTextStyle": "dark",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "数智工牌",
"navigationBarTextStyle": "black"
},
"condition" : { //模式配置,仅开发期间生效
"current": 0, //当前激活的模式(list 的索引项)
"list": [
{
"name": "访客二维码", //模式名称
"path": "pages/mine/registerForm", //启动页面,必选
"query": "" //启动参数,在页面的onLoad函数里面得到
}
]
}
}

+ 186
- 0
pages/center/Piabodata/Customerportrait/Detailsofthesearch.vue View File

@@ -0,0 +1,186 @@
<template>
<view class="translation">
<view style="display: flex;width: 100%;height: 100rpx;border-bottom: 1px solid #E0E0E0;">
<view style="width: 50%;display: flex;align-items: center;justify-content: center;font-size: 30rpx;">
<view style="line-height: 50rpx;" :class="roleindex == 0 ? 'bosdttom' : ''" @click="tapspagek(0)">
画像语义词选择</view>
</view>
<view style="width: 50%;display: flex;align-items: center;justify-content: center;font-size: 30rpx;">
<view style="line-height: 50rpx;" :class="roleindex == 1 ? 'bosdttom' : ''" @click="tapspagek(1)">关键词输入
</view>
</view>
</view>
<view v-if='roleindex==0' style="width: 690rpx;height: 64rpx;margin: 0 auto;margin-top: 30rpx;">
<view style="display: flex;align-items: center;border-bottom: 1px solid #C9C9C9;height: 80rpx;">
<view>画像语义词:</view>
<view style="width:70%" @click="oninputtap()">
<text v-if="Semanticword.length==0">请选择</text>
<text v-else>{{Semanticword}}</text>
</view>
<view>
<image src="https://qufang.oss-cn-beijing.aliyuncs.com/upload/icon/xcx/jjycrm/qf/more.png"
style="width:12rpx;height:23rpx;margin-left: 16rpx;">
</view>
</view>
</view>
<view v-if='roleindex==1' style="width: 690rpx;height: 64rpx;margin: 0 auto;margin-top: 30rpx;background: #F2F2F2;border-radius: 32rpx;
display: flex;align-items: center;">
<view style="width: 10%;height: 64rpx;display: flex;align-items: center;">
<image style="width: 28rpx;height: 28rpx;margin-left: 30rpx;" src="/static/images/search.png" mode="">
</image>
</view>
<view style="width: 90%;height: 64rpx;display: flex;align-items: center;">
<input type="text" @input="searchinfo" v-model="keyword" placeholder="请输入关键字"
style="width: 100%;color: #999999;font-size: 24rpx;" />
</view>
</view>
<view style="width: 690rpx;margin: 0 auto;margin-top: 10rpx;">

<view
style="width: 100%;border-bottom: 1px solid #E0E0E0;display: flex;padding-bottom: 10rpx;margin-top: 40rpx;"
v-for="(item,index) in listarr" :key='index' @click="toaidoinfo(item.Content,item.corpusId,item.index)">
<view style="width: 26rpx;height: 36rpx;margin-top: 4rpx;">
<image style="width: 26rpx;height: 28rpx;" src="/static/images/testimg.png" mode=""></image>
</view>
<view v-html="item.Content.text"
style="color: #666666;font-size: 28rpx;line-height: 36rpx;margin-left: 10rpx;width: 80%;"></view>
<view style="font-size: 28rpx;width: 10%;width: 14%;text-align: right;">{{item.Content.time}}</view>
</view>

</view>
<u-select v-model="Showhiddenunits" mode="single-column" :list="selectlist" @confirm="confirm"></u-select>
</view>
</template>

<script>
var util = require("../../../../utils/util.js");
var config = require("../../../../config");
export default {
data() {
return {
customerId: '',
listarr: [],
keyword: '',
skpl: '',
roleindex: 0,
Showhiddenunits: false,
selectlist: [],
Semanticword: '',
qujian: true,
from: '', // 来源
};
},
onLoad(options) {
this.customerId = options.customerId;
this.statistical()
},
methods: {
statistical() {
this.$u.get("/matchKeywords/findCARKeywords", {
customerId: this.customerId
}).then(res => {
res.forEach((item, index) => {
if (item.isInterval == 0) {
item.label = item.name + item.unit + '-' + item.endName + item.unit;
item.value = index
} else {
item.label = item.name;
item.value = index
}
})
this.selectlist = res;
})
},
oninputtap() {
this.Showhiddenunits = true;
},
confirm(e) {
let indexs = e[0].value;
this.selectlist.forEach((item, index) => {
if (indexs == item.value) {
this.Semanticword = item.name;
this.keyword = item.matchName;
if (item.isInterval == 0) {
this.qujian = false;
this.Semanticword = item.name + item.unit + '-' + item.endName + item.unit;
} else {
this.qujian = true;
}
}
})
this.searchinfo()
},
tapspagek(i) {
this.roleindex = i;
this.keyword = "";
this.Semanticword = '';
this.qujian = true;
this.listarr = [];
},
formatTime(num) {
//格式化时间格式
num = num.toFixed(0);
let second = num % 60;
if (second < 10) second = '0' + second;
let min = Math.floor(num / 60);
if (min < 10) min = '0' + min;
return min + ":" + second;
},
searchinfo() {
if (this.keyword.length == 0) {
return
} else {
let parames = {
keyword: this.keyword,
customerId: this.customerId
}
this.$u.post("/corpus/keyWordsMatching", parames).then(res => {
res.forEach(item => {
item.Content = JSON.parse(item.transferContent)
})
res.forEach(cet => {
cet.Content.time = this.formatTime(cet.Content.bg / 1000)
if (this.qujian == false) {
cet.Content.text = cet.Content.onebest;
} else {
cet.Content.text = this.brightKeyword(cet.Content.onebest)
}
})
this.listarr = res;
})
}
},
//替换方法
brightKeyword(val) {
if (val.indexOf(this.keyword) !== -1) {
return val.replace(this.keyword, `<font style='color: red'>${this.keyword}</font>`);
} else {
return val;
}
},
//跳转
toaidoinfo(item, id, index) {
uni.setStorageSync("entrance", 2); //写入缓存
item.customerId = this.customerId;
item.id = id;
item.index = index;

let pages = getCurrentPages() //获取当前页面栈的信息
let prevPage = pages[pages.length - 2] //获取上一个页面
prevPage.setData({ //把需要回传的值保存到上一个页面
info: item
});
uni.$emit('Receivedetailabout', item)
wx.navigateBack({ //然后返回上一个页面
delta: 1
})
}
},
}
</script>
<style lang="scss" scoped>
.bosdttom {
border-bottom: 2px solid #2671E2;
}
</style>

+ 2439
- 0
pages/center/Piabodata/Customerportrait/Receivedetailabout.vue
File diff suppressed because it is too large
View File


+ 717
- 0
pages/center/Piabodata/Customerportrait/Receivingrecords.vue View File

@@ -0,0 +1,717 @@
<template>
<view class="cenbox">
<view class="screeningtop">
<view class="screeningview" @click="clickscreening(1)">
<view>近一周</view>
<view class="viewimg">
<image v-if="screeningshow1==false" src="../../../../static/images/down1.png" mode=""></image>
<image v-if="screeningshow1==true" src="../../../../static/images/down2.png" mode=""></image>
</view>
</view>
<view class="screeningview" @click="clickscreening(2)">
<view>客户</view>
<view class="viewimg">
<image v-if="screeningshow2==false" src="../../../../static/images/down1.png" mode=""></image>
<image v-if="screeningshow2==true" src="../../../../static/images/down2.png" mode=""></image>
</view>
</view>
<view class="screeningview" @click="clickscreening(3)">
<view>置业顾问</view>
<view class="viewimg">
<image v-if="screeningshow3==false" src="../../../../static/images/down1.png" mode=""></image>
<image v-if="screeningshow3==true" src="../../../../static/images/down2.png" mode=""></image>
</view>
</view>
<view style="border: none;" class="screeningview" @click="clickscreening(4)">
<view>语义词</view>
<view class="viewimg">
<image v-if="screeningshow4==false" src="../../../../static/images/down1.png" mode=""></image>
<image v-if="screeningshow4==true" src="../../../../static/images/down2.png" mode=""></image>
</view>
</view>
</view>
<view class="zhuti">
<view v-if="tadelist.length!=0" class="cenforview" v-for="(item,index) in tadelist" :key='index' @click="toinfo(item)">
<view class="cenfortop">
<view class="fortopzuo">
<view class="topzuoimg">
<image src="../../../../static/images/userorder.png" mode=""></image>
</view>
</view>
<view class="fortopyou">
<view class="topyouview1">
<view class="youview1-1">{{item.agentName}}</view>
<view class="youview1-2">接待开始时间:{{item.staTime}}</view>
</view>
<view class="topyouview2">客户姓名:{{item.name}}</view>
</view>
</view>
<view class="cenforbottom">
<view class="forbottomview">
<view class="bottomview1">录音时长 (分钟)</view>
<view class="bottomview2">{{item.mm}}分钟</view>
</view>
<view class="forbottomview">
<view class="bottomview1">需求触达次数</view>
<view class="bottomview2">{{item.total}}次</view>
</view>
<view class="forbottomview" style="border: none;">
<view class="bottomview1">接访得分</view>
<view class="bottomview2" v-if="item.fraction==null">0分</view>
<view class="bottomview2" v-else>{{item.fraction}}分</view>
</view>
</view>
</view>
<view v-if="tadelist.length==0" style="width: 100%;height: 100%;display: flex;align-items: center;">
<view style="width: 100%;background: #FFFFFF;padding-top: 200rpx;">
<view style="width: 100%;text-align: center;">
<image style="width: 200rpx;height: 200rpx;" src="https://static.quhouse.com/zhikong_xcx_img/nodatalist.png" mode=""></image>
</view>
<view style="text-align: center;width: 100%;margin-top: 20rpx;color: #999999;">暂无数据</view>
</view>
</view>
</view>
<!-- 1 -->
<view v-if="screeningshow1==true" class="call_zhezhao" @click="allcancel()"></view>
<view v-if="screeningshow1==true" class="timepick">
<view class="tiempickbox">
<view :class="{ timeactive: activetime == 0 }" @click="activetimetab(0)">今日</view>
<view :class="{ timeactive: activetime == 1 }" @click="activetimetab(1)">昨日</view>
<view :class="{ timeactive: activetime == 2 }" @click="activetimetab(2)">近一周</view>
<view :class="{ timeactive: activetime == 3 }" @click="activetimetab(3)">本月</view>
</view>
<view class="tiempickzidingyi" @click="activetimetab(5)">
<text v-if="Datesicing.length==0">自定义时间:请选择</text>
<text v-else>{{Datesicing}}</text>
</view>
</view>
<!-- 2 -->
<view v-if="screeningshow2==true" class="call_zhezhao" @click="allcancel()"></view>
<view v-if="screeningshow2==true" class="userinput">
<view class="inputdlex">
<view class="flexzuo">
<input class="flexinput" @confirm="searchinfo()" v-model="name" type="text" placeholder="请输入客户名" />
</view>
<view class="flexyou" @click="searchinfo()">搜索</view>
</view>
</view>
<!-- 3 -->
<view v-if="screeningshow3==true" class="call_zhezhao" @click="allcancel()"></view>
<view v-if="screeningshow3==true" class="userinput">
<view class="inputdlex">
<view class="flexzuo">
<input class="flexinput" @confirm="searchinfo()" v-model="agentName" type="text" placeholder="请输入顾问名" />
</view>
<view class="flexyou" @click="searchinfo()">搜索</view>
</view>
</view>
<!-- 4 -->
<view v-if="screeningshow4==true" class="call_zhezhao" @click="allcancel()"></view>
<view v-if="screeningshow4==true" class="yuyipick">
<view class="inputdlex">
<!-- <view :class="{ timeactive111: keywordsId == item.keywordsId }" @click="semantictap(index)"
v-for="(item,index) in semanticlist" :key="index">{{item.name}}</view> -->
<view :class="{ timeactive111: item.checked }" @click="itemChcek(index)"
v-for="(item,index) in semanticlist" :key="index">{{item.name}}</view>
</view>
<view class="screen-foot">
<view class="screen-foot-reset" @click="reset">
重置
</view>
<view class="screen-foot-sure" @click="screensure">
确定
</view>
</view>
</view>
<u-calendar v-model="totalTimeShow" mode="range" @change="totalTimeChange"></u-calendar>
</view>
</template>

<script>
var app = getApp();
var util = require("../../../../utils/util.js");
var config = require("../../../../config");
export default {
data() {
return {
screeningshow1:false,
screeningshow2:false,
screeningshow3:false,
screeningshow4:false,
activetime:2,
totalTimeShow:false,
Datesicing:'',
Inthemiddletime:'',
starttime:'',//开始时间
endoftime:'',//结束时间
keywordsId:'',//选中语义词id
houseId:'',//项目id
semanticlist:[],//语义词集合
name:'',
agentName:'',
pageNum:1,
pageSize:10,
tadelist:[],
totalpage:0,
keywordIds:'',
type:0,
customerId: '', // 点击那一项的customerId
};
},
onLoad(options) {
console.log(options)
if(options.datatype==3){
this.activetime=5;
this.starttime=options.starttime;
this.endoftime=options.endoftime;
this.Datesicing=this.starttime+'至'+this.endoftime;
}else{
this.activetime=options.datatype;
this.starttime='';
this.endoftime='';
this.Datesicing='';
}
// this.keywordsId=options.keywordsId
this.keywordIds=options.keywordsId
this.houseId=uni.getStorageSync('buildingID').id;
this.Accesstolevel()
},
onReachBottom() {
if (this.totalpage < this.pageNum * this.pageSize) {
return uni.showToast({
title: "到底了",
})
}
this.pageNum++;
this.getinit();
},
methods: {
toinfo(item){
let parames = {
marketingId: this.keywordIds,
customerId: item.id,
type: '1'
}
this.$u.post("/corpus/pinWordMatching", parames).then(res => {
let items = JSON.parse(res[0].transferContent)
uni.setStorageSync("entrance", 1); //写入缓存
uni.navigateTo({
url: `/pages/center/Piabodata/Customerportrait/Receivedetailabout?customerId=${item.id}&info=${JSON.stringify(items)}`
})
}).catch(e => {
uni.setStorageSync("entrance", 1); //写入缓存
uni.navigateTo({
url: `/pages/center/Piabodata/Customerportrait/Receivedetailabout?customerId=${item.id}`
})
})
},
//搜索
searchinfo(){
this.totalpage=0;
this.tadelist=[];
this.pageNum=1;
this.getinit()
},
itemChcek(index){
this.semanticlist[index].checked=!this.semanticlist[index].checked
this.$forceUpdate()
},
reset(){
this.semanticlist.map(item=>{
item.checked=false
})
this.keywordIds=''
this.$forceUpdate()
this.allcancel()
this.totalpage=0;
this.tadelist=[];
this.pageNum=1;
this.getinit()
},
screensure(){
let arr=[]
this.semanticlist.map(item=>{
if(item.checked){
arr.push(item.keywordsId)
}
})
this.keywordIds=arr.join(',')
// console.log(this.keywordIds)
this.allcancel()
this.totalpage=0;
this.tadelist=[];
this.pageNum=1;
this.getinit()
},
//点击三级
semantictap(index){
this.keywordsId=this.semanticlist[index].keywordsId;
this.allcancel()
this.totalpage=0;
this.tadelist=[];
this.pageNum=1;
this.getinit()
},
//获取列表数据
getinit(){
uni.showToast({
title: '加载中',
icon:'loading',
duration: 1500
});
let datatype='';
if(this.activetime==5){
var parames={
pageNum:this.pageNum,
pageSize:this.pageSize,
query:{
staTime:this.starttime,
endTime:this.endoftime,
time:1,
name:this.name,
agentName:this.agentName,
type:this.type,
keywordIds:this.keywordIds,
// keywordsId:this.keywordsId,
projectId:this.houseId,
}
}
}else{
datatype=this.activetime;
var parames={
pageNum:this.pageNum,
pageSize:this.pageSize,
query:{
dateType:Number(datatype),
staTime:this.starttime,
endTime:this.endoftime,
time:1,
name:this.name,
agentName:this.agentName,
type:0,
keywordIds:this.keywordIds,
// keywordsId:this.keywordsId,
projectId:this.houseId,
}
}
}
this.$u.post("/matchKeywords/receptionRecord", parames).then(data => {
this.type=1;
if(data.results==null){
console.log("没有")
return
}else{
this.tadelist=[...this.tadelist, ...data.results];
this.totalpage=data.totalRecord;
}
})
},
//获取三级
Accesstolevel(){
let datatype='';
if(this.activetime==5){
var parames={
type:0,
statDateStart:this.starttime,
statDateEnd:this.endoftime,
houseId:this.houseId
}
}else{
datatype=this.activetime;
var parames={
type:0,
dateType:Number(datatype),
statDateStart:this.starttime,
statDateEnd:this.endoftime,
houseId:this.houseId
}
}
this.$u.post("/matchKeywords/findKeywords", parames).then(data => {
data.forEach(item=>{
if(item.isInterval==0){
item.name=item.name+item.unit+'-'+item.endName+item.unit
}
if(item.keywordsId==this.keywordIds){
item.checked=true
}else{
item.checked=false
}
})
this.semanticlist=data;
this.getinit();
})
},
//遮罩取消
allcancel(){
this.screeningshow1=false;
this.screeningshow2=false;
this.screeningshow3=false;
this.screeningshow4=false;
},
//自定义时间确认
totalTimeChange(e){
this.Datesicing=e.startDate+'至'+e.endDate;
this.starttime=e.startDate;
this.endoftime=e.endDate;
this.activetime=this.Inthemiddletime;
this.totalTimeShow=false;
this.tadelist=[]
this.allcancel()
this.Accesstolevel()
},
//时间选择
activetimetab(index){
if(index==5){
this.Inthemiddletime=index;
this.totalTimeShow=!this.totalTimeShow;
}else{
this.Datesicing='';
this.activetime=index;
this.tadelist=[]
this.allcancel()
this.Accesstolevel()
}
},
//筛选弹框
clickscreening(i){
if(i==1){
this.screeningshow1=!this.screeningshow1;
this.screeningshow2=false;
this.screeningshow3=false;
this.screeningshow4=false;
}else if(i==2){
this.screeningshow2=!this.screeningshow2;
this.screeningshow1=false;
this.screeningshow3=false;
this.screeningshow4=false;
}else if(i==3){
this.screeningshow3=!this.screeningshow3;
this.screeningshow2=false;
this.screeningshow1=false;
this.screeningshow4=false;
}else{
this.screeningshow4=!this.screeningshow4;
this.screeningshow2=false;
this.screeningshow3=false;
this.screeningshow1=false;
}
}
}
};
</script>
<style lang="scss" scoped>
.timeactive111{
color: #2671E2;
}
*{
margin:0;
padding:0;
box-sizing:border-box;
}
.cenbox{
width: 100%;
height: 100%;
background-color: #F8F8F8;
display:flex;
flex-direction:column;
.screeningtop{
width: 100%;
height: 75rpx;
background-color: #FFFFFF;
border-bottom: 1px solid #E0E0E0;
align-items: center;
display: flex;
align-items: center;
position: relative;
}
.screeningview{
flex: 1;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
border-right: 1px solid #E0E0E0;
}
.zhuti{
flex:1;
// soverflow:auto;
}
}
.viewimg{
width: 20rpx;
height: 100%;
line-height: 72rpx;
margin-left: 10rpx;
image{
width: 20rpx;
height: 12rpx;
}
}
.cenforview{
width: 100%;
height: 275rpx;
background: #FFFFFF;
margin-top: 20rpx;
.cenfortop{
width: 100%;
height: 146rpx;
display: flex;
// border-bottom: 1px solid #E0E0E0;
.fortopzuo{
width: 16%;
padding-top: 30rpx;
.topzuoimg{
width: 60rpx;
height: 60rpx;
margin-left: 30rpx;
border-radius: 50%;
image{
width: 100%;
height: 100%;
}
}
}
.fortopyou{
width: 84%;
height: 146rpx;
.topyouview1{
width: 100%;
margin-top: 28rpx;
display: flex;
.youview1-1{
width: 25%;
font-size: 28rpx;
font-weight: 400;
color: #333333;
overflow: hidden;
white-space:nowrap;
text-overflow:ellipsis;
}
.youview1-2{
width: 75%;
font-size: 26rpx;
font-weight: 400;
color: #666666;
}
}
.topyouview2{
width: 100%;
font-size: 28rpx;
font-weight: 400;
color: #333333;
margin-top: 20rpx;
}
}
}
.cenforbottom{
width: 100%;
height: 128rpx;
display: flex;
align-items: center;
.forbottomview{
flex: 1;
height: 128rpx;
// border-right: 1px solid #E0E0E0;
.bottomview1{
width: 100%;
height: 26rpx;
font-size: 26rpx;
font-weight: 400;
color: #666666;
line-height: 26rpx;
text-align: center;
margin-top: 24rpx;
}
.bottomview2{
width: 100%;
height: 30rpx;
font-size: 30rpx;
font-weight: 600;
color: #333333;
line-height: 30rpx;
text-align: center;
margin-top: 24rpx;
}
}
}
}
.timepick{
width: 100%;
height: 210rpx;
background: #FFFFFF;
position: absolute;
top: 74rpx;
left: 0;
z-index: 20;
.tiempickbox{
width: 94%;
margin: 0 auto;
height: 56rpx;
display: flex;
align-items: center;
margin-top: 25rpx;
}
.tiempickbox>view:nth-of-type(1){
width: 156rpx;
height: 56rpx;
border-radius: 4rpx;
text-align: center;
line-height: 56rpx;
font-size: 28rpx;
border: 1px solid #C9C9C9;
}
.tiempickbox>view:nth-of-type(2){
width: 156rpx;
height: 56rpx;
border-radius: 4rpx;
text-align: center;
line-height: 56rpx;
font-size: 28rpx;
border: 1px solid #C9C9C9;
margin-left: 28rpx;
}
.tiempickbox>view:nth-of-type(3){
width: 156rpx;
height: 56rpx;
border-radius: 4rpx;
text-align: center;
line-height: 56rpx;
font-size: 28rpx;
border: 1px solid #C9C9C9;
margin-left: 28rpx;
}
.tiempickbox>view:nth-of-type(4){
width: 156rpx;
height: 56rpx;
border-radius: 4rpx;
text-align: center;
line-height: 56rpx;
font-size: 28rpx;
border: 1px solid #C9C9C9;
margin-left: 28rpx;
}
.tiempickzidingyi{
width: 94%;
margin: 0 auto;
margin-top: 28rpx;
height: 60rpx;
background: #FFFFFF;
border-radius: 4rpx;
border: 1px solid #C9C9C9;
text-align: center;
line-height: 60rpx;
color: #666666;
}
}
.call_zhezhao {
position: fixed;
width: 100%;
height: 100%;
top: 75rpx;
left: 0rpx;
opacity: 0.5;
background-color: #666666;
z-index: 10;
}
.timeactive{
color: #FFFFFF;
background-color: #2671E2;
}
.userinput{
width: 100%;
height: 126rpx;
background: #FFFFFF;
position: absolute;
top: 74rpx;
left: 0;
z-index: 20;
.inputdlex{
width: 90%;
margin: 0 auto;
height: 56rpx;
display: flex;
align-items: center;
margin-top: 30rpx;
.flexzuo{
width: 80%;
.flexinput{
width: 96%;
height: 100%;
border-radius: 20rpx;
border: 1px solid #C9C9C9;
padding-left: 20rpx;
font-size: 24rpx;
}
}
.flexyou{
width: 20%;
font-size: 28rpx;
color: #2671E2;
text-indent: 28rpx;
}
}
}
.yuyipick{
width: 100%;
min-height: 300rpx;
max-height: 500rpx;
background: #FFFFFF;
overflow-y: auto;
// padding-bottom: 20rpx;
position: absolute;
top: 74rpx;
left: 0;
z-index: 20;
.inputdlex{
width: 90%;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
margin-top: 30rpx;
}
.inputdlex view{
width: 50%;
font-size: 26rpx;
font-weight: 400;
text-align: center;
margin-top: 26rpx;
}
}
.screen-foot{
width: 100%;
height: 88rpx;
display: flex;
margin-top: 20rpx;
border-top: 1px solid #E0E0E0;
.screen-foot-reset{
width: 50%;
text-align: center;
height: 88rpx;
line-height: 88rpx;
font-size: 30rpx;
font-weight: 400;
color: #666666;
}
.screen-foot-sure{
width: 50%;
text-align: center;
line-height: 88rpx;
height: 88rpx;
font-size: 30rpx;
font-weight: 400;
color: #FFFFFF;
background: #2671E2;
}
}
</style>

+ 405
- 0
pages/center/Piabodata/Employeesstatistics.vue View File

@@ -0,0 +1,405 @@
<template>
<view class="box">
<view class="boxtittab">
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 4 }" @click="tabtimetap(4)">近七天</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 5 }" @click="tabtimetap(5)">近15天</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 6 }" @click="tabtimetap(6)">近30天</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 3 }" @click="tabtimetap(3)">自定义</view>
</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1" style="flex: 1;">接待量排名(TOP10)</view>
</view>
<view class="hejisan">
<view class="sanbox1" style="width: 35%;">
<view class="text1-1">合计</view>
<view class="text1-2">{{newlisttabinfo1.total}}</view>
</view>
<view class="sanbox1" style="width: 40%;">
<view class="text1-1">顾问</view>
<view class="text1-2">{{newlisttabinfo1.count}}</view>
</view>
<view class="sanbox1" style="width: 25%;">
<view class="text1-1">人均接待量</view>
<view class="text1-2">{{newlisttabinfo1.avg}}</view>
</view>
</view>
<view class="jindu" style="height: 360rpx;overflow: auto;">
<view v-if="newlisttabinfo1.result.length!=0" class="jindu-box" v-for="(item,index) in newlisttabinfo1.result" :key="index">
<view class="jindu-boxche">
<view class="jindu-name" v-if="item.name">{{item.name.substring(0,4)}}</view>
<view style="width: 440rpx;margin-left: 10rpx;">
<u-line-progress height="24" :show-percent="false" active-color="#FBA448" :percent="item.zxl1"></u-line-progress>
</view>
<view class="jindu-zxl">{{item.zxl==null?0:item.zxl}}</view>
</view>
</view>
<view v-if="newlisttabinfo1.result.length==0" style="width: 100%;text-align: center;margin-top: 60rpx;">
暂无数据
</view>
</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1" style="flex: 1;">销讲执行率排行(TOP10)</view>
</view>
<view class="hejisan">
<view class="sanbox1" style="width: 40%;">
<view class="text1-1">顾问</view>
<view class="text1-2">{{newlisttabinfo3.count}}</view>
</view>
<view class="sanbox1" style="width: 25%;">
<view class="text1-1">人均执行率</view>
<view class="text1-2">{{newlisttabinfo3.avg}}</view>
</view>
</view>
<view class="jindu" style="height: 360rpx;overflow: auto;">
<view v-if="newlisttabinfo3.result.length!=0" class="jindu-box" v-for="(item,index) in newlisttabinfo3.result" :key="index">
<view class="jindu-boxche">
<view class="jindu-name" v-if="item.name">{{item.name.substring(0,4)}}</view>
<view style="width: 440rpx;margin-left: 10rpx;">
<u-line-progress height="24" :show-percent="false" active-color="#FBA448" :percent="item.zxl1"></u-line-progress>
</view>
<view class="jindu-zxl">{{item.zxl==null?0:item.zxl}}</view>
</view>
</view>
<view v-if="newlisttabinfo3.result.length==0" style="width: 100%;text-align: center;margin-top: 60rpx;">
暂无数据
</view>
</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1" style="flex: 1;">录音时长(TOP10)</view>
</view>
<view class="hejisan">
<view class="sanbox1" style="width: 35%;">
<view class="text1-1">合计</view>
<view class="text1-2">{{newlisttabinfo2.total}}</view>
</view>
<view class="sanbox1" style="width: 40%;">
<view class="text1-1">顾问</view>
<view class="text1-2">{{newlisttabinfo2.count}}</view>
</view>
<view class="sanbox1" style="width: 25%;">
<view class="text1-1">人均录音时长</view>
<view class="text1-2">{{newlisttabinfo2.avg}}</view>
</view>
</view>
<view class="jindu" style="height: 360rpx;overflow: auto;">
<view v-if="newlisttabinfo2.result.length!=0" class="jindu-box" v-for="(item,index) in newlisttabinfo2.result" :key="index">
<view class="jindu-boxche">
<view class="jindu-name" v-if="item.name">{{item.name.substring(0,4)}}</view>
<view style="width: 440rpx;margin-left: 10rpx;">
<u-line-progress height="24" :show-percent="false" active-color="#FBA448" :percent="item.zxl1"></u-line-progress>
</view>
<view class="jindu-zxl">{{item.zxl==null?0:item.zxl}}</view>
</view>
</view>
<view v-if="newlisttabinfo2.result.length==0" style="width: 100%;text-align: center;margin-top: 60rpx;">
暂无数据
</view>
</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1" style="flex: 1;">违禁次数排名(TOP10)</view>
</view>
<view class="hejisan">
<view class="sanbox1" style="width: 35%;">
<view class="text1-1">合计</view>
<view class="text1-2">{{newlisttabinfo4.total}}</view>
</view>
<view class="sanbox1" style="width: 40%;">
<view class="text1-1">顾问</view>
<view class="text1-2">{{newlisttabinfo4.count}}</view>
</view>
<view class="sanbox1" style="width: 25%;">
<view class="text1-1">人均违禁次数</view>
<view class="text1-2">{{newlisttabinfo4.avg}}</view>
</view>
</view>
<view class="jindu" style="height: 360rpx;overflow: auto;">
<view v-if="newlisttabinfo4.result.length!=0" class="jindu-box" v-for="(item,index) in newlisttabinfo4.result" :key="index">
<view class="jindu-boxche">
<view class="jindu-name" v-if="item.name">{{item.name.substring(0,4)}}</view>
<view style="width: 440rpx;margin-left: 10rpx;">
<u-line-progress height="24" :show-percent="false" active-color="#FBA448" :percent="item.zxl1"></u-line-progress>
</view>
<view class="jindu-zxl">{{item.zxl==null?0:item.zxl}}</view>
</view>
</view>
<view v-if="newlisttabinfo4.result.length==0" style="width: 100%;text-align: center;margin-top: 60rpx;">
暂无数据
</view>
</view>
</view>
<view v-if="false" style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single" v-if="false">
<view class="title">
<view class="title1" style="flex: 1;">接待未标顾问(TOP10)</view>
</view>
<view class="hejisan">
<view class="sanbox1" style="width: 35%;">
<view class="text1-1">合计</view>
<view class="text1-2">{{newlisttabinfo4.total}}</view>
</view>
<view class="sanbox1" style="width: 40%;">
<view class="text1-1">顾问</view>
<view class="text1-2">{{newlisttabinfo4.count}}</view>
</view>
<view class="sanbox1" style="width: 25%;">
<view class="text1-1">人均违禁次数</view>
<view class="text1-2">{{newlisttabinfo4.avg}}</view>
</view>
</view>
<view class="jindu" style="height: 360rpx;overflow: auto;">
<view v-if="newlisttabinfo4.result.length!=0" class="jindu-box" v-for="(item,index) in newlisttabinfo4.result" :key="index">
<view class="jindu-boxche">
<view class="jindu-name" v-if="item.name">{{item.name.substring(0,4)}}</view>
<view style="width: 440rpx;margin-left: 10rpx;">
<u-line-progress height="24" :show-percent="false" active-color="#FBA448" :percent="item.zxl1"></u-line-progress>
</view>
<view class="jindu-zxl">{{item.zxl==null?0:item.zxl}}</view>
</view>
</view>
<view v-if="newlisttabinfo4.result.length==0" style="width: 100%;text-align: center;margin-top: 60rpx;">
暂无数据
</view>
</view>
</view>
<u-calendar v-model="totalTimeShow" mode="range" @change="totalTimeChange"></u-calendar>
</view>
</template>

<script>
var app = getApp();
var util = require("../../../utils/util.js");
var config = require("../../../config");
export default {
data() {
return {
activeTotal: 4,
totalTimeShow: false,
// 项目id
houseId:'',
lastEndDate:'',
lastStartDate:'',
newlisttabinfo1:{
avg:'',
count:'',
total:'',
result:[],
},
newlisttabinfo2:{
avg:'',
count:'',
total:'',
result:[],
},
newlisttabinfo3:{
avg:'',
count:'',
total:'',
result:[],
},
newlisttabinfo4:{
avg:'',
count:'',
total:'',
result:[],
},
};
},
onLoad() {
// 获取项目id
this.houseId = uni.getStorageSync('buildingID').id;
this.init()
},
onPullDownRefresh() {
this.init()
setTimeout(function () {
uni.stopPullDownRefresh();
}, 1000);
},
methods: {
init(){
this.newlisttabinfo1={
avg:'',
count:'',
total:'',
result:[],
},
this.newlisttabinfo2={
avg:'',
count:'',
total:'',
result:[],
},
this.newlisttabinfo3={
avg:'',
count:'',
total:'',
result:[],
},
this.newlisttabinfo4={
avg:'',
count:'',
total:'',
result:[],
}
var activeTotal=0;
if(this.activeTotal==3){
activeTotal=null;
}else{
activeTotal=this.activeTotal;
this.lastEndDate='';
this.lastStartDate='';
}
var promse={
timeType:activeTotal,
lastStartDate:this.lastStartDate,
lastEndDate:this.lastEndDate,
houseId:this.houseId
}
this.staffStatisticsReceptionTop10(promse)
this.staffStatisticsRecordingTimTop10(promse)
this.staffStatisticsExecutionRateTop10(promse)
this.staffStatisticsProhibitedTop10(promse)
},
//接待量排名
staffStatisticsReceptionTop10(promse){
this.$u.post('/cusLvStatistics/staffStatisticsReceptionTop10',promse).then(res=>{
res.result.forEach(item=>{
item.zxl=item.data
item.name=item.accountName
})
res.result=this.dealData(res.result)
this.newlisttabinfo1=res;
})
},
//录音时长
staffStatisticsRecordingTimTop10(promse){
this.$u.post('/cusLvStatistics/staffStatisticsRecordingTimTop10',promse).then(res=>{
res.result.forEach(item=>{
item.zxl=item.data
item.name=item.accountName
})
res.result=this.dealData(res.result)
this.newlisttabinfo2=res;
})
},
//销讲
staffStatisticsExecutionRateTop10(promse){
this.$u.post('/cusLvStatistics/staffStatisticsExecutionRateTop10',promse).then(res=>{
res.result.forEach(item=>{
item.zxl=item.data;
item.zxl1=item.data;
item.name=item.accountName
})
this.newlisttabinfo3=res;
})
},
//j禁忌
staffStatisticsProhibitedTop10(promse){
this.$u.post('/cusLvStatistics/staffStatisticsProhibitedTop10',promse).then(res=>{
res.result.forEach(item=>{
item.zxl=item.data
item.name=item.accountName
})
res.result=this.dealData(res.result)
this.newlisttabinfo4=res;
})
},
//自定义时间
totalTimeChange(e) {
console.log(e.startDate, e.endDate)
this.activeTotal=3;
this.lastEndDate=e.endDate
this.lastStartDate=e.startDate
this.init()
},
//时间切换
tabtimetap(index) {
if (index == 3) {
this.totalTimeShow = true;
} else {
this.activeTotal = index;
this.lastEndDate='';
this.lastStartDate='';
this.init()
}
},
// 定义一个公共方法对数据进行处理
dealData(arr){
// 获取最大值
let num=Math.max.apply(Math, arr.map(function (o) { return o.zxl })) //结果:3
// console.log(num)
// if(num>100){
// // 获取最大值的下标
// // let idx=arr.findIndex(item=>item.zxl==num)
// // console.log(idx,123)
// arr.map(item=>{
// item.zxl1=Math.floor(item.zxl/num*100)
// })
// // console.log(arr)
// return arr
// }else{
// arr.map(item=>{
// item.zxl1=item.zxl
// })
// return arr
// }
arr.map(item=>{
item.zxl1=Math.floor(item.zxl/num*100)
})
return arr
},
}
};
</script>
<style lang="scss" scoped>
.box {
width: 100%;
height: 100%;
background: #FAFAFA;
padding-bottom: 60rpx;
}
.hejisan{
width: 92%;
margin: 0 auto;
display: flex;
padding-top: 20rpx;
padding-bottom:20rpx;
.text1-1{
color: #666666;
}
.text1-2{
color: #333333;
margin-top: 10rpx;
}
}
</style>

+ 495
- 0
pages/center/Piabodata/Groupcontrast.vue View File

@@ -0,0 +1,495 @@
<template>
<view class="box">
<view class="boxtittab">
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 4 }" @click="tabtimetap(4)">近七天</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 5 }" @click="tabtimetap(5)">近15天</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 6 }" @click="tabtimetap(6)">近30天</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 3 }" @click="tabtimetap(3)">自定义</view>
</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1">接待量(TOP10)</view>
</view>
<view class="hejibox">
<view class="heji">项目:{{newTeam1||0}}</view>
<view class="heji">均值:{{newAvg1||0}}</view>
</view>
<view class="jindu">
<scroll-view style="height: 300rpx;" scroll-y="true" >
<view class="jindu-box" v-for="(item,index) in newlisttabinfo1" :key="index">
<view class="jindu-boxche">
<view class="jindu-name">{{item.name.substring(0, 4)}}</view>
<view style="width: 440rpx;margin-left: 10rpx;">
<u-line-progress height="24" :show-percent="false" active-color="#FBA448" :percent="item.zxl1"></u-line-progress>
</view>
<view class="jindu-zxl">{{item.zxl==null?0:item.zxl}}</view>
</view>
</view>
</scroll-view>
</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1">接待时长(TOP10)</view>
</view>
<view class="hejibox">
<view class="heji">项目:{{newTeam2||0}}</view>
<view class="heji">均值:{{newAvg2||0}}</view>
</view>
<view class="jindu">
<scroll-view style="height: 300rpx;" scroll-y="true" >
<view class="jindu-box" v-for="(item,index) in newlisttabinfo2" :key="index">
<view class="jindu-boxche">
<view class="jindu-name">{{item.name.substring(0, 4)}}</view>
<view style="width: 440rpx;margin-left: 10rpx;">
<u-line-progress height="24" :show-percent="false" active-color="#4FC78F" :percent="item.zxl1"></u-line-progress>
</view>
<view class="jindu-zxl">{{item.zxl==null?0:item.zxl}}</view>
</view>
</view>
</scroll-view>
</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1" style="flex: 1;">销讲执行排名(TOP10)</view>
<!-- <view class="title3" style="flex: 1;">
<view class="title3-box">
<view style="height: 42rpx;" :class="{ activecltab: activeTotal2 == 0 }">执行率</view>
</view>
<view class="title3-box">
<view style="height: 42rpx;" :class="{ activecltab: activeTotal2 == 1 }">得分</view>
</view>
</view> -->
</view>
<view class="hejibox">
<view class="heji">项目:{{newTeam3||0}}</view>
<view class="heji">均值:{{newAvg3||0}}%</view>
</view>
<view class="jindu">
<scroll-view style="height: 300rpx;" scroll-y="true" >
<view class="jindu-box" v-for="(item,index) in newlisttabinfo3" :key="index">
<view class="jindu-boxche">
<view class="jindu-name">{{item.name.substring(0, 4)}}</view>
<view style="width: 440rpx;margin-left: 10rpx;">
<u-line-progress height="24" :show-percent="false" active-color="#9B6BDF" :percent="item.zxl1"></u-line-progress>
</view>
<view class="jindu-zxl">{{item.zxl==null?0:item.zxl}}%</view>
</view>
</view>
</scroll-view>
</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1" style="flex: 1;">顾问执行排名(TOP10)</view>
<!-- <view class="title3" style="flex: 1;">
<view class="title3-box">
<view style="height: 42rpx;" :class="{ activecltab: activeTotal2 == 0 }">执行率</view>
</view>
<view class="title3-box">
<view style="height: 42rpx;" :class="{ activecltab: activeTotal2 == 1 }">得分</view>
</view>
</view> -->
</view>
<!-- <view class="hejibox">
<view class="heji">项目:{{newTeam4||0}}</view>
<view class="heji">均值:{{newAvg4||0}}</view>
</view> -->
<view class="jindu">
<scroll-view style="height: 300rpx;" scroll-y="true" >
<view class="jindu-box" v-for="(item,index) in newlisttabinfo4" :key="index">
<view class="jindu-boxche">
<view class="jindu-name">{{item.name.substring(0, 4)}}</view>
<view style="width: 440rpx;margin-left: 10rpx;">
<u-line-progress height="24" :show-percent="false" active-color="#9B6BDF" :percent="item.zxl1"></u-line-progress>
</view>
<view class="jindu-zxl">{{item.zxl==null?0:item.zxl}}%</view>
</view>
</view>
</scroll-view>

</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title" style="padding-right: 30rpx;">
<view class="title1" style="flex: 1;">销讲能力</view>
<!-- <view class="title2" style="flex: 1;justify-content: flex-end;" @click="Groupcontrast">
<view class="title2-che">项目
<image class="righttochoose" src="../../../static/images/righttochoose.png" mode=""></image>
</view>
</view> -->
<view class="title2" style="flex: 1;justify-content: flex-end;" @click="staffShow=true">
<view class="title2-che" style="width: auto;"><text style="margin-right: 40rpx;">{{staff.label}}</text>
<image class="righttochoose" src="../../../static/images/righttochoose.png" mode=""></image>
</view>
</view>
</view>
<!-- <view class="hejibox">
<view class="heji">项目:50</view>
<view class="heji">均值:25</view>
</view> -->
<view class="uchaserbox">
<qiun-data-charts
type="radar"
:opts="opts"
:chartData="chartData"
:canvas2d="true"
canvasId="wangxiaohuaerlingeryilingwuyib88"
background="none"
/>
</view>
</view>
<!-- <view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1">禁忌执行率(TOP10)</view>
</view>
<view class="hejibox">
<view class="heji">合计:50</view>
<view class="heji">均值:25</view>
</view>
<view class="jindu">
<view class="jindu-box" v-for="(item,index) in newlisttabinfo" :key="index">
<view class="jindu-boxche">
<view class="jindu-name">{{item.name.substring(0, 4)}}</view>
<view style="width: 440rpx;margin-left: 10rpx;">
<u-line-progress height="24" :show-percent="false" active-color="#E6625B" :percent="item.zxl"></u-line-progress>
</view>
<view class="jindu-zxl">{{item.zxl==null?0:item.zxl}}%</view>
</view>
</view>
</view>
</view> -->
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<!-- <view class="single">
<view class="title" style="padding-right: 30rpx;">
<view class="title1" style="flex: 1;">违禁能力(TOP10)</view>
<view class="title2" style="flex: 1;justify-content: flex-end;">
<view class="title2-che">项目
<image class="righttochoose" src="../../../static/images/righttochoose.png" mode=""></image>
</view>
</view>
</view>
<view class="hejibox">
<view class="heji">合计:50</view>
<view class="heji">均值:25</view>
</view>
<view class="uchaserbox">
<qiun-data-charts
type="radar"
:chartData="chartData"
:canvas2d="true"
canvasId="wangxiaohuaerlingeryilingwuyib89"
background="none"
/>
</view>
</view> -->
<u-calendar v-model="totalTimeShow" mode="range" @change="totalTimeChange"></u-calendar>
<!-- 选择项目 -->
<u-select v-model="staffShow" :list="staffList" @confirm="staffSelectCallback" :default-value='selindex'></u-select>
</view>
</template>

<script>
var app = getApp();
var util = require("../../../utils/util.js");
var config = require("../../../config");
export default {
data() {
return {
activeTotal: 4,
activeTotal2: 0,
bocindex:0,
totalTimeShow: false,
// 项目id
houseId:'',
staffShow:false,
staffList:[],
lastStartDate:'',
lastEndDate :'',
newTeam1:'',
newAvg1:'',
newTeam2:'',
newAvg2:'',
newTeam3:'',
newAvg3:'',
newTeam4:'',
newAvg4:'',
staff:{
value:'',
label:''
},
newlisttabinfo1:[
{name:'接待量',zxl:'10'},
{name:'平均执行率',zxl:'50'},
{name:'接待客户',zxl:'80'},
],
newlisttabinfo2:[
{name:'接待量',zxl:'10'},
{name:'平均执行率',zxl:'50'},
{name:'接待客户',zxl:'80'},
],
newlisttabinfo3:[
{name:'接待量',zxl:'10'},
{name:'平均执行率',zxl:'50'},
{name:'接待客户',zxl:'80'},
],
newlisttabinfo4:[
{name:'接待量',zxl:'10'},
{name:'平均执行率',zxl:'50'},
{name:'接待客户',zxl:'80'},
],
chartData:{
"categories": ["维度1","维度2","维度3","维度4","维度5","维度6"],
"series": [
{
"name": "成交量",
"data": [90,110,165,195,187,172]
}
]
},
opts: {
fontSize: 10,
extra: {
radar: {
max: ''
}
}
}
};
},
onLoad() {
let that=this
uni.$on('updateGroup',function(data){
console.log(data)
that.houseId=data.arr.join(',')
// 获取销奖能力
that.getPowerList()
})
this.getSectionList()
},
onPullDownRefresh(){
let that=this
uni.$on('updateGroup',function(data){
console.log(data)
that.houseId=data.arr.join(',')
// 获取销奖能力
that.getPowerList()
})
this.getSectionList()
setTimeout(function () {
uni.stopPullDownRefresh();
}, 1000);
},
methods: {
// 获取部门列表
getSectionList(){
this.$u.post('/user/getHouseByToken',)
.then(res=>{
// console.log(res)
this.staffList=[]
res.map((item,index)=>{
let obj={}
obj.value=item.id
obj.label=item.propertyName
this.staffList.push(obj)
})
this.houseId=this.staffList[0].value
this.staff=this.staffList[0]
this.getdata()
// console.log(this.staffList,this.staffList,this.houseId)
})
},
//指标执行率分析tab
tapspagek2(index) {
this.bocindex = index;
},
staffSelectCallback(e){
this.staff=e[0]
this.houseId=e[0].value
this.getPowerList()
},
getdata(){
// 请求接口获取接待量
this.receptionCountList('1','/cusLvStatistics/groupComparisonReception')
// 接待时长
this.receptionCountList('2','/cusLvStatistics/groupComparisonReceptionTime')
// 小将排名
this.receptionCountList('3','/cusLvStatistics/groupComparisonTalkRank')
// 顾问牌名
this.receptionCountList('4','/cusLvStatistics/groupComparisonTalkRankByConsultant')
// 销奖能力
this.getPowerList()
},
//时间切换
tabtimetap(index) {
if (index == 3) {
this.totalTimeShow = true;
} else {
this.activeTotal = index;
this.lastEndDate=''
this.lastStartDate=''
this.getdata()
// // 获取数据
// // 团队对比接待量
// this.receptionCountList(0,1,'/cusLvStatistics/teamAnalysisReception')
// // 团队对比接待时长
// this.receptionCountList(0,2,'/cusLvStatistics/teamAnalysisReceptionTime')
// /* 销奖执行率 */
// this.receptionCountList(0,3,'/cusLvStatistics/teamAnalysisExecutionRate')
// // 获取销奖能力
// this.getPowerList()
}
},
// 接待时长
receptionCountList(index,url){
this.$u.post(url,{
timeType:this.lastEndDate?null:this.activeTotal+'',
lastEndDate:this.lastEndDate,
lastStartDate:this.lastStartDate
})
.then(res=>{
// console.log(res)
let result=res.result
this['newTeam'+index]=res.avg[0]
this['newAvg'+index]=res.avg[1]
// return
// 处理数据
// 先处理牌名数据,需要进行判断全部还是单个
// 当为全部时
this['newlisttabinfo'+index]=[]
// 当选择全部时
let arr=[]
// 当两个都选择的时候
result.map(item=>{
let obj={}
obj.name=item.houseName
obj.zxl=item.data
arr.push(obj)
})
arr=this.dealData(arr)
this['newlisttabinfo'+index]=arr
})
},
// 获取销奖能力
getPowerList(){
this.$u.post('/cusLvStatistics/groupComparisonMarketingAbility',{
houseIds:this.houseId,
timeType:this.lastEndDate?null:this.activeTotal+'',
lastEndDate:this.lastEndDate,
lastStartDate:this.lastStartDate
})
.then(res=>{
// console.log(res,123)
// 处理数据
// return
this.chartData={
categories:[],
series:[]
}
let allobj={
categories:[],
series:[]
}
let max = 0;
res.result.map((item,index)=>{
let obj={
name:item[0].houseName,
data:[]
}
item.map(item1=>{
if(index==0){
allobj.categories.push(item1.name)
}
obj.data.push(item1.avgExecutionRate)
if (max < item1.avgExecutionRate) max = item1.avgExecutionRate;
})
allobj.series.push(obj)
})
// console.log(allobj)
this.opts.extra.radar.max = max + 25
this.chartData=allobj
this.$forceUpdate()
})
},
//自定义时间
totalTimeChange(e) {
console.log(e.startDate, e.endDate)
this.activeTotal=3;
this.lastEndDate=e.endDate
this.lastStartDate=e.startDate
this.getdata()
},
//集团对比
Groupcontrast(){
uni.navigateTo({
url: `/pages/center/Piabodata/selectGroup?ids=${this.houseId}`
});
},
// 定义一个公共方法对数据进行处理
dealData(arr){
// 获取最大值
let num=Math.max.apply(Math, arr.map(function (o) { return o.zxl })) //结果:3
// console.log(num)
if(num>100){
// 获取最大值的下标
// let idx=arr.findIndex(item=>item.zxl==num)
// console.log(idx,123)
arr.map(item=>{
item.zxl1=Math.floor(item.zxl/num*100)
})
// console.log(arr)
return arr
}else{
arr.map(item=>{
item.zxl1=item.zxl
})
return arr
}
},
}
};
</script>
<style lang="scss" scoped>
.box {
width: 100%;
height: 100%;
background: #FAFAFA;
padding-bottom: 60rpx;
}
</style>

+ 642
- 0
pages/center/Piabodata/StaffAnalysis.vue View File

@@ -0,0 +1,642 @@
<template>
<view>
<view class="boxtittab">
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 4 }" @click="tabtimetap(4)">近七天</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 5 }" @click="tabtimetap(5)">近15天</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 6 }" @click="tabtimetap(6)">近30天</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 3 }" @click="tabtimetap(3)">自定义</view>
</view>
</view>
<view class="timepick">
<view class="timepicktime" @click="chiocStaff(0)">
<view>{{staff1.label}}</view>
<view>
<image class="Underimg" src="../../../static/images/Underimg.png" mode=""></image>
</view>
</view>
<view class="timepickpick">
<view @click="checkboxChange()" style="width: 40rpx;height:40rpx;border: 1rpx solid #E0E0E0;">
<image v-if="timepickpickisshow" style="width: 40rpx;height: 40rpx;" src="../../../static/images/xuanzhong.png" mode=""></image>
</view>
<view style="font-size:26rpx;text-indent: 12rpx;">对比</view>
</view>
<view class="timepicktime" v-if="timepickpickisshow" @click="chiocStaff(1)">
<view>{{staff2.label}}</view>
<view>
<image class="Underimg" src="../../../static/images/Underimg.png" mode=""></image>
</view>
</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1" style="flex: 1;">接待量</view>
</view>
<view class="hejibox">
<view class="heji">{{staff1.label}}:{{newTeam1||0}}</view>
<view class="heji" v-if="timepickpickisshow">{{staff2.label}}:{{newAvg1||0}}</view>
</view>
<view class="danwei">来访(人)</view>
<view class="uchaserbox">
<qiun-data-charts
type="line"
:chartData="lineOptsect"
background="none"
:ontouch="true"
canvasId="wangxiaohuaerlingeryilingwuyibbb"
:canvas2d="true"
/>
</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1" style="flex: 1;">录音时长</view>
<view class="title3" style="flex: 1;">
<!-- <view class="title3-box" style="width: 40%;" @click="tabtimetap1(0)">
<view style="height: 42rpx;" :class="{ activecltab: activeTotal2 == 0 }">有效录音</view>
</view>
<view class="title3-box" style="width: 40%;"@click="tabtimetap1(1)">
<view style="height: 42rpx;" :class="{ activecltab: activeTotal2 == 1 }">录音时长</view>
</view> -->
</view>
</view>
<view class="hejibox">
<view class="heji">{{staff1.label}}:{{newTeam2||0}}</view>
<view class="heji" v-if="timepickpickisshow">{{staff2.label}}:{{newAvg2||0}}</view>
</view>
<view class="danwei">录音时长</view>
<view class="uchaserbox">
<qiun-data-charts
type="line"
:chartData="lineOptsect1"
background="none"
:ontouch="true"
canvasId="wangxiaouaerlingeryilingwuyibhh"
:canvas2d="true"
/>
</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1" style="flex: 1;">销讲执行率</view>
<view class="title3" style="flex: 1;">
<!-- <view class="title3-box" style="width: 40%;" @click="tabtimetap1(0)">
<view style="height: 42rpx;" :class="{ activecltab: activeTotal2 == 0 }">有效录音</view>
</view>
<view class="title3-box" style="width: 40%;"@click="tabtimetap1(1)">
<view style="height: 42rpx;" :class="{ activecltab: activeTotal2 == 1 }">录音时长</view>
</view> -->
</view>
</view>
<view class="hejibox">
<view class="heji">{{staff1.label}}:{{newTeam3||0}}</view>
<view class="heji" v-if="timepickpickisshow">{{staff2.label}}:{{newAvg3||0}}</view>
</view>
<!-- <view class="danwei">录音时长</view> -->
<view class="uchaserbox">
<qiun-data-charts
type="line"
:chartData="lineOptsect2"
background="none"
:ontouch="true"
canvasId="wangxiaohuaerlingryilingwuyibhh"
:canvas2d="true"
:opts="lineOpts"
/>
</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title" style="padding-right: 30rpx;">
<view class="title1" style="flex: 1;">销讲能力</view>
</view>
<view class="uchaserbox" style="height: 70vh;">
<qiun-data-charts
type="radar"
:chartData="chartData"
:canvas2d="true"
canvasId="wangxiaohuaerlingeryilinwuycsdx"
background="none"
:opts="opts"
/>
</view>
</view>
<!-- <u-calendar v-model="totalTimeShow" mode="range" @change="totalTimeChange"></u-calendar> -->
<u-calendar v-model="totalTimeShow" mode="range" @change="totalTimeChange"></u-calendar>
<!-- 选择客户的选择框 -->
<u-select v-model="staffShow" :list="staffList" @confirm="staffSelectCallback" :default-value='selindex'></u-select>
<u-select v-model="staffShow1" :list="staffList1" @confirm="staffSelectCallback" :default-value='selindex'></u-select>
</view>
</template>
<script>
export default {
data() {
return {
timepickpickisshow:true,
totalTimeShow: false,
activeTotal:4,
activeTotal2:1,
// 项目id
houseId:'',
staffList:[],
staffList1:[],
staffShow:false,
staffShow1:false,
newTeam1:'',
newAvg1:'',
newTeam2:'',
newAvg2:'',
newTeam3:'',
newAvg3:'',
staff1:{
value:'',
label:''
},
staff2:{
value:'',
label:'平均'
},
lineOpts: {
yAxis: {
data: [
{
max: 100,
min: 0,
}
]
}
},
opts: {
fontSize: 10,
extra: {
radar: {
max: ''
}
}
},
lastStartDate:'',
lastEndDate :'',
selindex:[0],
choseStaffFlag:false,
lineOptsect:{
"categories": ["2016","2017","2018","2019","2020","2021"],
"series": [
{
"name": "成交量1",
"data": [35,8,25,37,4,20]
},
{
"name": "成交量2",
"data": [40,18,45,44,10,60]
}
]
},
lineOptsect1:{
"categories": ["2016","2017","2018","2019","2020","2021"],
"series": [
{
"name": "成交量1",
"data": [35,8,25,37,4,20]
},
{
"name": "成交量2",
"data": [40,18,45,44,10,60]
}
]
},
lineOptsect2:{
"categories": ["2016","2017","2018","2019","2020","2021"],
"series": [
{
"name": "成交量1",
"data": [35,8,25,37,4,20]
},
{
"name": "成交量2",
"data": [40,18,45,44,10,60]
}
]
},
chartData:{
"categories": ["维度1","维度2","维度3","维度4","维度5","维度6"],
"series": [
{
"name": "成交量",
"data": [90,110,165,195,187,172]
}
]
}
};
},
onLoad: function(options) {
// 获取项目id
this.houseId = uni.getStorageSync('buildingID').id;
// this.buildingname = uni.getStorageSync('buildingID').name;
// 请求接口获取所有置业顾问员工的列表
this.getStaffList()
},
onPullDownRefresh() {
this.getStaffList()
setTimeout(function () {
uni.stopPullDownRefresh();
}, 1000);
},
methods: {
//是否对比
checkboxChange(){
this.timepickpickisshow=!this.timepickpickisshow;
this.staff2.value=''
this.staff2.label='平均'
// this.getreception()
// this.getRecordList()
// this.getAwardList()
// this.getAward()
this.getdata()
},
// 点击员工对比
chiocStaff(idx){
if(idx==0){
// 当选择了第一个的时候
this.choseStaffFlag=false
this.staffShow=true
}else{
this.choseStaffFlag=true
this.staffShow1=true
}
},
// 获取员工列表
getStaffList(){
this.$u.post('/cusLvStatistics/selectAllAccountIdByHouseId',{houseId:this.houseId})
.then(res=>{
// console.log(res,'123')
this.staffList=[]
this.staffList1=[]
res.map(item=>{
let obj={}
obj.value=item.accountId
obj.label=item.name
this.staffList.push(obj)
})
this.staffList1=[...this.staffList]
this.staffList1.unshift({
value:'',
label:'平均'
})
this.staff1=this.staffList[0]
// this.getreception()
// this.getRecordList()
// this.getAwardList()
// this.getAward()
this.getdata()
})
},
getdata(){
this.getreception()
this.getRecordList()
this.getAward()
this.getAwardList()

},
// 获取接待量数据
getreception(){
this.$u.post('/cusLvStatistics/employeeAnalysisReception',{
userA:this.staff1.value,
userB:this.staff2.value,
houseId:this.houseId,
timeType:this.lastEndDate?null:this.activeTotal+'',
lastEndDate:this.lastEndDate,
lastStartDate:this.lastStartDate
})
.then(res=>{
this.newTeam1=res.avg[0]
this.newAvg1=res.avg[1]
// console.log(res)
let first=res.first
let second=res.second
this.lineOptsect.categories=[]
if(!this.timepickpickisshow){
this.lineOptsect.series=[
{
name:first[0].accountName,
data:[]
}
]
first.map(item=>{
this.lineOptsect.categories.push(item.statDate.slice(5,10))
this.lineOptsect.series[0].data.push(item.receptionCount||0)
})
}else{
this.lineOptsect.series=[
{
name:first[0].accountName,
data:[]
},
{
"name": second[0].accountName,
"data": []
}
]
first.map(item=>{
this.lineOptsect.categories.push(item.statDate.slice(5,10))
this.lineOptsect.series[0].data.push(item.receptionCount)
})
second.map(item=>{
this.lineOptsect.series[1].data.push(item.receptionCount)
})
}
// console.log(this.lineOptsect,'1')
})
},
// 销奖趋势
getAward(){
this.$u.post('/cusLvStatistics/employeeAnalysisExacutiveRate',{
userA:this.staff1.value,
userB:this.staff2.value,
houseId:this.houseId,
timeType:this.lastEndDate?null:this.activeTotal+'',
lastEndDate:this.lastEndDate,
lastStartDate:this.lastStartDate
})
.then(res=>{
this.newTeam3=res.avg[0]
this.newAvg3=res.avg[1]
// console.log(res)
let first=res.first
let second=res.second
this.lineOptsect2.categories=[]
if(!this.timepickpickisshow){
this.lineOptsect2.series=[
{
name:first[0].accountName,
data:[]
}
]
first.map(item=>{
// console.log(item)
this.lineOptsect2.categories.push(item.statDate.slice(5,10))
this.lineOptsect2.series[0].data.push(item.sumFraction)
})
}else{
this.lineOptsect2.series=[
{
name:first[0].accountName,
data:[]
},
{
"name": second[0].accountName,
"data": []
}
]
first.map(item=>{
this.lineOptsect2.categories.push(item.statDate.slice(5,10))
this.lineOptsect2.series[0].data.push(item.sumFraction)
})
second.map(item=>{
this.lineOptsect2.series[1].data.push(item.sumFraction)
})
}
// console.log(this.lineOptsect2,'3')
})
},
// 获取有效录音
async getRecordList(){
// 当选择有效录音时
let res=null
if(this.activeTotal2==0){
res= await this.$u.post('/cusLvStatistics/employeeAnalysisEffectiveRecording',{
userA:this.staff1.value,
userB:this.staff2.value,
houseId:this.houseId,
timeType:this.lastEndDate?null:this.activeTotal+'',
lastEndDate:this.lastEndDate,
lastStartDate:this.lastStartDate
})
}else{
res= await this.$u.post('/cusLvStatistics/employeeAnalysisRecordingTime',{
userA:this.staff1.value,
userB:this.staff2.value,
houseId:this.houseId,
timeType:this.lastEndDate?null:this.activeTotal+'',
lastEndDate:this.lastEndDate,
lastStartDate:this.lastStartDate
})
}
// console.log(res)
this.newTeam2=res.avg[0]
this.newAvg2=res.avg[1]
let first=res.first
let second=res.second
this.lineOptsect1.categories=[]
if(!this.timepickpickisshow){
this.lineOptsect1.series=[
{
name:first[0].accountName,
data:[]
}
]
first.map(item=>{
this.lineOptsect1.categories.push(item.statDate.slice(5,10))
this.lineOptsect1.series[0].data.push(item.sumDuration)
})
}else{
this.lineOptsect1.series=[
{
name:first[0].accountName,
data:[]
},
{
"name": second[0].accountName,
"data": []
}
]
first.map(item=>{
this.lineOptsect1.categories.push(item.statDate.slice(5,10))
this.lineOptsect1.series[0].data.push(item.sumDuration)
})
second.map(item=>{
this.lineOptsect1.series[1].data.push(item.sumDuration)
})
}
// console.log(this.lineOptsect1,'2')
},
// 获取销奖能力
getAwardList(){
this.$u.post('/cusLvStatistics/employeeAnalysisLevel1Fraction',{
userA:this.staff1.value,
userB:this.staff2.value,
houseId:this.houseId,
timeType:this.lastEndDate?null:this.activeTotal+'',
lastEndDate:this.lastEndDate,
lastStartDate:this.lastStartDate
})
.then(res=>{
// console.log(res)
let first=res.first
let second=res.second
let max = first[0].avgExecutionRate
this.chartData.categories=[]
if(!this.timepickpickisshow){
this.chartData.series=[
{
name:first[0].accountName,
data:[]
}
]
first.map(item=>{
if (max < item.avgExecutionRate) max = item.avgExecutionRate;
this.chartData.categories.push(item.name)
this.chartData.series[0].data.push(item.avgExecutionRate)
})
}else{
this.chartData.series=[
{
name:first[0].accountName,
data:[]
},
{
"name": second[0].accountName,
"data": []
}
]
first.map(item=>{
this.chartData.categories.push(item.name)
this.chartData.series[0].data.push(item.avgExecutionRate)
})
second.map(item=>{
this.chartData.series[1].data.push(item.avgExecutionRate)
})
let all = [...first, ...second]
all.map(item => {
if (max < item.avgExecutionRate) max = item.avgExecutionRate;
})
}
this.opts.extra.radar.max = max + 25
})
},
tabtimetap(index){
if (index == 3) {
this.totalTimeShow = true;
} else {
this.activeTotal = index;
this.lastEndDate=''
this.lastStartDate=''
// 获取数据
// this.getreception()
// this.getRecordList()
// this.getAwardList()
this.getdata()
}
},
tabtimetap1(index){
this.activeTotal2 = index;
// 调用方法
this.getRecordList()
},
//自定义时间
totalTimeChange(e) {
console.log(e.startDate, e.endDate)
this.activeTotal=3;
this.lastEndDate=e.endDate
this.lastStartDate=e.startDate
// 获取数据
// this.getreception()
// this.getRecordList()
// this.getAwardList()
this.getdata()
},
staffSelectCallback(e){
if(this.choseStaffFlag){
// 第二个客户
// console.log(e,'第二个')
this.staff2=e[0]
}else{
// 第一个客户
// console.log(e,'第一个')
this.staff1=e[0]
}
if(this.staff1.label==this.staff2.label){
uni.showToast({
title:'请勿选择重复',
icon:'none'
})
this.staff2.label='请选择'
// this.staff2.label='平均'
// this.staff2.value=''
return
}else{
// 获取数据
// this.getreception()
// this.getRecordList()
// this.getAwardList()
this.getdata()
}
},
},
}
</script>
<style lang="scss" scoped>
// 对比时间切换
.timepick{
width: 100%;
height: 90rpx;
display: flex;
align-items: center;
background: #FAFAFA;
}
.timepicktime{
width: 260rpx;
height: 50rpx;
border: 1rpx solid #E0E0E0;
margin-left: 30rpx;
display: flex;
background: #FFFFFF;
}
.timepicktime>view:nth-of-type(1){
width: 210rpx;
height: 100%;
line-height: 50rpx;
font-size: 26rpx;
font-weight: 400;
text-align: center;
}
.timepicktime>view:nth-of-type(2){
width: 49rpx;
height: 100%;
// border-left: 1px solid #E0E0E0;
}
.timepickpick{
width: 110rpx;
height: 50rpx;
margin-left: 30rpx;
display: flex;
align-items: center;
}
.Underimg{
width: 50rpx;
height:50rpx;
margin-top: -2rpx;
}
</style>

+ 1131
- 0
pages/center/Piabodata/Theteamcompared.vue
File diff suppressed because it is too large
View File


+ 1414
- 0
pages/center/Piabodata/TrendAnalysis.vue
File diff suppressed because it is too large
View File


+ 479
- 0
pages/center/Piabodata/Userinsightinto.vue View File

@@ -0,0 +1,479 @@
<template>
<view class="box">
<view class="boxtittab">
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 0 }" @click="tabtimetap(0)">今日</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 1 }" @click="tabtimetap(1)">昨日</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 2 }" @click="tabtimetap(2)">近一周</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 3 }" @click="tabtimetap(3)">自定义</view>
</view>
</view>
<view class="boxzonglan">
<view class="zonglantit">客群特征总览</view>
<view class="zonglanbox">
<view class="grid" v-for="(item,index) in numlist" :key="index" v-if="item.isshow">
<view class="audonum">{{item.name}}<text v-if="index!=0">触达次数</text></view>
<view class="num">{{item.num}}</view>
</view>
</view>
<view v-if="Afolding==true" class="anclack" @click="anclick(1)">展开 <u-icon style="margin-left: 8rpx;" label-color='#666666' name="arrow-down"></u-icon></view>
<view v-if="Afolding==false" class="anclack" @click="anclick(2)">收起 <u-icon style="margin-left: 8rpx;" label-color='#666666' name="arrow-up"></u-icon></view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="centerfor" v-for="(item,index) in objlist" :key="index">
<view class="fortit">
<view class="left">
<view class="lefti"></view>
<view class="lefttext">{{item.name}}触达排名</view>
</view>
<view class="right">
<view :class="{ activeclass: item.activeTab == 0 }" @click="charttoswitch(index,0)">表格</view>
<view style="margin-left: 16rpx;" :class="{ activeclass: item.activeTab == 1 }"
@click="charttoswitch(index,1)">饼状图</view>
</view>
</view>
<view v-if="item.activeTab==0" class="tabdada">
<view class="tabth">
<view>排名</view>
<view>画像语意词/触达客户</view>
<view>触达占比</view>
<view>沟通记录</view>
</view>
<view v-if="item.total==0" style="color: #999999;width: 100%;height: 500rpx;line-height: 500rpx;text-align: center;" >暂无数据</view>
<view class="tabtd" v-if="item.total!=0" v-for="(chend,i) in item.matchKeywords" :key="i">
<view>
<image v-if="i==0" class="ranking" src="../../../static/images/ranking1.png" mode=""></image>
<image v-else-if="i==1" class="ranking" src="../../../static/images/ranking2.png" mode=""></image>
<image v-else-if="i==2" class="ranking" src="../../../static/images/ranking3.png" mode=""></image>
<view class="ranking1" v-else>{{i+1}}</view>
</view>
<view>{{chend.name}}({{chend.total}})</view>
<view>{{chend.proportion}}%</view>
<view @click="Toview(item,i)">查看</view>
</view>
</view>
<view v-if="item.activeTab==1" class="tabech">
<qiun-data-charts
:key="item.id"
type="ring"
:chartData="item.chartData"
:canvas2d="true"
:canvasId="'wangxiaohuahahahahaha'+item.id"
:opts='item.opts'
background="none" />
</view>
</view>

<u-calendar v-model="totalTimeShow" mode="range" @change="totalTimeChange"></u-calendar>
<u-back-top :scroll-top="scrollTop"></u-back-top>
</view>
</template>

<script>
var app = getApp();
var util = require("../../../utils/util.js");
var config = require("../../../config");
export default {
data() {
return {
scrollTop: 0,
activeTotal: 2,
timeobj:{
statDateStart:'',
statDateEnd:''
},
buildingID:'',
totalTimeShow: false,
activeTab: 0,
numlist:[],
objlist:[],
Afolding:true
};
},
onPageScroll(e) {
this.scrollTop = e.scrollTop;
},
onLoad() {
this.buildingID=uni.getStorageSync('buildingID').id;
this.gitinit()
},
onPullDownRefresh() {
this.gitinit()
setTimeout(function () {
uni.stopPullDownRefresh();
}, 1000);
},
methods: {
anclick(i){
console.log(i)
this.Afolding=!this.Afolding;
this.numlist.forEach((citem,index)=>{
if(index<6){
citem.isshow=true;
}else{
citem.isshow=!citem.isshow;
}
})
this.$forceUpdate()
},
//获取数据
gitinit(){
this.objlist=[];
this.numlist=[];
var dateType='';
if(this.activeTotal==3){
dateType=null;
}else{
dateType=this.activeTotal;
}
let parames={
dateType:dateType,
statDateStart:this.timeobj.statDateStart,
statDateEnd:this.timeobj.statDateEnd,
houseId:this.buildingID
}
this.$u.post("/matchKeywords/findmatchdata", parames).then(data => {
this.numlist.push({
name:"客户数量",
num:data.total
})
data.list.forEach((item,index)=>{
this.numlist.push({
name:item.name,
num:item.total
})
item.activeTab=0;
item.opts={
"title": {
"name": item.total,
"color": '#666666',
"fontSize": 20
},
"subtitle": {
"name": '总触达次数',
"color": '#32363D',
"fontSize": 12,
"offsetY": 4
}
}
item.chartData={
"categories": [],
"series": [{
"data": []
}],
};
item.matchKeywords.forEach(chend=>{
item.chartData.series[0].data.push({
"name":chend.name,
"value": chend.proportion
})
})
})
data.list.forEach(item=>{
item.matchKeywords.forEach(chend=>{
if(chend.isInterval==0){
chend.name=chend.name+chend.unit+'-'+chend.endName+chend.unit
}else{
chend.name=chend.name
}
})
})
this.objlist=data.list;
this.Afolding=true;
this.numlist.forEach((citem,index)=>{
if(index<6){
citem.isshow=true
}else{
citem.isshow=false
}
})
})
},
//查看
Toview(item,i){
console.log(item)
let keywordsid = 0
if (item.matchKeywords[i].children && item.matchKeywords[i].children.length > 0) {
keywordsid = item.matchKeywords[i].children[0].keywordsId
} else {
keywordsid = item.matchKeywords[i].keywordsId
}
uni.navigateTo({
url: '/pages/center/Piabodata/Customerportrait/Receivingrecords?datatype='+this.activeTotal+"&keywordsId="+keywordsid+"&starttime="+this.timeobj.statDateStart+"&endoftime="+this.timeobj.statDateEnd
})
},
//时间切换
tabtimetap(index) {
if (index == 3) {
this.totalTimeShow = true;
} else {
this.activeTotal = index;
this.gitinit()
}
},
//自定义时间
totalTimeChange(e) {
this.timeobj.statDateStart = e.startDate;
this.timeobj.statDateEnd = e.endDate;
this.activeTotal=3;
this.gitinit()
},
charttoswitch(index,num) {
this.objlist[index].activeTab=num
}
}
};
</script>
<style lang="scss" scoped>
.anclack{
width: 100%;
height: 78rpx;
text-align: center;
line-height: 78rpx;
font-size: 30rpx;
border: 1rpx solid #E0E0E0;
font-weight: 400;
color: #666666;
}
.box {
width: 100%;
height: 100%;
background: #FAFAFA;
padding-bottom: 60rpx;
}

.boxtittab {
width: 100;
height: 92rpx;
background: #FFFFFF;
border: 1px solid #E0E0E0;
display: flex;
align-items: center;

.tabbox {
flex: 1;
height: 100%;
text-align: center;
line-height: 92rpx;
color: #666666;
font-size: 28rpx;
display: flex;
justify-content: center;

.activecllasscet {
width: 96rpx;
border-bottom: 2px solid #2671E2;
}
}
}

.tabtime {
width: 100%;
height: 50rpx;
text-align: center;
line-height: 50rpx;
font-size: 24rpx;
color: #666666;
}

.boxzonglan {
width: 100%;
min-height: 496rpx;
background: #FFFFFF;
padding: 30rpx 30rpx 30rpx 30rpx;

.zonglantit {
font-size: 30rpx;
color: #333333;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
}

.zonglanbox {
width: 100%;
display: flex;
flex-wrap: wrap;
margin-top: 24rpx;

.grid {
width: 50%;
height: 128rpx;
border: 1px solid #E0E0E0;

.audonum {
color: #666666;
text-indent: 40rpx;
font-size: 26rpx;
margin-top: 20rpx;
}

.num {
color: #333333;
text-indent: 40rpx;
font-size: 32rpx;
font-weight: 600;
margin-top: 10rpx;
}
}
}
}

.centerfor {
width: 100%;
height: 686rpx;
background: #FFFFFF;
padding-left: 30rpx;
padding-right: 30rpx;
margin-top: 20rpx;

.fortit {
width: 100%;
height: 86rpx;
display: flex;
border-bottom: 1px solid #E0E0E0;

.left {
width: 70%;
height: 100%;
display: flex;
align-items: center;

.lefti {
width: 6rpx;
height: 30rpx;
background: #2671E2;
}

.lefttext {
font-size: 30rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #333333;
margin-left: 10rpx;
}
}

.right {
width: 30%;
height: 70rpx;
display: flex;
font-size: 28rpx;
align-items: center;
margin-top: 16rpx;

}

.right view {
width: 92rpx;
height: 50rpx;
text-align: center;
}
}
}

.activeclass {
color: #2671E2;
border-bottom: 2px solid #2671E2;
}

.tabdada {
width: 100%;
height: 580rpx;
overflow-y: auto;
padding-bottom: 20rpx;
}

.tabth {
width: 100%;
height: 28rpx;
display: flex;
font-size: 28rpx;
line-height: 28rpx;
color: #666666;
margin-top: 28rpx;
}

.tabth>view:nth-of-type(1) {
width: 10%;
text-align: center;
}

.tabth>view:nth-of-type(2) {
width: 46%;
text-align: center;
}

.tabth>view:nth-of-type(3) {
width: 22%;
text-align: center;
}

.tabth>view:nth-of-type(4) {
width: 22%;
text-align: center;
}

.tabtd {
width: 100%;
height: 30rpx;
display: flex;
font-size: 26rpx;
line-height: 30rpx;
margin-top: 32rpx;
}

.tabtd>view:nth-of-type(1) {
width: 10%;
text-align: center;
line-height: 30rpx;
}

.tabtd>view:nth-of-type(2) {
width: 46%;
text-align: center;
color: #333333;
}

.tabtd>view:nth-of-type(3) {
width: 22%;
text-align: center;
color: #333333;
}

.tabtd>view:nth-of-type(4) {
width: 22%;
text-align: center;
color: #2671E2;
}

.ranking {
width: 34rpx;
height: 34rpx;
}
.ranking1 {
width: 30rpx;
height: 30rpx;
background: #ECF1FF;
color: #424D64;
font-size: 18rpx;
text-align: center;
line-height: 30rpx;
border-radius: 50%;
margin: 0 auto;
}

.tabech {
width: 100%;
height: 600rpx;
}
</style>

+ 752
- 0
pages/center/Piabodata/index.vue View File

@@ -0,0 +1,752 @@
<template>
<view class="box">
<view class="boxtittab">
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 4 }" @click="tabtimetap(4)">近七天</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 5 }" @click="tabtimetap(5)">近15天</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 6 }" @click="tabtimetap(6)">近30天</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 3 }" @click="tabtimetap(3)">自定义</view>
</view>
</view>
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="Piabodata-box">
<view class="Piabodata" @click="toTrendAnalysis()">
<view class="Piabodata-img">
<image class="Piabodata-img1" src="../../../static/images/qushi.png" mode=""></image>
</view>
<view class="Piabodata-text">趋势分析</view>
</view>
<view class="Piabodata" @click="toStaffAnalysis()">
<view class="Piabodata-img">
<image class="Piabodata-img1" src="../../../static/images/yuangong.png" mode=""></image>
</view>
<view class="Piabodata-text">员工分析</view>
</view>
<view class="Piabodata" @click="toUserinsightinto()">
<view class="Piabodata-img">
<image class="Piabodata-img1" src="../../../static/images/yinghu.png" mode=""></image>
</view>
<view class="Piabodata-text">用户洞察</view>
</view>
<view class="Piabodata" @click="Theteamcompared()" v-if="Theteamcomparedisshow">
<view class="Piabodata-img">
<image class="Piabodata-img1" src="../../../static/images/tuandui.png" mode=""></image>
</view>
<view class="Piabodata-text">团队对比</view>
</view>
<view class="Piabodata" @click="Groupcontrast()" v-if="Groupcontrastisshow">
<view class="Piabodata-img">
<image class="Piabodata-img1" src="../../../static/images/jituan.png" mode=""></image>
</view>
<view class="Piabodata-text">集团对比</view>
</view>

</view>

<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="boxzonglan" style="min-height: 400rpx;">
<view class="zonglantit">简报</view>
<view class="zonglanbox">
<view class="grid" v-for="(item,index) in numlist" :key="index">
<view class="audonum">{{item.name}}</text></view>
<view class="num">{{item.num}}</view>
</view>
</view>
</view>


<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1">接待趋势</view>
</view>
<view class="swiper-box">
<u-tabs-swiper ref="tabs" font-size="30" :bold="true" swiper-width="600" :current="bocindex"
@change="tapspagek2()" inactive-color="#b1b1b1" active-color="#008ef2" :list="newlistoj1"
:is-scroll="true">
</u-tabs-swiper>
</view>
<!-- <view class="hejibox">
<view class="heji">合计:50</view>
<view class="heji">均值:25</view>
</view> -->
<view class="danwei">{{danwei}} </view>
<view class="uchaserbox">
<template v-if="danwei == '单位(%)'">
<qiun-data-charts type="line" :chartData="lineOptsect" :opts="lineOpts" background="none"
:ontouch="true" canvasId="wangxiaohuaerlingilingwuyiba1" :canvas2d="true" />
</template>
<template v-else>
<qiun-data-charts type="line" :chartData="lineOptsect" background="none" :ontouch="true"
canvasId="wangxiaohuaerlingilingwuyiba1" :canvas2d="true" />
</template>
</view>
</view>


<view class="" v-if="teamFlag">
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title" @click="staffShow1=true">
<view class="title1">团队接待趋势</view>
<view class="title2">
<view class="title2-che" style="width: 220rpx;">{{team.label}}
<image class="righttochoose" src="../../../static/images/righttochoose.png" mode=""></image>
</view>

</view>
</view>
<view class="danwei">单位(%)</view>
<view class="uchaserbox">
<qiun-data-charts type="line" :chartData="lineOptsect1" background="none" :ontouch="true"
canvasId="wangxiaohuaerlineryiliwuyibao" :canvas2d="true" :opts="lineOpts" />
</view>
</view>
</view>

<view class="" v-if="staffFlag">
<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1">员工接待趋势</view>
<view class="title2" @click="staffShow=true">
<view class="title2-che" style="width: 220rpx;">{{staff.label}}
<image class="righttochoose" src="../../../static/images/righttochoose.png" mode=""></image>
</view>
<!-- <view class="title2-che">执行率
<image class="righttochoose" src="../../../static/images/righttochoose.png" mode=""></image>
</view> -->
</view>
</view>
<!-- <view class="hejibox">
<view class="heji">合计:{{allnum1||0}}</view>
<view class="heji">均值:{{allavg1||0}}</view>
</view> -->
<view class="danwei">单位(%)</view>
<view class="uchaserbox">
<qiun-data-charts type="line" :chartData="lineOptsect2" background="none" :ontouch="true"
canvasId="wangxiaohuaerlingeryilingwuyibao" :canvas2d="true" :opts="lineOpts" />
</view>
</view>
</view>

<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1">场景触达分析</view>
<!-- <view class="title3">
<view class="title3-box">
<view style="height: 42rpx;" :class="{ activecltab: activeTotal2 == 0 }">执行率</view>
</view>
<view class="title3-box">
<view style="height: 42rpx;" :class="{ activecltab: activeTotal2 == 1 }">得分</view>
</view>
</view> -->
</view>
<!-- <view class="hejibox">
<view class="heji">合计:50</view>
<view class="heji">均值:25</view>
</view> -->
<view style="width: 100%;height: 300rpx;text-align: center;line-height: 300rpx;"
v-if="newlisttabinfo.length==0">暂无数据</view>
<view v-else class="jindu" style="margin-top: 20rpx;">
<scroll-view style="height: 300rpx;" scroll-y="true">
<view class="jindu-box" v-for="(item,index) in newlisttabinfo" :key="index">
<view class="jindu-boxche">
<view class="jindu-name">{{item.name.substring(0, 4)}}</view>
<view style="width: 440rpx;margin-left: 10rpx;">
<u-line-progress height="24" :show-percent="false" active-color="#4FC78F"
:percent="item.zxl"></u-line-progress>
</view>
<view class="jindu-zxl">{{item.zxl==null?0:item.zxl}}%</view>
</view>
</view>
</scroll-view>
</view>
</view>

<view style="width: 100%;height: 20rpx;background: #FAFAFA;"></view>
<view class="single">
<view class="title">
<view class="title1">销讲指标执行率</view>
</view>
<view class="swiper-box">
<u-tabs-swiper ref="tabs" font-size="30" :bold="true" swiper-width="600" :current="bocindex1"
@change="tapspagek3" inactive-color="#b1b1b1" active-color="#008ef2" :list="newlistoj"
:is-scroll="true">
</u-tabs-swiper>
</view>
<view style="width: 100%;height: 300rpx;text-align: center;line-height: 300rpx;"
v-if="newlisttabinfo1.length==0">暂无数据</view>
<view class="jindu" v-else>
<scroll-view style="height: 300rpx;" scroll-y="true">
<view class="jindu-box" v-for="(item,index) in newlisttabinfo1" :key="index">
<view class="jindu-boxche">
<view class="jindu-name">{{item.name.substring(0, 4)}}</view>
<view style="width: 440rpx;margin-left: 10rpx;">
<u-line-progress height="24" :show-percent="false" active-color="#4FC78F"
:percent="item.zxl"></u-line-progress>
</view>
<view class="jindu-zxl">{{item.zxl==null?0:item.zxl}}%</view>
</view>
</view>
</scroll-view>

</view>

</view>

<u-calendar v-model="totalTimeShow" mode="range" @change="totalTimeChange"></u-calendar>
<u-select v-model="staffShow" :list="staffList" @confirm="staffSelectCallback($event,0)"
:default-value='selindex'></u-select>
<u-select v-model="staffShow1" :list="teamList" @confirm="staffSelectCallback($event,1)"
:default-value='selindex'></u-select>
</view>
</template>

<script>
var app = getApp();
// var util = require("../../../utils/util.js");
var config = require("../../../config");
export default {
data() {
return {
activeTotal: 4,
activeTotal2: 0,
houseId: '',
timeobj: {
statDateStart: '',
statDateEnd: ''
},
// 员工列表
staffList: [],
// 团队列表
teamList: [],
staffShow: false,
staff: {
value: '',
label: ''
},
team: {
value: '',
label: ''
},
teamFlag: true,
bocindex1: 0,
staffFlag: true,
staffShow1: false,
lastStartDate: '',
lastEndDate: '',
allnum: '',
allavg: '',
allnum1: '',
allavg1: '',
danwei: '单位(次)',
totalTimeShow: false,
activeTab: 0,

numlist: [
{
name: '接待量',
num: '',
setName: 'sumCustomer'
},{
name: '有效接待',
num: '',
setName: 'receptionCount'
},
{
name: '平均执行率',
num: '',
setName: 'fraction'
},
{
name: '平均接待时长',
num: '',
setName: 'sumDuration'
},
],

lineOptsect: {
"categories": ["2016", "2017", "2018", "2019", "2020", "2021"],
"series": [{
"name": "成交量",
"data": [35, 8, 25, 37, 4, 20]
}]
},
lineOptsect1: {
"categories": [],
"series": []
},
lineOptsect2: {
"categories": ["2016", "2017", "2018", "2019", "2020", "2021"],
"series": [{
"name": "成交量",
"data": [35, 8, 25, 37, 4, 20]
}]
},
newlistoj: [],

newlistoj1: [
{
name: "接待量",
id: 3,
title: '单位(个)',
setName: 'sumCustomer'
},
{
name: "有效接待",
id: 1,
title: '单位(次)',
setName: 'receptionCount'
},
{
name: "平均执行率",
id: 2,
title: '单位(%)',
setName: 'fraction'
},
{
name: "平均接待时长",
id: 5,
title: '单位(min)',
setName: 'sumDuration'
},
],
bocindex: 0,
newlisttabinfo: [{
name: '接待量',
zxl: '10'
},
{
name: '平均执行率',
zxl: '50'
},
{
name: '接待客户',
zxl: '80'
},
],
newlisttabinfo1: [],
Theteamcomparedisshow: false,
Groupcontrastisshow: false,
allechar: [],
allList: [],

lineOpts: {
yAxis: {
data: [{
max: 100,
min: 0,
}]
}
},
};
},
onShow() {
// 获取项目id
this.houseId = uni.getStorageSync('buildingID').id;
// 获取数据看板

// 获取员工
this.getStaffList()
// 获取团队
this.getSectionList()
// 获取团队是否显示权限

this.queryHaveDept()
// 获取简报
this.getReport()
// 获取接待趋势
this.getRtrent()
// 获取维度
this.getindexZxl()
},
onPullDownRefresh() {
// 获取员工
this.getStaffList()
// 获取团队
this.getSectionList()
// 获取团队是否显示权限

// 获取简报
this.getReport()
// 获取接待趋势
this.getRtrent()
// 获取维度
this.getindexZxl()
setTimeout(function() {
uni.stopPullDownRefresh();
}, 1000);
},
methods: {
queryHaveDept() {
return new Promise((resolve, reject) => {
this.$u.get("/user/queryHaveDept?houseId=" + this.houseId).then(res => {
this.permissions(res)
})
})
},
permissions(res) {
if (res == 1) {
this.Theteamcomparedisshow = false;
this.Groupcontrastisshow = false;
return
}

let totle = uni.getStorageSync('weapp_session_userInfo_data').total;
if (totle == 1) {
this.Theteamcomparedisshow = true;
this.Groupcontrastisshow = false;
} else {
this.Theteamcomparedisshow = true;
this.Groupcontrastisshow = true;
}
},
// 获取员工列表
getStaffList() {
this.$u.post('/cusLvStatistics/selectAllAccountIdByHouseId', {
houseId: this.houseId
})
.then(res => {
// console.log(res,'123')
this.staffList = []
res.map(item => {
let obj = {}
obj.value = item.accountId
obj.label = item.name
this.staffList.push(obj)
})
this.staff = this.staffList[0]
this.getAward()
})
},
// 获取接待趋势
getRtrent() {
this.$u.post('/cusLvStatistics/receptionTrend', {
houseId: this.houseId,
timeType: this.lastEndDate ? null : this.activeTotal,
lastEndDate: this.lastEndDate,
lastStartDate: this.lastStartDate
})
.then(res => {
// console.log(res)
this.allechar = res
this.tapspagek2(this.bocindex)

})
},
// 销奖维度
getindexZxl() {
this.$u.post('/cusLvStatistics/indexZxl', {
houseId: this.houseId,
timeType: this.lastEndDate ? null : this.activeTotal,
lastEndDate: this.lastEndDate,
lastStartDate: this.lastStartDate
})
.then(res => {
// console.log(res)
// 处理销奖维度执行率
// this.newlisttabinfo
let arr = []
this.newlistoj = []
res.list.map((item, index) => {
arr.push({
name: item.name,
zxl: item.zxl
})
this.newlistoj.push({
name: item.name,
id: index
})
})
this.newlisttabinfo = arr
this.allList = res.list
this.tapspagek3(this.bocindex1)
})
},
// 获取简报
getReport() {
this.$u.post('/cusLvStatistics/xiaojiangAnalysis', {
houseId: this.houseId,
timeType: this.lastEndDate ? null : this.activeTotal,
lastEndDate: this.lastEndDate,
lastStartDate: this.lastStartDate
})
.then(res => {
res.sumDuration = Math.floor(res.sumDuration / 60) || 0
res.fraction = (res.fraction || 0) + '%'
this.numlist.map(item => {
item.num = res[item.setName]
})
})
},
// 获取团队列表
getSectionList() {
this.$u.post('/cusLvStatistics/findAllDeptIdByHouseId', {
houseId: this.houseId
})
.then(res => {
this.teamList = []
res.map(item => {
let obj = {}
obj.value = item.deptId
obj.label = item.deptName
this.teamList.push(obj)
})
this.team = this.teamList[0]
this.receptionCountList()
})
},
// 员工销奖趋势
getAward() {
if (this.staffList.length == 0) {
this.staffFlag = false
this.$forceUpdate()
return
}
this.$u.post('/cusLvStatistics/employeeAnalysisExacutiveRate', {
userA: this.staff.value,
userB: '',
houseId: this.houseId,
timeType: this.lastEndDate ? null : this.activeTotal + '',
lastEndDate: this.lastEndDate,
lastStartDate: this.lastStartDate
})
.then(res => {
this.allnum1 = res.avg[0]
this.allavg1 = res.avg[1]
// console.log(res)
let first = res.first
let second = res.second
this.lineOptsect2.categories = []
this.lineOptsect2.series = [{
name: first[0].accountName,
data: []
}]
first.map(item => {
this.lineOptsect2.categories.push(item.statDate.slice(5, 10))
this.lineOptsect2.series[0].data.push(item.sumFraction)
})
})
},
// 团队接待趋势
receptionCountList() {
if (this.teamList.length == 0) {
this.teamFlag = false
this.$forceUpdate()
return
}
this.$u.post('/cusLvStatistics/teamAnalysisExecutionRate', {
deptIds: this.team.value,
showRank: 1,
houseId: this.houseId,
timeType: this.lastEndDate ? null : this.activeTotal + '',
lastEndDate: this.lastEndDate,
lastStartDate: this.lastStartDate
})
.then(res => {
// console.log(res)
let result = res.result
this.allnum = res.avg[0]
this.allavg = res.avg[1]
// 当选择趋势时
this.lineOptsect1 = {}
let allobj = {
categories: [],
series: []
}
// 先处理时间
// 当选择全部时
// 当选择只有一个时
let obj = {}
obj.data = []
obj.name = result[0][0].deptName
result[0].map(item => {
allobj.categories.push(item.statDate.slice(5, 10))
obj.data.push(item.data)
})
allobj.series.push(obj)
this.lineOptsect1 = allobj

})
},
//时间切换
tabtimetap(index) {
if (index == 3) {
this.totalTimeShow = true;
} else {
this.activeTotal = index;
this.lastEndDate = ''
this.lastStartDate = ''
this.getdata()
}
},
// 获取数据
getdata() {
this.receptionCountList()
this.getReport()
this.getRtrent()
this.getindexZxl()
this.getAward()
},
staffSelectCallback(e, idx) {
if (idx == 0) {
this.staff = e[0]
this.getAward()
} else {
this.team = e[0]
this.receptionCountList()
}
// console.log(e,idx)
},
//自定义时间
totalTimeChange(e) {
console.log(e.startDate, e.endDate)
this.activeTotal = 3;
this.lastEndDate = e.endDate
this.lastStartDate = e.startDate
this.getdata()
},
//指标执行率分析tab
tapspagek2(index) {
console.log(index)
// 对数据进行分析和处理
// 先处理日期
let allobj = {
"categories": [],
"series": [{
name: '接待量',
data: []
}]
}

this.danwei = this.newlistoj1[index].title
allobj.series[0].name = this.newlistoj1[index].name
this.allechar.map(item => {
allobj.categories.push(item.statDate.slice(5, 10))
allobj.series[0].data.push(item[this.newlistoj1[index].setName])
})

this.bocindex = index;
this.lineOptsect = allobj
this.$forceUpdate()
},
tapspagek3(index) {
let arr = []
// return
// console.log(index,this.allList[index])
this.allList[index].children.map(item => {
arr.push({
name: item.name,
zxl: item.zxl
})
})
this.newlisttabinfo1 = arr
this.bocindex1 = index;
},
//集团对比
Groupcontrast() {
uni.navigateTo({
url: '/pages/center/Piabodata/Groupcontrast'
});
},
//团队对比
Theteamcompared() {
if (this.teamList.length == 0) {
uni.showToast({
title: '没有团队呢',
icon: 'none'
})
return
}
uni.navigateTo({
url: '/pages/center/Piabodata/Theteamcompared'
});
},
//用户洞察
toUserinsightinto() {
uni.navigateTo({
url: '/pages/center/Piabodata/Userinsightinto'
});
},
//趋势分析
toTrendAnalysis() {
uni.navigateTo({
url: '/pages/center/Piabodata/TrendAnalysis'
});
},
//员工分析
toStaffAnalysis() {
if (this.staffList.length == 0) {
uni.showToast({
title: '没有团队呢',
icon: 'none'
})
return
}
uni.navigateTo({
url: '/pages/center/Piabodata/StaffAnalysis'
});
}
}
};
</script>
<style lang="scss" scoped>
.box {
width: 100%;
height: 100%;
background: #FAFAFA;
padding-bottom: 60rpx;
}

.Piabodata-box {
width: 100%;
background: #FFFFFF;
display: flex;
flex-wrap: wrap;
padding-bottom: 30rpx;

.Piabodata {
width: 33.3%;

.Piabodata-img {
width: 100%;
text-align: center;

.Piabodata-img1 {
width: 134rpx;
height: 134rpx;
}
}

.Piabodata-text {
width: 100%;
text-align: center;
font-size: 24rpx;
font-weight: 400;
color: #333333;
margin-top: -10rpx;
}
}
}

.grid:nth-child(1) {
border-right: none;
border-bottom: none;
}

.grid:nth-child(2) {
border-bottom: none;
}

.grid:nth-child(3) {
border-right: none;
}
</style>

+ 151
- 0
pages/center/Piabodata/selectGroup.vue View File

@@ -0,0 +1,151 @@
<template>
<view class="box">
<!-- 顾问选择 -->
<view class="nextcon">
最多选择五项
</view>
<view class="content">
<scroll-view style="height: 1170rpx;" scroll-y="true" >
<checkbox-group v-model="value" @change="checkboxChange">
<view v-for="(item,index) in items" :key="index">
<view class="content-tips">
<view class="left">
{{item.propertyName}}
</view>
<view class="right">
<radio :value="item.id" style="transform:scale(0.8)" color="#2671E2" :checked="item.checked" @click="addclick(index)"></radio>
</view>
</view>
</view>
</checkbox-group>
</scroll-view>

<view class="zhedang"></view>
<view class="btn" @click="goback">
确定
</view>
</view>
</view>
</template>

<script>
export default {
data(){
return{
value:[],
items:[],
ids:''
}
},
onLoad(e) {
// 获取项目id
// console.log(e)
this.ids=e.ids
// this.houseId = uni.getStorageSync('buildingID').id;
this.getSectionList()
},
methods:{
checkboxChange (e) {
// console.log(e)
},
// 获取部门列表
getSectionList(){
this.$u.post('/user/getHouseByToken',)
.then(res=>{
// console.log(res)
res.map((item,index)=>{
if(index<5){
item.checked=true
}else{
item.checked=false
}
})
this.items=res
// console.log(this.items)
if(this.ids){
let arr=this.ids.split(',')
this.items.map((item,index)=>{
let idx=arr.findIndex(item1=>item1==item.id)
if(idx!=-1){
item.checked=true
}else{
item.checked=false
}
})
}
})
},
addclick(index){
this.items[index].checked=!this.items[index].checked
},
goback(){
// 循环遍历所有选定的内容
let arr=[]
this.items.map(item=>{
if(item.checked){
arr.push(item.id)
}
})
uni.$emit('updateGroup',{arr})
uni.navigateBack()
},
}
}
</script>

<style lang="scss" scoped>
.box{
background: #F8F8F8;
width: 100%;
height: 100%;
font-size: 30rpx;
font-weight: 400;
// line-height: 30px;
.nextcon{
height: 78rpx;
background: #F4F8FD;
color: #2671E2;
text-align: center;
line-height: 78rpx;
}
.content-tips{
display: flex;
justify-content: space-between;
background: #fff;
padding: 0 30rpx;
height: 92rpx;
margin-bottom: 20rpx;
.left{
display: flex;
// margin-top: 30rpx;
font-weight: 500;
color: #303030;
line-height: 92rpx;
font-size: 30rpx;
}
.right{
margin: 24rpx 0;
}
}
.btn{
width: 690rpx;
height: 88rpx;
background: #2671E2;
border-radius: 8rpx;
font-size: 32rpx;
font-weight: 400;
color: #FFFFFF;
line-height: 88rpx;
text-align: center;
position: fixed;
left: 30rpx;
bottom: 80rpx;
}
.zhedang{
height: 168rpx;
opacity: 0;
}
}
</style>

+ 150
- 0
pages/center/Piabodata/selectTeam.vue View File

@@ -0,0 +1,150 @@
<template>
<view class="box">
<!-- 顾问选择 -->
<view class="nextcon">
最多选择五项
</view>
<view class="content">
<scroll-view style="height: 1170rpx;" scroll-y="true" >
<checkbox-group v-model="value" @change="checkboxChange">
<view v-for="(item,index) in items" :key="index">
<view class="content-tips">
<view class="left">
{{item.deptName}}
</view>
<view class="right">
<radio :value="item.deptId" style="transform:scale(0.8)" color="#2671E2" :checked="item.checked" @click="addclick(index)"></radio>
</view>
</view>
</view>
</checkbox-group>
</scroll-view>

<view class="zhedang"></view>
<view class="btn" @click="goback">
确定
</view>
</view>
</view>
</template>

<script>
export default {
data(){
return{
value:[],
items:[],
ids:''
}
},
onLoad(e) {
// 获取项目id
// console.log(e)
this.ids=e.ids
this.houseId = uni.getStorageSync('buildingID').id;
this.getSectionList()
},
methods:{
checkboxChange (e) {
// console.log(e)
},
// 获取部门列表
getSectionList(){
this.$u.post('/cusLvStatistics/findAllDeptIdByHouseId',{houseId:this.houseId})
.then(res=>{
console.log(res)
res.map((item,index)=>{
if(index<5){
item.checked=true
}else{
item.checked=false
}
})
this.items=res
if(this.ids){
let arr=this.ids.split(',')
this.items.map((item,index)=>{
let idx=arr.findIndex(item1=>item1==item.deptId)
if(idx!=-1){
item.checked=true
}else{
item.checked=false
}
})
}
})
},
addclick(index){
this.items[index].checked=!this.items[index].checked
},
goback(){
// 循环遍历所有选定的内容
let arr=[]
this.items.map(item=>{
if(item.checked){
arr.push(item.deptId)
}
})
uni.$emit('update',{arr})
uni.navigateBack()
},
}
}
</script>

<style lang="scss" scoped>
.box{
background: #F8F8F8;
width: 100%;
height: 100%;
font-size: 30rpx;
font-weight: 400;
// line-height: 30px;
.nextcon{
height: 78rpx;
background: #F4F8FD;
color: #2671E2;
text-align: center;
line-height: 78rpx;
}
.content-tips{
display: flex;
justify-content: space-between;
background: #fff;
padding: 0 30rpx;
height: 92rpx;
margin-bottom: 20rpx;
.left{
display: flex;
// margin-top: 30rpx;
font-weight: 500;
color: #303030;
line-height: 92rpx;
font-size: 30rpx;
}
.right{
margin: 24rpx 0;
}
}
.btn{
width: 690rpx;
height: 88rpx;
background: #2671E2;
border-radius: 8rpx;
font-size: 32rpx;
font-weight: 400;
color: #FFFFFF;
line-height: 88rpx;
text-align: center;
position: fixed;
left: 30rpx;
bottom: 80rpx;
}
.zhedang{
height: 168rpx;
opacity: 0;
}
}
</style>

+ 1163
- 0
pages/center/consumer/consumerDetail.vue
File diff suppressed because it is too large
View File


+ 495
- 0
pages/center/consumer/edit.vue View File

@@ -0,0 +1,495 @@
<template>
<view class="box">
<!-- 编辑 -->
<view class="conmsg">
<view class="conmsg-title">
客户信息
</view>
<view class="conmsg-msg">
<view class="conmsg-msg-lab">
<view class="conmsg-msg-lab-1">
客户姓名
<view class="star">
*
</view>
</view>
<view class="conmsg-msg-lab-inp">
<input type="text" placeholder="请输入客户姓名" placeholder-style="color:#B2B2B2;"
v-model="form.name" />
</view>
</view>
<view class="conmsg-msg-lab">
<view class="conmsg-msg-lab-1">
客户性别
</view>
<view class="conmsg-msg-lab-inp" style="margin-top: 20rpx;">
<view style="border: none; display: flex;">
<view class="sexchose" @click="form.sex=1"
:style="{border:form.sex==1?'1px solid #0A6EE9':'1px solid #E0E0E0'}">
</view>
<view class="sexchose" @click="form.sex=2"
:style="{border:form.sex==2?'1px solid #0A6EE9':'1px solid #E0E0E0'}">
</view>
</view>
</view>
</view>
<view class="conmsg-msg-lab">
<view class="conmsg-msg-lab-1">
联系电话
</view>
<view class="conmsg-msg-lab-inp">
<input type="number" @focus="callPhoneFocus" @blur="callPhoneBlur" placeholder="请输入联系电话" placeholder-style="color:#B2B2B2;" maxlength="11"
v-model="form.showPhone" />
</view>
</view>
<view class="conmsg-msg-lab">
<view class="conmsg-msg-lab-1">
微信账号
</view>
<view class="conmsg-msg-lab-inp">
<input type="text" placeholder="请输入微信账号" placeholder-style="color:#B2B2B2;"
v-model="form.chatNo" />
</view>
</view>
<view class="conmsg-msg-lab" @click="levelshow = true">
<view class="conmsg-msg-lab-1">
客户等级
</view>
<view class="conmsg-msg-lab-inp">
<input type="text" placeholder="请选择客户等级" v-model="selectform.level" disabled />
</view>
<view class="conmsg-msg-lab-img">
<image class="screen-sel-img" src="../../../static/images/right.png" mode=""></image>
</view>
</view>
<view class="conmsg-msg-lab">
<view class="conmsg-msg-lab-1">
客户来源
</view>
<view class="conmsg-msg-lab-inp">
<input type="text" placeholder="请选择客户来源" @click="Buildingselection" v-model="form.sourceName"
disabled />
</view>
<view class="conmsg-msg-lab-img">
<image class="screen-sel-img" src="../../../static/images/right.png" mode=""></image>
</view>
</view>
<view class="conmsg-msg-lab" style="border: none;">
<view class="conmsg-msg-lab-1">
备注内容
</view>
<view class="conmsg-msg-lab-inp">
<input type="text" placeholder="请输入备注内容" placeholder-style="color:#B2B2B2;"
v-model="form.remarks" />
</view>
</view>
</view>
</view>

<view class="conmsg" v-if="allList.length!=0">
<view class="conmsg-title">
客户标签
</view>
<view class="conmsg-msg">

<view v-for="(item,index) in allList" :key="index">
<view class="">
<view class="conmsg-msg-lab" style="border: none;">
<view class="conmsg-msg-lab-1">
{{item.name}}
</view>
</view>
<view class="con-msg-con"
:style="{borderBottom:index==allList.length-1?'none':'1px solid #E0E0E0'}">
<view v-for="(item1,i) in item.children" :key="i" @click="Edittag(item,item1,index,i)"
:style="{border:item1.selected==0?'1px solid #0A6EE9':'1px solid #E0E0E0'}"
class="chebox">
{{item1.label}}
</view>
</view>
</view>
</view>

</view>
</view>

<view class="submit">
<view class="btn" @click="submit">
确定
</view>
</view>
<view class="" style="height: 220rpx;">
<!-- :style="{marginTop:allList.length!=0?'0':'500rpx'}" -->
</view>

<!-- 客户等级 -->
<u-select v-model="levelshow" :list="levellist" @confirm="levelshowCallback"></u-select>


<u-select :mask-close-able="false" label-name="sourceName" value-name="id" v-model="Showhiddenunits"
mode="single-column" :list="list" @cancel="cancel" @confirm="confirm"></u-select>
</view>
</template>

<script>
const config = require("@/config");
export default {
data() {
return {
Showhiddenunits: false, // 控制客户来源弹窗
form: {
name: '',
sex: '1',
phone: '',
chatNo: '',
level: '1',
remarks: '',
sourceId: ''
},
selectform: {
level: 'A',
stage: '',
demand: '',
area: '',
budget: '',
fouce: '',
soure: '',

},

list: [], // 客户来源数组

levelshow: false,
customerId: '',
// 等级
levellist: [{
value: 1,
label: 'A'
},
{
value: 2,
label: 'B'
},
{
value: 3,
label: 'C'
},
{
value: 4,
label: 'D'
},
],
allList: [],
dataCode: '',
projectId: '', // 项目ID
userInfo: {}, // 当前用户信息
}
},
onLoad(e) {
this.userInfo = uni.getStorageSync("weapp_session_userInfo_data");
console.log()
this.dataCode = this.userInfo.dataCode
console.log(e)
// 先调用借口查询数据
this.customerId = e.id
if (e.projectId) this.projectId = e.projectId
this.getdetail()
this.getFromSource()
},
methods: {
// 获取客户来源
getFromSource() {
uni.request({
url: config.service.sourceList + "?houseId=" + this.projectId,
method: "GET",
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
success: (data) => {
console.log(data)
if (data.data.code == 10000) {
this.list = data.data.data
}
},
fail: (res) => {
console.log(res)
}
})
},
// 选择客户来源
Buildingselection() {
this.Showhiddenunits = true;
},
cancel() {
this.Showhiddenunits = false;
},
confirm(e) {
this.form.sourceName = e[0].label;
this.form.sourceId = e[0].value;
this.Showhiddenunits = false;
},

Edittag(item, item1, index, i) {

if (this.allList[index].children[i].selected == 0) {
this.allList[index].children[i].selected = 1;
} else {
this.allList[index].children[i].selected = 0;
}
this.$forceUpdate()

},
sourecheck(index) {
this.sourelist[index].checked = !this.sourelist[index].checked
this.$forceUpdate()
},
demandcheck(index) {
this.demandlist[index].checked = !this.demandlist[index].checked
this.$forceUpdate()
},
areacheck(index) {
this.arealist[index].checked = !this.arealist[index].checked
this.$forceUpdate()
},
levelshowCallback(e) {
this.selectform.level = e[0].label
this.form.level = e[0].value
},
// 获取用户数据
getdetail() {
this.$u.get("customer/findById?", {
id: this.customerId
})
.then(res => {
this.form = res
if (!this.form.phone) {
this.form.showPhone = '--'
} else {
if (this.form.isShow == 1 && this.form.phone.length == 11) {
this.form.showPhone = this.form.phone.substr(0, 3) + '****' + this.form.phone.substr(7)
} else {
this.form.showPhone = this.form.phone
}
}
this.form.showPhones = this.form.showPhone
// 给客户等级赋值
let idx = this.levellist.findIndex(item => item.value == res.level)
if (idx != -1) {
this.selectform.level = this.levellist[idx].label
} else {
this.selectform.level = 'A';
this.form.level = 1;
}
this.showSourceName = res.sourceName;
// 获取置业需求
this.getListByType()
})
},
// 字典表接口
getListByType() {
this.$u.get("/matchKeywords/findPersonalMatchData", {
customerId: this.customerId
})
.then(res => {
// console.log(res)
res.forEach(item1 => {
item1.children.map(item => {
if (item.isInterval == 0) {
item.label = item.name + item.unit + '-' + item.endName + item
.unit;
} else {
item.label = item.name
}
item.value = item.id;
})
})
// console.log(res)
this.allList = res
// return
})
},
// 输入框获取焦点
callPhoneFocus() {
if (this.form.isShow == 1 && this.form.showPhone == this.form.showPhones) {
this.form.showPhone = ''
this.$forceUpdate()
}
},
// 输入框失去焦点
callPhoneBlur() {
if (this.form.isShow == 1 && this.form.showPhone == '') {
this.form.showPhone = this.form.showPhones
this.$forceUpdate()
}
},
// 提交
submit() {
let param = {}
let str = []
if (this.form.name == '') {
uni.showToast({
title: '请输入客户姓名',
icon: 'none'
})
return
}
if (this.form.showPhones != this.form.showPhone) {
this.form.phone = this.form.showPhone
}
this.allList.map(item => {
item.children.map(item1 => {
if (item1.selected == 0) {
str.push(item1.keywordsId)
}
})
})
str = str.join(',')
param = this.form
param.keywordIds = str
console.log(param)
// return
this.$u.post("customer/update", param)
.then(res => {
// console.log(res)
uni.showToast({
title: '操作成功',
icon: 'none',
success: () => {
uni.navigateBack()
}
})

})
},
}
}
</script>

<style lang="scss" scoped>
.box {
width: 100%;
height: 100%;
background: #F8F8F8;
overflow: hidden;
}

.conmsg {
background: #FFFFFF;
margin-top: 20rpx;

.conmsg-title {
height: 92rpx;
line-height: 92rpx;
font-weight: bold;
padding: 0 30rpx;
// font-weight: 500;
color: #303030;
font-size: 32rpx;
border-bottom: 1px solid #E0E0E0;
}

.conmsg-msg {
padding: 0 30rpx;

.conmsg-msg-lab {
height: 102rpx;
display: flex;
font-size: 30rpx;
font-weight: 400;
color: #333333;
border-bottom: 1px solid #E0E0E0;
line-height: 102rpx;

.conmsg-msg-lab-1 {
display: flex;
min-width: 136rpx;

.star {
color: #E7483C;
line-height: 108rpx;
}
}

.conmsg-msg-lab-inp {
margin-top: 30rpx;
margin-left: 44rpx;

}

.conmsg-msg-lab-img {
width: 14rpx;
height: 30rpx;
margin-top: 6rpx;
margin-left: auto;

image {
width: 100%;
height: 100%;
}
}
}
}
}

.submit {
position: fixed;
bottom: 20rpx;
left: 20rpx;
height: 120rpx;
background: #FFFFFF;

.btn {
// margin: 60rpx auto;
text-align: center;
width: 690rpx;
height: 88rpx;
background: #2671E2;
border-radius: 8rpx;
font-size: 32tpx;
font-weight: 400;
color: #FFFFFF;
line-height: 88rpx;
}
}

.con-msg-con {
display: flex;
flex-wrap: wrap;
// justify-content: space-around;
border-bottom: 1px solid #E0E0E0;
padding-bottom: 16rpx;

.chebox {
// width: 20%;
height: 60rpx;
line-height: 60rpx;
// margin: 10rpx 0;
margin-bottom: 25rpx;
margin-right: 20rpx;
border: 1px solid #E0E0E0;
box-sizing: border-box;
padding: 0 10rpx;
}
}

.sexchose {
width: 120rpx;
height: 60rpx;
background: #FFFFFF;
border-radius: 4rpx;
border: 1px solid #E0E0E0;
text-align: center;
line-height: 60rpx;
margin-right: 20rpx;

}
</style>

+ 1075
- 0
pages/center/consumer/index.vue
File diff suppressed because it is too large
View File


+ 322
- 0
pages/center/consumer/newFollowup/newFollowup.vue View File

@@ -0,0 +1,322 @@
<template>
<view class="box">

<view class="screen">
<!-- 录音标示 -->
<view class="screen-record">
<view class="screen-record-text">
最新状态
</view>
<view class="screen-record-tab">
<scroll-view scroll-x style="width: 100%;">
<view style="display: flex;">
<block v-for="(item,index) in stateList" :key="index">
<view style="flex-shrink: 0;"
:class="[screen.state==index?'screen-record-chose':'screen-record-nochose']"
@click="screen.state=index">
{{item.stageName}}
</view>
</block>
</view>
</scroll-view>
</view>
</view>
<!-- 录音标示 -->
<view class="screen-record">
<view class="screen-record-text">
意向级别
</view>
<view class="screen-record-tab">
<view :class="[screen.level==1?'screen-record-chose':'screen-record-nochose']"
@click="screen.level=1">
A
</view>
<view :class="[screen.level==2?'screen-record-chose':'screen-record-nochose']"
@click="screen.level=2">
B
</view>
<view :class="[screen.level==3?'screen-record-chose':'screen-record-nochose']"
@click="screen.level=3">
C
</view>
<view :class="[screen.level==4?'screen-record-chose':'screen-record-nochose']"
@click="screen.level=4">
D
</view>
</view>
</view>
<!-- <view class="screen-record" style="height: auto;">
<view class="screen-record-text" style="margin-bottom: 20rpx;">
客户类型
</view>
<u-search placeholder="请输入搜索" v-model="keyword" :clearabled="true" :show-action="false" @change="search"></u-search>
<scroll-view style="height: 180rpx;" scroll-y="true" >
<view class="screen-record-tab" style="flex-wrap: wrap;">
<view v-for="(item,index) in customerType" :key="index">
<view :class="[item.check?'screen-record-chose':'screen-record-nochose']" style="margin-bottom: 20rpx;" @click="checkbox(index)">
{{item.keywords}}
</view>
</view>
</view>
</scroll-view>
</view> -->
<view class="screen-record">
<view class="screen-record-text">
跟进内容
</view>
<view class="screen-record-tab">
<input type="text" placeholder="请输入跟进内容" v-model="screen.con" />
</view>
</view>
<view class="screen-foot">
<view class="screen-foot-sure" @click="screensure">
保存
</view>
</view>
</view>


</view>
</template>

<script>
export default {
data() {
return {
value: '',
screenShow: false,
selectshow: false,
selectTipshow: false,
buildingID: '',
keyword: '',
screen: {
state: '0',
con: "",
level: '1'
},
stateList: [],
recordList: [],
nextPage: 1,
totalRecord: '',
freeList: [],
customerType: [],
customerId: ''
}
},
onShow() {

},
onLoad(e) {
this.customerId = e.id
this.buildingID = uni.getStorageSync('buildingID').id;
this.recordList = []
// this.getMyCustom()
// this.getFreeList()
this.getNewStatus()
this.getCustomerType();
},
methods: {
//选择顾问
actionSelectCallback(e) {
this.screen.agentId = e[0].value;
this.screen.agentIdtext = e[0].label;
},
getCustomerType() {
this.$u.get("/customer/queryKeyWords").then(res => {
res.map(item => {
item.check = false
})
this.customerType = res;
})
},
getNewStatus() {
var that = this;
let premo = {
houseId: uni.getStorageSync('buildingID').id
}
this.$u.post('/customer/getStage', premo)
.then(res => {
this.stateList = res
})

},
checkbox(idx) {
console.log(idx)
this.customerType[idx].check = !this.customerType[idx].check
},
search(e) {
console.log(e)
},
//选择标签
selectCallback(e) {
console.log(e[0].label)
},
//筛选确认
screensure() {
// 获取选择过的数据
// let type=[]
let words = []
this.customerType.map(item => {
if (item.check) {
// type.push(item.id)
words.push(item.keywords)
}
})
// if (words.length == 0 ) {
// uni.showModal({
// title: '提示',
// content: '请选择、类型',
// showCancel: false
// });
// return;
// }
uni.showLoading({
title: "保存中~",
mask: true
})
// console.log(type)
let param = {
"stageCode": this.stateList[this.screen.state].stageCode,
"stageName": this.stateList[this.screen.state].stageName,
"remarks": this.screen.con,
words,
// "settingTime":"",
"agentRelationPo": {
"customerId": this.customerId,
"level": this.screen.level,
"state": this.stateList[this.screen.state].id
}
}
this.$u.post('/customer/addZkDailyWorkRecord', param)
.then(res => {
// util.showSuccess("提交成功");
uni.hideLoading();
uni.navigateBack();
})
},
}
}
</script>

<style lang="scss" scoped>
.box {
width: 100%;
height: 100%;
background: #F8F8F8;
}

.screen {
// box-sizing: border-box;
// padding: 0 30rpx;
background: #FFFFFF;

.screen-counselor {
display: flex;
height: 106rpx;
// padding: 40rpx 30rpx 36rpx 30rpx;
padding: 0 30rpx;
box-sizing: border-box;
border-bottom: 1px solid #CCCCCC;

.screen-text {
margin: 40rpx 0 36rpx 0;
font-size: 30rpx;
font-weight: 400;
color: #333333;
line-height: 30rpx;
}

.screen-sel {
display: flex;
justify-content: space-between;
width: 500rpx;
margin-left: 60rpx;

.screen-sel-img {
margin: 40rpx 0 36rpx 0;
width: 14rpx;
height: 30rpx;
}

.screen-inp {
margin-top: 20rpx;
}
}
}

.screen-record {
height: 192rpx;
// width: 100%;
overflow: hidden;
padding: 0 30rpx;
box-sizing: border-box;
border-bottom: 1px solid #CCCCCC;

.screen-record-text {
margin-top: 36rpx;
font-size: 30rpx;
font-weight: 400;
color: #333333;
line-height: 30rpx;
}

.screen-record-tab {
margin-top: 30rpx;
display: flex;

// justify-content: space-around;
.screen-record-chose {
width: 151rpx;
height: 60rpx;
background: #FFFFFF;
border-radius: 4rpx;
border: 1px solid #2671E2;
text-align: center;
line-height: 60rpx;
margin-right: 22rpx;
}

.screen-record-nochose {
width: 151rpx;
height: 60rpx;
background: #FFFFFF;
border-radius: 4rpx;
border: 1px solid #C9C9C9;
text-align: center;
line-height: 60rpx;
margin-right: 22rpx;
}

}
}

.screen-foot {
height: 88rpx;
display: flex;
width: 100%;
margin-top: 160rpx;

.screen-foot-reset {
width: 80%;
text-align: center;
margin: 0 auto;
line-height: 88rpx;
font-size: 30rpx;
font-weight: 400;
color: #666666;
}

.screen-foot-sure {
width: 80%;
margin: 0 auto;
text-align: center;
line-height: 88rpx;
font-size: 30rpx;
font-weight: 400;
color: #FFFFFF;
background: #2671E2;
}
}
}
</style>

+ 1511
- 0
pages/center/prohibited/details.vue
File diff suppressed because it is too large
View File


+ 773
- 0
pages/center/prohibited/index.vue View File

@@ -0,0 +1,773 @@
<template>
<view class="box">
<!-- 选择器 -->
<view class="boxtittab">
<view class="tabbox" @click="taptimeisshow">
{{ timeText }}
<u-icon name="arrow-down" size="24" style="padding-left: 12rpx;"></u-icon>
</view>
<view class="tabbox" @click="selectshow = true">
{{ guwenText }}
<u-icon name="arrow-down" size="24" style="padding-left: 12rpx;"></u-icon>
</view>

<view class="tabbox" @click="tapsoltishow">
{{ steyStatus }}
<u-icon name="arrow-down" size="24" style="padding-left: 12rpx;"></u-icon>
</view>
<view class="tabbox" @click="showIdent = true">
{{ weijinTag }}
<u-icon name="arrow-down" size="24" style="padding-left: 12rpx;"></u-icon>
</view>

</view>
<view class="count" v-if="recordList.length > 0">
筛选结果:<text>{{totalRecords}} </text>条
</view>
<view class="content">
<view v-if="recordList.length==0"
style="width: 100%;height: 100%;display: flex;align-items: center;background: #FFFFFF;">
<view style="width: 100%;padding-top: 200rpx;">
<view style="width: 100%;text-align: center;">
<image style="width: 220rpx;height: 200rpx;"
src="https://static.quhouse.com/zhikong_xcx_img/nodatalist.png" mode=""></image>
</view>
<view style="text-align: center;width: 100%;margin-top: 20rpx;color: #999999;">暂无数据</view>
</view>
</view>
<view v-if="recordList.length!=0" class="content-tips" v-for="(item,index) in recordList" :key='index'
@click="tapThevisiting(item, index)">
<view class="content-first">
<view class="left">
<view class="img">顾</view>
<view class="name">{{item.agentName}}</view>
<view class="status" v-if="item.replaceReception==1">代接待</view>
</view>
<view class="right">
<view class="">
{{ item.violatedStatus | ViolatedStatus }}|{{ item.disposeStatus | DisposeStatus }}
</view>
</view>
</view>

<view class="content-last">
<view class="item">
<image src="@/static/images/img/time.png" mode=""></image>
<text>{{item.createTime}}</text>
</view>
<view class="item">
<image src="@/static/images/img/voice.png" mode=""></image>
<text>{{item.mm || '0'}}min</text>
</view>
<view class="item">
<image src="@/static/images/img/hit.png" mode=""></image>
<text>{{item.violatedFrequency || '0'}}</text>
</view>
</view>
</view>
</view>


<!-- 选择顾问的选择框 -->
<u-select v-model="selectshow" :list="freeList" @confirm="actionSelectCallback"></u-select>
<u-calendar v-model="totalTimeShow" mode="range" @change="totalTimeChange"></u-calendar>
<u-popup v-model="timeshow" mode="bottom">
<block v-for="(data, index) in activeList" :key="index">
<view class="timeview" :style="{ color: activeTotal == data.id ? '#2B6EFF' : '#333333' }"
@click="tabtimetap(data.id, data.title)">{{ data.title }}</view>
</block>
</u-popup>
<u-select v-model="soltishow" :list="orderBylist" @confirm="selectCallback2"></u-select>

<u-select v-model="showIdent" :list="identList" @confirm="selectIdent"></u-select>
</view>
</template>

<script>
export default {
data() {
return {
orderBylist: [{
label: '全部',
value: null
}, {
label: '待处理',
value: 0
}, {
label: '已处理',
value: 1
}],
activeTotal: 5,
activeList: [ // 时间筛选数组
{
title: '全部',
id: 5,
},
{
title: '今天',
id: 0,
},
{
title: '昨天',
id: 1,
},
{
title: '近7天',
id: 2,
},
{
title: '近30天',
id: 3,
},
{
title: '自定义',
id: 4,
},
],
showIdent: false, // 显示选择违禁标识列表
identList: [ // 违禁标识列表
{
label: '全部',
value: null
},
{
label: '有效',
value: 1
},
{
label: '无效',
value: 2
},
],
violatedStatus: null, // 违禁状态
selectshow: false,
totalTimeShow: false,
screen: {
agentId: '', //顾问id
record: '0',
},
freeList: [], //顾问
recordList: [],
buildingID: '',
nextPage: 1,
totalRecord: "",
staTime: '',
endtime: '',
isnorefresh: '',
activeTotal2: 0,
timeshow: false,
soltishow: false,
orderBy: null,
userInfo: {},
totalRecords: '', // 列表全部的条数
isRefresh: false,
nextPageObj: {}, // 跳转详情页面的参数


// 页面文字展示内容
timeText: '接待时间', //
guwenText: '顾问', //
steyStatus: '处理状态', //
weijinTag: '违禁标识', // 违禁标识

}
},
onLoad(options) {
this.isnorefresh = options.refresh;
if (options.activeTotal) {
this.activeTotal = options.activeTotal
}
if (options.staTime) {
this.staTime = options.staTime;
this.endtime = options.endtime;
}
if (options.violatedStatus) this.violatedStatus = options.violatedStatus
},
onShow() {
this.userInfo = uni.getStorageSync('weapp_session_userInfo_data');
if (this.isnorefresh == 'refresh') {
this.buildingID = uni.getStorageSync('buildingID').id;
this.recordList = [];
this.nextPage = 1;
this.isRefresh = false;
this.getMyCustom()
this.getFreeList();
this.isnorefresh = '';
}
var pages = getCurrentPages();
pages[0].$vm.path = '/pages/index/index'
console.log(pages[0].$vm.path)
},
onPullDownRefresh() {
this.nextPage = 1;
this.isRefresh = true;
this.getMyCustom()
this.resetRefreshParams()
setTimeout(function() {
uni.stopPullDownRefresh();
}, 1000);
},
onReachBottom() {
if (this.totalRecord == this.nextPage) {
uni.showToast({
icon: 'none',
title: '到底了',
duration: 2000
});
return
} else {
this.nextPage += 1;
this.isRefresh = false;
this.getMyCustom();
}
},
methods: {
// 重置参数
resetRefreshParams() {
this.timeText = '接待时间'
this.activeTotal = 5
this.guwenText = '顾问'
this.screen.agentId = '' // 顾问id
this.steyStatus = '处理状态'
this.orderBy = null
this.weijinTag = '违禁标识'
this.violatedStatus = null // 违禁状态
},

tapsoltishow() {
this.soltishow = true;
},

taptimeisshow() {
this.timeshow = true;
},

//选择标签
selectCallback2(e) {
this.orderBy = e[0].value;
this.steyStatus = e[0].label;
this.nextPage = 1;
this.recordList = [];
this.isRefresh = false;
this.getMyCustom();
},

// 选择违禁标识
selectIdent(e) {
this.violatedStatus = e[0].value
this.weijinTag = e[0].label
this.nextPage = 1;
this.recordList = [];
this.isRefresh = false;
this.getMyCustom();
},

//时间选择
tabtimetap(index, title) {
this.timeshow = false;
if (index == 4) {
this.totalTimeShow = true;
} else {
this.timeText = title
this.activeTotal = index;
this.staTime = '';
this.endtime = '';
this.nextPage = 1;
this.recordList = [];
this.isRefresh = false;
this.getMyCustom();
}
},
//自定义时间
totalTimeChange(e) {
this.staTime = e.startDate;
this.endtime = e.endDate;
this.timeText = `${e.startDate}-${e.endDate}`
this.activeTotal = 4;
this.nextPage = 1;
this.recordList = [];
this.isRefresh = false;
this.getMyCustom();
},

// 跳转违禁详情
tapThevisiting(item, index) {
if (item.status == 0) {
uni.showToast({
icon: "none",
title: "排队中"
})
return
} else {
const parames = {
pageNum: 1,
pageSize: 100,
query: {
customerId: item.id,
}
}
this.$u.post("/customer/prohibitedMatch", {
customerId: item.id
}).then(res => {
let newweijin = res[0];
newweijin.transferContent = JSON.parse(newweijin.transferContent)
var item = {
bg: newweijin.transferContent.bg,
customerId: newweijin.corpusId,
}
uni.setStorageSync("searchobj", item); //写入缓存
this.$u.post("/corpus/findByPage", parames).then(res => {
if (res == null) {
uni.showToast({
icon: "none",
title: "暂无音频"
})
return
} else {
let newobj = res[0];

let obj = {
pageSize: index+1,
num: this.totalRecords,
query: {
...this.nextPageObj
}
}
uni.setStorageSync('nextPageObj', JSON.stringify(obj))
uni.navigateTo({
url: `/pages/center/prohibited/details?customerId=${newobj.customerId}&status=${newobj.status}&stateisshow=${"2"}&index=${index}&isMerge=${res[0].merge}`
})
// if (res[0].merge == 0) {
// }
// else {
// uni.navigateTo({
// url: `/pages/mine/details?customerId=${newobj.customerId}&status=${newobj.status}&stateisshow=${"2"}`
// })
// }
}
})
})
}

},

// 获取围巾列表
getMyCustom() {
let dateType = 0;
if (this.activeTotal == 5) {
dateType = null;
} else if (this.activeTotal == 4) {
dateType = null;
} else {
dateType = this.activeTotal;
}

var parames = {
pageNum: this.nextPage,
pageSize: 10,
query: {
projectId: this.buildingID,
time: 1,
staTime: this.staTime,
endtime: this.endtime,
taboo: 1,
dateType: dateType,
disposeStatus: this.orderBy, // 处理状态
violatedStatus: this.violatedStatus, // 违禁状态
}
};
if (this.screen.agentId) {
parames.query.agentId = this.screen.agentId
}

this.$u.post("/customer/findbypage", parames).then(data => {
var list = data.results || [];
if (this.isRefresh) {
this.recordList = list;
} else {
this.recordList = [...this.recordList, ...list];
}
this.totalRecord = data.totalPage;
this.totalRecords = data.totalRecord;
this.nextPageObj = parames.query
})
},
//获取顾问列表
getFreeList() {
this.$u.post("/cusLvStatistics/selectAllAccountIdByHouseId", {
houseId: this.buildingID
}).then(res => {
this.freeList = res;
this.freeList.forEach(item => {
item.label = item.name;
item.value = item.accountId
})
this.freeList.unshift({
label: '全部',
value: null,
})
})
},
//顾问确认
actionSelectCallback(e) {
this.screen.agentId = e[0].value;
this.guwenText = e[0].label;
this.recordList = [];
this.nextPage = 1;
this.selectshow = false;
this.isRefresh = false;
this.getMyCustom();
},
},


filters: {
// violatedStatus
ViolatedStatus(status) {
let str = '';
switch (status) {
case 0:
str = '有效违禁'
break;
case 1:
str = '有效违禁'
break;
case 2:
str = '无效违禁'
break;
}
return str
},
// DisposeStatus
DisposeStatus(status) {
let str = '';
switch (status) {
case 0:
str = '待处理'
break;
case 1:
str = '已处理'
break;
}
return str
},
}
}
</script>

<style lang="scss" scoped>
.box {
width: 100vw;
min-height: calc(100vh - var(--window-top));
background: #F8F8F8;
}

.count {
width: 100%;
height: 90rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: #FBE4E4;

text {
color: #F71616;
}
}

.timeview {
height: 80rpx;
line-height: 80rpx;
width: 100%;
text-align: center;
border-bottom: 1px solid #F8F8F8;
}

//时间切换的样式
.boxtittab {
position: sticky;
top: var(--window-top);
z-index: 100;
width: 100;
height: 92rpx;
background: #FFFFFF;
border: 1px solid #E0E0E0;
display: flex;
align-items: center;

.tabbox {
flex: 1;
height: 100%;
text-align: center;
line-height: 92rpx;
color: #666666;
font-size: 28rpx;
overflow: hidden;
/* 超出一行文字自动隐藏 */
text-overflow: ellipsis;
/*文字隐藏后添加省略号*/
white-space: nowrap;
/*强制不换行*/
}
}

.search-box {
width: 100%;
height: 102rpx;
background: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;

.search {
width: 94%;
height: 70rpx;
display: flex;
align-items: center;
background: #F8F8F8;
border-radius: 33rpx;

.search-img {
width: 26rpx;
height: 30rpx;
margin-left: 20rpx;

.search-img1 {
width: 100%;
height: 100%;
margin-top: 2rpx;
}
}

.search-text {
font-size: 28rpx;
font-weight: 400;
color: #999999;
margin-left: 10rpx;
}
}

.search-screen {
width: 40rpx;
height: 40rpx;
margin-left: 30rpx;

.search-screen1 {
width: 100%;
height: 100%;
}
}
}

.content {
.content-tips {
margin: 0 0 20rpx 0;
background: #fff;
box-sizing: border-box;
display: flex;
flex-direction: column;

.content-first {
padding: 20rpx 30rpx;
display: flex;
justify-content: space-between;
background-color: #EEF4FD;

.left {
display: flex;

.img {
margin-right: 10rpx;
width: 52rpx;
height: 52rpx;
background: #FFFFFF;
border: 1px solid #C9C9C9;
border-radius: 50%;
text-align: center;
line-height: 52rpx;
}

.name {
font-weight: 600;
color: #333333;
// margin-left: 20rpx;
margin-top: 11rpx;
}

.status {
width: 110rpx;
height: 42rpx;
background: #FFF9F5;
border-radius: 4rpx;
font-size: 26rpx;
font-weight: 400;
color: #EC8D49;
line-height: 42rpx;
text-align: center;
margin-left: 19rpx;
margin-top: 11rpx;
}
}

.right {
display: flex;
margin-top: 11rpx;

.point {
width: 12rpx;
height: 12rpx;
background: #2B6EFF;
border-radius: 50%;
margin-right: 9rpx;
margin-top: 16rpx;

}
}
}


.content-last {
padding: 24rpx 30rpx;
font-size: 30rpx;
font-weight: 400;
color: #666666;
display: flex;
justify-content: space-between;

.item {
flex-shrink: 0;
display: flex;
align-items: center;

image {
margin-right: 10rpx;
width: 32rpx;
height: 32rpx;
}

text {
font-size: 28rpx;
}
}
}
}
}

// 这是弹出层
.screen {
// box-sizing: border-box;
// padding: 0 30rpx;
position: absolute;

.screen-counselor {
display: flex;
height: 106rpx;
// padding: 40rpx 30rpx 36rpx 30rpx;
padding: 0 30rpx;
box-sizing: border-box;
border-bottom: 1px solid #EEEEEE;

.screen-text {
margin: 40rpx 0 36rpx 0;
font-size: 30rpx;
font-weight: 400;
color: #333333;
line-height: 30rpx;
}

.screen-sel {
display: flex;
justify-content: space-between;
width: 500rpx;
margin-left: 60rpx;

.screen-sel-img {
margin: 40rpx 0 36rpx 0;
width: 14rpx;
height: 30rpx;
}

.screen-inp {
margin-top: 20rpx;
}
}
}

.screen-record {
height: 192rpx;
// width: 100%;
overflow: hidden;
padding: 0 30rpx;
box-sizing: border-box;
border-bottom: 1px solid #EEEEEE;

.screen-record-text {
margin-top: 36rpx;
font-size: 30rpx;
font-weight: 400;
color: #333333;
line-height: 30rpx;
}

.screen-record-tab {
margin-top: 30rpx;
display: flex;

// justify-content: space-around;
.screen-record-chose {
width: 156rpx;
height: 60rpx;
background: #2671E2;
border-radius: 4rpx;
border: 1px solid #2671E2;
text-align: center;
line-height: 60rpx;
margin-right: 22rpx;
color: #FFFFFF;
}

.screen-record-nochose {
width: 156rpx;
height: 60rpx;
background: #FFFFFF;
border-radius: 4rpx;
border: 1px solid #C9C9C9;
text-align: center;
line-height: 60rpx;
margin-right: 22rpx;
}

}
}

.screen-foot {
width: 100%;
height: 100rpx;
display: flex;

.screen-foot-reset {
width: 50%;
text-align: center;
height: 100rpx;
line-height: 100rpx;
font-size: 30rpx;
font-weight: 400;
color: #666666;
}

.screen-foot-sure {
width: 50%;
text-align: center;
line-height: 100rpx;
height: 100rpx;
font-size: 30rpx;
font-weight: 400;
color: #FFFFFF;
background: #2671E2;
}
}
}
</style>

+ 1025
- 0
pages/center/records/index.vue
File diff suppressed because it is too large
View File


+ 275
- 0
pages/center/records/recordSearch.vue View File

@@ -0,0 +1,275 @@
<template>
<view class="box">
<view style="width: 690rpx;margin: 0 auto;margin-top: 20rpx;">
<u-search @search='searchinfo()' :show-action='false' placeholder="请输入" v-model="keyword"></u-search>
</view>
<!-- <view @click="searchinfo()">搜索</view> -->
<view class="content" style="background: #F8F8F8;">
<view class="content-tips" v-for="(item,index) in recordList" :key='index' @click="tapThevisiting(item)">
<view class="content-first">
<view class="left">
<!-- <view class="img">{{item.agentName.slice(0,1)}}</view> -->
<view class="name">{{item.agentName}}</view>
<view class="status" v-if="item.replaceReception==1">代接待</view>
<view style="margin-left: 6rpx;margin-top: 11rpx;">{{item.receptionStatusName || ''}}</view>
</view>
<view class="right" v-if="item.recording!=0">
<view style="margin-right: 6rpx;">{{item.validInvalidName||''}}</view>
<view v-if="methodsisshow==true">
<text style="color: red;" v-if="item.taboo==1">违禁接待</text>
<text v-if="item.taboo==1"> |</text>
</view>
<!-- <view class="point"></view> -->
<view v-if="item.markAdvisor==0" class="">未标记</view>
<view v-if="item.markAdvisor==1" class="">已标记</view>
</view>
<view class="right" v-else>
<view class="">无录音</view>
</view>
</view>
<view class="content-sec">
<view class="left">
<view class="cus">客户:{{item.name || '--'}} |</view>
<view class="arriveNum">{{item.visitRecord || "0"}}次到访</view>
</view>
<view class="right">
{{item.fraction || '0'}}%
<!-- | {{item.fraction || '0'}}分 -->
</view>
</view>
<view class="content-last">
{{item.createTime}} | {{item.mm || '0'}}分钟
</view>
</view>
</view>
</view>
</template>

<script>
export default{
data(){
return{
keyword:'',
recordList:[],
buildingID:'',
nextPage:1,
totalRecord:"",
methodsisshow:false,
userInfo:{}
}
},
onShow() {
this.userInfo = uni.getStorageSync('weapp_session_userInfo_data');
if(this.userInfo.dataCode==6 || this.userInfo.dataCode==3){
this.methodsisshow=false;
}else{
this.methodsisshow=true;
}
this.buildingID = uni.getStorageSync('buildingID').id;
this.nextPage=1;
this.recordList=[];
},
onReachBottom() {
if(this.totalRecord==this.nextPage){
uni.showToast({
icon:'none',
title: '到底了',
duration: 2000
});
return
}else{
this.nextPage+=1;
this.getMyCustom();
}
},
methods:{
tapThevisiting(item) {
console.log("11111111111111")
uni.showLoading({
title: '加载中',
mask:true
});
if(item.status==0){
setTimeout(function () {
uni.hideLoading();
}, 2000);
uni.showToast({
icon: "none",
title: "排队中"
})
return
}else{
const parames = {
pageNum: 1,
pageSize: 100,
query: {
customerId: item.id,
}
}
var item={
bg:0,
customerId:item.id,
}
uni.setStorageSync("entrance", 1); //写入缓存
uni.setStorageSync("searchobj", item); //写入缓存
this.$u.post("/corpus/findByPage", parames).then(res => {
if(res==null){
setTimeout(function () {
uni.hideLoading();
}, 2000);
uni.showToast({
icon: "none",
title: "暂无音频"
})
return
}else{
setTimeout(function () {
uni.hideLoading();
}, 2000);
let newobj = res[0];
if(res[0].merge==0){
uni.navigateTo({
url: `/pages/mine/details2?customerId=${newobj.customerId}&status=${newobj.status}&stateisshow=${"2"}`
})
}else{
uni.navigateTo({
url: `/pages/mine/details?customerId=${newobj.customerId}&status=${newobj.status}&stateisshow=${"1"}`
})
}
}
})
}
},
searchinfo(){
this.nextPage=1;
this.recordList=[];
this.getMyCustom();
},
getMyCustom(){
var parames = {
pageNum: this.nextPage,
pageSize: 10,
query: {
projectId:this.buildingID,
time:1,
nameOrPhone:this.keyword
}
};
this.$u.post("/customer/findbypage", parames).then(data => {
var list = data.results || [];
this.recordList = [...this.recordList, ...list];
this.totalRecord=data.totalPage;
})
},
}
}
</script>

<style lang="scss" scoped>
.box {
width: 100%;
height: 100vh;
background: #FFFFFF;
}
.content{
.content-tips{
background: #fff;
padding: 0 20rpx;
box-sizing: border-box;
overflow: hidden;
margin-top: 20rpx;
.content-first{
margin-top: 19rpx;
display: flex;
justify-content: space-between;
.left{
display: flex;
.img{
width: 52rpx;
height: 52rpx;
background: #FFFFFF;
border: 1px solid #C9C9C9;
border-radius: 50%;
text-align: center;
line-height: 52rpx;
}
.name{
font-weight: 600;
color: #333333;
// margin-left: 20rpx;
margin-top: 11rpx;
}
.status{
width: 110rpx;
height: 42rpx;
background: #FFF9F5;
border-radius: 4rpx;
font-size: 26rpx;
font-weight: 400;
color: #EC8D49;
line-height: 42rpx;
text-align: center;
margin-left: 19rpx;
margin-top: 11rpx;
}
}
.right{
display: flex;
margin-top: 11rpx;
.point{
width: 12rpx;
height: 12rpx;
background: #2B6EFF;
border-radius: 50%;
margin-right: 9rpx;
margin-top: 16rpx;
}
}
}
.content-sec{
display: flex;
justify-content: space-between;
margin-top: 19rpx;
.left{
display: flex;
.cus{
font-size: 30rpx;
font-weight: 400;
color: #666666;
line-height: 30rpx;
}
.arriveNum{
font-size: 30rpx;
font-weight: 400;
line-height: 30rpx;
margin-left: 10rpx;
}
}
.right{
width: 120rpx;
height: 46rpx;
background: #F4F8FD;
border-radius: 6rpx;
text-align: center;
line-height: 46rpx;
font-weight: 400;
color: #2671E2;
}
}
.content-last{
margin: 30rpx 0;
font-size: 30rpx;
font-weight: 400;
color: #666666;
line-height: 30rpx;
}
}
}
</style>

+ 453
- 0
pages/index/customer.vue View File

@@ -0,0 +1,453 @@
<template>
<view class="cented-box">
<view v-if="waitCustomList.length==0" style="width: 100%;height: 100%;display: flex;align-items: center;">
<view style="width: 100%;padding-top: 200rpx;">
<view style="width: 100%;text-align: center;">
<image style="width: 220rpx;height: 200rpx;"
src="https://static.quhouse.com/zhikong_xcx_img/nodatalist.png" mode=""></image>
</view>
<view style="text-align: center;width: 100%;margin-top: 20rpx;color: #999999;">暂无数据</view>
</view>
</view>
<view class="customer" v-if="waitCustomList.length!=0" v-for="(item,index) in waitCustomList" :key='index'
@click="tapThevisiting(item)">
<view class="title">
<view class="zuo">
<!-- <view class="zuoimg">A</view> -->
<view class="zuoname">{{item.name}}</view>
</view>
<view class="you">
<view class="youimg1" v-if="item.status!=0"></view>
<view class="youimg1-1" v-if="item.status==0"></view>
<view class="youtext">{{item.status==0?"排队中":item.status==1?"接待中":"已完成"}}</view>
</view>
</view>
<view class="centerbox" v-if="item.status!=0">
<view class="centerbox-che">手机号码:<text class="shizai">{{item.phone || "--"}}</text></view>
<view class="centerbox-che">开始时间:<text class="shizai">{{item.createTime}}</text></view>
<view class="centerbox-che">顾问姓名:<text class="shizai" style="color: #333333;">{{item.agentName}}</text>
</view>

<view class="centerbox-che2" v-if="item.status==1">
<view class="Workcard" v-if="item.status==1&&item.zkEquipmentState.onLine==0">设备状态:<text
class="shizai" style="color: red;">离线</text></view>
<view class="Workcard" v-if="item.status==1&&item.zkEquipmentState.onLine!=0">工牌电量:<text
class="shizai" style="color: #333333;">{{item.zkEquipmentState.electricity}}%</text></view>
<view class="Workcard" v-if="item.status==1&&item.zkEquipmentState.onLine==1">录音状态:
<text v-if="item.zkEquipmentState.audioStatus=='true'" class="shizai"
style="color: #333333;">使用中</text>
<text v-if="item.zkEquipmentState.audioStatus=='false'" class="shizai"
style="color: #333333;">未使用</text>
</view>
</view>


</view>
<view class="footer-button" v-if="item.status!=0">
<view class="footer1" @click.stop="addTime(item)">接待延时</view>
<view class="footer1" @click.stop="assign(item)">重新指派</view>
<template v-if="endReception">
<view class="footer3" @click.stop="changeEnd(item.id)">结束接待</view>
</template>
</view>

<view class="centerbox" v-if="item.status==0">
<view class="centerbox-che">手机号码:<text class="shizai">{{item.phone || "--"}}</text></view>
</view>
<view class="footer-button" v-if="item.status==0">
<view class="footer3" @click.stop="assign(item)">指派顾问</view>
</view>

</view>
<image v-if="isAdd == 0 && (dataCode!=6||(dataCode==6&&addAccount==0))" @click="addreception()" class="add"
src="/static/images/add.png" mode=""></image>
<image class="add2" @click="reshCustom()" src="https://static.quhouse.com/zhikong_xcx_img/refresh.png" mode="">
</image>
<u-tabbar activeColor="#1296db" inactiveColor="#999999" v-model="current" :list="tabbarList"></u-tabbar>
</view>
</template>

<script>
var util = require("../../utils/util.js");
var config = require("../../config");
import tabbarList from '@/utils/tabbar.js'
export default {
data() {
return {
noClick:true,
tabbarList:tabbarList,
current: 0,
buildingID: '',
waitCustomList: [],
isAdd: '',
dataCode: '',
addAccount: '',
endReception: true,
fdFlag:null
};
},
components: {},
onLoad() {},
onShow() {
this.buildingID = uni.getStorageSync('buildingID').id;
const {
addAccount,
dataCode
} = uni.getStorageSync("weapp_session_userInfo_data");
let menulist = uni.getStorageSync('weapp_session_Menu_data')
this.endReception = menulist.findIndex(item => { return item.name == '结束接待' }) != -1
this.addAccount = addAccount;
this.dataCode = dataCode;
console.log(this.menulist)
this.init()
this.queryHaveDept()
this.updateInit()
},
methods: {
updateInit() {
uni.request({
url: config.service.notReadNum,
method: "GET",
data: {
id: uni.getStorageSync('weapp_session_userInfo_data').accountId,
projectId: uni.getStorageSync('buildingID').id,
},
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
success: (res) => {
this.count = res.data.data
this.tabbarList[3].count = res.data.data || 0
}
})
},
reshCustom() {
this.init()
},
tapThevisiting(item) {
uni.showLoading({
title: '加载中',
mask: true
});
if (item.status == 0) {
setTimeout(function() {
uni.hideLoading();
}, 2000);
uni.showToast({
icon: "none",
title: "排队中"
})
return
} else {
const parames = {
pageNum: 1,
pageSize: 100,
query: {
customerId: item.id,
}
}
var itemsd = {
bg: 0,
customerId: item.id,
id: '',
onebest: ''
}
this.$u.post("/corpus/findByPage", parames).then(res => {
setTimeout(function() {
uni.hideLoading();
}, 2000);
if (res) {
let newobj = res[0];
uni.navigateTo({
url: `/pages/mine/details?customerId=${newobj.customerId}&status=${newobj.status}&itemobj=${JSON.stringify(itemsd)}&stateisshow=${"1"}`
})
} else {
uni.showToast({
icon: "none",
title: "暂无音频"
})
return
}
})
}

},
queryHaveDept() {
return new Promise((resolve, reject) => {
this.$u.get("/user/queryHaveDept?houseId=" + this.buildingID).then(res => {
this.isAdd = res;
resolve();
})
})
},
init() {
this.waitCustomList = []
let parames = {
itemId: this.buildingID
}
this.$u.post("/customer/reception", parames).then(data => {
this.waitCustomList = data;
});
},
//延时接待
addTime(item) {
uni.showModal({
content: "确定延长半小时接待时间?",
cancelColor: "#999999",
success: res => {
if (res.confirm) {
this.$u.post("/customer/delayed", {
cusId: item.id
}).then(res => {
uni.showToast({
icon: "none",
title: "操作成功"
})
});
}
}
})
},
//结束接待
changeEnd(id) {
uni.showModal({
content: "确定更改当前客户接待状态为结束?",
cancelColor: "#999999",
success: res => {
if (this.noClick) {
this.noClick= false;
if (res.confirm) {
if (res.confirm) {
this.$u.post("/customer/endReception", {
id: id,
houseId: this.buildingID
}).then(res => {
uni.showToast({
icon: "none",
title: "操作成功"
})
this.init();
});
}
}
setTimeout(()=> {
this.noClick= true;
}, 2000)
} else {
// 这里是重复点击的判断
}
}
})
},
//新增接待
addreception() {
const {
dataCode,
addAccount
} = uni.getStorageSync("weapp_session_userInfo_data");

if (dataCode == 6) {
if (addAccount != 0) {
uni.showToast({
title: '不允许自建客户!',
duration: 2000
});
return
}
if (this.waitCustomList.length == 0) {
uni.navigateTo({
url: '/pages/mine/reception/addreception'
})
return
} else {
for (var i = 0; i < this.waitCustomList.length; i++) {
if (this.waitCustomList[i].status == 1) {
uni.showLoading({
title: '当前还有未完成的客户项'
});
setTimeout(function() {
uni.hideLoading();
}, 1000);
return
} else {
uni.navigateTo({
url: '/pages/mine/reception/addreception'
})
return
}
}
}
} else {
uni.navigateTo({
url: '/pages/mine/reception/addreception'
});
}
},
assign(item) {
let url = `/pages/mine/reception/consultant?id=${item.id}`
if (item.beforeAgentId) {
url += `&beforeAgentId=${item.beforeAgentId}`;
}
uni.navigateTo({
url: url
})
},

},

};
</script>

<style lang="scss" scoped>
.cented-box {
background: #F8F8F8;
width: 100%;
height: 100vh;
padding-bottom: 30rpx;
}

.customer {
margin-top: 30rpx;
width: 100%;
background: #FFFFFF;
box-shadow: 0px 0px 12px 0px rgba(224, 224, 224, 0.3);

.title {
height: 90rpx;
border-bottom: 1px solid #E0E0E0;
display: flex;
align-items: center;

.zuo {
width: 80%;
height: 100%;
display: flex;
align-items: center;

.zuoimg {
width: 52rpx;
height: 52rpx;
border-radius: 50%;
border: 1px solid #C9C9C9;
font-size: 30rpx;
color: #292929;
font-weight: 400;
line-height: 52rpx;
text-align: center;
margin-left: 30rpx;
}

.zuoname {
font-size: 30rpx;
font-weight: 500;
color: #333333;
line-height: 30rpx;
margin-left: 20rpx;
}
}

.you {
width: 20%;
height: 100%;
display: flex;
align-items: center;

.youimg1 {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background: #2B6EFF;
}

.youimg1-1 {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background: #F2A269;
}

.youtext {
font-size: 30rpx;
font-weight: 400;
color: #292929;
line-height: 30rpx;
margin-left: 10rpx;
}
}
}

.centerbox {
.centerbox-che {
width: 100%;
margin-top: 30rpx;
height: 30rpx;
font-size: 30rpx;
font-weight: 400;
color: #666666;
line-height: 30rpx;
text-indent: 30rpx;

.shizai {
color: #333333;
}
}

.centerbox-che2 {
width: 100%;
margin-top: 30rpx;
height: 30rpx;
font-size: 30rpx;
font-weight: 400;
color: #666666;
line-height: 30rpx;
text-indent: 30rpx;
display: flex;

.Workcard {
width: 50%;
}
}
}

.footer-button {
margin-top: 30rpx;
width: 100%;
height: 90rpx;
display: flex;
font-size: 30rpx;
font-weight: 400;
color: #333333;
border-top: 1rpx solid #E0E0E0;

.footer1 {
flex: 1;
text-align: center;
line-height: 90rpx;
border-right: 1rpx solid #E0E0E0;
}

.footer3 {
flex: 1;
text-align: center;
line-height: 90rpx;
}
}
}

.add {
width: 90upx;
height: 90upx;
position: fixed;
bottom:275upx;
right: 44upx;
}

.add2 {
width: 90upx;
height: 90upx;
position: fixed;
bottom: 160upx;
right: 44upx;
}
</style>

+ 182
- 0
pages/index/guide.vue View File

@@ -0,0 +1,182 @@
<template>
<view class="boox">
<view class="title">
数智工牌
</view>
<view class="booximg">
<!-- <image class="img" src="https://qufang.oss-cn-beijing.aliyuncs.com/zkgj/xcx/guidepage.png" mode=""></image> -->
<image class="img" src="https://qufang.oss-cn-beijing.aliyuncs.com/zkgj/xcx/images1.png" mode=""></image>
</view>
<view class="center-dingwei">
<view style="height: 44rpx;display: flex;margin-left: 213rpx;">
<image style="width: 44rpx;height: 44rpx;" src="https://qufang.oss-cn-beijing.aliyuncs.com/zkgj/xcx/images2.png" mode=""></image>
<view style="line-height: 44rpx;margin-left: 10rpx;font-size: 32rpx;color: #333333;">智能语音转写</view>
</view>
<view style="height: 44rpx;display: flex;margin-left: 213rpx;margin-top: 20rpx;">
<image style="width: 44rpx;height: 44rpx;" src="https://qufang.oss-cn-beijing.aliyuncs.com/zkgj/xcx/images2.png" mode=""></image>
<view style="line-height: 44rpx;margin-left: 10rpx;font-size: 32rpx;color: #333333;">高效的判客机制</view>
</view>
<view style="height: 44rpx;display: flex;margin-left: 213rpx;margin-top: 20rpx;">
<image style="width: 44rpx;height: 44rpx;" src="https://qufang.oss-cn-beijing.aliyuncs.com/zkgj/xcx/images2.png" mode=""></image>
<view style="line-height: 44rpx;margin-left: 10rpx;font-size: 32rpx;color: #333333;">全方位的客户跟进</view>
</view>
<view style="height: 44rpx;display: flex;margin-left: 213rpx;margin-top: 20rpx;">
<image style="width: 44rpx;height: 44rpx;" src="https://qufang.oss-cn-beijing.aliyuncs.com/zkgj/xcx/images2.png" mode=""></image>
<view style="line-height: 44rpx;margin-left: 10rpx;font-size: 32rpx;color: #333333;">专业的经济管家</view>
</view>
<view style="height: 44rpx;display: flex;margin-left: 213rpx;margin-top: 20rpx;">
<image style="width: 44rpx;height: 44rpx;" src="https://qufang.oss-cn-beijing.aliyuncs.com/zkgj/xcx/images2.png" mode=""></image>
<view style="line-height: 44rpx;margin-left: 10rpx;font-size: 32rpx;color: #333333;">在线实时沟通</view>
</view>
</view>
<view @click="bindWxBLogin" class="button">
<view class="view">
立即去登录
</view>
</view>
</view>
</template>

<script>
var app = getApp();
var config = require("../../config");
export default {
data() {
return {
name:"",
path:'/pages/index/index',
pathurl:'/pages/index/index',
pathur2:'/pages/index/customer',
pathur3:'/pages/center/prohibited/index',
};
},
onLoad(opts) {
this.name=opts.loginName ||'';
let stat=opts.path||'';
if(stat==1){
this.path=this.pathur3;
}else if(stat==2){
this.path=this.pathur2;
}else{
this.path=this.pathurl;
}
},
onShow: function() {
if(this.name==''){
uni.request({
url: config.service.verify,
method: "GET",
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
success: (data) => {
if (data.data.code == 10000) {
uni.switchTab({
url: '/pages/index/index'
});
}
}
})
}else{
var userInfo=uni.getStorageSync('weapp_session_userInfo_data');
if(userInfo){
console.log(userInfo.loginName)
if(this.name==userInfo.loginName){
uni.request({
url: config.service.verify,
method: "GET",
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
success: (data) => {
if (data.data.code == 10000) {
if(this.path=='/pages/center/prohibited/index'){
uni.navigateTo({
url:this.path
});
}else{
uni.switchTab({
url:this.path
});
}
}
}
})
}else{
console.log("不是本人")
}
}else{
console.log("没有用户信息")
}
}
},
methods: {
bindWxBLogin() {
wx.navigateTo({
url: '/pages/login/index'
});
}

}
};
</script>
<style lang="scss">
.boox{
width: 100vw;
height: 100vh;
position: relative;
.title {
width: 100%;
position: absolute;
left: 0rpx;
top: 100rpx;
text-align: center;
color: #FFFFFF;
font-size: 32rpx;
font-weight: 500;
z-index: 1000;
}
.booximg{
width: 100vw;
height: 96vh;
.img{
width: 100%;
height: 100%;
}
}
.center-dingwei{
width: 100%;
position: absolute;
left: 0rpx;
bottom:230rpx;
}
.button {
width: 100%;
position: absolute;
left: 0rpx;
bottom:80rpx;
.view{
width: 630rpx;
height: 86rpx;
margin: 0 auto;
background: #2671E2;
box-shadow: 0px 2rpx 20rpx 0rpx rgba(38, 113, 226, 0.5);
border-radius: 49rpx;
color: #FFFFFF;
text-align: center;
line-height: 86rpx;
font-size: 32rpx;
}
}
}
</style>

+ 1064
- 0
pages/index/index.vue
File diff suppressed because it is too large
View File


+ 626
- 0
pages/index/learning.vue View File

@@ -0,0 +1,626 @@
<template>
<view class="main">
<view class="tab-box">
<view class="tab-item-wrap">
<view v-for="(item, index) in tablist" :key="index"
:class="activeClass == index ? 'bottom' : ''" @click="clocktab(index, item.id)">
{{ item.name }}
<view class="bottomLine" v-if="activeClass == index"></view>
</view>
</view>
</view>
<view class="cented" v-if="activeClass==0">
<view class="ceninfo" v-for="(item,index) in alllist" @click="quclick(item)" :key="index">
<view class="infoview">
<view class="infozuo">
<view class="infozuochiud1">{{item.jbaName}}</view>
<view class="infozuochiud2">置业顾问</view>
</view>
<view class="infoyou">
<view class="infoyouchiud2" >去学习</view>
</view>
</view>
<view class="footerinfo">
<view class="footerinfozuo">{{item.assignedTime}}</view>
<view class="footerinfoyou"></view>
</view>
<view class="footicon">
<view class="icon">
<image class="Piabodata-img1" src="../../static/images/studyhot.png" mode=""></image>
<!-- 浏览量 -->
{{item.pageviews}}
</view>
<view class="icon">
<image class="Piabodata-img1" src="../../static/images/viewstudy.png" mode=""></image>
<!-- 热度 -->
{{item.heat}}
</view>
</view>
</view>
</view>
<view class="biaoqianview" v-if="activeClass==1">
<view class="boxintention">
<view class="title">分点标签列表</view>
<view class="boxcenten" v-for="(item,index) in equinoctial" :key="index" @click="routerclick(item)">
<view class="boxcenteninfotext">{{item.name}}</view>
<view class="boxcenteninfoimg"><u-icon size="20px" name="arrow-right"></u-icon></view>
</view>
</view>
</view>
<u-tabbar activeColor="#1296db" inactiveColor="#999999" v-model="current" :list="tabbarList"></u-tabbar>
</view>
</template>

<script>
var config = require("../../config");
var util = require("@/utils/util.js");
import tabbarList from '@/utils/tabbar.js'
export default {
data() {
return {
tabbarList:tabbarList,
current: 0,
tablist:[
{name:"全文"},
{name:"分点"}
],
activeClass:0,
equinoctial:[],
alllist:[],
buildingID:''
};
},
onShow(){
var i=uni.getStorageSync('fendianindex')
this.buildingID=uni.getStorageSync('buildingID').id;
this.clocktab(i)
this.updateInit()
},
onPullDownRefresh() {
var i=uni.getStorageSync('fendianindex')
this.clocktab(i)
setTimeout(function () {
uni.stopPullDownRefresh();
}, 1000);
},
methods: {
updateInit() {
uni.request({
url: config.service.notReadNum,
method: "GET",
data: {
id: uni.getStorageSync('weapp_session_userInfo_data').accountId,
projectId: uni.getStorageSync('buildingID').id,
},
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
success: (res) => {
this.count = res.data.data
this.tabbarList[3].count = res.data.data || 0
}
})
},
//全部学习跳转
quclick(item){
uni.showLoading({
title: '加载中',
mask:true
});
const parames = {
pageNum: 1,
pageSize: 100,
query: {
customerId: item.carId,
}
}
var cet={
bg:0,
customerId:item.id,
id:''
}
this.$u.post("/corpus/findByPage", parames).then(res => {
setTimeout(function () {
uni.hideLoading();
}, 2000);
var newobj = res[0];
if(res[0].merge==0){
uni.navigateTo({
url: `/pages/learning/Thefulltext/index2?customerId=${newobj.customerId}&status=${newobj.status}&itemobj=${JSON.stringify(cet)}&stateisshow=${"2"}`
})
}else{
uni.navigateTo({
url: `/pages/learning/Thefulltext/index?customerId=${newobj.customerId}`
})
}
})
},
//分点学习跳转
routerclick(item){
uni.navigateTo({
url: "/pages/learning/Equinoctiallearning?id="+item.marketingId+"&biaoqian="+item.name
})
},
// tab切换
clocktab(index) {
this.activeClass = index;
if(this.activeClass==0){
uni.setStorageSync("fendianindex", 0); //写入缓存
this.ceninit()
}else{
uni.setStorageSync("fendianindex", 1); //写入缓存
this.infoinit()
}
},
ceninit(){
let infoobj={
"pageNum":1,
"pageSize":100,
"query":{
"status":0,
'itemId':this.buildingID,
}
}
uni.request({
url: config.service.findAllZATD,
method:"POST",
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
data:infoobj,
success: (data) => {
if(data.data.code==10000){
this.alllist=data.data.data.results
}else{
uni.showToast({
title: data.data.message,
duration: 2000
});
}
}
})
},
infoinit(){
let obj={
itemId:this.buildingID
}
uni.request({
url: config.service.findSelectedLabel,
method:"POST",
data:obj,
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
success: (data) => {
if(data.data.code==10000){
this.equinoctial=data.data.data
}else{
uni.showToast({
title: data.data.message,
duration: 2000
});
}
}
})
}
},
}
</script>

<style lang="scss" scoped>
.main {
background: #F1F1F1;;
min-height: 100vh;
}
.tab-box {
height: auto;
overflow: auto;
width: 100%;
.tab-item-wrap {
height: 100rpx;
width: 80%;
margin: 0 auto;
line-height: 100rpx;
display: flex;
justify-content: space-around;
font-size: 36rpx;
color: #959dad;
}
}
.bottom {
color: #008EF2;
position: relative;
}
.bottomLine {
position: absolute;
width: 96rpx;
height: 6rpx;
top: 80rpx;
background-color: #298dff;
border-radius: 8rpx 8rpx 0rpx 0rpx;
left: -13rpx;
}
.cented{
width: 100%;
padding-top: 14rpx;
.ceninfo{
width: 690rpx;
// height: 160rpx;
background: #FFFFFF;
border-radius: 8rpx;
margin: 0 auto;
margin-top: 20rpx;
padding-top: 23rpx;
position: relative;
.infoview{
width: 100%;
height: 64rpx;
display: flex;
.infozuo{
width: 454rpx;
height: 100%;
display: flex;
align-items: center;
.infozuochiud1{
font-size: 36rpx;
font-weight: 600;
color: #0C0C0C;
text-indent: 28rpx;
}
.infozuochiud2{
width: 113rpx;
height: 42rpx;
border-radius: 5rpx;
margin-left: 19rpx;
border: 1px solid #008EF2;
font-size: 24rpx;
font-weight: 400;
color: #008EF2;
line-height: 42rpx;
text-align: center;
}
}
.infoyou{
width:236rpx;
height: 100%;
display: flex;
align-items: center;
.infoyouchiud1{
display: block;
width: 64rpx;
height: 64rpx;
border-radius: 50%;
}
.infoyouchiud2{
width: 133rpx;
height: 56rpx;
background: #008EF2;
border-radius: 8rpx;
text-align: center;
color: #FFFFFF;
font-size: 30rpx;
line-height: 56rpx;
margin-left: 80rpx;
}
}
}
.footerinfo{
width: 100%;
height: 42rpx;
display: flex;
margin-top: 14rpx;
.footerinfozuo{
width: 454rpx;
font-size: 30rpx;
color: #0C0C0C;
line-height: 42rpx;
margin-left: 26rpx;
}
.footerinfoyou{
width: 236rpx;
font-size: 24rpx;
color: #999999;
line-height: 42rpx;
text-indent: 42rpx;
}
}
.dingwei{
width: 100%;
height: 60rpx;
border: 1px solid red;
position: absolute;
top: 160rpx;
left: 0rpx;
}
}
}
.biaoqianview{
width: 100%;
.boxintention {
width: 690rpx;
margin: 0 auto;
.title {
font-size: 36upx;
color: #333333;
position: relative;
display: flex;
align-items: center;
padding-left: 19upx;
&:before {
content: '';
position: absolute;
left: 0;
height: 30upx;
width: 9upx;
background: #008ef2;
border-radius: 5rpx;
}
}
.boxcenten{
width: 100%;
height: 100rpx;
background: #FFFFFF;
border-radius: 8rpx;
margin-top: 22rpx;
display: flex;
.boxcenteninfotext{
width: 90%;
height: 100%;
text-indent: 20rpx;
line-height: 100rpx;
font-size: 30rpx;
color: #0C0C0C;
}
.boxcenteninfoimg{
width: 10%;
height: 100%;
line-height: 100rpx;
}
}
}
}
.footicon{
display: flex;
align-items: center;
margin-top: 30rpx;
padding:20rpx;
flex-direction: row-reverse;
.icon{
margin-left: 20rpx;
}
image{
width: 36rpx;
height: 36rpx;
margin-right: 20rpx;
vertical-align: -7rpx;
}
}
</style>



<!-- <template>
<view class="cented-box">
<view class="search-box">
<view class="search">
<view class="search-img">
<image class="search-img1" src="../../static/images/search.png" mode=""></image>
</view>
<view class="search-text">输入话术关键字</view>
</view>
</view>
<view class="caseid-box">
<view class="caseid">
<image class="caseid-img1" src="../../static/images/good.png" mode=""></image>
<view class="caseid-text">优秀案例</view>
</view>
<view class="caseid">
<image class="caseid-img1" src="../../static/images/problem.png" mode=""></image>
<view class="caseid-text">问题库</view>
</view>
<view class="caseid">
<image class="caseid-img1" src="../../static/images/reverse.png" mode=""></image>
<view class="caseid-text">反面案例</view>
</view>
</view>
<view class="Pinspeak">销讲话术</view>
<view class="chented">
<view class="title">
<view class="title1"></view>
<view class="titletext">逼单话术</view>
<view class="titleimg">
<image class="titleimg1" src="../../static/images/arrow.png" mode=""></image>
</view>
</view>
</view>
<view class="chented">
<view class="title" style="border: none;">
<view class="title1"></view>
<view class="titletext">品牌介绍</view>
</view>
<view class="chented-for">
<view class="chented-che">2021销售额</view>
<view class="chented-che">2021销售额</view>
<view class="chented-che">2021销售额</view>
<view class="chented-che">2021销售额</view>
</view>
</view>
<view class="chented">
<view class="title" style="border: none;">
<view class="title1"></view>
<view class="titletext">品牌介绍</view>
</view>
<view class="chented-for">
<view class="chented-che">2021销售额</view>
<view class="chented-che">2021销售额</view>
<view class="chented-che">2021销售额</view>
<view class="chented-che">2021销售额</view>
</view>
</view>
</view>
</template>

<script>
export default {
data() {
return {};
},
components: {},
onLoad() {},
onShow() {},
methods: {
},
};
</script>

<style lang="scss" scoped>
.cented-box{
background: #F8F8F8;
width: 100%;
height: 100%;
}
.search-box{
width: 100%;
height: 102rpx;
background: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
.search{
width: 690rpx;
height: 70rpx;
display: flex;
align-items: center;
background: #F8F8F8;
border-radius: 33rpx;
.search-img{
width: 26rpx;
height: 30rpx;
margin-left: 20rpx;
.search-img1{
width: 100%;
height: 100%;
margin-top: 2rpx;
}
}
.search-text{
font-size: 28rpx;
font-weight: 400;
color: #999999;
margin-left:10rpx;
}
}
}
.caseid-box{
width: 100%;
height: 204rpx;
margin-top: 10rpx;
background: #FFFFFF;
display: flex;
.caseid{
flex: 1;
height: 100%;
text-align: center;
margin-top: 13rpx;
.caseid-img1{
width: 134rpx;
height: 134rpx;
}
.caseid-text{
width: 100%;
text-align: center;
font-size: 24rpx;
font-weight: 400;
color: #333333;
}
}
}
.Pinspeak{
width: 100%;
height: 92rpx;
border-bottom: 1rpx solid #E0E0E0;
font-size: 32rpx;
font-weight: 600;
color: #333333;
text-indent: 30rpx;
line-height: 92rpx;
background: #FFFFFF;
margin-top: 20rpx;
}
.chented{
width: 100%;
padding-left: 30rpx;
padding-right: 30rpx;
background-color: #FFFFFF;
.title{
width: 100%;
height: 90rpx;
border-bottom: 1rpx solid #E0E0E0;
display: flex;
align-items: center;
.title1{
width: 6rpx;
height: 30rpx;
background: #2671E2;
}
.titletext{
width: 90%;
height: 30rpx;
font-size: 30rpx;
font-weight: 600;
color: #333333;
line-height: 30rpx;
text-indent: 10rpx;
}
.titleimg{
width: 8%;
text-align: right;
.titleimg1{
width: 14rpx;
height: 30rpx;
}
}
}
.chented-for{
width: 100%;
display: flex;
flex-wrap: wrap;
margin-top: -20rpx;
border-bottom: 1rpx solid #E0E0E0;
padding-bottom: 30rpx;
.chented-che{
width: 210rpx;
height: 60rpx;
background: #FFFFFF;
border-radius: 4rpx;
border: 1px solid #C9C9C9;
text-align: center;
line-height: 60rpx;
font-size: 30rpx;
font-weight: 400;
color: #333333;
margin-right: 20rpx;
margin-top: 20rpx;
}
}
}
</style>
-->

+ 305
- 0
pages/index/personal.vue View File

@@ -0,0 +1,305 @@
<template>
<view class="main">
<view class="backTop"></view>
<!-- 头部开始 -->
<view class="header box">
<view class="header-zuo">
<u-avatar
:src="photo?photo:'https://qufang.oss-cn-beijing.aliyuncs.com/upload/icon/xcx/zkgj/headPicture.png'"
size="148"></u-avatar>
</view>
<view class="header-you">
<view class="userName">{{name}}</view>
<view class="mobile">{{mobile}}</view>
</view>
</view>
<view class="settingGroup box">
<navigator class="line" url="/pages/mine/messageList">
<view class="title" style="width: 21%;">
<image src="/static/images/studyhot.png" style="width: 36rpx;height: 36rpx;" mode=""></image>
消息
</view>
<view class="right" style="display: flex;align-items: center;">
<view class="count" v-if="count!=0">{{count}}</view>
<image src="/static/images/arrow.png" style="width: 18rpx;height: 32rpx;" mode=""></image>
</view>
</navigator>
<navigator class="line" url="/pages/mine/subscribe">
<view class="title">
<image src="/static/images/studyhot.png" style="width: 36rpx;height: 36rpx;" mode=""></image>
订阅消息
</view>
<view class="right">
<image src="/static/images/arrow.png" style="width: 18rpx;height: 32rpx;" mode=""></image>
</view>
</navigator>
<navigator class="line" url="/pages/mine/Myprofile">
<view class="title">
<image src="/static/images/setting.png" style="width: 36rpx;height: 36rpx;" mode=""></image>
编辑资料
</view>
<view class="right">
<image src="/static/images/arrow.png" style="width: 18rpx;height: 32rpx;" mode=""></image>
</view>
</navigator>
<view class="line" @click="phone">
<view class="title">
<image src="/static/images/Customer.png" style="width: 36rpx;height: 36rpx;" mode=""></image>
客服电话
</view>
<view class="right">
<image src="/static/images/arrow.png" style="width: 18rpx;height: 32rpx;" mode=""></image>
</view>
</view>
<view class="line" @click="scan">
<view class="title" style="width: 220rpx;">
<image src="/static/images/reg.png" style="width: 36rpx;height: 36rpx;" mode=""></image>
访客登记码
</view>
<view class="right">
<image src="/static/images/arrow.png" style="width: 18rpx;height: 32rpx;" mode=""></image>
</view>
</view>
<view class="line" @click="Changehepassword">
<view class="title">
<image src="/static/images/password.png" style="width: 36rpx;height: 36rpx;" mode=""></image>
修改密码
</view>
<view class="right">
<image src="/static/images/arrow.png" style="width: 18rpx;height: 32rpx;" mode=""></image>
</view>
</view>
<view class="line" @click="logout" style="border: none;">
<view class="title">
<image src="/static/images/exit.png" style="width: 36rpx;height: 36rpx;" mode=""></image>
退出登录
</view>
<view class="right">
<image src="/static/images/arrow.png" style="width: 18rpx;height: 32rpx;" mode=""></image>
</view>
</view>

</view>
<u-tabbar activeColor="#1296db" inactiveColor="#999999" v-model="current" :list="tabbarList"></u-tabbar>
</view>
</template>

<script>
var app = getApp();
var util = require("../../utils/util.js");
var config = require("../../config");
import tabbarList from '@/utils/tabbar.js'

export default {
data() {
return {
tabbarList:tabbarList,
current: 0,
tabList: [
{
name: '系统消息'
},
{
name: '升级公告'
},
],
name: "",
photo: "",
mobile: "",
count:0,
};
},
onShow: function() {
var userInfos = uni.getStorageSync('weapp_session_userInfo_data');
this.name = userInfos.name,
this.photo = userInfos.picUrl,
this.mobile = userInfos.loginName
this.updateInit()
},
methods: {
updateInit() {
uni.request({
url: config.service.notReadNum,
method: "GET",
data: {
id: uni.getStorageSync('weapp_session_userInfo_data').accountId,
projectId: uni.getStorageSync('buildingID').id,
},
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
success: (res) => {
this.count = res.data.data
this.tabbarList[3].count = res.data.data || 0
}
})
},
scan(){
uni.navigateTo({
url:"../mine/registerCode"
})
},
//拨打电话
phone() {
wx.makePhoneCall({
phoneNumber: '4008191707,8888' //仅为示例,并非真实的电话号码
})
},
//修改密码
Changehepassword() {
uni.navigateTo({
url: '/pages/mine/Changehepassword'
});
},
//退出
logout() {
uni.showModal({
title: '提示',
content: '确定要退出?',
cancelColor: "#999999",
showCancel: true,
success(res) {
if (res.confirm) {
app.Closewebsocke()
uni.clearStorageSync(); //清除缓存
uni.showToast({
icon: "none",
title: "退出成功"
})
uni.reLaunch({
url: '/pages/login/index'
});
}
}
});
},
// tosubscr(){
// let that=this;
// wx.login({
// success (res) {
// if (res.code) {
// let appid ='wxd9748307889cbe0d';
// let secret = 'cfc40d2b86b650e216e900a2c430cd2b'
// let url = 'https://api.weixin.qq.com/sns/jscode2session?appid=' + appid + '&secret=' + secret + '&js_code=' +res.code + '&grant_type=authorization_code';
// uni.request({
// url: url, // 请求路径
// success: result => {
// that.$u.get("/user/bindMessage",{
// openId:result.data.openid,
// loginName:that.mobile
// }).then(data => {
// console.log(data)
// })
// }
// })
// } else {
// console.log('登录失败!' + res.errMsg)
// }
// }
// })
// // /pages/mine/subscribe
// },

}
};
</script>
<style lang="scss" scoped>
.count{
background: red;
width: 50rpx;
height: 50rpx;
border-radius: 40rpx;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
font-size: 24rpx;
margin-right: 20rpx;
}
.main {
padding: 0 30rpx;
background: #F8F8F8;
display: flex;
flex-direction: column;
min-height: 100vh;
padding-bottom: 40rpx;

.backTop {
background: #2671E2;
position: absolute;
left: 0;
top: 0;
width: 750rpx;
height: 171rpx;
}

.box {
background: #ffffff;
}
}

.header {
z-index: 2;
width: 100%;
height: 212rpx;
border-radius: 12rpx;
margin-top: 42rpx;
display: flex;

.header-zuo {
width: 148rpx;
height: 148rpx;
margin-top: 32rpx;
margin-left: 30rpx;
}

.header-you {
margin-left: 20rpx;

.userName {
font-size: 36rpx;
font-weight: 500;
color: #303030;
margin-top: 56rpx;
}

.mobile {
font-size: 30rpx;
color: #BDBDBD;
margin-top: 20rpx;
}
}
}

.settingGroup {
box-shadow: 0px 0px 12px 0px rgba(224, 224, 224, 0.3);
border-radius: 12rpx;
margin-top: 30rpx;
color: #333333;
font-size: 30rpx;
display: flex;
flex-direction: column;

.line {
height: 118rpx;
border-bottom: 1rpx solid #EEEEEE;
margin: 0 38rpx 0 30rpx;
display: flex;
align-items: center;
justify-content: space-between;

.title {
display: flex;
align-items: center;
width: 190rpx;
justify-content: space-between;
}
}
}
</style>

+ 1537
- 0
pages/learning/Equinoctial/index.vue
File diff suppressed because it is too large
View File


+ 1567
- 0
pages/learning/Equinoctial/index2.vue
File diff suppressed because it is too large
View File


+ 237
- 0
pages/learning/Equinoctiallearning.vue View File

@@ -0,0 +1,237 @@
<template>
<view class="main">
<view class="cented">
<view class="ceninfo" v-for="(item,index) in alllist" :key="index">
<view class="infoview">
<view class="infozuo">
<view class="infozuochiud1">{{item.jbaName}}</view>
<view class="infozuochiud2">置业顾问</view>
</view>
<view class="infoyou">
<view class="infoyouchiud2" @click="quclick(item)">去学习</view>
</view>
</view>
<view class="footerinfo">
<view class="footerinfozuo">{{item.assignedTime}}</view>
<view class="footerinfoyou"></view>
</view>
</view>
</view>

</view>
</template>


<script>
var config = require("../../config");
var util = require("../../utils/util.js");
export default {
data() {
return {
alllist: [],
id: "",
biaoqian:""
};
},
onLoad(options) {
this.id = options.id;
this.biaoqian=options.biaoqian
this.ceninit()
},
onPullDownRefresh() {
this.ceninit()
setTimeout(function () {
uni.stopPullDownRefresh();
}, 1000);
},
methods: {
quclick(item) {
uni.showLoading({
title: '加载中',
mask:true
});
const parames = {
pageNum: 1,
pageSize: 100,
query: {
whetherFinish: 1,
customerId: item.carId,
id:item.startFile
}
}
var cet={
bg:0,
customerId:item.id,
id:''
}
this.$u.post("/corpus/fendianFindByPage", parames).then(res => {
var newobj = res[0];
setTimeout(function () {
uni.hideLoading();
}, 2000);
if(res[0].merge==0){
uni.navigateTo({
url: `/pages/learning/Equinoctial/index2?customerId=${newobj.customerId}&biaoqian=${this.biaoqian}&startTime=${item.startTime}&startFile=${item.startFile}`
})
}else{
uni.navigateTo({
url: `/pages/learning/Equinoctial/index?customerId=${newobj.customerId}&biaoqian=${this.biaoqian}&startTime=${item.startTime}&startFile=${item.startFile}`
})
}
})
},
ceninit() {
let itemid=uni.getStorageSync('buildingID').id;
let infoobj = {
"pageNum": 1,
"pageSize": 100,
"query": {
"status": 1,
"marketingId": this.id,
"itemId":itemid
}
}
uni.request({
url: config.service.findAllZATD,
method: "POST",
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
data: infoobj,
success: (data) => {
console.log(data.data.data.results, "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq");
if (data.data.code == 10000) {
this.alllist = data.data.data.results
} else {
uni.showToast({
title: data.data.message,
duration: 2000
});
}
}
})
},



},
}
</script>

<style lang="scss" scoped>
.main {
background: #F1F1F1;
;
min-height: 100vh;
padding-top: 30rpx;
}

.cented {
width: 100%;
padding-top: 14rpx;

.ceninfo {
width: 690rpx;
height: 160rpx;
background: #FFFFFF;
border-radius: 8rpx;
margin: 0 auto;
padding-top: 23rpx;
position: relative;
margin-top: 20rpx;
.infoview {
width: 100%;
height: 64rpx;
display: flex;

.infozuo {
width: 454rpx;
height: 100%;
display: flex;
align-items: center;

.infozuochiud1 {
font-size: 36rpx;
font-weight: 600;
color: #0C0C0C;
text-indent: 28rpx;
}

.infozuochiud2 {
width: 113rpx;
height: 42rpx;
border-radius: 5rpx;
margin-left: 19rpx;
border: 1px solid #008EF2;
font-size: 24rpx;
font-weight: 400;
color: #008EF2;
line-height: 42rpx;
text-align: center;
}
}

.infoyou {
width: 236rpx;
height: 100%;
display: flex;
align-items: center;

.infoyouchiud1 {
display: block;
width: 64rpx;
height: 64rpx;
border-radius: 50%;
}

.infoyouchiud2 {
width: 133rpx;
height: 56rpx;
background: #008EF2;
border-radius: 8rpx;
text-align: center;
color: #FFFFFF;
font-size: 30rpx;
line-height: 56rpx;
margin-left: 80rpx;
}
}
}

.footerinfo {
width: 100%;
height: 42rpx;
display: flex;
margin-top: 14rpx;

.footerinfozuo {
width: 454rpx;
font-size: 30rpx;
color: #0C0C0C;
line-height: 42rpx;
margin-left: 26rpx;
}

.footerinfoyou {
width: 236rpx;
font-size: 24rpx;
color: #999999;
line-height: 42rpx;
text-indent: 42rpx;
}
}

.dingwei {
width: 100%;
height: 60rpx;
border: 1px solid red;
position: absolute;
top: 160rpx;
left: 0rpx;
}
}
}
</style>

+ 146
- 0
pages/learning/Keywordsearch.vue View File

@@ -0,0 +1,146 @@
<template>
<view class="translation">
<view style="width: 690rpx;height: 64rpx;margin: 0 auto;margin-top: 30rpx;background: #F2F2F2;border-radius: 32rpx;
display: flex;align-items: center;">
<view style="width: 10%;height: 64rpx;display: flex;align-items: center;">
<image style="width: 28rpx;height: 28rpx;margin-left: 30rpx;" src="/static/images/search.png" mode=""></image>
</view>
<view style="width: 90%;height: 64rpx;display: flex;align-items: center;">
<input type="text" @input="searchinfo" :disabled="disabled" v-model="keyword" placeholder="请输入关键字"
style="width: 100%;color: #999999;font-size: 24rpx;"/>
</view>
</view>
<view style="width: 690rpx;margin: 0 auto;margin-top: 10rpx;">
<view style="width: 100%;border-bottom: 1px solid #E0E0E0;display: flex;padding-bottom: 10rpx;margin-top: 40rpx;"
v-for="(item,index) in listarr" :key='index' @click="toaidoinfo(item.Content,item.corpusId,item.index)">
<view style="width: 26rpx;height: 36rpx;margin-top: 4rpx;">
<image style="width: 26rpx;height: 28rpx;" src="../../static/images/testimg.png" mode=""></image>
</view>
<view v-html="item.Content.text" style="color: #666666;font-size: 28rpx;line-height: 36rpx;margin-left: 10rpx;width: 80%;"></view>
<view style="font-size: 28rpx;width: 10%;width: 14%;text-align: right;">{{item.Content.time}}</view>
</view>
</view>
</view>
</template>

<script>
var util = require("../../utils/util.js");
var config = require("../../config");
export default {
data() {
return {
customerId:'',
listarr:[],
keyword:'',
skpl:'',
disabled:false,
tipsFncName: '', // 通知其他页面的方法名称
};
},
onLoad(options) {
this.customerId = options.customerId;
this.keyword=options.keyword;
this.skpl=options.skpl;
if (options.UpDateEvent) this.tipsFncName = options.UpDateEvent
if(this.skpl==2){
this.searchinfo()
this.disabled=true;
}else{
this.disabled=false;
}
},
methods: {
formatTime(num) {
//格式化时间格式
num = num.toFixed(0);
let second = num % 60;
if (second < 10) second = '0' + second;
let min = Math.floor(num / 60);
if (min < 10) min = '0' + min;
return min + ":" + second;
},
searchinfo(){
if(this.keyword.length==0){
return
}else{
let parames={
keyword:this.keyword,
customerId:this.customerId
}
this.$u.post("/corpus/keyWordsMatching", parames).then(res => {
res.forEach(item=>{
item.Content=JSON.parse(item.transferContent)
})
res.forEach(cet=>{
cet.Content.time=this.formatTime(cet.Content.bg/1000)
cet.Content.text=this.brightKeyword(cet.Content.onebest)
})
this.listarr=res;
})
}
},
//替换方法
brightKeyword(val) {
if (val.indexOf(this.keyword) !== -1) {
return val.replace(this.keyword, `<font style='color: red'>${this.keyword}</font>`);
} else {
return val;
}
},
//跳转
toaidoinfo(item,id,index){
uni.setStorageSync("entrance", 2); //写入缓存
item.customerId=this.customerId;
item.id=id;
item.index=index;
if(this.skpl==2){
this.infostust(item)
}else{
let pages = getCurrentPages() //获取当前页面栈的信息
let prevPage = pages[pages.length - 2] //获取上一个页面
if (this.tipsFncName) uni.$emit(this.tipsFncName, item)
prevPage.setData({ //把需要回传的值保存到上一个页面
info: item
});
wx.navigateBack({ //然后返回上一个页面
delta: 1
})
}
},
//只有一条的时候
infostust(item){
uni.setStorageSync("searchobj", item); //写入缓存
const parames = {
pageNum: 1,
pageSize: 100,
query: {
customerId: this.customerId,
}
}
this.$u.post("/corpus/findByPage", parames).then(res => {
if(res[0].merge==0){
let newobj = res[0];
if (this.tipsFncName) {
uni.$emit(this.tipsFncName, item)
uni.navigateBack()
return
}
uni.navigateTo({
url: `/pages/mine/details2?customerId=${newobj.customerId}&status=${newobj.status}&stateisshow=${'2'}`
})
}else{
let newobj = res[0];
uni.navigateTo({
url: `/pages/mine/details?customerId=${newobj.customerId}&status=${newobj.status}&stateisshow=${'2'}`
})
}
})
},
},
}
</script>
<style lang="scss" scoped>

</style>

+ 1685
- 0
pages/learning/Thefulltext/index.vue
File diff suppressed because it is too large
View File


+ 1506
- 0
pages/learning/Thefulltext/index2.vue
File diff suppressed because it is too large
View File


+ 144
- 0
pages/learning/Thefulltext/search.vue View File

@@ -0,0 +1,144 @@
<template>
<view class="translation">
<view style="width: 690rpx;height: 64rpx;margin: 0 auto;margin-top: 30rpx;background: #F2F2F2;border-radius: 32rpx;
display: flex;align-items: center;">
<view style="width: 10%;height: 64rpx;display: flex;align-items: center;">
<image style="width: 28rpx;height: 28rpx;margin-left: 30rpx;" src="/static/images/search.png" mode=""></image>
</view>
<view style="width: 90%;height: 64rpx;display: flex;align-items: center;">
<input type="text" @input="searchinfo" :disabled="disabled" v-model="keyword" placeholder="请输入关键字"
style="width: 100%;color: #999999;font-size: 24rpx;"/>
</view>
</view>
<view style="width: 690rpx;margin: 0 auto;margin-top: 10rpx;">
<view style="width: 100%;border-bottom: 1px solid #E0E0E0;display: flex;padding-bottom: 10rpx;margin-top: 40rpx;"
v-for="(item,index) in listarr" :key='index' @click="toaidoinfo(item.Content,item.corpusId,item.index)">
<view style="width: 26rpx;height: 36rpx;margin-top: 4rpx;">
<image style="width: 26rpx;height: 28rpx;" src="/static/images/testimg.png" mode=""></image>
</view>
<view v-html="item.Content.text" style="color: #666666;font-size: 28rpx;line-height: 36rpx;margin-left: 10rpx;width: 80%;"></view>
<view style="font-size: 28rpx;width: 10%;width: 14%;text-align: right;">{{item.Content.time}}</view>
</view>
</view>
</view>
</template>

<script>
var util = require("../../../utils/util.js");
var config = require("../../../config");
export default {
data() {
return {
customerId:'',
listarr:[],
keyword:'',
skpl:'',
disabled:false,
tipsFncEvent: "",
};
},
onLoad(options) {
this.customerId = options.customerId;
this.keyword=options.keyword;
this.skpl=options.skpl;
if (options.UpDateEvent) this.tipsFncEvent = options.UpDateEvent
},
methods: {
formatTime(num) {
//格式化时间格式
num = num.toFixed(0);
let second = num % 60;
if (second < 10) second = '0' + second;
let min = Math.floor(num / 60);
if (min < 10) min = '0' + min;
return min + ":" + second;
},
searchinfo(){
if(this.keyword.length==0){
return
}else{
let parames={
keyword:this.keyword,
customerId:this.customerId
}
this.$u.post("/corpus/keyWordsMatching", parames).then(res => {
res.forEach(item=>{
item.Content=JSON.parse(item.transferContent)
})
res.forEach(cet=>{
cet.Content.time=this.formatTime(cet.Content.bg/1000)
cet.Content.text=this.brightKeyword(cet.Content.onebest)
})
this.listarr=res;
})
}
},
//替换方法
brightKeyword(val) {
if (val.indexOf(this.keyword) !== -1) {
return val.replace(this.keyword, `<font style='color: red'>${this.keyword}</font>`);
} else {
return val;
}
},
//跳转
toaidoinfo(item,id,index){
item.customerId=this.customerId;
item.id=id;
item.index=index;
if(this.skpl==2){
this.infostust(item)
}else{
let pages = getCurrentPages() //获取当前页面栈的信息
let prevPage = pages[pages.length - 2] //获取上一个页面
uni.$emit(this.tipsFncEvent, item)
prevPage.setData({ //把需要回传的值保存到上一个页面
info: item
});
wx.navigateBack({ //然后返回上一个页面
delta: 1
})
}
},
//只有一条的时候
infostust(item){
let d = JSON.parse(JSON.stringify([item]))
var itemobjhh={
bg:d[0].bg,
customerId:d[0].customerId,
id:'',
onebest:d[0].onebest,
}
const parames = {
pageNum: 1,
pageSize: 100,
query: {
customerId: this.customerId,
}
}
console.log(item)
this.$u.post("/corpus/findByPage", parames).then(res => {
if(res[0].merge==0){
let newobj = res[0];
uni.navigateTo({
url: `/pages/learning/Thefulltext/index2?customerId=${newobj.customerId}&status=${newobj.status}&itemobj=${JSON.stringify(itemobjhh)}&stateisshow=${'2'}`
})
}else{
let newobj = res[0];
uni.navigateTo({
url: `/pages/learning/Thefulltext/index?customerId=${newobj.customerId}&status=${newobj.status}&itemobj=${JSON.stringify(itemobjhh)}&stateisshow=${'2'}`
})
}
})
},
},
}
</script>
<style lang="scss" scoped>

</style>

+ 348
- 0
pages/login/Setthepassword.vue View File

@@ -0,0 +1,348 @@
<template>
<view>
<view style="width: 100%;height: 180rpx;"></view>
<view class="input">
<view class="zcasfdasf">设置密码</view>
<view class="tejHdgasd">设置密码后,就可以使用手机号码与密码登录了~</view>
<view style="margin-top:60rpx" class="cwjs-cells item-flex">
<view class="cwjs-item center">
<input class="cwjs-item cwjs-input" v-model="username" password="true" placeholder="请设置6~12位的登录密码"
placeholder-style='color:#AAAAAA' maxlength="12" />
</view>
</view>

</view>
<view class="button" @tap="bindWxBLogin">确认</view>
</view>
</template>
<script>
var util = require("../../utils/util.js");
var config = require("../../config");
var app = getApp();
var WXB_SESSION_LOGIN_DATA = 'weapp_session_login_data';
export default {
data() {
return {
username: '', //获取到的密码
phone: ''
}
},
onLoad: function(options) {
this.phone = options.username
},
methods: {
bindWxBLogin() {
if (this.username.length < 6) {
util.showNone("密码小于6位,请重试");
return false;
} else {
var loginParams = {
name: this.phone, //手机号
newPassword: this.username, //密码
}
uni.request({
url: config.service.forgotPassword,
header: {
'content-type': 'application/json'
},
data: loginParams,
method: "POST",
success: function(result) {
if (result.data.code == 10000) {
uni.reLaunch({
url: '/pages/login/index',
})
} else {
util.showNone(result.data.message);
return false;
}
}
})
}
}
}
};
</script>

<style lang="scss">
.cwjs-logo {
display: block;
width: 219rpx;
height: 158rpx;
margin: 54rpx auto 66rpx;
}

.cwjs-tips {
font-size: 24rpx;
padding: 80rpx 0;
color: #8a8a8a;
}

.cwjs-form {
position: relative;
margin: 0;
background-color: #fff;
border-radius: 10px;
padding: 20rpx 40rpx 113rpx;
}

.zcasfdasf {
height: 48rpx;
font-size: 48rpx;
font-weight: 400;
color: #303030;
line-height: 48rpx;
margin-top: 80rpx;
}

.tejHdgasd {
height: 28rpx;
font-size: 26rpx;
font-weight: 400;
color: #303030;
line-height: 28rpx;
margin-top: 28rpx;

}

.cwjs-cells {
width: 600rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin: 0 auto;
height: 88rpx;
overflow: hidden;
border-bottom: 1rpx solid #BFC7D3;
position: relative;
}

.center {
flex: 1;
display: flex;
}

.texteasda {
height: 88rpx;
line-height: 88rpx;
font-size: 28rpx;
color: #000;
}

.cwjs-input {
width: 100%;
height: 88rpx;
line-height: 88rpx;
font-size: 28rpx;
color: #000;
}

.images {
display: block;
width: 40rpx;
height: 21rpx;
margin-right: 30rpx;
margin-top: 33.5rpx;
}

.mod-btn {
position: absolute;
bottom: -80rpx;
left: 50%;
margin-left: -80rpx;
}

.mod-btn .button {
width: 160rpx;
height: 160rpx;
background: linear-gradient(180deg, rgba(116, 197, 230, 1) 0%, rgba(64, 147, 201, 1) 100%);
border: 10rpx solid rgba(255, 255, 255, 1);
border-radius: 100%;
font-size: 36rpx;
color: #fff;
display: flex;
justify-content: center;
align-items: center;

}

.mod-btn .button::after {
content: ""
}

.retPassword {
display: inline;
width: auto;
font-size: 28rpx;
color: rgba(64, 147, 201, 1);
line-height: 40rpx;
float: right;
}

.retPassword:active {
background-color: #fff;
}

.appliyAdmin {
position: absolute;
left: 50%;
margin-left: -57rpx;
bottom: 100rpx;
width: 114rpx;
font-size: 28rpx;
color: rgba(255, 255, 255, 1);
line-height: 40rpx;
}

/* 头部 */

.head {
width: 750rpx;
height: 355rpx;
}

.background {
width: 750rpx;
height: 400rpx;
position: absolute;
top: -3rpx;
left: 0;
}

.logo {
width: 123rpx;
height: 107rpx;
display: block;
position: absolute;
top: 84rpx;
left: 313.5rpx;
}

.head text {
font-size: 34rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #2343BD;
position: absolute;
top: 222rpx;
left: 203rpx;
}

/* 输入框 */
.input {
width: 100%;
height: auto;
padding: 0 90rpx;
box-sizing: border-box;
}

.logo_input {
width: 34rpx;
height: 38rpx;
position: absolute;
top: 25rpx;
left: 0;
}

/* 登录 */
.button {
width: 630rpx;
height: 86rpx;
background: #2671E2;
box-shadow: 0px 2rpx 20rpx 0px rgba(38, 113, 226, 0.5);
border-radius: 49rpx;
text-align: center;
line-height: 89rpx;
color: #fff;
margin: 0 auto;
margin-top: 239rpx;
font-size: 34rpx;
}

.footer {
width: 100%;
height: 157rpx;
position: absolute;
bottom: 0;
left: 0;
}

.agreeBox {
/* text-align: center; */
/* width: 450rpx; */
/* padding-left: 145rpx; */
font-size: 28rpx;
color: #88909E;
margin: 0 auto;
margin-top: 30rpx;
position: relative;
display: flex;

}

checkbox {
transform: scale(0.5);
}

checkbox-group {
display: inline;
}

navigator {
display: inline
}

.agreeBox image {
width: 26rpx;
height: 26rpx;
display: block;
position: absolute;
top: 9rpx;
left: 18rpx;
margin-right: 19rpx;
}

.imagesBox {
width: 80rpx;
height: 88rpx;
}

.chooseBox {
width: 60rpx;
height: 60rpx;
}

.login {
text-decoration: underline;
text-align: center;
margin-top: 40px;
color: #88909E;
font-size: 28rpx;
}

.textbox {
width: 569rpx;
display: flex;
margin-top: 40rpx;
}

.textbox-1 {
width: 30%;
font-size: 30rpx;
color: #999999;
}

.textbox-11 {
width: 30%;
text-align: right;
font-size: 30rpx;
color: #999999;
}

.textbox-2 {
width: 40%;
}
</style>

+ 250
- 0
pages/login/Verification.vue View File

@@ -0,0 +1,250 @@
<template>
<view>
<view class="head">
<template v-if="role == 2">
<view class="phones">输入手机号</view>
</template>
<template v-else>
<image class="head-immg" src="https://qufang.oss-cn-beijing.aliyuncs.com/zkgj/xcx/login.png" mode=""></image>
</template>
</view>
<view class="input">
<view class="cwjs-cells item-flex">
<view class="cwjs-item center">
<input type="text" v-model="username" placeholder="请输入手机号码" maxlength="11"
placeholder-style='color:#AAAAAA' />
</view>
</view>
<view class="textbox">
<view class="textbox-1" @tap="bindVerification">密码登录</view>
<view class="textbox-2"></view>
<view class="textbox-11"></view>
</view>
</view>
<view class="button" @tap="bindWxBLogin">获取验证码</view>
</view>
</template>

<script>
var util = require("../../utils/util.js");
var config = require("../../config");
var app = getApp();
export default {
data() {
return {
username: '',
role: ''
};
},
onLoad: function(options) {
this.role=options.role;
},
methods: {
//账号密码登录
bindVerification() {
uni.navigateTo({
url: '/pages/login/index',
})
},
//获取验证码
bindWxBLogin: function(e) {
if (!(/^[1][3,4,5,7,8,9][0-9]{9}$/.test(this.username))) {
util.showNone("手机号码错误");
this.username='';
return false;
} else {
uni.request({
url: config.service.sendCode + "?mobile=" + this.username,
method: "GET",
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
success: (data) => {
console.log(data)
// 成功地响应会话信息
if (data.data.code == 10000) {
util.showSuccess('发送成功');
if(this.role==1){
uni.navigateTo({
url: '/pages/login/yinzhongmalogin?username=' + this.username +
'&role=' + this.role,
})
}else{
uni.navigateTo({
url: '/pages/login/Verifythelogin?username=' + this.username +
'&role=' + this.role,
})
}
// 没有正确响应会话信息
} else {
util.showNone(data.data.message);
return false;
}
},
})
}
},
}
};
</script>
<style lang="scss">
.cwjs-logo {
display: block;
width: 219rpx;
height: 158rpx;
margin: 54rpx auto 66rpx;
}

.cwjs-tips {
font-size: 24rpx;
padding: 80rpx 0;
color: #8a8a8a;
}

.cwjs-form {
position: relative;
margin: 0;
background-color: #fff;
border-radius: 10px;
padding: 20rpx 40rpx 113rpx;
}

.cwjs-cells {
width: 569rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin: 0 auto;
height: 88rpx;
overflow: hidden;
border-bottom: 1rpx solid #BFC7D3;
position: relative;
}

.center {
flex: 1;
}

.cwjs-input {
height: 48rpx;
line-height: 48rpx;
padding: 23rpx 23rpx 23rpx 78rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
color: #000;
}

.images {
display: block;
width: 40rpx;
height: 21rpx;
margin-right: 30rpx;
margin-top: 33.5rpx;
}







/* 头部 */

.head {
width: 750rpx;
height: 500rpx;
position: relative;
.phones {
position: absolute;
top: 300rpx;
left: 100rpx;
color: #0A6EE9;
font-size: 36rpx;
font-weight: bold;
}
.head-immg {
width: 118rpx;
height: 61rpx;
position: absolute;
top: 300rpx;
left: 100rpx;
}
}

.logo {
width: 248upx;
height: 248upx;
display: block;
position: absolute;
top: 134rpx;
left: 240.5rpx;
}



/* 输入框 */
.input {
width: 100%;
height: auto;
padding: 0 105rpx;
box-sizing: border-box;
}

.logo_input {
width: 34rpx;
height: 38rpx;
position: absolute;
top: 25rpx;
left: 0;
}

/* 登录 */
.button {
width: 630rpx;
height: 86rpx;
background: #2671E2;
box-shadow: 0px 2rpx 20rpx 0px rgba(38, 113, 226, 0.5);
border-radius: 49rpx;
text-align: center;
line-height: 89rpx;
color: #fff;
margin: 0 auto;
margin-top: 239rpx;
font-size: 34rpx;
}

.login {
text-decoration: underline;
text-align: center;
margin-top: 40px;
color: #88909E;
font-size: 28rpx;
}

.textbox {
width: 569rpx;
display: flex;
margin-top: 40rpx;
}

.textbox-1 {
width: 30%;
font-size: 30rpx;
color: #999999;
}

.textbox-11 {
width: 30%;
text-align: right;
font-size: 30rpx;
color: #999999;
}

.textbox-2 {
width: 40%;
}
</style>

+ 262
- 0
pages/login/Verifythelogin.vue View File

@@ -0,0 +1,262 @@
<template>
<view class="content">
<view class="head">
<view class="text">
<view class="text1">
<view style="color: #666666;">输入短信验证码</view>
<view style="color: #303030;margin-top: 20rpx;">短信已发送至{{phone}},请在下方输入框内输入4位数字验证码</view>
</view>
</view>
</view>
<view class="sction">
<view class="mama">
<view class="mamaz">
<input type="text" v-model="msg" maxlength="4" placeholder="请输入验证码" placeholder-class="input-class" class="input" />
</view>
<view class="mamay">
<view class="sada" v-if="sendAuthCode" style="font-size: 35rpx;" @click="getAuthCode">获取验证码</view>
<text class="sada" v-if="!sendAuthCode">
重新发送
<text>({{ auth_time }})</text>
</text>
</view>
</view>
<view class="login-btn" :style="{ background: msg == '' ? '#F2F2F2' : '#2671E2' }" @click="denglu"><text
class="">确认</text></view>
<view class="code-login" @click="passwordlogin"><text>密码登录</text></view>
</view>
</view>
</template>

<script>
var util = require("../../utils/util.js");
var config = require("../../config");
var app = getApp();
export default {
data() {
return {
sendAuthCode: true,
auth_time: 0,
msg: '',
phonecet: '',
role:'',
phone:''
};
},
onLoad: function(options) {
var phonese = options.username;
var phonexxz = phonese.substring(0, 3) + '****' + phonese.substring(7);
this.phone = phonexxz,
this.phonecet = options.username,
this.role = options.role
if (options.role == 2) {
uni.setNavigationBarTitle({
title: '验证手机号'
})
}
this.sendAuthCode = false;
this.auth_time = 60;
var auth_timetimer = setInterval(() => {
this.auth_time--;
if (this.auth_time <= 0) {
this.sendAuthCode = true;
clearInterval(auth_timetimer);
}
}, 1000);
},
methods: {
//跳转密码登录页面
passwordlogin() {
uni.reLaunch({
url: '/pages/login/index',
})
},
//获取验证码
getAuthCode() {
this.sendAuthCode = false;
this.auth_time = 60;
var auth_timetimer = setInterval(() => {
this.auth_time--;
if (this.auth_time <= 0) {
this.sendAuthCode = true;
clearInterval(auth_timetimer);
}
}, 1000);
},
//登录
denglu() {
if (this.msg=='') {
uni.showToast({
title: '验证码不能为空',
icon: 'none'
});
return
}
if (this.msg.length == 4) {
uni.navigateTo({
url: '/pages/login/Setthepassword?username='+this.phonecet,
})
} else {
uni.showToast({
title: '验证码位数不正确',
icon: 'none'
});
}

},
}
};
</script>

<style lang="scss">
.head {
width: 750rpx;
height:400rpx;
position: relative;
.text{
width: 100%;
position: absolute;
top: 180rpx;
left: 0rpx;
.text1{
width: 80%;
margin: 0 auto;
}
}
}
.mama {
width: 620rpx;
display: flex;
border-bottom: 1px solid #E1E1E1;
margin: 60rpx auto;
}

.sadsadasdasdsadasd {
font-size: 34rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #008EF2;
width: 100%;
text-align: center;
padding-top: 340rpx;
}

.mamaz {
width: 50%;
height: 90rpx;
}

.mamay {
width: 50%;
height: 90rpx;
}

.input {
width: 350rpx;
color: #78DFB0;
height: 100%;
line-height: 90rpx;
font-size: 17px;
color: #171717;
}

.sada {
width: 70%;
line-height: 90rpx;
color: #2B6EFF;
text-align: right;
font-size: 35rpx;
margin-left: 100rpx;
display: block;
}
.content {
margin: 0;
padding: 0;
border-top: 1rpx solid #E0E0E0;
}
.login-text {
font-size: 60rpx;
font-family: PingFang SC;
font-weight: 500;
color: rgba(23, 23, 23, 1);
letter-spacing: 8rpx;
margin-left: 75rpx;
font-weight: bold;
}

.login-input {
border-bottom: 1px solid #e1e1e1;
color: #c9cac9;
margin: 98rpx 64rpx 200rpx 75rpx;
font-size: 17px;

}

.login-btn {
margin: 0 auto;
margin-top: 240rpx;
width: 630rpx;
height: 86rpx;
border-radius: 49rpx;
font-size: 17px;
font-weight: bold;
border: none;
display: flex;
justify-content: center;
align-items: center;
color: #ffffff;
}

.code-login {
display: flex;
justify-content: center;
margin-top: 40rpx;
color: #D6D7D6;
margin-bottom: 200rpx;
font-size: 30rpx;
}

.log-box {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 28rpx;
color: #bfc0bf;
margin-bottom: 65rpx;
}

.hengx {
margin: 0 20rpx 0 20rpx;
height: 2rpx;
width: 232rpx;
background: #e1e1e1;
}

.wechat {
display: flex;
justify-content: center;
align-items: center;
width: 93rpx;
height: 93rpx;
background: rgba(255, 255, 255, 1);
box-shadow: 0px 10rpx 30rpx rgba(120, 223, 176, 0.22);
border-radius: 50%;
margin: 0 auto;
}

.btn-get {
width: 250rpx;
font-size: 17px;
color: #c9cac9;
position: relative;
top: -290rpx;
right: -450rpx;
}

.input-class {
color: #D6D7D6;
font-size: 17px;
letter-spacing: 1rpx;
}
</style>

+ 324
- 0
pages/login/index.vue View File

@@ -0,0 +1,324 @@
<template>
<view>
<view class="head">
<image class="head-immg" src="https://qufang.oss-cn-beijing.aliyuncs.com/zkgj/xcx/login.png" mode=""></image>
</view>
<view class="input">
<view class="cwjs-cells item-flex">
<view class="cwjs-item center">
<image src="https://qufang.oss-cn-beijing.aliyuncs.com/channelHelper/user.png" class="logo_input">
</image>
<input class="cwjs-item cwjs-input" v-model="username" placeholder="请输入账号名" type="number" maxlength="11" placeholder-style="color:#AAAAAA"></input>
</view>
</view>
<view class="cwjs-cells item-flex" style="margin-top:13rpx;">
<view class="cwjs-item center">
<image src="https://qufang.oss-cn-beijing.aliyuncs.com/channelHelper/lock.png" class="logo_input">
</image>
<input class="cwjs-item cwjs-input" placeholder="请输入密码" placeholder-style="color:#AAAAAA" type="password" v-model="password" maxlength="16" v-if="passwordType"></input>
<input class="cwjs-item cwjs-input" placeholder="请输入密码" placeholder-style="color:#AAAAAA" maxlength="16" v-model="password" v-else></input>
</view>
<view class="imagesBox" @tap="changeBindPassword">
<image v-if="passwordType==false" src="../../static/images/zhengkai.png" class="images" mode="scaleToFill"></image>
<image v-if="passwordType==true" src="../../static/images/bishang.png" class="images" mode="scaleToFill"></image>
</view>
</view>
<view class="textbox">
<view class="textbox-1" @tap="bindVerification">验证码登录</view>
<view class="textbox-2"></view>
<view class="textbox-11" @tap="bindpassword">忘记密码</view>
</view>
</view>
<view class="button" @tap="bindWxBLogin">立即登录</view>
</view>
</template>

<script>
var util = require("../../utils/util.js");
var config = require("../../config");
var app = getApp();
var WXB_SESSION_LOGIN_DATA = 'weapp_session_login_data';
export default {
data() {
return {
username: '',
//获取到的用户名的值
password: '',
//获取到的密码栏中的值
passwordType: true,
agreeChecked: true
};
},
onLoad: function(options) {
uni.hideToast();
},
methods: {
//验证码登录
bindVerification() {
uni.navigateTo({
url: '/pages/login/Verification?role=1',
})
},
//忘记密码
bindpassword() {
uni.navigateTo({
url: '/pages/login/Verification?role=2',
})
},
//密码选择
changeBindPassword: function(e) {
this.passwordType=!this.passwordType;
},
//登录
bindWxBLogin: function(e) {
util.showBusy('正在登录...');
var that = this;
if (this.username == '') {
util.showNone("请输入账号名");
return false;
}
if (this.password == '') {
util.showNone("请输入密码");
return false;
}
var loginParams = {
loginName: this.username,
password: this.password
};
// 请求服务器登录地址,获得会话信息
uni.request({
url: config.service.login,
header: {
'content-type': 'application/json'
},
method: "POST",
data: loginParams,
success: function(result) {
var data = result.data; //console.log("登陆信息", data);
if (data && data.code == 10000) {
var res = data.data;
if (res) {
var data = {
'token': res
};
uni.setStorageSync(WXB_SESSION_LOGIN_DATA, data); //写入缓存
that.getMenu()
that.getUser();
util.showSuccess('登录成功');
} else {
util.showNone("账号名或密码错误,请重试");
return false;
}
// 没有正确响应会话信息
} else {
util.showNone(data.message);
return false;
}
},
// 响应错误
fail: function(loginResponseError) {
util.showNone("网络异常,请重试");
return false;
}
});
},
getUser(){
util.getRequestPromise(config.service.getUser, {}, false, "GET").then(data => {
if (data.zkProperties) {
} else {
data.zkProperties = [{
id: "",
propertyName: ''
}]
}
let lopan = {
id: data.zkProperties[0].id,
name: data.zkProperties[0].propertyName
}
uni.setStorageSync("fendianindex", 0); //写入缓存
uni.setStorageSync("weapp_session_userInfo_data", data); //写入缓存
uni.setStorageSync("buildingID", lopan); //项目id写入缓存
uni.switchTab({
url: '/pages/index/index'
});
});
},
getMenu(){
this.$u.get("/user/getMenu").then(data => {
uni.setStorageSync("weapp_session_Menu_data", data)
})
}
}
};
</script>
<style lang="scss">
.cwjs-logo {
display: block;
width: 219rpx;
height: 158rpx;
margin: 54rpx auto 66rpx;
}

.cwjs-tips {
font-size: 24rpx;
padding: 80rpx 0;
color: #8a8a8a;
}

.cwjs-form {
position: relative;
margin: 0;
background-color: #fff;
border-radius: 10px;
padding: 20rpx 40rpx 113rpx;
}

.cwjs-cells {
width: 569rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin: 0 auto;
height: 88rpx;
overflow: hidden;
border-bottom: 1rpx solid #BFC7D3;
position: relative;
}

.center {
flex: 1;
}

.cwjs-input {
height: 48rpx;
line-height: 48rpx;
padding: 23rpx 23rpx 23rpx 78rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
color: #000;
}

.images {
display: block;
width: 40rpx;
height: 21rpx;
margin-right: 30rpx;
margin-top: 33.5rpx;
}

.mod-btn {
position: absolute;
bottom: -80rpx;
left: 50%;
margin-left: -80rpx;
}




/* 头部 */

.head {
width: 750rpx;
height: 500rpx;
position: relative;
.head-immg{
width: 118rpx;
height: 61rpx;
position: absolute;
top: 300rpx;
left: 100rpx;
}
}


.logo {
width: 248upx;
height: 248upx;
display: block;
position: absolute;
top: 134rpx;
left: 240.5rpx;
}

/* 输入框 */
.input {
width: 100%;
height: auto;
padding: 0 105rpx;
box-sizing: border-box;
}

.logo_input {
width: 34rpx;
height: 38rpx;
position: absolute;
top: 25rpx;
left: 0;
}

/* 登录 */
.button {
width: 630rpx;
height: 86rpx;
background: #2671E2;
box-shadow: 0px 2rpx 20rpx 0px rgba(38, 113, 226, 0.5);
border-radius: 49rpx;
text-align: center;
line-height: 89rpx;
color: #fff;
margin: 0 auto;
margin-top: 239rpx;
font-size: 34rpx;
}

.footer {
width: 100%;
height: 157rpx;
position: absolute;
bottom: 0;
left: 0;
}

.imagesBox {
width: 80rpx;
height: 88rpx;
}



.login {
text-decoration: underline;
text-align: center;
margin-top: 40px;
color: #88909E;
font-size: 28rpx;
}

.textbox {
width: 569rpx;
display: flex;
margin-top: 40rpx;
}

.textbox-1 {
width: 30%;
font-size: 30rpx;
color: #999999;
}

.textbox-11 {
width: 30%;
text-align: right;
font-size: 30rpx;
color: #999999;
}

.textbox-2 {
width: 40%;
}
</style>

+ 328
- 0
pages/login/yinzhongmalogin.vue View File

@@ -0,0 +1,328 @@
<template>
<view class="content">
<view class="head">
<view class="text">
<view class="text1">
<view style="color: #666666;">输入短信验证码</view>
<view style="color: #303030;margin-top: 20rpx;">短信已发送至{{phone}},请在下方输入框内输入4位数字验证码</view>
</view>
</view>
</view>
<view class="sction">
<view class="mama">
<view class="mamaz">
<input type="text" v-model="msg" maxlength="4" placeholder="请输入验证码" placeholder-class="input-class" class="input" />
</view>
<view class="mamay">
<view class="sada" v-if="sendAuthCode" style="font-size: 35rpx;" @click="getAuthCode">获取验证码</view>
<text class="sada" v-if="!sendAuthCode">
重新发送
<text>({{ auth_time }})</text>
</text>
</view>
</view>
<view class="login-btn" :style="{ background: msg == '' ? '#F2F2F2' : '#2671E2' }" @click="denglu"><text
class="">登录</text></view>
<view class="code-login" @click="passwordlogin"><text>密码登录</text></view>
</view>
</view>
</template>

<script>
var util = require("../../utils/util.js");
var config = require("../../config");
var app = getApp();
var WXB_SESSION_LOGIN_DATA = 'weapp_session_login_data';
export default {
data() {
return {
sendAuthCode: true,
auth_time: 0,
msg: '',
phonecet: '',
role:'',
phone:''
};
},
onLoad: function(options) {
var phonese = options.username;
var phonexxz = phonese.substring(0, 3) + '****' + phonese.substring(7);
this.phone = phonexxz,
this.phonecet = options.username,
this.role = options.role
this.sendAuthCode = false;
this.auth_time = 60;
var auth_timetimer = setInterval(() => {
this.auth_time--;
if (this.auth_time <= 0) {
this.sendAuthCode = true;
clearInterval(auth_timetimer);
}
}, 1000);
},
methods: {
//跳转密码登录页面
passwordlogin() {
uni.reLaunch({
url: '/pages/login/index',
})
},
//获取验证码
getAuthCode() {
uni.request({
url: config.service.sendCode + "?mobile=" + this.phonecet,
method: "GET",
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
success: (data) => {
console.log(data)
// 成功地响应会话信息
if (data.data.code == 10000) {
util.showSuccess('发送成功');
this.sendAuthCode = false;
this.auth_time = 60;
var auth_timetimer = setInterval(() => {
this.auth_time--;
if (this.auth_time <= 0) {
this.sendAuthCode = true;
clearInterval(auth_timetimer);
}
}, 1000);
} else {
util.showNone(data.data.message);
return false;
}
},
})
},
//登录
denglu() {
if (this.msg=='') {
uni.showToast({
title: '验证码不能为空',
icon: 'none'
});
return
}
if (this.msg.length == 4) {
let porme = {
loginName: this.phonecet,
password: this.msg
}
uni.request({
url: config.service.plogin,
method: "POST",
data: porme,
header: {
'content-type': 'application/json',
'Access-Token': uni.getStorageSync('weapp_session_login_data').token
},
success: (data) => {
// 成功地响应会话信息
if (data.data.code == 10000) {
util.showSuccess('登录成功');
var token = {
'token': data.data.data
};
uni.setStorageSync(WXB_SESSION_LOGIN_DATA, token); //写入缓存
this.getMenu()
this.getUser()
} else {
util.showNone(data.data.message);
return false;
}
},
})
} else {
uni.showToast({
title: '验证码位数不正确',
icon: 'none'
});
}
},
getMenu(){
this.$u.get("/user/getMenu").then(data => {
uni.setStorageSync("weapp_session_Menu_data", data)
})
},
getUser(){
util.getRequestPromise(config.service.getUser, {}, false, "GET").then(data => {
if (data.zkProperties) {
} else {
data.zkProperties = [{
id: "",
propertyName: ''
}]
}
let lopan = {
id: data.zkProperties[0].id,
name: data.zkProperties[0].propertyName
}
uni.setStorageSync("fendianindex", 0); //写入缓存
uni.setStorageSync("weapp_session_userInfo_data", data); //写入缓存
uni.setStorageSync("buildingID", lopan); //项目id写入缓存
uni.switchTab({
url: '/pages/index/index'
});
});
}
}
};
</script>

<style lang="scss">
.head {
width: 750rpx;
height:400rpx;
position: relative;
.text{
width: 100%;
position: absolute;
top: 180rpx;
left: 0rpx;
.text1{
width: 80%;
margin: 0 auto;
}
}
}
.mama {
width: 620rpx;
display: flex;
border-bottom: 1px solid #E1E1E1;
margin: 60rpx auto;
}

.sadsadasdasdsadasd {
font-size: 34rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #008EF2;
width: 100%;
text-align: center;
padding-top: 340rpx;
}

.mamaz {
width: 50%;
height: 90rpx;
}

.mamay {
width: 50%;
height: 90rpx;
}

.input {
width: 350rpx;
color: #78DFB0;
height: 100%;
line-height: 90rpx;
font-size: 17px;
color: #171717;
}

.sada {
width: 70%;
line-height: 90rpx;
color: #2B6EFF;
text-align: right;
font-size: 35rpx;
margin-left: 100rpx;
display: block;
}
.content {
margin: 0;
padding: 0;
border-top: 1rpx solid #E0E0E0;
}

.login-text {
font-size: 60rpx;
font-family: PingFang SC;
font-weight: 500;
color: rgba(23, 23, 23, 1);
letter-spacing: 8rpx;
margin-left: 75rpx;
font-weight: bold;
}

.login-input {
border-bottom: 1px solid #e1e1e1;
color: #c9cac9;
margin: 98rpx 64rpx 200rpx 75rpx;
font-size: 17px;

}

.login-btn {
margin: 0 auto;
margin-top: 240rpx;
width: 630rpx;
height: 86rpx;
border-radius: 49rpx;
font-size: 17px;
font-weight: bold;
border: none;
display: flex;
justify-content: center;
align-items: center;
color: #ffffff;
}

.code-login {
display: flex;
justify-content: center;
margin-top: 40rpx;
color: #D6D7D6;
margin-bottom: 200rpx;
font-size: 30rpx;
}

.log-box {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 28rpx;
color: #bfc0bf;
margin-bottom: 65rpx;
}

.hengx {
margin: 0 20rpx 0 20rpx;
height: 2rpx;
width: 232rpx;
background: #e1e1e1;
}

.wechat {
display: flex;
justify-content: center;
align-items: center;
width: 93rpx;
height: 93rpx;
background: rgba(255, 255, 255, 1);
box-shadow: 0px 10rpx 30rpx rgba(120, 223, 176, 0.22);
border-radius: 50%;
margin: 0 auto;
}

.btn-get {
width: 250rpx;
font-size: 17px;
color: #c9cac9;
position: relative;
top: -290rpx;
right: -450rpx;
}

.input-class {
color: #D6D7D6;
font-size: 17px;
letter-spacing: 1rpx;
}
</style>

+ 116
- 0
pages/mine/ScoringPlaylist.vue View File

@@ -0,0 +1,116 @@
<template>
<view class="translation">
<view style="width: 690rpx;margin: 0 auto;margin-top: 10rpx;">
<view style="width: 100%;border-bottom: 1px solid #E0E0E0;display: flex;padding-bottom: 10rpx;margin-top: 40rpx;"
v-for="(item,index) in listarr" :key='index' @click="toaidoinfo(item.Content,item.corpusId,item.index)">
<view style="width: 26rpx;height: 36rpx;margin-top: 4rpx;">
<image style="width: 26rpx;height: 28rpx;" src="../../static/images/testimg.png" mode=""></image>
</view>
<view v-html="item.Content.onebest" style="color: #666666;font-size: 28rpx;line-height: 36rpx;margin-left: 10rpx;width: 80%;"></view>
<view style="font-size: 28rpx;width: 10%;width: 14%;text-align: right;">{{item.Content.time}}</view>
</view>
</view>
</view>
</template>

<script>
var util = require("../../utils/util.js");
var config = require("../../config");
export default {
data() {
return {
customerId:'',
listarr:[],
id:'',
type:'',
tipsFncName: '', // 提醒页面变更的值
from: '', // 标记需要刷新的来源
};
},
onLoad: function(options) {
this.customerId = options.customerId;
this.id=options.id;
this.type=options.type;
if (options.UpDateEvent) this.tipsFncName = options.UpDateEvent
if (options.from) this.from = options.from
this.searchinfo()
},
methods: {
formatTime(num) {
//格式化时间格式
num = num.toFixed(0);
let second = num % 60;
if (second < 10) second = '0' + second;
let min = Math.floor(num / 60);
if (min < 10) min = '0' + min;
return min + ":" + second;
},
//搜索
searchinfo(){
let parames={
marketingId:this.id,
customerId:this.customerId,
type:this.type
}
this.$u.post("/corpus/pinWordMatching", parames).then(res => {
res.forEach(item=>{
item.Content=JSON.parse(item.transferContent)
})
res.forEach(cet=>{
cet.Content.time=this.formatTime(cet.Content.bg/1000)
})
this.listarr=res;
})
},
//跳转
toaidoinfo(item,id,index){
item.customerId=this.customerId;
item.id=id;
item.index=index;
this.infostust(item)
},
//只有一条的时候
infostust(item){
console.log("zobudao")
let d = JSON.parse(JSON.stringify([item]))
d[0].onebest="";
console.log(d)
const parames = {
pageNum: 1,
pageSize: 100,
query: {
customerId: this.customerId,
}
}
this.$u.post("/corpus/findByPage", parames).then(res => {
uni.setStorageSync("entrance", 2); //写入缓存
uni.setStorageSync("searchobj", d[0]); //写入缓存
if(res[0].merge==0){
let newobj = res[0];
if (this.tipsFncName) {
uni.$emit(this.tipsFncName, d[0])
uni.$emit('newobjStatus', newobj.status)
uni.navigateBack()
return
}
uni.navigateTo({
url: `/pages/mine/details2?customerId=${newobj.customerId}&status=${newobj.status}&itemobj=${JSON.stringify(d[0])}&stateisshow=${'2'}`
})
}else{
let newobj = res[0];
uni.navigateTo({
url: `/pages/mine/details?customerId=${newobj.customerId}&status=${newobj.status}&itemobj=${JSON.stringify(d[0])}&stateisshow=${'2'}`
})
}
})
},
},
}
</script>
<style lang="scss" scoped>

</style>

+ 237
- 0
pages/mine/calibration.vue View File

@@ -0,0 +1,237 @@
<template>
<view class="box">

<view class="conmsg" v-if="allList.length!=0">
<view class="conmsg-msg">
<view v-for="(item,index) in allList" :key="index">
<view class="">
<view class="conmsg-msg-lab" style="border: none;">
<view class="conmsg-msg-lab-1">
{{item.name}}
</view>
</view>
<view class="con-msg-con"
:style="{borderBottom:index==allList.length-1?'none':'1px solid #E0E0E0'}">
<view v-for='(item1,i) in item.children' :key='i' @click="Edittag(item,item1,index,i)"
:style="{border:item1.selected==0?'1px solid #0A6EE9':'1px solid #E0E0E0'}"
class="chebox">
{{item1.label}}
</view>
</view>
</view>
</view>
</view>
</view>

<view class="submit">
<view class="btn" @click="submit">
确定
</view>
</view>
<view class="" style="height: 220rpx;"></view>
</view>
</template>

<script>
export default {
data() {
return {
allList:[],
customerId:''
}
},
onLoad(e) {
this.customerId=e.id;
this.getListByType()
},
methods: {
Edittag(item,item1,index,i){
if(this.allList[index].children[i].selected==0){
this.allList[index].children[i].selected=1;
}else{
this.allList[index].children[i].selected=0;
}
this.$forceUpdate()
},
// 字典表接口
getListByType() {
this.$u.get("/matchKeywords/findManualCalibration", {
customerId: this.customerId,
type:2
})
.then(res => {
res.forEach(item1 => {
item1.children.map(item => {
if (item.isInterval == 0) {
item.label = item.name + item.unit + '-' + item.endName + item
.unit;
} else {
item.label = item.name
}
item.value = item.id;
})
})
this.allList = res
})
},
// 提交
submit() {
let param = {
keywordIds:'',
id: this.customerId,
}
let str = []
this.allList.map(item => {
item.children.map(item1 => {
if (item1.selected == 0) {
str.push(item1.keywordsId)
}
})
})
str = str.join(',')
param.keywordIds = str
this.$u.post("matchKeywords/updateManualCalibration", param).then(res => {
uni.showToast({
title: '操作成功',
icon: 'none',
success: () => {
let sdd={
keywordIds: this.customerId,
id: this.customerId,
bg:0,
speaker:0
}
let pages = getCurrentPages() //获取当前页面栈的信息
let prevPage = pages[pages.length - 2] //获取上一个页面
prevPage.setData({ //把需要回传的值保存到上一个页面
info: sdd
});
uni.navigateBack()
}
})
})
},
}
}
</script>

<style lang="scss" scoped>
.box {
width: 100%;
height: 100%;
background: #F8F8F8;
overflow: hidden;
}

.conmsg {
background: #FFFFFF;
margin-top: 20rpx;

.conmsg-title {
height: 92rpx;
line-height: 92rpx;
font-weight: bold;
padding: 0 30rpx;
// font-weight: 500;
color: #303030;
font-size: 32rpx;
border-bottom: 1px solid #E0E0E0;
}

.conmsg-msg {
padding: 0 30rpx;

.conmsg-msg-lab {
height: 102rpx;
display: flex;
font-size: 30rpx;
font-weight: 400;
color: #333333;
border-bottom: 1px solid #E0E0E0;
line-height: 102rpx;

.conmsg-msg-lab-1 {
display: flex;
min-width: 136rpx;

.star {
color: #E7483C;
line-height: 108rpx;
}
}

.conmsg-msg-lab-inp {
margin-top: 30rpx;
margin-left: 44rpx;

}

.conmsg-msg-lab-img {
width: 14rpx;
height: 30rpx;
margin-top: 6rpx;
margin-left: auto;

image {
width: 100%;
height: 100%;
}
}
}
}
}

.submit {
position: fixed;
bottom: 20rpx;
left: 20rpx;
height: 120rpx;
background: #FFFFFF;

.btn {
// margin: 60rpx auto;
text-align: center;
width: 690rpx;
height: 88rpx;
background: #2671E2;
border-radius: 8rpx;
font-size: 32tpx;
font-weight: 400;
color: #FFFFFF;
line-height: 88rpx;
}
}

.con-msg-con {
display: flex;
flex-wrap: wrap;
// justify-content: space-around;
border-bottom: 1px solid #E0E0E0;
padding-bottom: 16rpx;

.chebox {
// width: 20%;
height: 60rpx;
line-height: 60rpx;
// margin: 10rpx 0;
margin-bottom: 25rpx;
margin-right: 20rpx;
border: 1px solid #E0E0E0;
box-sizing: border-box;
padding: 0 10rpx;
}
}

.sexchose {
width: 120rpx;
height: 60rpx;
background: #FFFFFF;
border-radius: 4rpx;
border: 1px solid #E0E0E0;
text-align: center;
line-height: 60rpx;
margin-right: 20rpx;

}
</style>

+ 239
- 0
pages/mine/consultanonduty/index.vue View File

@@ -0,0 +1,239 @@
<template>
<view class="box">
<!-- 顾问选择 -->
<view class="nextcon">
下一位接待顾问:{{agentList[0].name||'没有下一位了'}}
</view>
<view class="tab">
<!-- <view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 0 }" @click="tabtimetap(0)">全部</view>
</view> -->
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 1 }" @click="tabtimetap(1)">排队顾问</view>
</view>
<view class="tabbox">
<view :class="{ activecllasscet: activeTotal == 2 }" @click="tabtimetap(2)">暂停顾问</view>
</view>
</view>
<view class="content">
<view v-if="activeAgentList.length>0">
<view v-for="(item,index) in activeAgentList" :key="index">
<view class="content-tips">
<view class="top">
<view class="tit">
<view class="img">
{{item.name.slice(0,1)}}
</view>
<view class="test">
{{item.name}}
</view>
</view>
<!-- <view class="state">
<view class="point" v-if="activeTotal==1"></view>
{{activeTotal==1?'接待中':'空闲'}}
</view> -->
</view>
<view class="reception">
<view class="" style="line-height: 50rpx;">
今日接待:<test class="num">{{item.receiveNum||0}}</test>
</view>
<view class="btn" @click="changeAgentStatus(item.agentId)">
{{activeTotal==1?'暂停':'恢复'}}
</view>
</view>
</view>
</view>
</view>
<view class="nolist" v-else>
暂无数据
</view>
</view>
</view>
</template>

<script>
export default {
data(){
return{
value:"",
activeTotal: 1,
agentList:[],
pausedAgentList:[],
houseId:''
}
},
onLoad() {
this.houseId = uni.getStorageSync('buildingID').id;
this.changeAgentListShow()
this.changePausedAgentListShow()
},
onPullDownRefresh() {
this.changeAgentListShow()
this.changePausedAgentListShow()
setTimeout(function () {
uni.stopPullDownRefresh();
}, 1000);
},
computed: {
activeAgentList() {
return this.activeTotal == 1 ? this.agentList : this.pausedAgentList
},
},
methods:{
tabtimetap(idx){
// console.log(idx)
this.activeTotal=idx
},
changeAgentListShow() {
this.$u.get("/zkAgentPool/nextFreeAgent?itemId="+this.houseId).then(res => {
this.agentList = res;
})
},
// 获取暂停的经纪人列表
changePausedAgentListShow() {
this.$u.get("/zkAgentPool/stopAgentList?itemId="+this.houseId).then(res => {
this.pausedAgentList = res;
})
},
changeAgentStatus(id) {
let content = "";
if (this.activeTotal == 1) {
content = "确定当前顾问暂停接待?";
} else {
content = "确定取消暂停?";
}
uni.showModal({
content,
cancelColor: "#999999",
success: res => {
if (res.confirm) {
this.$u.get("/zkAgentPool/update", {
agentId: id,
status: this.activeTotal == 1 ? 2 : 0
}).then(res => {
uni.showToast({
icon: "none",
title: "操作成功",
})
this.changeAgentListShow()
this.changePausedAgentListShow()
})
}
},
})
},
}
}
</script>

<style lang="scss" scoped>
.box{
background: #F8F8F8;
width: 100%;
height: 100vh;
font-size: 30rpx;
font-weight: 400;
// line-height: 30px;
.tab{
height: 88rpx;
border-bottom: 1px solid #E0E0E0;
background: #FFFFFF;
display: flex;
align-items: center;
.tabbox {
flex: 1;
height: 100%;
text-align: center;
line-height: 92rpx;
color: #666666;
font-size: 28rpx;
display: flex;
justify-content: center;
.activecllasscet {
border-bottom: 2px solid #2671E2;
color: #2671E2;
font-weight: 600;
}
}
}
.nextcon{
height: 78rpx;
background: #F4F8FD;
color: #2671E2;
text-align: center;
line-height: 78rpx;
}
.content-tips{
background: #fff;
padding: 0 30rpx;
height: 168rpx;
margin-bottom: 20rpx;
overflow: hidden;
.top{
margin-top: 19rpx;
display: flex;
justify-content: space-between;
.tit{
height: 52rpx;
display: flex;
.img{
width: 52rpx;
height: 52rpx;
border-radius: 50%;
line-height: 47rpx;
text-align: center;
background: #FFFFFF;
border: 1px solid #C9C9C9;
margin-right: 20rpx;
}
.test{
font-weight: 600;
color: #333333;
margin-top: 6rpx;
}
}
.state{
display: flex;
.point{
width: 12rpx;
height: 12rpx;
background: #2B6EFF;
border-radius: 50%;
margin-right: 9rpx;
margin-top: 16rpx;
}
}
}
.reception{
display: flex;
font-weight: 400;
width: 100%;
margin-top: 28rpx;
justify-content: space-between;
color: #666666;
line-height: 30rpx;
.btn{
width: 100rpx;
height: 48rpx;
background: #FFFFFF;
border-radius: 4rpx;
border: 1px solid #C9C9C9;
text-align: center;
line-height: 48rpx;
color: #333333;
font-size: 28rpx;
}
}
}
}
.nolist{
text-align: center;
height: 300rpx;
color: #CCCCCC;
line-height: 300rpx;
}
</style>

+ 1824
- 0
pages/mine/details.vue
File diff suppressed because it is too large
View File


Some files were not shown because too many files changed in this diff

||||||
x
 
000:0
Loading…
Cancel
Save